mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-15 10:21:05 +00:00
Rename Palette to FRAME (#4182)
* palette -> frame * PALETTE, Palette -> FRAME * Move folder pallete -> frame * Update docs/Structure.adoc Co-Authored-By: Benjamin Kampmann <ben.kampmann@googlemail.com> * Update docs/README.adoc Co-Authored-By: Benjamin Kampmann <ben.kampmann@googlemail.com> * Update README.adoc
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
// Copyright 2018-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/>.
|
||||
|
||||
//! Definition of macros that hides boilerplate of defining external environment
|
||||
//! for a wasm module.
|
||||
//!
|
||||
//! Most likely you should use `define_env` macro.
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! convert_args {
|
||||
() => (vec![]);
|
||||
( $( $t:ty ),* ) => ( vec![ $( { use $crate::wasm::env_def::ConvertibleToWasm; <$t>::VALUE_TYPE }, )* ] );
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! gen_signature {
|
||||
( ( $( $params: ty ),* ) ) => (
|
||||
{
|
||||
parity_wasm::elements::FunctionType::new(convert_args!($($params),*), None)
|
||||
}
|
||||
);
|
||||
|
||||
( ( $( $params: ty ),* ) -> $returns: ty ) => (
|
||||
{
|
||||
parity_wasm::elements::FunctionType::new(convert_args!($($params),*), Some({
|
||||
use $crate::wasm::env_def::ConvertibleToWasm; <$returns>::VALUE_TYPE
|
||||
}))
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! gen_signature_dispatch {
|
||||
(
|
||||
$needle_name:ident,
|
||||
$needle_sig:ident ;
|
||||
$name:ident
|
||||
( $ctx:ident $( , $names:ident : $params:ty )* ) $( -> $returns:ty )* , $($rest:tt)* ) => {
|
||||
if stringify!($name).as_bytes() == $needle_name {
|
||||
let signature = gen_signature!( ( $( $params ),* ) $( -> $returns )* );
|
||||
if $needle_sig == &signature {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
gen_signature_dispatch!($needle_name, $needle_sig ; $($rest)*);
|
||||
}
|
||||
};
|
||||
( $needle_name:ident, $needle_sig:ident ; ) => {
|
||||
};
|
||||
}
|
||||
|
||||
/// Unmarshall arguments and then execute `body` expression and return its result.
|
||||
macro_rules! unmarshall_then_body {
|
||||
( $body:tt, $ctx:ident, $args_iter:ident, $( $names:ident : $params:ty ),* ) => ({
|
||||
$(
|
||||
let $names : <$params as $crate::wasm::env_def::ConvertibleToWasm>::NativeType =
|
||||
$args_iter.next()
|
||||
.and_then(|v| <$params as $crate::wasm::env_def::ConvertibleToWasm>
|
||||
::from_typed_value(v.clone()))
|
||||
.expect(
|
||||
"precondition: all imports should be checked against the signatures of corresponding
|
||||
functions defined by `define_env!` macro by the user of the macro;
|
||||
signatures of these functions defined by `$params`;
|
||||
calls always made with arguments types of which are defined by the corresponding imports;
|
||||
thus types of arguments should be equal to type list in `$params` and
|
||||
length of argument list and $params should be equal;
|
||||
thus this can never be `None`;
|
||||
qed;
|
||||
"
|
||||
);
|
||||
)*
|
||||
$body
|
||||
})
|
||||
}
|
||||
|
||||
/// Since we can't specify the type of closure directly at binding site:
|
||||
///
|
||||
/// ```nocompile
|
||||
/// let f: FnOnce() -> Result<<u32 as ConvertibleToWasm>::NativeType, _> = || { /* ... */ };
|
||||
/// ```
|
||||
///
|
||||
/// we use this function to constrain the type of the closure.
|
||||
#[inline(always)]
|
||||
pub fn constrain_closure<R, F>(f: F) -> F
|
||||
where
|
||||
F: FnOnce() -> Result<R, sandbox::HostError>,
|
||||
{
|
||||
f
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! unmarshall_then_body_then_marshall {
|
||||
( $args_iter:ident, $ctx:ident, ( $( $names:ident : $params:ty ),* ) -> $returns:ty => $body:tt ) => ({
|
||||
let body = $crate::wasm::env_def::macros::constrain_closure::<
|
||||
<$returns as $crate::wasm::env_def::ConvertibleToWasm>::NativeType, _
|
||||
>(|| {
|
||||
unmarshall_then_body!($body, $ctx, $args_iter, $( $names : $params ),*)
|
||||
});
|
||||
let r = body()?;
|
||||
return Ok(sandbox::ReturnValue::Value({ use $crate::wasm::env_def::ConvertibleToWasm; r.to_typed_value() }))
|
||||
});
|
||||
( $args_iter:ident, $ctx:ident, ( $( $names:ident : $params:ty ),* ) => $body:tt ) => ({
|
||||
let body = $crate::wasm::env_def::macros::constrain_closure::<(), _>(|| {
|
||||
unmarshall_then_body!($body, $ctx, $args_iter, $( $names : $params ),*)
|
||||
});
|
||||
body()?;
|
||||
return Ok(sandbox::ReturnValue::Unit)
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! define_func {
|
||||
( < E: $ext_ty:tt > $name:ident ( $ctx: ident $(, $names:ident : $params:ty)*) $(-> $returns:ty)* => $body:tt ) => {
|
||||
fn $name< E: $ext_ty >(
|
||||
$ctx: &mut $crate::wasm::Runtime<E>,
|
||||
args: &[sandbox::TypedValue],
|
||||
) -> Result<sandbox::ReturnValue, sandbox::HostError> {
|
||||
#[allow(unused)]
|
||||
let mut args = args.iter();
|
||||
|
||||
unmarshall_then_body_then_marshall!(
|
||||
args,
|
||||
$ctx,
|
||||
( $( $names : $params ),* ) $( -> $returns )* => $body
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! register_func {
|
||||
( $reg_cb:ident, < E: $ext_ty:tt > ; ) => {};
|
||||
|
||||
( $reg_cb:ident, < E: $ext_ty:tt > ;
|
||||
$name:ident ( $ctx:ident $( , $names:ident : $params:ty )* )
|
||||
$( -> $returns:ty )* => $body:tt $($rest:tt)*
|
||||
) => {
|
||||
$reg_cb(
|
||||
stringify!($name).as_bytes(),
|
||||
{
|
||||
define_func!(
|
||||
< E: $ext_ty > $name ( $ctx $(, $names : $params )* ) $( -> $returns )* => $body
|
||||
);
|
||||
$name::<E>
|
||||
}
|
||||
);
|
||||
register_func!( $reg_cb, < E: $ext_ty > ; $($rest)* );
|
||||
};
|
||||
}
|
||||
|
||||
/// Define a function set that can be imported by executing wasm code.
|
||||
///
|
||||
/// **NB**: Be advised that all functions defined by this macro
|
||||
/// will panic if called with unexpected arguments.
|
||||
///
|
||||
/// It's up to the user of this macro to check signatures of wasm code to be executed
|
||||
/// and reject the code if any imported function has a mismatched signature.
|
||||
macro_rules! define_env {
|
||||
( $init_name:ident , < E: $ext_ty:tt > ,
|
||||
$( $name:ident ( $ctx:ident $( , $names:ident : $params:ty )* )
|
||||
$( -> $returns:ty )* => $body:tt , )*
|
||||
) => {
|
||||
pub struct $init_name;
|
||||
|
||||
impl $crate::wasm::env_def::ImportSatisfyCheck for $init_name {
|
||||
fn can_satisfy(name: &[u8], func_type: &parity_wasm::elements::FunctionType) -> bool {
|
||||
gen_signature_dispatch!( name, func_type ; $( $name ( $ctx $(, $names : $params )* ) $( -> $returns )* , )* );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Ext> $crate::wasm::env_def::FunctionImplProvider<E> for $init_name {
|
||||
fn impls<F: FnMut(&[u8], $crate::wasm::env_def::HostFunc<E>)>(f: &mut F) {
|
||||
register_func!(f, < E: $ext_ty > ; $( $name ( $ctx $( , $names : $params )* ) $( -> $returns)* => $body )* );
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use parity_wasm::elements::FunctionType;
|
||||
use parity_wasm::elements::ValueType;
|
||||
use sr_primitives::traits::Zero;
|
||||
use sandbox::{self, ReturnValue, TypedValue};
|
||||
use crate::wasm::tests::MockExt;
|
||||
use crate::wasm::Runtime;
|
||||
use crate::exec::Ext;
|
||||
use crate::gas::Gas;
|
||||
|
||||
#[test]
|
||||
fn macro_unmarshall_then_body_then_marshall_value_or_trap() {
|
||||
fn test_value(
|
||||
_ctx: &mut u32,
|
||||
args: &[sandbox::TypedValue],
|
||||
) -> Result<ReturnValue, sandbox::HostError> {
|
||||
let mut args = args.iter();
|
||||
unmarshall_then_body_then_marshall!(
|
||||
args,
|
||||
_ctx,
|
||||
(a: u32, b: u32) -> u32 => {
|
||||
if b == 0 {
|
||||
Err(sandbox::HostError)
|
||||
} else {
|
||||
Ok(a / b)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
let ctx = &mut 0;
|
||||
assert_eq!(
|
||||
test_value(ctx, &[TypedValue::I32(15), TypedValue::I32(3)]).unwrap(),
|
||||
ReturnValue::Value(TypedValue::I32(5)),
|
||||
);
|
||||
assert!(test_value(ctx, &[TypedValue::I32(15), TypedValue::I32(0)]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_unmarshall_then_body_then_marshall_unit() {
|
||||
fn test_unit(
|
||||
ctx: &mut u32,
|
||||
args: &[sandbox::TypedValue],
|
||||
) -> Result<ReturnValue, sandbox::HostError> {
|
||||
let mut args = args.iter();
|
||||
unmarshall_then_body_then_marshall!(
|
||||
args,
|
||||
ctx,
|
||||
(a: u32, b: u32) => {
|
||||
*ctx = a + b;
|
||||
Ok(())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
let ctx = &mut 0;
|
||||
let result = test_unit(ctx, &[TypedValue::I32(2), TypedValue::I32(3)]).unwrap();
|
||||
assert_eq!(result, ReturnValue::Unit);
|
||||
assert_eq!(*ctx, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_define_func() {
|
||||
define_func!( <E: Ext> ext_gas (_ctx, amount: u32) => {
|
||||
let amount = Gas::from(amount);
|
||||
if !amount.is_zero() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(sandbox::HostError)
|
||||
}
|
||||
});
|
||||
let _f: fn(&mut Runtime<MockExt>, &[sandbox::TypedValue])
|
||||
-> Result<sandbox::ReturnValue, sandbox::HostError> = ext_gas::<MockExt>;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_gen_signature() {
|
||||
assert_eq!(
|
||||
gen_signature!((i32)),
|
||||
FunctionType::new(vec![ValueType::I32], None),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
gen_signature!( (i32, u32) -> u32 ),
|
||||
FunctionType::new(vec![ValueType::I32, ValueType::I32], Some(ValueType::I32)),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_unmarshall_then_body() {
|
||||
let args = vec![TypedValue::I32(5), TypedValue::I32(3)];
|
||||
let mut args = args.iter();
|
||||
|
||||
let ctx: &mut u32 = &mut 0;
|
||||
|
||||
let r = unmarshall_then_body!(
|
||||
{
|
||||
*ctx = a + b;
|
||||
a * b
|
||||
},
|
||||
ctx,
|
||||
args,
|
||||
a: u32,
|
||||
b: u32
|
||||
);
|
||||
|
||||
assert_eq!(*ctx, 8);
|
||||
assert_eq!(r, 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_define_env() {
|
||||
use crate::wasm::env_def::ImportSatisfyCheck;
|
||||
|
||||
define_env!(Env, <E: Ext>,
|
||||
ext_gas( _ctx, amount: u32 ) => {
|
||||
let amount = Gas::from(amount);
|
||||
if !amount.is_zero() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(sandbox::HostError)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
assert!(Env::can_satisfy(b"ext_gas", &FunctionType::new(vec![ValueType::I32], None)));
|
||||
assert!(!Env::can_satisfy(b"not_exists", &FunctionType::new(vec![], None)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2018-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 super::Runtime;
|
||||
use crate::exec::Ext;
|
||||
|
||||
use sandbox::{self, TypedValue};
|
||||
use parity_wasm::elements::{FunctionType, ValueType};
|
||||
|
||||
#[macro_use]
|
||||
pub(crate) mod macros;
|
||||
|
||||
pub trait ConvertibleToWasm: Sized {
|
||||
const VALUE_TYPE: ValueType;
|
||||
type NativeType;
|
||||
fn to_typed_value(self) -> TypedValue;
|
||||
fn from_typed_value(_: TypedValue) -> Option<Self>;
|
||||
}
|
||||
impl ConvertibleToWasm for i32 {
|
||||
type NativeType = i32;
|
||||
const VALUE_TYPE: ValueType = ValueType::I32;
|
||||
fn to_typed_value(self) -> TypedValue {
|
||||
TypedValue::I32(self)
|
||||
}
|
||||
fn from_typed_value(v: TypedValue) -> Option<Self> {
|
||||
v.as_i32()
|
||||
}
|
||||
}
|
||||
impl ConvertibleToWasm for u32 {
|
||||
type NativeType = u32;
|
||||
const VALUE_TYPE: ValueType = ValueType::I32;
|
||||
fn to_typed_value(self) -> TypedValue {
|
||||
TypedValue::I32(self as i32)
|
||||
}
|
||||
fn from_typed_value(v: TypedValue) -> Option<Self> {
|
||||
match v {
|
||||
TypedValue::I32(v) => Some(v as u32),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ConvertibleToWasm for u64 {
|
||||
type NativeType = u64;
|
||||
const VALUE_TYPE: ValueType = ValueType::I64;
|
||||
fn to_typed_value(self) -> TypedValue {
|
||||
TypedValue::I64(self as i64)
|
||||
}
|
||||
fn from_typed_value(v: TypedValue) -> Option<Self> {
|
||||
match v {
|
||||
TypedValue::I64(v) => Some(v as u64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type HostFunc<E> =
|
||||
fn(
|
||||
&mut Runtime<E>,
|
||||
&[sandbox::TypedValue]
|
||||
) -> Result<sandbox::ReturnValue, sandbox::HostError>;
|
||||
|
||||
pub(crate) trait FunctionImplProvider<E: Ext> {
|
||||
fn impls<F: FnMut(&[u8], HostFunc<E>)>(f: &mut F);
|
||||
}
|
||||
|
||||
/// This trait can be used to check whether the host environment can satisfy
|
||||
/// a requested function import.
|
||||
pub trait ImportSatisfyCheck {
|
||||
/// Returns `true` if the host environment contains a function with
|
||||
/// the specified name and its type matches to the given type, or `false`
|
||||
/// otherwise.
|
||||
fn can_satisfy(name: &[u8], func_type: &FunctionType) -> bool;
|
||||
}
|
||||
Reference in New Issue
Block a user