[contracts] API host functions: remove seal_ name prefix + enable aliasing (#12126)

* works but ugly

* refactored + renamed host fns

* fixed tests

* fix benchmarks

* updated marco docs

* Update frame/contracts/proc-macro/src/lib.rs

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* fix for the duplicated prefixed alias bug + test

* refactored a bit

* fix warnings + try to make macro rustdoc compile

* fmt after clearing

* examples update + nocompile

* add seal_ prefixes to unstable host functions

* updated after a review

Co-authored-by: Alexander Theißen <alex.theissen@me.com>
This commit is contained in:
Sasha Gryaznov
2022-09-07 11:54:17 +03:00
committed by GitHub
parent 56e536f6e8
commit d8e9fff3e4
5 changed files with 262 additions and 162 deletions
+59 -13
View File
@@ -174,22 +174,16 @@ impl ToTokens for HostFn {
}
impl HostFn {
pub fn try_from(item: syn::Item) -> syn::Result<Self> {
pub fn try_from(item: syn::ItemFn) -> syn::Result<Self> {
let err = |span, msg| {
let msg = format!("Invalid host function definition. {}", msg);
syn::Error::new(span, msg)
};
let msg = "only #[version(<u8>)] or #[unstable] attribute is allowed.";
let span = item.span();
let item = match item {
syn::Item::Fn(i_fn) => Ok(i_fn),
_ => Err(err(span, msg)),
}?;
let mut attrs = item.attrs.clone();
attrs.retain(|a| !(a.path.is_ident("doc") || a.path.is_ident("prefixed_alias")));
let name = item.sig.ident.to_string();
let attrs: Vec<&syn::Attribute> =
item.attrs.iter().filter(|m| !m.path.is_ident("doc")).collect();
let module = match attrs.len() {
0 => Ok("seal0".to_string()),
1 => {
@@ -306,6 +300,7 @@ impl HostFn {
}
}
}
impl EnvDef {
pub fn try_from(item: syn::ItemMod) -> syn::Result<Self> {
let span = item.span();
@@ -316,9 +311,32 @@ impl EnvDef {
.ok_or(err("Invalid environment definition, expected `mod` to be inlined."))?
.1;
let extract_fn = |i: &syn::Item| match i {
syn::Item::Fn(i_fn) => Some(i_fn.clone()),
_ => None,
};
let selector = |a: &syn::Attribute| a.path.is_ident("prefixed_alias");
let aliases = items
.iter()
.filter_map(extract_fn)
.filter(|i| i.attrs.iter().any(selector))
.map(|mut i| {
i.attrs.retain(|i| !selector(i));
i.sig.ident = syn::Ident::new(
&format!("seal_{}", &i.sig.ident.to_string()),
i.sig.ident.span(),
);
i
})
.map(|i| HostFn::try_from(i));
let host_funcs = items
.iter()
.map(|i| HostFn::try_from(i.clone()))
.filter_map(extract_fn)
.map(|i| HostFn::try_from(i))
.chain(aliases)
.collect::<Result<Vec<_>, _>>()?;
Ok(Self { host_funcs })
@@ -484,7 +502,7 @@ fn expand_impls(def: &mut EnvDef) -> proc_macro2::TokenStream {
/// ```nocompile
/// #[define_env]
/// pub mod some_env {
/// fn some_host_fn(ctx: Runtime<E: Ext>, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<(), TrapReason> {
/// fn some_host_fn(ctx: Runtime<E>, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<(), TrapReason> {
/// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ())
/// }
/// }
@@ -499,17 +517,45 @@ fn expand_impls(def: &mut EnvDef) -> proc_macro2::TokenStream {
/// #[define_env]
/// pub mod some_env {
/// #[version(1)]
/// fn some_host_fn(ctx: Runtime<E: Ext>, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<ReturnCode, TrapReason> {
/// fn some_host_fn(ctx: Runtime<E>, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<ReturnCode, TrapReason> {
/// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ())
/// }
///
/// #[unstable]
/// fn some_host_fn(ctx: Runtime<E: Ext>, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<u32, TrapReason> {
/// fn some_host_fn(ctx: Runtime<E>, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<u32, TrapReason> {
/// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ())
/// }
/// }
/// ```
///
/// In legacy versions of pallet_contracts, it was a naming convention that all host functions had
/// to be named with the `seal_` prefix. For the sake of backwards compatibility, each host function
/// now can get a such prefix-named alias function generated by marking it by the
/// `#[prefixed_alias]` attribute:
///
/// ## Example
///
/// ```nocompile
/// #[define_env]
/// pub mod some_env {
/// #[version(1)]
/// #[prefixed_alias]
/// fn some_host_fn(ctx: Runtime<E>, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<ReturnCode, TrapReason> {
/// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ())
/// }
///
/// #[unstable]
/// fn some_host_fn(ctx: Runtime<E>, key_ptr: u32, value_ptr: u32, value_len: u32) -> Result<u32, TrapReason> {
/// ctx.some_host_fn(KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ())
/// }
/// }
/// ```
///
/// In this example, the following host functions will be generated by the macro:
/// - `some_host_fn()` in module `seal1`,
/// - `seal_some_host_fn()` in module `seal1`,
/// - `some_host_fn()` in module `__unstable__`.
///
/// Only following return types are allowed for the host functions defined with the macro:
/// - `Result<(), TrapReason>`,
/// - `Result<ReturnCode, TrapReason>`,