Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

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

Merged
merged 19 commits into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frame/contracts/fixtures/call_runtime.wat
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
;; This passes its input to `seal_call_runtime` and returns the return value to its caller.
(module
(import "__unstable__" "seal_call_runtime" (func $seal_call_runtime (param i32 i32) (result i32)))
(import "__unstable__" "call_runtime" (func $call_runtime (param i32 i32) (result i32)))
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
(import "env" "memory" (memory 1 1))
Expand All @@ -17,7 +17,7 @@
)
;; Just use the call passed as input and store result to memory
(i32.store (i32.const 0)
(call $seal_call_runtime
(call $call_runtime
(i32.const 4) ;; Pointer where the call is stored
(i32.load (i32.const 0)) ;; Size of the call
)
Expand Down
67 changes: 60 additions & 7 deletions frame/contracts/proc-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,20 @@ impl HostFn {
};
let msg = "only #[version(<u8>)] or #[unstable] attribute is allowed.";
let span = item.span();
let item = match item {
let mut item = match item {
syn::Item::Fn(i_fn) => Ok(i_fn),
_ => Err(err(span, msg)),
}?;

let name = item.sig.ident.to_string();
let attrs: Vec<&syn::Attribute> =
item.attrs.iter().filter(|m| !m.path.is_ident("doc")).collect();
let attrs = &mut item.attrs;

let name = if attrs.iter().any(|a| a.path.is_ident("prefixed_alias")) {
"seal_".to_string() + &item.sig.ident.to_string()
} else {
item.sig.ident.to_string()
};

attrs.retain(|a| !(a.path.is_ident("doc") || a.path.is_ident("prefixed_alias")));

let module = match attrs.len() {
0 => Ok("seal0".to_string()),
Expand Down Expand Up @@ -306,6 +312,7 @@ impl HostFn {
}
}
}

impl EnvDef {
pub fn try_from(item: syn::ItemMod) -> syn::Result<Self> {
let span = item.span();
Expand All @@ -316,9 +323,27 @@ 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
})
.map(|i| HostFn::try_from(syn::Item::Fn(i)));

let host_funcs = items
.iter()
.map(|i| HostFn::try_from(i.clone()))
.chain(aliases)
.collect::<Result<Vec<_>, _>>()?;

Ok(Self { host_funcs })
Expand Down Expand Up @@ -484,7 +509,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(|_| ())
/// }
/// }
Expand All @@ -499,17 +524,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>, 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: 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 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>`,
Expand Down
22 changes: 11 additions & 11 deletions frame/contracts/src/benchmarking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,7 @@ benchmarks! {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_set_storage",
name: "set_storage",
params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
Expand Down Expand Up @@ -968,7 +968,7 @@ benchmarks! {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_set_storage",
name: "set_storage",
params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
Expand Down Expand Up @@ -1016,7 +1016,7 @@ benchmarks! {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_set_storage",
name: "set_storage",
params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
Expand Down Expand Up @@ -1068,7 +1068,7 @@ benchmarks! {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_clear_storage",
name: "clear_storage",
params: vec![ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
Expand Down Expand Up @@ -1115,7 +1115,7 @@ benchmarks! {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_clear_storage",
name: "clear_storage",
params: vec![ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
Expand Down Expand Up @@ -1163,7 +1163,7 @@ benchmarks! {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_get_storage",
name: "get_storage",
params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
Expand Down Expand Up @@ -1217,7 +1217,7 @@ benchmarks! {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_get_storage",
name: "get_storage",
params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
Expand Down Expand Up @@ -1272,7 +1272,7 @@ benchmarks! {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_contains_storage",
name: "contains_storage",
params: vec![ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
Expand Down Expand Up @@ -1319,7 +1319,7 @@ benchmarks! {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_contains_storage",
name: "contains_storage",
params: vec![ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
Expand Down Expand Up @@ -1367,7 +1367,7 @@ benchmarks! {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_take_storage",
name: "take_storage",
params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
Expand Down Expand Up @@ -1421,7 +1421,7 @@ benchmarks! {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_take_storage",
name: "take_storage",
params: vec![ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32],
return_type: Some(ValueType::I32),
}],
Expand Down
66 changes: 54 additions & 12 deletions frame/contracts/src/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,7 @@ mod tests {
(module
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
(import "__unstable__" "seal_contains_storage" (func $seal_contains_storage (param i32 i32) (result i32)))
(import "__unstable__" "contains_storage" (func $contains_storage (param i32 i32) (result i32)))
(import "env" "memory" (memory 1 1))


Expand All @@ -947,7 +947,7 @@ mod tests {
)
;; Call seal_clear_storage and save what it returns at 0
(i32.store (i32.const 0)
(call $seal_contains_storage
(call $contains_storage
(i32.const 8) ;; key_ptr
(i32.load (i32.const 4)) ;; key_len
)
Expand Down Expand Up @@ -1678,11 +1678,53 @@ mod tests {
)
(func (export "deploy"))
)
"#;

const CODE_TIMESTAMP_NOW_UNPREFIXED: &str = r#"
(module
(import "seal0" "now" (func $now (param i32 i32)))
(import "env" "memory" (memory 1 1))

;; size of our buffer is 32 bytes
(data (i32.const 32) "\20")

(func $assert (param i32)
(block $ok
(br_if $ok
(get_local 0)
)
(unreachable)
)
)

(func (export "call")
;; This stores the block timestamp in the buffer
(call $now (i32.const 0) (i32.const 32))

;; assert len == 8
(call $assert
(i32.eq
(i32.load (i32.const 32))
(i32.const 8)
)
)

;; assert that contents of the buffer is equal to the i64 value of 1111.
(call $assert
(i64.eq
(i64.load (i32.const 0))
(i64.const 1111)
)
)
)
(func (export "deploy"))
)
"#;

#[test]
fn now() {
assert_ok!(execute(CODE_TIMESTAMP_NOW, vec![], MockExt::default()));
assert_ok!(execute(CODE_TIMESTAMP_NOW_UNPREFIXED, vec![], MockExt::default()));
}

const CODE_MINIMUM_BALANCE: &str = r#"
Expand Down Expand Up @@ -2221,7 +2263,7 @@ mod tests {
#[cfg(feature = "unstable-interface")]
const CODE_CALL_RUNTIME: &str = r#"
(module
(import "__unstable__" "seal_call_runtime" (func $seal_call_runtime (param i32 i32) (result i32)))
(import "__unstable__" "call_runtime" (func $call_runtime (param i32 i32) (result i32)))
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
(import "env" "memory" (memory 1 1))
Expand All @@ -2238,7 +2280,7 @@ mod tests {
)
;; Just use the call passed as input and store result to memory
(i32.store (i32.const 0)
(call $seal_call_runtime
(call $call_runtime
(i32.const 4) ;; Pointer where the call is stored
(i32.load (i32.const 0)) ;; Size of the call
)
Expand Down Expand Up @@ -2350,7 +2392,7 @@ mod tests {
(module
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
(import "__unstable__" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32 i32) (result i32)))
(import "__unstable__" "set_storage" (func $set_storage (param i32 i32 i32 i32) (result i32)))
(import "env" "memory" (memory 1 1))

;; [0, 4) size of input buffer
Expand All @@ -2367,7 +2409,7 @@ mod tests {
)
;; Store the passed value to the passed key and store result to memory
(i32.store (i32.const 168)
(call $seal_set_storage
(call $set_storage
(i32.const 8) ;; key_ptr
(i32.load (i32.const 4)) ;; key_len
(i32.add ;; value_ptr = 8 + key_len
Expand Down Expand Up @@ -2421,7 +2463,7 @@ mod tests {
(module
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
(import "__unstable__" "seal_get_storage" (func $seal_get_storage (param i32 i32 i32 i32) (result i32)))
(import "__unstable__" "get_storage" (func $get_storage (param i32 i32 i32 i32) (result i32)))
(import "env" "memory" (memory 1 1))

;; [0, 4) size of input buffer (160 bytes as we copy the key+len here)
Expand All @@ -2442,7 +2484,7 @@ mod tests {
)
;; Load a storage value and result of this call into the output buffer
(i32.store (i32.const 168)
(call $seal_get_storage
(call $get_storage
(i32.const 12) ;; key_ptr
(i32.load (i32.const 8)) ;; key_len
(i32.const 172) ;; Pointer to the output buffer
Expand Down Expand Up @@ -2515,7 +2557,7 @@ mod tests {
(module
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
(import "__unstable__" "seal_clear_storage" (func $seal_clear_storage (param i32 i32) (result i32)))
(import "__unstable__" "clear_storage" (func $clear_storage (param i32 i32) (result i32)))
(import "env" "memory" (memory 1 1))

;; size of input buffer
Expand All @@ -2532,7 +2574,7 @@ mod tests {
)
;; Call seal_clear_storage and save what it returns at 0
(i32.store (i32.const 0)
(call $seal_clear_storage
(call $clear_storage
(i32.const 8) ;; key_ptr
(i32.load (i32.const 4)) ;; key_len
)
Expand Down Expand Up @@ -2601,7 +2643,7 @@ mod tests {
(module
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
(import "__unstable__" "seal_take_storage" (func $seal_take_storage (param i32 i32 i32 i32) (result i32)))
(import "__unstable__" "take_storage" (func $take_storage (param i32 i32 i32 i32) (result i32)))
(import "env" "memory" (memory 1 1))

;; [0, 4) size of input buffer (160 bytes as we copy the key+len here)
Expand All @@ -2623,7 +2665,7 @@ mod tests {

;; Load a storage value and result of this call into the output buffer
(i32.store (i32.const 168)
(call $seal_take_storage
(call $take_storage
(i32.const 12) ;; key_ptr
(i32.load (i32.const 8)) ;; key_len
(i32.const 172) ;; Pointer to the output buffer
Expand Down
Loading