Reorganising the repository - external renames and moves (#4074)

* Adding first rough ouline of the repository structure

* Remove old CI stuff

* add title

* formatting fixes

* move node-exits job's script to scripts dir

* Move docs into subdir

* move to bin

* move maintainence scripts, configs and helpers into its own dir

* add .local to ignore

* move core->client

* start up 'test' area

* move test client

* move test runtime

* make test move compile

* Add dependencies rule enforcement.

* Fix indexing.

* Update docs to reflect latest changes

* Moving /srml->/paint

* update docs

* move client/sr-* -> primitives/

* clean old readme

* remove old broken code in rhd

* update lock

* Step 1.

* starting to untangle client

* Fix after merge.

* start splitting out client interfaces

* move children and blockchain interfaces

* Move trie and state-machine to primitives.

* Fix WASM builds.

* fixing broken imports

* more interface moves

* move backend and light to interfaces

* move CallExecutor

* move cli off client

* moving around more interfaces

* re-add consensus crates into the mix

* fix subkey path

* relieve client from executor

* starting to pull out client from grandpa

* move is_decendent_of out of client

* grandpa still depends on client directly

* lemme tests pass

* rename srml->paint

* Make it compile.

* rename interfaces->client-api

* Move keyring to primitives.

* fixup libp2p dep

* fix broken use

* allow dependency enforcement to fail

* move fork-tree

* Moving wasm-builder

* make env

* move build-script-utils

* fixup broken crate depdencies and names

* fix imports for authority discovery

* fix typo

* update cargo.lock

* fixing imports

* Fix paths and add missing crates

* re-add missing crates
This commit is contained in:
Benjamin Kampmann
2019-11-14 21:51:17 +01:00
committed by Bastian Köcher
parent becc3b0a4f
commit 60e5011c72
809 changed files with 7801 additions and 6464 deletions
@@ -0,0 +1,41 @@
[package]
name = "substrate-runtime-interface"
version = "2.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
wasm-interface = { package = "substrate-wasm-interface", path = "../wasm-interface", optional = true }
rstd = { package = "sr-std", path = "../sr-std", default-features = false }
substrate-runtime-interface-proc-macro = { path = "proc-macro" }
externalities = { package = "substrate-externalities", path = "../externalities", optional = true }
codec = { package = "parity-scale-codec", version = "1.0.6", default-features = false }
environmental = { version = "1.0.2", optional = true }
static_assertions = "1.0.0"
primitive-types = { version = "0.6.1", default-features = false }
[dev-dependencies]
executor = { package = "substrate-executor", path = "../../client/executor" }
test-wasm = { package = "substrate-runtime-interface-test-wasm", path = "test-wasm" }
state_machine = { package = "substrate-state-machine", path = "../../primitives/state-machine" }
primitives = { package = "substrate-primitives", path = "../core" }
runtime-io = { package = "sr-io", path = "../sr-io" }
[features]
default = [ "std" ]
std = [
"wasm-interface",
"rstd/std",
"codec/std",
"externalities",
"environmental",
"primitive-types/std",
]
# ATTENTION
#
# Only use when you know what you are doing.
#
# Disables static assertions in `impls.rs` that checks the word size. To prevent any footgun, the
# check is changed into a runtime check.
disable_target_static_assertions = []
@@ -0,0 +1,27 @@
[package]
name = "substrate-runtime-interface-proc-macro"
version = "2.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[lib]
proc-macro = true
[dependencies]
syn = { version = "1.0.5", features = [ "full", "visit", "fold", "extra-traits" ] }
quote = "1.0.2"
proc-macro2 = "1.0.3"
Inflector = "0.11.4"
proc-macro-crate = "0.1.4"
[dev-dependencies]
runtime-interface = { package = "substrate-runtime-interface", path = ".." }
codec = { package = "parity-scale-codec", version = "1.0.6", features = [ "derive" ] }
externalities = { package = "substrate-externalities", path = "../../externalities" }
rustversion = "1.0.0"
trybuild = "1.0.17"
# We actually don't need the `std` feature in this crate, but the tests require it.
[features]
default = [ "std" ]
std = []
@@ -0,0 +1,265 @@
// 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 <http://www.gnu.org/licenses/>.
//! This crate provides procedural macros for usage within the context of the Substrate runtime
//! interface.
//!
//! The following macros are provided:
//!
//! 1. The [`#[runtime_interface]`](attr.runtime_interface.html) attribute macro for generating the
//! runtime interfaces.
//! 2. The [`PassByCodec`](derive.PassByCodec.html) derive macro for implementing `PassBy` with `Codec`.
//! 3. The [`PassByEnum`](derive.PassByInner.html) derive macro for implementing `PassBy` with `Enum`.
//! 4. The [`PassByInner`](derive.PassByInner.html) derive macro for implementing `PassBy` with `Inner`.
extern crate proc_macro;
use syn::{parse_macro_input, ItemTrait, DeriveInput};
mod pass_by;
mod runtime_interface;
mod utils;
/// Attribute macro for transforming a trait declaration into a runtime interface.
///
/// A runtime interface is a fixed interface between a Substrate compatible runtime and the native
/// node. This interface is callable from a native and a wasm runtime. The macro will generate the
/// corresponding code for the native implementation and the code for calling from the wasm
/// side to the native implementation.
///
/// The macro expects the runtime interface declaration as trait declaration:
///
/// ```
/// # use runtime_interface::runtime_interface;
///
/// #[runtime_interface]
/// trait Interface {
/// /// A function that can be called from native/wasm.
/// ///
/// /// The implementation given to this function is only compiled on native.
/// fn call_some_complex_code(data: &[u8]) -> Vec<u8> {
/// // Here you could call some rather complex code that only compiles on native or
/// // is way faster in native than executing it in wasm.
/// Vec::new()
/// }
///
/// /// A function can take a `&self` or `&mut self` argument to get access to the
/// /// `Externalities`. (The generated method does not require
/// /// this argument, so the function can be called just with the `optional` argument)
/// fn set_or_clear(&mut self, optional: Option<Vec<u8>>) {
/// match optional {
/// Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value),
/// None => self.clear_storage(&[1, 2, 3, 4]),
/// }
/// }
/// }
/// ```
///
///
/// The given example will generate roughly the following code for native:
///
/// ```
/// // The name of the trait is converted to snake case and used as mod name.
/// //
/// // Be aware that this module is not `public`, the visibility of the module is determined based
/// // on the visibility of the trait declaration.
/// mod interface {
/// trait Interface {
/// fn call_some_complex_code(data: &[u8]) -> Vec<u8>;
/// fn set_or_clear(&mut self, optional: Option<Vec<u8>>);
/// }
///
/// impl Interface for &mut dyn externalities::Externalities {
/// fn call_some_complex_code(data: &[u8]) -> Vec<u8> { Vec::new() }
/// fn set_or_clear(&mut self, optional: Option<Vec<u8>>) {
/// match optional {
/// Some(value) => self.set_storage([1, 2, 3, 4].to_vec(), value),
/// None => self.clear_storage(&[1, 2, 3, 4]),
/// }
/// }
/// }
///
/// pub fn call_some_complex_code(data: &[u8]) -> Vec<u8> {
/// <&mut dyn externalities::Externalities as Interface>::call_some_complex_code(data)
/// }
///
/// pub fn set_or_clear(optional: Option<Vec<u8>>) {
/// externalities::with_externalities(|mut ext| Interface::set_or_clear(&mut ext, optional))
/// .expect("`set_or_clear` called outside of an Externalities-provided environment.")
/// }
///
/// /// This type implements the `HostFunctions` trait (from `substrate-wasm-interface`) and
/// /// provides the host implementation for the wasm side. The host implementation converts the
/// /// arguments from wasm to native and calls the corresponding native function.
/// ///
/// /// This type needs to be passed to the wasm executor, so that the host functions will be
/// /// registered in the executor.
/// pub struct HostFunctions;
/// }
/// ```
///
///
/// The given example will generate roughly the following code for wasm:
///
/// ```
/// mod interface {
/// mod extern_host_functions_impls {
/// extern "C" {
/// /// Every function is exported as `ext_TRAIT_NAME_FUNCTION_NAME_version_VERSION`.
/// ///
/// /// `TRAIT_NAME` is converted into snake case.
/// ///
/// /// The type for each argument of the exported function depends on
/// /// `<ARGUMENT_TYPE as RIType>::FFIType`.
/// ///
/// /// `data` holds the pointer and the length to the `[u8]` slice.
/// pub fn ext_Interface_call_some_complex_code_version_1(data: u64) -> u64;
/// /// `optional` holds the pointer and the length of the encoded value.
/// pub fn ext_Interface_set_or_clear_version_1(optional: u64);
/// }
/// }
///
/// /// The type is actually `ExchangeableFunction` (from `substrate-runtime-interface`).
/// ///
/// /// This can be used to replace the implementation of the `call_some_complex_code` function.
/// /// Instead of calling into the host, the callee will automatically call the other
/// /// implementation.
/// ///
/// /// To replace the implementation:
/// ///
/// /// `host_call_some_complex_code.replace_implementation(some_other_impl)`
/// pub static host_call_some_complex_code: () = ();
/// pub static host_set_or_clear: () = ();
///
/// pub fn call_some_complex_code(data: &[u8]) -> Vec<u8> {
/// // This is the actual call: `host_call_some_complex_code.get()(data)`
/// //
/// // But that does not work for several reasons in this example, so we just return an
/// // empty vector.
/// Vec::new()
/// }
///
/// pub fn set_or_clear(optional: Option<Vec<u8>>) {
/// // Same as above
/// }
/// }
/// ```
///
/// # Argument types
///
/// The macro supports any kind of argument type, as long as it implements `RIType` and the required
/// `FromFFIValue`/`IntoFFIValue` from `substrate-runtime-interface`. The macro will convert each
/// argument to the corresponding FFI representation and will call into the host using this FFI
/// representation. On the host each argument is converted back to the native representation and
/// the native implementation is called. Any return value is handled in the same way.
///
/// # Wasm only interfaces
///
/// Some interfaces are only required from within the wasm runtime e.g. the allocator interface.
/// To support this, the macro can be called like `#[runtime_interface(wasm_only)]`. This instructs
/// the macro to make two significant changes to the generated code:
///
/// 1. The generated functions are not callable from the native side.
/// 2. The trait as shown above is not implemented for `Externalities` and is instead implemented
/// for `FunctionExecutor` (from `substrate-wasm-interface`).
#[proc_macro_attribute]
pub fn runtime_interface(
attrs: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let trait_def = parse_macro_input!(input as ItemTrait);
let wasm_only = parse_macro_input!(attrs as Option<runtime_interface::keywords::wasm_only>);
runtime_interface::runtime_interface_impl(trait_def, wasm_only.is_some())
.unwrap_or_else(|e| e.to_compile_error())
.into()
}
/// Derive macro for implementing `PassBy` with the `Codec` strategy.
///
/// This requires that the type implements `Encode` and `Decode` from `parity-scale-codec`.
///
/// # Example
///
/// ```
/// # use runtime_interface::pass_by::PassByCodec;
/// # use codec::{Encode, Decode};
/// #[derive(PassByCodec, Encode, Decode)]
/// struct EncodableType {
/// name: Vec<u8>,
/// param: u32,
/// }
/// ```
#[proc_macro_derive(PassByCodec)]
pub fn pass_by_codec(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
pass_by::codec_derive_impl(input).unwrap_or_else(|e| e.to_compile_error()).into()
}
/// Derive macro for implementing `PassBy` with the `Inner` strategy.
///
/// Besides implementing `PassBy`, this derive also implements the helper trait `PassByInner`.
///
/// The type is required to be a struct with just one field. The field type needs to implement
/// the required traits to pass it between the wasm and the native side. (See the runtime interface
/// crate for more information about these traits.)
///
/// # Example
///
/// ```
/// # use runtime_interface::pass_by::PassByInner;
/// #[derive(PassByInner)]
/// struct Data([u8; 32]);
/// ```
///
/// ```
/// # use runtime_interface::pass_by::PassByInner;
/// #[derive(PassByInner)]
/// struct Data {
/// data: [u8; 32],
/// }
/// ```
#[proc_macro_derive(PassByInner)]
pub fn pass_by_inner(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
pass_by::inner_derive_impl(input).unwrap_or_else(|e| e.to_compile_error()).into()
}
/// Derive macro for implementing `PassBy` with the `Enum` strategy.
///
/// Besides implementing `PassBy`, this derive also implements `TryFrom<u8>` and `From<Self> for u8`
/// for the type.
///
/// The type is required to be an enum with only unit variants and at maximum `256` variants. Also
/// it is required that the type implements `Copy`.
///
/// # Example
///
/// ```
/// # use runtime_interface::pass_by::PassByEnum;
/// #[derive(PassByEnum, Copy, Clone)]
/// enum Data {
/// Okay,
/// NotOkay,
/// // This will not work with the derive.
/// //Why(u32),
/// }
/// ```
#[proc_macro_derive(PassByEnum)]
pub fn pass_by_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
pass_by::enum_derive_impl(input).unwrap_or_else(|e| e.to_compile_error()).into()
}
@@ -0,0 +1,58 @@
// 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 <http://www.gnu.org/licenses/>.
//! Derive macro implementation of `PassBy` with the associated type set to `Codec`.
//!
//! It is required that the type implements `Encode` and `Decode` from the `parity-scale-codec`
//! crate.
use crate::utils::{generate_crate_access, generate_runtime_interface_include};
use syn::{DeriveInput, Result, Generics, parse_quote};
use quote::quote;
use proc_macro2::TokenStream;
/// The derive implementation for `PassBy` with `Codec`.
pub fn derive_impl(mut input: DeriveInput) -> Result<TokenStream> {
add_trait_bounds(&mut input.generics);
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let crate_include = generate_runtime_interface_include();
let crate_ = generate_crate_access();
let ident = input.ident;
let res = quote! {
const _: () = {
#crate_include
impl #impl_generics #crate_::pass_by::PassBy for #ident #ty_generics #where_clause {
type PassBy = #crate_::pass_by::Codec<#ident>;
}
};
};
Ok(res)
}
/// Add the `codec::Codec` trait bound to every type parameter.
fn add_trait_bounds(generics: &mut Generics) {
let crate_ = generate_crate_access();
generics.type_params_mut()
.for_each(|type_param| type_param.bounds.push(parse_quote!(#crate_::codec::Codec)));
}
@@ -0,0 +1,101 @@
// 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 <http://www.gnu.org/licenses/>.
//! Derive macro implementation of `PassBy` with the associated type set to `Enum`.
//!
//! Besides `PassBy`, `TryFrom<u8>` and `From<Self> for u8` are implemented for the type.
use crate::utils::{generate_crate_access, generate_runtime_interface_include};
use syn::{DeriveInput, Result, Data, Fields, Error, Ident};
use quote::quote;
use proc_macro2::{TokenStream, Span};
/// The derive implementation for `PassBy` with `Enum`.
pub fn derive_impl(input: DeriveInput) -> Result<TokenStream> {
let crate_include = generate_runtime_interface_include();
let crate_ = generate_crate_access();
let ident = input.ident;
let enum_fields = get_enum_field_idents(&input.data)?
.enumerate()
.map(|(i, v)| {
let i = i as u8;
v.map(|v| (quote!(#i => Ok(#ident::#v)), quote!(#ident::#v => #i)))
})
.collect::<Result<Vec<_>>>()?;
let try_from_variants = enum_fields.iter().map(|i| &i.0);
let into_variants = enum_fields.iter().map(|i| &i.1);
let res = quote! {
const _: () = {
#crate_include
impl #crate_::pass_by::PassBy for #ident {
type PassBy = #crate_::pass_by::Enum<#ident>;
}
impl #crate_::rstd::convert::TryFrom<u8> for #ident {
type Error = ();
fn try_from(inner: u8) -> #crate_::rstd::result::Result<Self, ()> {
match inner {
#( #try_from_variants, )*
_ => Err(()),
}
}
}
impl From<#ident> for u8 {
fn from(var: #ident) -> u8 {
match var {
#( #into_variants ),*
}
}
}
};
};
Ok(res)
}
/// Get the enum fields idents of the given `data` object as iterator.
///
/// Returns an error if the number of variants is greater than `256`, the given `data` is not an
/// enum or a variant is not an unit.
fn get_enum_field_idents<'a>(data: &'a Data) -> Result<impl Iterator<Item = Result<&'a Ident>>> {
match data {
Data::Enum(d) => {
if d.variants.len() <= 256 {
Ok(
d.variants.iter().map(|v| if let Fields::Unit = v.fields {
Ok(&v.ident)
} else {
Err(Error::new(
Span::call_site(),
"`PassByEnum` only supports unit variants.",
))
})
)
} else {
Err(Error::new(Span::call_site(), "`PassByEnum` only supports `256` variants."))
}
},
_ => Err(Error::new(Span::call_site(), "`PassByEnum` only supports enums as input type."))
}
}
@@ -0,0 +1,110 @@
// 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 <http://www.gnu.org/licenses/>.
//! Derive macro implementation of `PassBy` with the associated type set to `Inner` and of the
//! helper trait `PassByInner`.
//!
//! It is required that the type is a newtype struct, otherwise an error is generated.
use crate::utils::{generate_crate_access, generate_runtime_interface_include};
use syn::{DeriveInput, Result, Generics, parse_quote, Type, Data, Error, Fields, Ident};
use quote::quote;
use proc_macro2::{TokenStream, Span};
/// The derive implementation for `PassBy` with `Inner` and `PassByInner`.
pub fn derive_impl(mut input: DeriveInput) -> Result<TokenStream> {
add_trait_bounds(&mut input.generics);
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let crate_include = generate_runtime_interface_include();
let crate_ = generate_crate_access();
let ident = input.ident;
let (inner_ty, inner_name) = extract_inner_ty_and_name(&input.data)?;
let access_inner = match inner_name {
Some(ref name) => quote!(self.#name),
None => quote!(self.0),
};
let from_inner = match inner_name {
Some(name) => quote!(Self { #name: inner }),
None => quote!(Self(inner)),
};
let res = quote! {
const _: () = {
#crate_include
impl #impl_generics #crate_::pass_by::PassBy for #ident #ty_generics #where_clause {
type PassBy = #crate_::pass_by::Inner<#ident, #inner_ty>;
}
impl #impl_generics #crate_::pass_by::PassByInner for #ident #ty_generics #where_clause {
type Inner = #inner_ty;
fn into_inner(self) -> Self::Inner {
#access_inner
}
fn inner(&self) -> &Self::Inner {
&#access_inner
}
fn from_inner(inner: Self::Inner) -> Self {
#from_inner
}
}
};
};
Ok(res)
}
/// Add the `RIType` trait bound to every type parameter.
fn add_trait_bounds(generics: &mut Generics) {
let crate_ = generate_crate_access();
generics.type_params_mut()
.for_each(|type_param| type_param.bounds.push(parse_quote!(#crate_::RIType)));
}
/// Extract the inner type and optional name from given input data.
///
/// It also checks that the input data is a newtype struct.
fn extract_inner_ty_and_name(data: &Data) -> Result<(Type, Option<Ident>)> {
if let Data::Struct(ref struct_data) = data {
match struct_data.fields {
Fields::Named(ref named) if named.named.len() == 1 => {
let field = &named.named[0];
return Ok((field.ty.clone(), field.ident.clone()))
},
Fields::Unnamed(ref unnamed) if unnamed.unnamed.len() == 1 => {
let field = &unnamed.unnamed[0];
return Ok((field.ty.clone(), field.ident.clone()))
}
_ => {},
}
}
Err(
Error::new(
Span::call_site(),
"Only newtype/one field structs are supported by `PassByInner`!",
)
)
}
@@ -0,0 +1,25 @@
// 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 <http://www.gnu.org/licenses/>.
//! All the `PassBy*` derive implementations.
mod codec;
mod enum_;
mod inner;
pub use self::codec::derive_impl as codec_derive_impl;
pub use enum_::derive_impl as enum_derive_impl;
pub use inner::derive_impl as inner_derive_impl;
@@ -0,0 +1,186 @@
// 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 <http://www.gnu.org/licenses/>.
//! Generates the bare function interface for a given trait definition.
//!
//! The bare functions are the ones that will be called by the user. On the native/host side, these
//! functions directly execute the provided implementation. On the wasm side, these
//! functions will prepare the parameters for the FFI boundary, call the external host function
//! exported into wasm and convert back the result.
//!
//! [`generate`](bare_function_interface::generate) is the entry point for generating for each
//! trait method one bare function.
//!
//! [`function_for_method`](bare_function_interface::function_for_method) generates the bare
//! function per trait method. Each bare function contains both implementations. The implementations
//! are feature-gated, so that one is compiled for the native and the other for the wasm side.
use crate::utils::{
generate_crate_access, create_exchangeable_host_function_ident, get_function_arguments,
get_function_argument_names, get_trait_methods,
};
use syn::{
Ident, ItemTrait, TraitItemMethod, FnArg, Signature, Result, spanned::Spanned, parse_quote,
};
use proc_macro2::{TokenStream, Span};
use quote::{quote, quote_spanned};
use std::iter;
/// Generate one bare function per trait method. The name of the bare function is equal to the name
/// of the trait method.
pub fn generate(trait_def: &ItemTrait, is_wasm_only: bool) -> Result<TokenStream> {
let trait_name = &trait_def.ident;
get_trait_methods(trait_def).try_fold(TokenStream::new(), |mut t, m| {
t.extend(function_for_method(trait_name, m, is_wasm_only)?);
Ok(t)
})
}
/// Generates the bare function implementation for the given method for the host and wasm side.
fn function_for_method(
trait_name: &Ident,
method: &TraitItemMethod,
is_wasm_only: bool,
) -> Result<TokenStream> {
let std_impl = function_std_impl(trait_name, method, is_wasm_only)?;
let no_std_impl = function_no_std_impl(method)?;
Ok(
quote! {
#std_impl
#no_std_impl
}
)
}
/// Generates the bare function implementation for `cfg(not(feature = "std"))`.
fn function_no_std_impl(method: &TraitItemMethod) -> Result<TokenStream> {
let function_name = &method.sig.ident;
let host_function_name = create_exchangeable_host_function_ident(&method.sig.ident);
let args = get_function_arguments(&method.sig);
let arg_names = get_function_argument_names(&method.sig);
let return_value = &method.sig.output;
let attrs = &method.attrs;
Ok(
quote! {
#[cfg(not(feature = "std"))]
#( #attrs )*
pub fn #function_name( #( #args, )* ) #return_value {
// Call the host function
#host_function_name.get()( #( #arg_names, )* )
}
}
)
}
/// Generates the bare function implementation for `cfg(feature = "std")`.
fn function_std_impl(
trait_name: &Ident,
method: &TraitItemMethod,
is_wasm_only: bool,
) -> Result<TokenStream> {
let function_name = &method.sig.ident;
let crate_ = generate_crate_access();
let args = get_function_arguments(&method.sig).map(FnArg::Typed).chain(
// Add the function context as last parameter when this is a wasm only interface.
iter::from_fn(||
if is_wasm_only {
Some(
parse_quote!(
mut __function_context__: &mut dyn #crate_::wasm_interface::FunctionContext
)
)
} else {
None
}
).take(1),
);
let return_value = &method.sig.output;
let attrs = &method.attrs;
// Don't make the function public accessible when this is a wasm only interface.
let vis = if is_wasm_only { quote!() } else { quote!(pub) };
let call_to_trait = generate_call_to_trait(trait_name, method, is_wasm_only);
Ok(
quote_spanned! { method.span() =>
#[cfg(feature = "std")]
#( #attrs )*
#vis fn #function_name( #( #args, )* ) #return_value {
#call_to_trait
}
}
)
}
/// Generate the call to the interface trait.
fn generate_call_to_trait(
trait_name: &Ident,
method: &TraitItemMethod,
is_wasm_only: bool,
) -> TokenStream {
let crate_ = generate_crate_access();
let method_name = &method.sig.ident;
let expect_msg = format!(
"`{}` called outside of an Externalities-provided environment.",
method_name,
);
let arg_names = get_function_argument_names(&method.sig);
if takes_self_argument(&method.sig) {
let instance = if is_wasm_only {
Ident::new("__function_context__", Span::call_site())
} else {
Ident::new("__externalities__", Span::call_site())
};
let impl_ = quote!( #trait_name::#method_name(&mut #instance, #( #arg_names, )*) );
if is_wasm_only {
quote_spanned! { method.span() => #impl_ }
} else {
quote_spanned! { method.span() =>
#crate_::with_externalities(|mut #instance| #impl_).expect(#expect_msg)
}
}
} else {
// The name of the trait the interface trait is implemented for
let impl_trait_name = if is_wasm_only {
quote!( #crate_::wasm_interface::FunctionContext )
} else {
quote!( #crate_::Externalities )
};
quote_spanned! { method.span() =>
<&mut dyn #impl_trait_name as #trait_name>::#method_name(
#( #arg_names, )*
)
}
}
}
/// Returns if the given `Signature` takes a `self` argument.
fn takes_self_argument(sig: &Signature) -> bool {
match sig.inputs.first() {
Some(FnArg::Receiver(_)) => true,
_ => false,
}
}
@@ -0,0 +1,415 @@
// 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 <http://www.gnu.org/licenses/>.
//! Generates the extern host functions and the implementation for these host functions.
//!
//! The extern host functions will be called by the bare function interface from the Wasm side.
//! The implementation of these host functions will be called on the host side from the Wasm
//! executor. These implementations call the bare function interface.
use crate::utils::{
generate_crate_access, create_host_function_ident, get_function_argument_names,
get_function_argument_types_without_ref, get_function_argument_types_ref_and_mut,
get_function_argument_names_and_types_without_ref, get_trait_methods, get_function_arguments,
get_function_argument_types, create_exchangeable_host_function_ident,
};
use syn::{
ItemTrait, TraitItemMethod, Result, ReturnType, Ident, TraitItem, Pat, Error, Signature,
spanned::Spanned,
};
use proc_macro2::{TokenStream, Span};
use quote::{quote, ToTokens};
use inflector::Inflector;
use std::iter::{Iterator, self};
/// Generate the extern host functions for wasm and the `HostFunctions` struct that provides the
/// implementations for the host functions on the host.
pub fn generate(trait_def: &ItemTrait, is_wasm_only: bool) -> Result<TokenStream> {
let trait_name = &trait_def.ident;
let extern_host_function_impls = get_trait_methods(trait_def)
.try_fold(TokenStream::new(), |mut t, m| {
t.extend(generate_extern_host_function(m, trait_name)?);
Ok::<_, Error>(t)
})?;
let exchangeable_host_functions = get_trait_methods(trait_def)
.try_fold(TokenStream::new(), |mut t, m| {
t.extend(generate_exchangeable_host_function(m)?);
Ok::<_, Error>(t)
})?;
let host_functions_struct = generate_host_functions_struct(trait_def, is_wasm_only)?;
Ok(
quote! {
/// The implementations of the extern host functions. This special implementation module
/// is required to change the extern host functions signature to
/// `unsafe fn name(args) -> ret` to make the function implementations exchangeable.
#[cfg(not(feature = "std"))]
mod extern_host_function_impls {
use super::*;
#extern_host_function_impls
}
#exchangeable_host_functions
#host_functions_struct
}
)
}
/// Generate the extern host function for the given method.
fn generate_extern_host_function(method: &TraitItemMethod, trait_name: &Ident) -> Result<TokenStream> {
let crate_ = generate_crate_access();
let args = get_function_arguments(&method.sig);
let arg_types = get_function_argument_types_without_ref(&method.sig);
let arg_types2 = get_function_argument_types_without_ref(&method.sig);
let arg_names = get_function_argument_names(&method.sig);
let arg_names2 = get_function_argument_names(&method.sig);
let arg_names3 = get_function_argument_names(&method.sig);
let function = &method.sig.ident;
let ext_function = create_host_function_ident(&method.sig.ident, trait_name);
let doc_string = format!(
" Default extern host function implementation for [`super::{}`].",
method.sig.ident,
);
let return_value = &method.sig.output;
let ffi_return_value = match method.sig.output {
ReturnType::Default => quote!(),
ReturnType::Type(_, ref ty) => quote! {
-> <#ty as #crate_::RIType>::FFIType
},
};
let convert_return_value = match return_value {
ReturnType::Default => quote!(),
ReturnType::Type(_, ref ty) => quote! {
<#ty as #crate_::wasm::FromFFIValue>::from_ffi_value(result)
}
};
Ok(
quote! {
#[doc = #doc_string]
pub fn #function ( #( #args ),* ) #return_value {
extern "C" {
/// The extern function.
pub fn #ext_function (
#( #arg_names: <#arg_types as #crate_::RIType>::FFIType ),*
) #ffi_return_value;
}
// Generate all wrapped ffi values.
#(
let #arg_names2 = <#arg_types2 as #crate_::wasm::IntoFFIValue>::into_ffi_value(
&#arg_names2,
);
)*
let result = unsafe { #ext_function( #( #arg_names3.get() ),* ) };
#convert_return_value
}
}
)
}
/// Generate the host exchangeable function for the given method.
fn generate_exchangeable_host_function(method: &TraitItemMethod) -> Result<TokenStream> {
let crate_ = generate_crate_access();
let arg_types = get_function_argument_types(&method.sig);
let function = &method.sig.ident;
let exchangeable_function = create_exchangeable_host_function_ident(&method.sig.ident);
let doc_string = format!(" Exchangeable host function used by [`{}`].", method.sig.ident);
let output = &method.sig.output;
Ok(
quote! {
#[cfg(not(feature = "std"))]
#[allow(non_upper_case_globals)]
#[doc = #doc_string]
pub static #exchangeable_function : #crate_::wasm::ExchangeableFunction<
fn ( #( #arg_types ),* ) #output
> = #crate_::wasm::ExchangeableFunction::new(extern_host_function_impls::#function);
}
)
}
/// Generate the `HostFunctions` struct that implements `wasm-interface::HostFunctions` to provide
/// implementations for the extern host functions.
fn generate_host_functions_struct(trait_def: &ItemTrait, is_wasm_only: bool) -> Result<TokenStream> {
let crate_ = generate_crate_access();
let host_functions = trait_def
.items
.iter()
.filter_map(|i| match i {
TraitItem::Method(ref method) => Some(method),
_ => None,
})
.map(|m| generate_host_function_implementation(&trait_def.ident, m, is_wasm_only))
.collect::<Result<Vec<_>>>()?;
Ok(
quote! {
/// Provides implementations for the extern host functions.
#[cfg(feature = "std")]
pub struct HostFunctions;
#[cfg(feature = "std")]
impl #crate_::wasm_interface::HostFunctions for HostFunctions {
fn host_functions() -> Vec<&'static dyn #crate_::wasm_interface::Function> {
vec![ #( #host_functions ),* ]
}
}
}
)
}
/// Generates the host function struct that implements `wasm_interface::Function` and returns a static
/// reference to this struct.
///
/// When calling from wasm into the host, we will call the `execute` function that calls the native
/// implementation of the function.
fn generate_host_function_implementation(
trait_name: &Ident,
method: &TraitItemMethod,
is_wasm_only: bool,
) -> Result<TokenStream> {
let name = create_host_function_ident(&method.sig.ident, trait_name).to_string();
let struct_name = Ident::new(&name.to_pascal_case(), Span::call_site());
let crate_ = generate_crate_access();
let signature = generate_wasm_interface_signature_for_host_function(&method.sig)?;
let wasm_to_ffi_values = generate_wasm_to_ffi_values(
&method.sig,
trait_name,
).collect::<Result<Vec<_>>>()?;
let ffi_to_host_values = generate_ffi_to_host_value(&method.sig).collect::<Result<Vec<_>>>()?;
let host_function_call = generate_host_function_call(&method.sig, is_wasm_only);
let into_preallocated_ffi_value = generate_into_preallocated_ffi_value(&method.sig)?;
let convert_return_value = generate_return_value_into_wasm_value(&method.sig);
Ok(
quote! {
{
struct #struct_name;
#[allow(unused)]
impl #crate_::wasm_interface::Function for #struct_name {
fn name(&self) -> &str {
#name
}
fn signature(&self) -> #crate_::wasm_interface::Signature {
#signature
}
fn execute(
&self,
__function_context__: &mut dyn #crate_::wasm_interface::FunctionContext,
args: &mut dyn Iterator<Item = #crate_::wasm_interface::Value>,
) -> std::result::Result<Option<#crate_::wasm_interface::Value>, String> {
#( #wasm_to_ffi_values )*
#( #ffi_to_host_values )*
#host_function_call
#into_preallocated_ffi_value
#convert_return_value
}
}
&#struct_name as &dyn #crate_::wasm_interface::Function
}
}
)
}
/// Generate the `wasm_interface::Signature` for the given host function `sig`.
fn generate_wasm_interface_signature_for_host_function(sig: &Signature) -> Result<TokenStream> {
let crate_ = generate_crate_access();
let return_value = match &sig.output {
ReturnType::Type(_, ty) =>
quote! {
Some( <<#ty as #crate_::RIType>::FFIType as #crate_::wasm_interface::IntoValue>::VALUE_TYPE )
},
ReturnType::Default => quote!( None ),
};
let arg_types = get_function_argument_types_without_ref(sig)
.map(|ty| quote! {
<<#ty as #crate_::RIType>::FFIType as #crate_::wasm_interface::IntoValue>::VALUE_TYPE
});
Ok(
quote! {
#crate_::wasm_interface::Signature {
args: std::borrow::Cow::Borrowed(&[ #( #arg_types ),* ][..]),
return_value: #return_value,
}
}
)
}
/// Generate the code that converts the wasm values given to `HostFunctions::execute` into the FFI
/// values.
fn generate_wasm_to_ffi_values<'a>(
sig: &'a Signature,
trait_name: &'a Ident,
) -> impl Iterator<Item = Result<TokenStream>> + 'a {
let crate_ = generate_crate_access();
let function_name = &sig.ident;
let error_message = format!(
"Number of arguments given to `{}` does not match the expected number of arguments!",
function_name,
);
get_function_argument_names_and_types_without_ref(sig)
.map(move |(name, ty)| {
let try_from_error = format!(
"Could not instantiate `{}` from wasm value while executing `{}` from interface `{}`!",
name.to_token_stream(),
function_name,
trait_name,
);
let var_name = generate_ffi_value_var_name(&name)?;
Ok(quote! {
let val = args.next().ok_or_else(|| #error_message)?;
let #var_name = <
<#ty as #crate_::RIType>::FFIType as #crate_::wasm_interface::TryFromValue
>::try_from_value(val).ok_or_else(|| #try_from_error)?;
})
})
}
/// Generate the code to convert the ffi values on the host to the host values using `FromFFIValue`.
fn generate_ffi_to_host_value<'a>(
sig: &'a Signature,
) -> impl Iterator<Item = Result<TokenStream>> + 'a {
let mut_access = get_function_argument_types_ref_and_mut(sig);
let crate_ = generate_crate_access();
get_function_argument_names_and_types_without_ref(sig)
.zip(mut_access.map(|v| v.and_then(|m| m.1)))
.map(move |((name, ty), mut_access)| {
let ffi_value_var_name = generate_ffi_value_var_name(&name)?;
Ok(
quote! {
let #mut_access #name = <#ty as #crate_::host::FromFFIValue>::from_ffi_value(
__function_context__,
#ffi_value_var_name,
)?;
}
)
})
}
/// Generate the code to call the host function and the ident that stores the result.
fn generate_host_function_call(sig: &Signature, is_wasm_only: bool) -> TokenStream {
let host_function_name = &sig.ident;
let result_var_name = generate_host_function_result_var_name(&sig.ident);
let ref_and_mut = get_function_argument_types_ref_and_mut(sig).map(|ram|
ram.map(|(vr, vm)| quote!(#vr #vm))
);
let names = get_function_argument_names(sig);
let var_access = names.zip(ref_and_mut)
.map(|(n, ref_and_mut)| {
quote!( #ref_and_mut #n )
})
// If this is a wasm only interface, we add the function context as last parameter.
.chain(
iter::from_fn(|| if is_wasm_only { Some(quote!(__function_context__)) } else { None })
.take(1)
);
quote! {
let #result_var_name = #host_function_name ( #( #var_access ),* );
}
}
/// Generate the variable name that stores the result of the host function.
fn generate_host_function_result_var_name(name: &Ident) -> Ident {
Ident::new(&format!("{}_result", name), Span::call_site())
}
/// Generate the variable name that stores the FFI value.
fn generate_ffi_value_var_name(pat: &Pat) -> Result<Ident> {
match pat {
Pat::Ident(pat_ident) => {
if let Some(by_ref) = pat_ident.by_ref {
Err(Error::new(by_ref.span(), "`ref` not supported!"))
} else if let Some(sub_pattern) = &pat_ident.subpat {
Err(Error::new(sub_pattern.0.span(), "Not supported!"))
} else {
Ok(Ident::new(&format!("{}_ffi_value", pat_ident.ident), Span::call_site()))
}
}
_ => Err(Error::new(pat.span(), "Not supported as variable name!"))
}
}
/// Generate code that copies data from the host back to preallocated wasm memory.
///
/// Any argument that is given as `&mut` is interpreted as preallocated memory and it is expected
/// that the type implements `IntoPreAllocatedFFIValue`.
fn generate_into_preallocated_ffi_value(sig: &Signature) -> Result<TokenStream> {
let crate_ = generate_crate_access();
let ref_and_mut = get_function_argument_types_ref_and_mut(sig).map(|ram|
ram.and_then(|(vr, vm)| vm.map(|v| (vr, v)))
);
let names_and_types = get_function_argument_names_and_types_without_ref(sig);
ref_and_mut.zip(names_and_types)
.filter_map(|(ram, (name, ty))| ram.map(|_| (name, ty)))
.map(|(name, ty)| {
let ffi_var_name = generate_ffi_value_var_name(&name)?;
Ok(
quote! {
<#ty as #crate_::host::IntoPreallocatedFFIValue>::into_preallocated_ffi_value(
#name,
__function_context__,
#ffi_var_name,
)?;
}
)
})
.collect()
}
/// Generate the code that converts the return value into the appropriate wasm value.
fn generate_return_value_into_wasm_value(sig: &Signature) -> TokenStream {
let crate_ = generate_crate_access();
match &sig.output {
ReturnType::Default => quote!( Ok(None) ),
ReturnType::Type(_, ty) => {
let result_var_name = generate_host_function_result_var_name(&sig.ident);
quote! {
<#ty as #crate_::host::IntoFFIValue>::into_ffi_value(
#result_var_name,
__function_context__,
).map(#crate_::wasm_interface::IntoValue::into_value).map(Some)
}
}
}
}
@@ -0,0 +1,65 @@
// 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 <http://www.gnu.org/licenses/>.
use crate::utils::generate_runtime_interface_include;
use proc_macro2::{Span, TokenStream};
use syn::{Ident, ItemTrait, Result};
use inflector::Inflector;
use quote::quote;
mod bare_function_interface;
mod host_function_interface;
mod trait_decl_impl;
/// Custom keywords supported by the `runtime_interface` attribute.
pub mod keywords {
// Custom keyword `wasm_only` that can be given as attribute to [`runtime_interface`].
syn::custom_keyword!(wasm_only);
}
/// Implementation of the `runtime_interface` attribute.
///
/// It expects the trait definition the attribute was put above and if this should be an wasm only
/// interface.
pub fn runtime_interface_impl(trait_def: ItemTrait, is_wasm_only: bool) -> Result<TokenStream> {
let bare_functions = bare_function_interface::generate(&trait_def, is_wasm_only)?;
let crate_include = generate_runtime_interface_include();
let mod_name = Ident::new(&trait_def.ident.to_string().to_snake_case(), Span::call_site());
let trait_decl_impl = trait_decl_impl::process(&trait_def, is_wasm_only)?;
let host_functions = host_function_interface::generate(&trait_def, is_wasm_only)?;
let vis = trait_def.vis;
let attrs = &trait_def.attrs;
let res = quote! {
#( #attrs )*
#vis mod #mod_name {
use super::*;
#crate_include
#bare_functions
#trait_decl_impl
#host_functions
}
};
Ok(res)
}
@@ -0,0 +1,146 @@
// 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 <http://www.gnu.org/licenses/>.
//! Checks the trait declaration, makes the trait declaration module local, removes all method
//! default implementations and implements the trait for `&mut dyn Externalities`.
use crate::utils::{generate_crate_access, get_function_argument_types_without_ref};
use syn::{
ItemTrait, TraitItemMethod, Result, TraitItem, Error, fold::{self, Fold}, spanned::Spanned,
Visibility, Receiver, Type, Generics,
};
use proc_macro2::TokenStream;
use quote::quote;
/// Process the given trait definition, by checking that the definition is valid, fold it to the
/// essential definition and implement this essential definition for `dyn Externalities`.
pub fn process(trait_def: &ItemTrait, is_wasm_only: bool) -> Result<TokenStream> {
let impl_trait = impl_trait_for_externalities(trait_def, is_wasm_only)?;
let essential_trait_def = ToEssentialTraitDef::convert(trait_def.clone())?;
Ok(
quote! {
#impl_trait
#essential_trait_def
}
)
}
/// Converts the given trait definition into the essential trait definition without method
/// default implementations and visibility set to inherited.
struct ToEssentialTraitDef {
/// All errors found while doing the conversion.
errors: Vec<Error>,
}
impl ToEssentialTraitDef {
/// Convert the given trait definition to the essential trait definition.
fn convert(trait_def: ItemTrait) -> Result<ItemTrait> {
let mut folder = ToEssentialTraitDef {
errors: Vec::new(),
};
let res = folder.fold_item_trait(trait_def);
if let Some(first_error) = folder.errors.pop() {
Err(
folder.errors.into_iter().fold(first_error, |mut o, n| {
o.combine(n);
o
})
)
} else {
Ok(res)
}
}
fn push_error<S: Spanned>(&mut self, span: &S, msg: &str) {
self.errors.push(Error::new(span.span(), msg));
}
fn error_on_generic_parameters(&mut self, generics: &Generics) {
if let Some(param) = generics.params.first() {
self.push_error(param, "Generic parameters not supported.");
}
}
}
impl Fold for ToEssentialTraitDef {
fn fold_trait_item_method(&mut self, mut method: TraitItemMethod) -> TraitItemMethod {
if method.default.take().is_none() {
self.push_error(&method, "Methods need to have an implementation.");
}
let arg_types = get_function_argument_types_without_ref(&method.sig);
arg_types.filter_map(|ty|
match *ty {
Type::ImplTrait(impl_trait) => Some(impl_trait),
_ => None
}
).for_each(|invalid| self.push_error(&invalid, "`impl Trait` syntax not supported."));
self.error_on_generic_parameters(&method.sig.generics);
fold::fold_trait_item_method(self, method)
}
fn fold_item_trait(&mut self, mut trait_def: ItemTrait) -> ItemTrait {
self.error_on_generic_parameters(&trait_def.generics);
trait_def.vis = Visibility::Inherited;
fold::fold_item_trait(self, trait_def)
}
fn fold_receiver(&mut self, receiver: Receiver) -> Receiver {
if receiver.reference.is_none() {
self.push_error(&receiver, "Taking `Self` by value is not allowed.");
}
fold::fold_receiver(self, receiver)
}
}
/// Implements the given trait definition for `dyn Externalities`.
fn impl_trait_for_externalities(trait_def: &ItemTrait, is_wasm_only: bool) -> Result<TokenStream> {
let trait_ = &trait_def.ident;
let crate_ = generate_crate_access();
let methods = trait_def
.items
.iter()
.filter_map(|i| match i {
TraitItem::Method(ref method) => Some(method),
_ => None,
});
let impl_type = if is_wasm_only {
quote!( &mut dyn #crate_::wasm_interface::FunctionContext )
} else {
quote!( &mut dyn #crate_::Externalities )
};
Ok(
quote! {
#[cfg(feature = "std")]
impl #trait_ for #impl_type {
#( #methods )*
}
}
)
}
@@ -0,0 +1,162 @@
// 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 <http://www.gnu.org/licenses/>
//! Util function used by this crate.
use proc_macro2::{TokenStream, Span};
use syn::{
Ident, Error, Signature, Pat, PatType, FnArg, Type, token, TraitItemMethod, ItemTrait,
TraitItem, parse_quote, spanned::Spanned,
};
use proc_macro_crate::crate_name;
use std::env;
use quote::quote;
use inflector::Inflector;
/// Generates the include for the runtime-interface crate.
pub fn generate_runtime_interface_include() -> TokenStream {
if env::var("CARGO_PKG_NAME").unwrap() == "substrate-runtime-interface" {
TokenStream::new()
} else {
match crate_name("substrate-runtime-interface") {
Ok(crate_name) => {
let crate_name = Ident::new(&crate_name, Span::call_site());
quote!(
#[doc(hidden)]
extern crate #crate_name as proc_macro_runtime_interface;
)
},
Err(e) => {
let err = Error::new(Span::call_site(), &e).to_compile_error();
quote!( #err )
}
}
}
}
/// Generates the access to the `substrate-runtime-interface` crate.
pub fn generate_crate_access() -> TokenStream {
if env::var("CARGO_PKG_NAME").unwrap() == "substrate-runtime-interface" {
quote!( substrate_runtime_interface )
} else {
quote!( proc_macro_runtime_interface )
}
}
/// Create the exchangeable host function identifier for the given function name.
pub fn create_exchangeable_host_function_ident(name: &Ident) -> Ident {
Ident::new(&format!("host_{}", name), Span::call_site())
}
/// Create the host function identifier for the given function name.
pub fn create_host_function_ident(name: &Ident, trait_name: &Ident) -> Ident {
Ident::new(
&format!(
"ext_{}_{}_version_1",
trait_name.to_string().to_snake_case(),
name,
),
Span::call_site(),
)
}
/// Returns the function arguments of the given `Signature`, minus any `self` arguments.
pub fn get_function_arguments<'a>(sig: &'a Signature) -> impl Iterator<Item = PatType> + 'a {
sig.inputs
.iter()
.filter_map(|a| match a {
FnArg::Receiver(_) => None,
FnArg::Typed(pat_type) => Some(pat_type),
})
.enumerate()
.map(|(i, arg)| {
let mut res = arg.clone();
if let Pat::Wild(wild) = &*arg.pat {
let ident = Ident::new(
&format!("__runtime_interface_generated_{}_", i),
wild.span(),
);
res.pat = Box::new(parse_quote!( #ident ))
}
res
})
}
/// Returns the function argument names of the given `Signature`, minus any `self`.
pub fn get_function_argument_names<'a>(sig: &'a Signature) -> impl Iterator<Item = Box<Pat>> + 'a {
get_function_arguments(sig).map(|pt| pt.pat)
}
/// Returns the function argument types of the given `Signature`, minus any `Self` type.
pub fn get_function_argument_types<'a>(sig: &'a Signature) -> impl Iterator<Item = Box<Type>> + 'a {
get_function_arguments(sig).map(|pt| pt.ty)
}
/// Returns the function argument types, minus any `Self` type. If any of the arguments
/// is a reference, the underlying type without the ref is returned.
pub fn get_function_argument_types_without_ref<'a>(
sig: &'a Signature,
) -> impl Iterator<Item = Box<Type>> + 'a {
get_function_arguments(sig)
.map(|pt| pt.ty)
.map(|ty| match *ty {
Type::Reference(type_ref) => type_ref.elem,
_ => ty,
})
}
/// Returns the function argument names and types, minus any `self`. If any of the arguments
/// is a reference, the underlying type without the ref is returned.
pub fn get_function_argument_names_and_types_without_ref<'a>(
sig: &'a Signature,
) -> impl Iterator<Item = (Box<Pat>, Box<Type>)> + 'a {
get_function_arguments(sig)
.map(|pt| match *pt.ty {
Type::Reference(type_ref) => (pt.pat, type_ref.elem),
_ => (pt.pat, pt.ty),
})
}
/// Returns the `&`/`&mut` for all function argument types, minus the `self` arg. If a function
/// argument is not a reference, `None` is returned.
pub fn get_function_argument_types_ref_and_mut<'a>(
sig: &'a Signature,
) -> impl Iterator<Item = Option<(token::And, Option<token::Mut>)>> + 'a {
get_function_arguments(sig)
.map(|pt| pt.ty)
.map(|ty| match *ty {
Type::Reference(type_ref) => Some((type_ref.and_token, type_ref.mutability)),
_ => None,
})
}
/// Returns an iterator over all trait methods for the given trait definition.
pub fn get_trait_methods<'a>(trait_def: &'a ItemTrait) -> impl Iterator<Item = &'a TraitItemMethod> {
trait_def
.items
.iter()
.filter_map(|i| match i {
TraitItem::Method(ref method) => Some(method),
_ => None,
})
}
@@ -0,0 +1,27 @@
// 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 <http://www.gnu.org/licenses/>.
use std::env;
#[rustversion::attr(not(stable), ignore)]
#[test]
fn ui() {
// As trybuild is using `cargo check`, we don't need the real WASM binaries.
env::set_var("BUILD_DUMMY_WASM_BINARY", "1");
let t = trybuild::TestCases::new();
t.compile_fail("tests/ui/*.rs");
}
@@ -0,0 +1,8 @@
use runtime_interface::runtime_interface;
#[runtime_interface]
trait Test<T> {
fn test<R>() {}
}
fn main() {}
@@ -0,0 +1,11 @@
error: Generic parameters not supported.
--> $DIR/no_generic_parameters.rs:5:10
|
5 | fn test<R>() {}
| ^
error: Generic parameters not supported.
--> $DIR/no_generic_parameters.rs:4:12
|
4 | trait Test<T> {
| ^
@@ -0,0 +1,8 @@
use runtime_interface::runtime_interface;
#[runtime_interface]
trait Test {
fn test();
}
fn main() {}
@@ -0,0 +1,5 @@
error: Methods need to have an implementation.
--> $DIR/no_method_implementation.rs:5:2
|
5 | fn test();
| ^^
@@ -0,0 +1,6 @@
use runtime_interface::pass_by::PassByEnum;
#[derive(PassByEnum)]
struct Test;
fn main() {}
@@ -0,0 +1,5 @@
error: `PassByEnum` only supports enums as input type.
--> $DIR/pass_by_enum_with_struct.rs:3:10
|
3 | #[derive(PassByEnum)]
| ^^^^^^^^^^
@@ -0,0 +1,8 @@
use runtime_interface::pass_by::PassByEnum;
#[derive(PassByEnum)]
enum Test {
Var0(u32),
}
fn main() {}
@@ -0,0 +1,5 @@
error: `PassByEnum` only supports unit variants.
--> $DIR/pass_by_enum_with_value_variant.rs:3:10
|
3 | #[derive(PassByEnum)]
| ^^^^^^^^^^
@@ -0,0 +1,9 @@
use runtime_interface::pass_by::PassByInner;
#[derive(PassByInner)]
struct Test {
data: u32,
data2: u32,
}
fn main() {}
@@ -0,0 +1,5 @@
error: Only newtype/one field structs are supported by `PassByInner`!
--> $DIR/pass_by_inner_with_two_fields.rs:3:10
|
3 | #[derive(PassByInner)]
| ^^^^^^^^^^^
@@ -0,0 +1,8 @@
use runtime_interface::runtime_interface;
#[runtime_interface]
trait Test {
fn test(self) {}
}
fn main() {}
@@ -0,0 +1,5 @@
error: Taking `Self` by value is not allowed.
--> $DIR/take_self_by_value.rs:5:10
|
5 | fn test(self) {}
| ^^^^
@@ -0,0 +1,62 @@
// 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 <http://www.gnu.org/licenses/>.
//! Traits required by the runtime interface from the host side.
use crate::RIType;
use wasm_interface::{FunctionContext, Result};
/// Something that can be converted into a ffi value.
pub trait IntoFFIValue: RIType {
/// Convert `self` into a ffi value.
fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result<Self::FFIType>;
}
/// Something that can be converted into a preallocated ffi value.
///
/// Every type parameter that should be given as `&mut` into a runtime interface function, needs
/// to implement this trait. After executing the host implementation of the runtime interface
/// function, the value is copied into the preallocated wasm memory.
///
/// This should only be used for types which have a fixed size, like slices. Other types like a vec
/// do not work with this interface, as we can not call into wasm to reallocate memory. So, this
/// trait should be implemented carefully.
pub trait IntoPreallocatedFFIValue: RIType {
/// As `Self` can be an unsized type, it needs to be represented by a sized type at the host.
/// This `SelfInstance` is the sized type.
type SelfInstance;
/// Convert `self_instance` into the given preallocated ffi value.
fn into_preallocated_ffi_value(
self_instance: Self::SelfInstance,
context: &mut dyn FunctionContext,
allocated: Self::FFIType,
) -> Result<()>;
}
/// Something that can be created from a ffi value.
pub trait FromFFIValue: RIType {
/// As `Self` can be an unsized type, it needs to be represented by a sized type at the host.
/// This `SelfInstance` is the sized type.
type SelfInstance;
/// Create `SelfInstance` from the given
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<Self::SelfInstance>;
}
@@ -0,0 +1,491 @@
// 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 <http://www.gnu.org/licenses/>.
//! Provides implementations for the runtime interface traits.
use crate::{RIType, Pointer, pass_by::{PassBy, Codec, Inner, PassByInner}};
#[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 wasm_interface::{FunctionContext, Result};
use codec::{Encode, Decode};
use rstd::{any::TypeId, mem, vec::Vec};
#[cfg(feature = "std")]
use rstd::borrow::Cow;
#[cfg(not(feature = "std"))]
use rstd::{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);
/// Converts a pointer and length into an `u64`.
pub fn pointer_and_len_to_u64(ptr: u32, len: u32) -> u64 {
// The static assertions from above are changed into a runtime check.
#[cfg(all(feature = "std", not(feature = "disable_target_static_assertions")))]
assert_eq!(4, rstd::mem::size_of::<usize>());
(u64::from(len) << 32) | u64::from(ptr)
}
/// Splits an `u64` into the pointer and length.
pub fn pointer_and_len_from_u64(val: u64) -> (u32, u32) {
// The static assertions from above are changed into a runtime check.
#[cfg(all(feature = "std", not(feature = "disable_target_static_assertions")))]
assert_eq!(4, rstd::mem::size_of::<usize>());
let ptr = (val & (!0u32 as u64)) as u32;
let len = (val >> 32) as u32;
(ptr, len)
}
/// 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<u8> {
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<bool> {
Ok(arg == 1)
}
}
#[cfg(feature = "std")]
impl IntoFFIValue for bool {
fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result<u8> {
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<T> RIType for Vec<T> {
type FFIType = u64;
}
#[cfg(feature = "std")]
impl<T: 'static + Encode> IntoFFIValue for Vec<T> {
fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result<u64> {
let vec: Cow<'_, [u8]> = if TypeId::of::<T>() == TypeId::of::<u8>() {
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(pointer_and_len_to_u64(ptr.into(), vec.len() as u32))
}
}
#[cfg(feature = "std")]
impl<T: 'static + Decode> FromFFIValue for Vec<T> {
type SelfInstance = Vec<T>;
fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result<Vec<T>> {
<[T] as FromFFIValue>::from_ffi_value(context, arg)
}
}
#[cfg(not(feature = "std"))]
impl<T: 'static + Encode> IntoFFIValue for Vec<T> {
type Owned = Vec<u8>;
fn into_ffi_value(&self) -> WrappedFFIValue<u64, Vec<u8>> {
self[..].into_ffi_value()
}
}
#[cfg(not(feature = "std"))]
impl<T: 'static + Decode> FromFFIValue for Vec<T> {
fn from_ffi_value(arg: u64) -> Vec<T> {
let (ptr, len) = pointer_and_len_from_u64(arg);
let len = len as usize;
if TypeId::of::<T>() == TypeId::of::<u8>() {
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<T> RIType for [T] {
type FFIType = u64;
}
#[cfg(feature = "std")]
impl<T: 'static + Decode> FromFFIValue for [T] {
type SelfInstance = Vec<T>;
fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result<Vec<T>> {
let (ptr, len) = pointer_and_len_from_u64(arg);
let vec = context.read_memory(Pointer::new(ptr), len)?;
if TypeId::of::<T>() == TypeId::of::<u8>() {
Ok(unsafe { mem::transmute(vec) })
} else {
Ok(Vec::<T>::decode(&mut &vec[..]).expect("Wasm to host values are encoded correctly; qed"))
}
}
}
#[cfg(feature = "std")]
impl IntoPreallocatedFFIValue for [u8] {
type SelfInstance = Vec<u8>;
fn into_preallocated_ffi_value(
self_instance: Self::SelfInstance,
context: &mut dyn FunctionContext,
allocated: u64,
) -> Result<()> {
let (ptr, len) = pointer_and_len_from_u64(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<T: 'static + Encode> IntoFFIValue for [T] {
type Owned = Vec<u8>;
fn into_ffi_value(&self) -> WrappedFFIValue<u64, Vec<u8>> {
if TypeId::of::<T>() == TypeId::of::<u8>() {
let slice = unsafe { mem::transmute::<&[T], &[u8]>(self) };
pointer_and_len_to_u64(slice.as_ptr() as u32, slice.len() as u32).into()
} else {
let data = self.encode();
let ffi_value = pointer_and_len_to_u64(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<u32> {
(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 = unsafe { mem::MaybeUninit::<[u8; $n]>::zeroed().assume_init() };
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 = unsafe { mem::MaybeUninit::<[u8; $n]>::zeroed().assume_init() };
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<u32> {
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<T: codec::Codec, E: codec::Codec> PassBy for rstd::result::Result<T, E> {
type PassBy = Codec<Self>;
}
impl<T: codec::Codec> PassBy for Option<T> {
type PassBy = Codec<Self>;
}
/// 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<Self, [u8; $n]>;
}
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<String> {
let (ptr, len) = pointer_and_len_from_u64(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<u64, ()> {
let bytes = self.as_bytes();
pointer_and_len_to_u64(bytes.as_ptr() as u32, bytes.len() as u32).into()
}
}
#[cfg(feature = "std")]
impl<T: wasm_interface::PointerType> RIType for Pointer<T> {
type FFIType = u32;
}
/// The type is passed as `u32`.
#[cfg(not(feature = "std"))]
impl<T> RIType for Pointer<T> {
type FFIType = u32;
}
#[cfg(not(feature = "std"))]
impl<T> IntoFFIValue for Pointer<T> {
type Owned = ();
fn into_ffi_value(&self) -> WrappedFFIValue<u32> {
(*self as u32).into()
}
}
#[cfg(not(feature = "std"))]
impl<T> FromFFIValue for Pointer<T> {
fn from_ffi_value(arg: u32) -> Self {
arg as _
}
}
#[cfg(feature = "std")]
impl<T: wasm_interface::PointerType> FromFFIValue for Pointer<T> {
type SelfInstance = Self;
fn from_ffi_value(_: &mut dyn FunctionContext, arg: u32) -> Result<Self> {
Ok(Pointer::new(arg))
}
}
#[cfg(feature = "std")]
impl<T: wasm_interface::PointerType> IntoFFIValue for Pointer<T> {
fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result<u32> {
Ok(self.into())
}
}
@@ -0,0 +1,212 @@
// 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 <http://www.gnu.org/licenses/>.
//! Substrate runtime interface
//!
//! This crate provides types, traits and macros around runtime interfaces. A runtime interface is
//! a fixed interface between a Substrate runtime and a Substrate node. For a native runtime the
//! interface maps to a direct function call of the implementation. For a wasm runtime the interface
//! maps to an external function call. These external functions are exported by the wasm executor
//! and they map to the same implementation as the native calls.
//!
//! # Using a type in a runtime interface
//!
//! Any type that should be used in a runtime interface as argument or return value needs to
//! implement [`RIType`]. The associated type `FFIType` is the type that is used in the FFI
//! function to represent the actual type. For example `[T]` is represented by an `u64`. The slice
//! pointer and the length will be mapped to an `u64` value. For more information, see the
//! implementation of [`RIType`] for [`T`]. The FFI function definition is used when calling from
//! the wasm runtime into the node.
//!
//! Traits are used to convert from a type to the corresponding [`RIType::FFIType`].
//! Depending on where and how a type should be used in a function signature, a combination of the
//! following traits need to be implemented:
//!
//! 1. Pass as function argument: [`wasm::IntoFFIValue`] and [`host::FromFFIValue`]
//! 2. As function return value: [`wasm::FromFFIValue`] and [`host::IntoFFIValue`]
//! 3. Pass as mutable function argument: [`host::IntoPreallocatedFFIValue`]
//!
//! The traits are implemented for most of the common types like `[T]`, `Vec<T>`, arrays and
//! primitive types.
//!
//! For custom types, we provide the [`PassBy`](pass_by::PassBy) trait and strategies that define
//! how a type is passed between the wasm runtime and the node. Each strategy also provides a derive
//! macro to simplify the implementation.
//!
//! # Performance
//!
//! To not waste any more performance when calling into the node, not all types are SCALE encoded
//! when being passed as arguments between the wasm runtime and the node. For most types that
//! are raw bytes like `Vec<u8>`, `[u8]` or `[u8; N]` we pass them directly, without SCALE encoding
//! them in front of. The implementation of [`RIType`] each type provides more information on how
//! the data is passed.
//!
//! # Declaring a runtime interface
//!
//! Declaring a runtime interface is similar to declaring a trait in Rust:
//!
//! ```
//! #[substrate_runtime_interface::runtime_interface]
//! trait RuntimeInterface {
//! fn some_function(value: &[u8]) -> bool {
//! value.iter().all(|v| *v > 125)
//! }
//! }
//! ```
//!
//! For more information on declaring a runtime interface, see
//! [`#[runtime_interface]`](attr.runtime_interface.html).
#![cfg_attr(not(feature = "std"), no_std)]
#[doc(hidden)]
#[cfg(feature = "std")]
pub use wasm_interface;
#[doc(hidden)]
pub use rstd;
pub use substrate_runtime_interface_proc_macro::runtime_interface;
#[doc(hidden)]
#[cfg(feature = "std")]
pub use externalities::{
set_and_run_with_externalities, with_externalities, Externalities, ExternalitiesExt, ExtensionStore,
};
#[doc(hidden)]
pub use codec;
pub(crate) mod impls;
#[cfg(feature = "std")]
pub mod host;
#[cfg(not(feature = "std"))]
pub mod wasm;
pub mod pass_by;
/// Something that can be used by the runtime interface as type to communicate between wasm and the
/// host.
///
/// Every type that should be used in a runtime interface function signature needs to implement
/// this trait.
pub trait RIType {
/// The ffi type that is used to represent `Self`.
#[cfg(feature = "std")]
type FFIType: wasm_interface::IntoValue + wasm_interface::TryFromValue;
#[cfg(not(feature = "std"))]
type FFIType;
}
/// A pointer that can be used in a runtime interface function signature.
#[cfg(not(feature = "std"))]
pub type Pointer<T> = *mut T;
/// A pointer that can be used in a runtime interface function signature.
#[cfg(feature = "std")]
pub type Pointer<T> = wasm_interface::Pointer<T>;
#[cfg(test)]
mod tests {
use super::*;
use test_wasm::{WASM_BINARY, test_api::HostFunctions};
use wasm_interface::HostFunctions as HostFunctionsT;
type TestExternalities = state_machine::TestExternalities<primitives::Blake2Hasher, u64>;
fn call_wasm_method<HF: HostFunctionsT>(method: &str) -> TestExternalities {
let mut ext = TestExternalities::default();
let mut ext_ext = ext.ext();
executor::call_in_wasm::<
_,
(
HF,
runtime_io::SubstrateHostFunctions,
executor::deprecated_host_interface::SubstrateExternals
)
>(
method,
&[],
executor::WasmExecutionMethod::Interpreted,
&mut ext_ext,
&WASM_BINARY[..],
8,
).expect(&format!("Executes `{}`", method));
ext
}
#[test]
fn test_return_data() {
call_wasm_method::<HostFunctions>("test_return_data");
}
#[test]
fn test_return_option_data() {
call_wasm_method::<HostFunctions>("test_return_option_data");
}
#[test]
fn test_set_storage() {
let mut ext = call_wasm_method::<HostFunctions>("test_set_storage");
let expected = "world";
assert_eq!(expected.as_bytes(), &ext.ext().storage("hello".as_bytes()).unwrap()[..]);
}
#[test]
fn test_return_value_into_mutable_reference() {
call_wasm_method::<HostFunctions>("test_return_value_into_mutable_reference");
}
#[test]
fn test_get_and_return_array() {
call_wasm_method::<HostFunctions>("test_get_and_return_array");
}
#[test]
fn test_array_as_mutable_reference() {
call_wasm_method::<HostFunctions>("test_array_as_mutable_reference");
}
#[test]
fn test_return_input_public_key() {
call_wasm_method::<HostFunctions>("test_return_input_public_key");
}
#[test]
#[should_panic(
expected = "Other(\"Instantiation: Export ext_test_api_return_input_version_1 not found\")"
)]
fn host_function_not_found() {
call_wasm_method::<()>("test_return_data");
}
#[test]
#[should_panic(
expected =
"FunctionExecution(\"ext_test_api_invalid_utf8_data_version_1\", \
\"Invalid utf8 data provided\")"
)]
fn test_invalid_utf8_data_should_return_an_error() {
call_wasm_method::<HostFunctions>("test_invalid_utf8_data_should_return_an_error");
}
#[test]
fn test_overwrite_native_function_implementation() {
call_wasm_method::<HostFunctions>("test_overwrite_native_function_implementation");
}
}
@@ -0,0 +1,384 @@
// 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 <http://www.gnu.org/licenses/>.
//! Provides the [`PassBy`](pass_by::PassBy) trait to simplify the implementation of the
//! runtime interface traits for custom types.
//!
//! [`Codec`](pass_by::Codec), [`Inner`](pass_by::Inner) and [`Enum`](pass_by::Enum) are the
//! provided strategy implementations.
use crate::{RIType, impls::{pointer_and_len_from_u64, pointer_and_len_to_u64}};
#[cfg(feature = "std")]
use crate::host::*;
#[cfg(not(feature = "std"))]
use crate::wasm::*;
#[cfg(feature = "std")]
use wasm_interface::{FunctionContext, Pointer, Result};
use rstd::{marker::PhantomData, convert::TryFrom};
#[cfg(not(feature = "std"))]
use rstd::{slice, vec::Vec};
pub use substrate_runtime_interface_proc_macro::{PassByCodec, PassByInner, PassByEnum};
/// Something that should be passed between wasm and the host using the given strategy.
///
/// See [`Codec`], [`Inner`] or [`Enum`] for more information about the provided strategies.
pub trait PassBy: Sized {
/// The strategy that should be used to pass the type.
type PassBy: PassByImpl<Self>;
}
/// Something that provides a strategy for passing a type between wasm and the host.
///
/// This trait exposes the same functionality as [`crate::host::IntoFFIValue`] and
/// [`crate::host::FromFFIValue`] to delegate the implementation for a type to a different type.
///
/// This trait is used for the host implementation.
#[cfg(feature = "std")]
pub trait PassByImpl<T>: RIType {
/// Convert the given instance to the ffi value.
///
/// For more information see: [`crate::host::IntoFFIValue::into_ffi_value`]
fn into_ffi_value(
instance: T,
context: &mut dyn FunctionContext,
) -> Result<Self::FFIType>;
/// Create `T` from the given ffi value.
///
/// For more information see: [`crate::host::FromFFIValue::from_ffi_value`]
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<T>;
}
/// Something that provides a strategy for passing a type between wasm and the host.
///
/// This trait exposes the same functionality as [`crate::wasm::IntoFFIValue`] and
/// [`crate::wasm::FromFFIValue`] to delegate the implementation for a type to a different type.
///
/// This trait is used for the wasm implementation.
#[cfg(not(feature = "std"))]
pub trait PassByImpl<T>: RIType {
/// The owned rust type that is stored with the ffi value in [`crate::wasm::WrappedFFIValue`].
type Owned;
/// Convert the given `instance` into [`crate::wasm::WrappedFFIValue`].
///
/// For more information see: [`crate::wasm::IntoFFIValue::into_ffi_value`]
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned>;
/// Create `T` from the given ffi value.
///
/// For more information see: [`crate::wasm::FromFFIValue::from_ffi_value`]
fn from_ffi_value(arg: Self::FFIType) -> T;
}
impl<T: PassBy> RIType for T {
type FFIType = <T::PassBy as RIType>::FFIType;
}
#[cfg(feature = "std")]
impl<T: PassBy> IntoFFIValue for T {
fn into_ffi_value(
self,
context: &mut dyn FunctionContext,
) -> Result<<T::PassBy as RIType>::FFIType> {
T::PassBy::into_ffi_value(self, context)
}
}
#[cfg(feature = "std")]
impl<T: PassBy> FromFFIValue for T {
type SelfInstance = Self;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: <T::PassBy as RIType>::FFIType,
) -> Result<Self> {
T::PassBy::from_ffi_value(context, arg)
}
}
#[cfg(not(feature = "std"))]
impl<T: PassBy> IntoFFIValue for T {
type Owned = <T::PassBy as PassByImpl<T>>::Owned;
fn into_ffi_value(&self) -> WrappedFFIValue<<T::PassBy as RIType>::FFIType, Self::Owned> {
T::PassBy::into_ffi_value(self)
}
}
#[cfg(not(feature = "std"))]
impl<T: PassBy> FromFFIValue for T {
fn from_ffi_value(arg: <T::PassBy as RIType>::FFIType) -> Self {
T::PassBy::from_ffi_value(arg)
}
}
/// The implementation of the pass by codec strategy. This strategy uses a SCALE encoded
/// representation of the type between wasm and the host.
///
/// Use this type as associated type for [`PassBy`] to implement this strategy for a type.
///
/// This type expects the type that wants to implement this strategy as generic parameter.
///
/// [`PassByCodec`](derive.PassByCodec.html) is a derive macro to implement this strategy.
///
/// # Example
/// ```
/// # use substrate_runtime_interface::pass_by::{PassBy, Codec};
/// #[derive(codec::Encode, codec::Decode)]
/// struct Test;
///
/// impl PassBy for Test {
/// type PassBy = Codec<Self>;
/// }
/// ```
pub struct Codec<T: codec::Codec>(PhantomData<T>);
#[cfg(feature = "std")]
impl<T: codec::Codec> PassByImpl<T> for Codec<T> {
fn into_ffi_value(
instance: T,
context: &mut dyn FunctionContext,
) -> Result<Self::FFIType> {
let vec = instance.encode();
let ptr = context.allocate_memory(vec.len() as u32)?;
context.write_memory(ptr, &vec)?;
Ok(pointer_and_len_to_u64(ptr.into(), vec.len() as u32))
}
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<T> {
let (ptr, len) = pointer_and_len_from_u64(arg);
let vec = context.read_memory(Pointer::new(ptr), len)?;
T::decode(&mut &vec[..])
.map_err(|e| format!("Could not decode value from wasm: {}", e.what()))
}
}
#[cfg(not(feature = "std"))]
impl<T: codec::Codec> PassByImpl<T> for Codec<T> {
type Owned = Vec<u8>;
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
let data = instance.encode();
let ffi_value = pointer_and_len_to_u64(data.as_ptr() as u32, data.len() as u32);
(ffi_value, data).into()
}
fn from_ffi_value(arg: Self::FFIType) -> T {
let (ptr, len) = pointer_and_len_from_u64(arg);
let len = len as usize;
let slice = unsafe { slice::from_raw_parts(ptr as *const u8, len) };
T::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`
///
/// `Self` is encoded and the length and the pointer are taken from the encoded vector.
impl<T: codec::Codec> RIType for Codec<T> {
type FFIType = u64;
}
/// Trait that needs to be implemented by a type that should be passed between wasm and the host,
/// by using the inner type. See [`Inner`] for more information.
pub trait PassByInner: Sized {
/// The inner type that is wrapped by `Self`.
type Inner: RIType;
/// Consumes `self` and returns the inner type.
fn into_inner(self) -> Self::Inner;
/// Returns the reference to the inner type.
fn inner(&self) -> &Self::Inner;
/// Construct `Self` from the given `inner`.
fn from_inner(inner: Self::Inner) -> Self;
}
/// The implementation of the pass by inner type strategy. The type that uses this strategy will be
/// passed between wasm and the host by using the wrapped inner type. So, this strategy is only
/// usable by newtype structs.
///
/// Use this type as associated type for [`PassBy`] to implement this strategy for a type. Besides
/// that the `PassByInner` trait need to be implemented as well.
///
/// This type expects the type that wants to use this strategy as generic parameter `T` and the
/// inner type as generic parameter `I`.
///
/// [`PassByInner`](derive.PassByInner.html) is a derive macro to implement this strategy.
///
/// # Example
/// ```
/// # use substrate_runtime_interface::pass_by::{PassBy, Inner, PassByInner};
/// struct Test([u8; 32]);
///
/// impl PassBy for Test {
/// type PassBy = Inner<Self, [u8; 32]>;
/// }
///
/// impl PassByInner for Test {
/// type Inner = [u8; 32];
///
/// fn into_inner(self) -> [u8; 32] {
/// self.0
/// }
/// fn inner(&self) -> &[u8; 32] {
/// &self.0
/// }
/// fn from_inner(inner: [u8; 32]) -> Self {
/// Self(inner)
/// }
/// }
/// ```
pub struct Inner<T: PassByInner<Inner = I>, I: RIType>(PhantomData<(T, I)>);
#[cfg(feature = "std")]
impl<T: PassByInner<Inner = I>, I: RIType> PassByImpl<T> for Inner<T, I>
where I: IntoFFIValue + FromFFIValue<SelfInstance=I>
{
fn into_ffi_value(
instance: T,
context: &mut dyn FunctionContext,
) -> Result<Self::FFIType> {
instance.into_inner().into_ffi_value(context)
}
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<T> {
I::from_ffi_value(context, arg).map(T::from_inner)
}
}
#[cfg(not(feature = "std"))]
impl<T: PassByInner<Inner = I>, I: RIType> PassByImpl<T> for Inner<T, I>
where I: IntoFFIValue + FromFFIValue
{
type Owned = I::Owned;
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
instance.inner().into_ffi_value()
}
fn from_ffi_value(arg: Self::FFIType) -> T {
T::from_inner(I::from_ffi_value(arg))
}
}
/// The type is passed as the inner type.
impl<T: PassByInner<Inner = I>, I: RIType> RIType for Inner<T, I> {
type FFIType = I::FFIType;
}
/// The implementation of the pass by enum strategy. This strategy uses an `u8` internally to pass
/// the enum between wasm and the host. So, this strategy only supports enums with unit variants.
///
/// Use this type as associated type for [`PassBy`] to implement this strategy for a type.
///
/// This type expects the type that wants to implement this strategy as generic parameter. Besides
/// that the type needs to implement `TryFrom<u8>` and `From<Self> for u8`.
///
/// [`PassByEnum`](derive.PassByEnum.html) is a derive macro to implement this strategy.
///
/// # Example
/// ```
/// # use substrate_runtime_interface::pass_by::{PassBy, Enum};
/// #[derive(Clone, Copy)]
/// enum Test {
/// Test1,
/// Test2,
/// }
///
/// impl From<Test> for u8 {
/// fn from(val: Test) -> u8 {
/// match val {
/// Test::Test1 => 0,
/// Test::Test2 => 1,
/// }
/// }
/// }
///
/// impl std::convert::TryFrom<u8> for Test {
/// type Error = ();
///
/// fn try_from(val: u8) -> Result<Test, ()> {
/// match val {
/// 0 => Ok(Test::Test1),
/// 1 => Ok(Test::Test2),
/// _ => Err(()),
/// }
/// }
/// }
///
/// impl PassBy for Test {
/// type PassBy = Enum<Self>;
/// }
/// ```
pub struct Enum<T: Copy + Into<u8> + TryFrom<u8>>(PhantomData<T>);
#[cfg(feature = "std")]
impl<T: Copy + Into<u8> + TryFrom<u8>> PassByImpl<T> for Enum<T> {
fn into_ffi_value(
instance: T,
_: &mut dyn FunctionContext,
) -> Result<Self::FFIType> {
Ok(instance.into())
}
fn from_ffi_value(
_: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<T> {
T::try_from(arg).map_err(|_| format!("Invalid enum discriminant: {}", arg))
}
}
#[cfg(not(feature = "std"))]
impl<T: Copy + Into<u8> + TryFrom<u8, Error = ()>> PassByImpl<T> for Enum<T> {
type Owned = ();
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
let value: u8 = (*instance).into();
value.into()
}
fn from_ffi_value(arg: Self::FFIType) -> T {
T::try_from(arg).expect("Host to wasm provides a valid enum discriminant; qed")
}
}
/// The type is passed as `u8`.
///
/// The value is corresponds to the discriminant of the variant.
impl<T: Copy + Into<u8> + TryFrom<u8>> RIType for Enum<T> {
type FFIType = u8;
}
@@ -0,0 +1,142 @@
// 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 <http://www.gnu.org/licenses/>.
//! Traits required by the runtime interface from the wasm side.
use crate::RIType;
use rstd::cell::Cell;
/// Something that can be created from a ffi value.
///
/// # Safety
///
/// It is unsafe behavior to call `Something::into_ffi_value().get()` and take this as input for
/// `from_ffi_value`. Implementations are safe to assume that the `arg` given to `from_ffi_value`
/// is only generated by the corresponding `host::IntoFFIValue` implementation.
pub trait FromFFIValue: Sized + RIType {
/// Create `Self` from the given ffi value.
fn from_ffi_value(arg: Self::FFIType) -> Self;
}
/// Something that can be converted into a ffi value.
pub trait IntoFFIValue: RIType {
/// The owned rust type that is stored with the ffi value in [`WrappedFFIValue`].
///
/// If no owned value is required, `()` can be used as a type.
type Owned;
/// Convert `self` into a [`WrappedFFIValue`].
fn into_ffi_value(&self) -> WrappedFFIValue<Self::FFIType, Self::Owned>;
}
/// Represents a wrapped ffi value.
///
/// It is either the ffi value itself or the ffi value plus some other owned value. By providing
/// support for storing another owned value besides the actual ffi value certain performance
/// optimizations can be applied. For example using the pointer to a `Vec<u8>`, while using the
/// pointer to a SCALE encoded `Vec<u8>` that is stored in this wrapper for any other `Vec<T>`.
pub enum WrappedFFIValue<T, O = ()> {
Wrapped(T),
WrappedAndOwned(T, O),
}
impl<T: Copy, O> WrappedFFIValue<T, O> {
/// Returns the wrapped ffi value.
pub fn get(&self) -> T {
match self {
Self::Wrapped(data) | Self::WrappedAndOwned(data, _) => *data,
}
}
}
impl<T, O> From<T> for WrappedFFIValue<T, O> {
fn from(val: T) -> Self {
WrappedFFIValue::Wrapped(val)
}
}
impl<T, O> From<(T, O)> for WrappedFFIValue<T, O> {
fn from(val: (T, O)) -> Self {
WrappedFFIValue::WrappedAndOwned(val.0, val.1)
}
}
/// The state of an exchangeable function.
#[derive(Clone, Copy)]
enum ExchangeableFunctionState {
/// Original function is present
Original,
/// The function has been replaced.
Replaced,
}
/// A function which implementation can be exchanged.
///
/// Internally this works by swapping function pointers.
pub struct ExchangeableFunction<T>(Cell<(T, ExchangeableFunctionState)>);
impl<T> ExchangeableFunction<T> {
/// Create a new instance of `ExchangeableFunction`.
pub const fn new(impl_: T) -> Self {
Self(Cell::new((impl_, ExchangeableFunctionState::Original)))
}
}
impl<T: Copy> ExchangeableFunction<T> {
/// Replace the implementation with `new_impl`.
///
/// # Panics
///
/// Panics when trying to replace an already replaced implementation.
///
/// # Returns
///
/// Returns the original implementation wrapped in [`RestoreImplementation`].
pub fn replace_implementation(&'static self, new_impl: T) -> RestoreImplementation<T> {
if let ExchangeableFunctionState::Replaced = self.0.get().1 {
panic!("Trying to replace an already replaced implementation!")
}
let old = self.0.replace((new_impl, ExchangeableFunctionState::Replaced));
RestoreImplementation(self, Some(old.0))
}
/// Restore the original implementation.
fn restore_orig_implementation(&self, orig: T) {
self.0.set((orig, ExchangeableFunctionState::Original));
}
/// Returns the internal function pointer.
pub fn get(&self) -> T {
self.0.get().0
}
}
// Wasm does not support threads, so this is safe; qed.
unsafe impl<T> Sync for ExchangeableFunction<T> {}
/// Restores a function implementation on drop.
///
/// Stores a static reference to the function object and the original implementation.
pub struct RestoreImplementation<T: 'static + Copy>(&'static ExchangeableFunction<T>, Option<T>);
impl<T: Copy> Drop for RestoreImplementation<T> {
fn drop(&mut self) {
self.0.restore_orig_implementation(self.1.take().expect("Value is only taken on drop; qed"));
}
}
@@ -0,0 +1,19 @@
[package]
name = "substrate-runtime-interface-test-wasm"
version = "2.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
build = "build.rs"
[dependencies]
runtime-interface = { package = "substrate-runtime-interface", path = "../", default-features = false }
rstd = { package = "sr-std", path = "../../sr-std", default-features = false }
runtime-io = { package = "sr-io", path = "../../sr-io", default-features = false }
primitives = { package = "substrate-primitives", path = "../../core", default-features = false }
[build-dependencies]
wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.3", path = "../../../client/utils/wasm-builder-runner" }
[features]
default = [ "std" ]
std = [ "runtime-interface/std", "rstd/std", "primitives/std", "runtime-io/std" ]
@@ -0,0 +1,30 @@
// 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 <http://www.gnu.org/licenses/>.
use wasm_builder_runner::{build_current_project_with_rustflags, WasmBuilderSource};
fn main() {
build_current_project_with_rustflags(
"wasm_binary.rs",
WasmBuilderSource::CratesOrPath {
path: "../../../utils/wasm-builder",
version: "1.0.6",
},
// This instructs LLD to export __heap_base as a global variable, which is used by the
// external memory allocator.
"-Clink-arg=--export=__heap_base",
);
}
@@ -0,0 +1,194 @@
// 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 <http://www.gnu.org/licenses/>.
//! Tests for the runtime interface traits and proc macros.
#![cfg_attr(not(feature = "std"), no_std)]
use runtime_interface::runtime_interface;
#[cfg(not(feature = "std"))]
use rstd::{vec, vec::Vec, mem, convert::TryFrom};
use primitives::{sr25519::Public, wasm_export_functions};
// Inlucde the WASM binary
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
/// Used in the `test_array_as_mutable_reference` test.
const TEST_ARRAY: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
#[runtime_interface]
pub trait TestApi {
/// Returns the input data as result.
fn return_input(data: Vec<u8>) -> Vec<u8> {
data
}
/// Set the storage at key with value.
fn set_storage(&mut self, key: &[u8], data: &[u8]) {
self.place_storage(key.to_vec(), Some(data.to_vec()));
}
/// Copy `hello` into the given mutable reference
fn return_value_into_mutable_reference(&self, data: &mut [u8]) {
let res = "hello";
data[..res.as_bytes().len()].copy_from_slice(res.as_bytes());
}
/// Returns the input data wrapped in an `Option` as result.
fn return_option_input(data: Vec<u8>) -> Option<Vec<u8>> {
Some(data)
}
/// Get an array as input and returns a subset of this array.
fn get_and_return_array(data: [u8; 34]) -> [u8; 16] {
let mut res = [0u8; 16];
res.copy_from_slice(&data[..16]);
res
}
/// Take and fill mutable array.
fn array_as_mutable_reference(data: &mut [u8; 16]) {
data.copy_from_slice(&TEST_ARRAY);
}
/// Returns the given public key as result.
fn return_input_public_key(key: Public) -> Public {
key
}
/// A function that is called with invalid utf8 data from the runtime.
///
/// This also checks that we accept `_` (wild card) argument names.
fn invalid_utf8_data(_: &str) {}
/// Overwrite the native implementation in wasm. The native implementation always returns
/// `false` and the replacement function will return always `true`.
fn overwrite_native_function_implementation() -> bool {
false
}
}
/// Two random external functions from the old runtime interface.
/// This ensures that we still inherently export these functions from the host and that we are still
/// compatible with old wasm runtimes.
extern "C" {
pub fn ext_clear_storage(key_data: *const u8, key_len: u32);
pub fn ext_keccak_256(data: *const u8, len: u32, out: *mut u8);
}
/// Make sure the old runtime interface needs to be imported.
#[no_mangle]
pub fn force_old_runtime_interface_import() {
unsafe { ext_clear_storage(rstd::ptr::null(), 0); }
unsafe { ext_keccak_256(rstd::ptr::null(), 0, rstd::ptr::null_mut()); }
}
/// This function is not used, but we require it for the compiler to include `runtime-io`.
/// `runtime-io` is required for its panic and oom handler.
#[no_mangle]
pub fn import_runtime_io() {
runtime_io::misc::print_utf8(&[]);
}
wasm_export_functions! {
fn test_return_data() {
let input = vec![1, 2, 3, 4, 5, 6];
let res = test_api::return_input(input.clone());
assert_eq!(input, res);
}
fn test_return_option_data() {
let input = vec![1, 2, 3, 4, 5, 6];
let res = test_api::return_option_input(input.clone());
assert_eq!(Some(input), res);
}
fn test_set_storage() {
let key = "hello";
let value = "world";
test_api::set_storage(key.as_bytes(), value.as_bytes());
}
fn test_return_value_into_mutable_reference() {
let mut data = vec![1, 2, 3, 4, 5, 6];
test_api::return_value_into_mutable_reference(&mut data);
let expected = "hello";
assert_eq!(expected.as_bytes(), &data[..expected.len()]);
}
fn test_get_and_return_array() {
let mut input = unsafe { mem::MaybeUninit::<[u8; 34]>::zeroed().assume_init() };
input.copy_from_slice(&[
24, 3, 23, 20, 2, 16, 32, 1, 12, 26, 27, 8, 29, 31, 6, 5, 4, 19, 10, 28, 34, 21, 18, 33, 9,
13, 22, 25, 15, 11, 30, 7, 14, 17,
]);
let res = test_api::get_and_return_array(input);
assert_eq!(&res, &input[..16]);
}
fn test_array_as_mutable_reference() {
let mut array = [0u8; 16];
test_api::array_as_mutable_reference(&mut array);
assert_eq!(array, TEST_ARRAY);
}
fn test_return_input_public_key() {
let key = Public::try_from(
&[
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,
][..],
).unwrap();
let ret_key = test_api::return_input_public_key(key.clone());
let key_data: &[u8] = key.as_ref();
let ret_key_data: &[u8] = ret_key.as_ref();
assert_eq!(key_data, ret_key_data);
}
fn test_invalid_utf8_data_should_return_an_error() {
let data = vec![0, 159, 146, 150];
// I'm an evil hacker, trying to hack!
let data_str = unsafe { rstd::str::from_utf8_unchecked(&data) };
test_api::invalid_utf8_data(data_str);
}
fn test_overwrite_native_function_implementation() {
fn new_implementation() -> bool {
true
}
// Check native implementation
assert!(!test_api::overwrite_native_function_implementation());
let _guard = test_api::host_overwrite_native_function_implementation
.replace_implementation(new_implementation);
assert!(test_api::overwrite_native_function_implementation());
}
}