-
Notifications
You must be signed in to change notification settings - Fork 2.6k
[contracts] define_env!
re-write as a proc macro
#11888
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it. Just one thing that came to mind: I proposed using Result<ReturnCode, TrapReason>
but that can be confusing because we actually call .into()
on it in the macro. So I think we should be using: Result<ReturnCode, impl Into<TrapReason>>
so that it is clear that any type that can be converted it is okay.
Hm, I don't see any places where such a conversion happens. E.g. this host function definition #[version(1)]
fn seal_set_storage(
ctx: Runtime<E: Ext>,
key_ptr: u32,
value_ptr: u32,
value_len: u32,
) -> Result<u32, TrapReason> {
ctx.set_storage(KeyType::Fix, key_ptr, value_ptr, value_len)
} expands the following piece of code: f("seal1".as_bytes(), "seal_set_storage".as_bytes(), {
fn seal_set_storage<E: Ext>(
ctx: &mut crate::wasm::Runtime<E>,
args: &[sp_sandbox::Value],
) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError>
where
<E::T as frame_system::Config>::AccountId: sp_core::crypto::UncheckedFrom<<E::T as frame_system::Config>::Hash>
+ AsRef<[u8]>,
{
#[allow(unused)]
let mut args = args.iter();
let mut body = || {
let key_ptr : < u32 as crate :: wasm :: env_def :: ConvertibleToWasm > :: NativeType = args . next () . and_then (| v | < u32 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]` proc macro by the user of the macro;
thus this can never be `None`;
qed;") ;
let value_ptr : < u32 as crate :: wasm :: env_def :: ConvertibleToWasm > :: NativeType = args . next () . and_then (| v | < u32 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]` proc macro by the user of the macro;
thus this can never be `None`;
qed;") ;
let value_len : < u32 as crate :: wasm :: env_def :: ConvertibleToWasm > :: NativeType = args . next () . and_then (| v | < u32 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]` proc macro by the user of the macro;
thus this can never be `None`;
qed;") ;
{
ctx.set_storage(KeyType::Fix, key_ptr, value_ptr, value_len)
}
};
let r = body().map_err(|reason| {
ctx.set_trap_reason(reason);
sp_sandbox::HostError
})?;
return Ok(sp_sandbox::ReturnValue::Value({ r.to_typed_value() }));
}
seal_set_storage::<E>
}); it just stores the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. The conversion happens explicitly. Mostly through ?
.
.ok_or(err("Invalid environment definition, expected `mod` to be inlined."))? | ||
.1; | ||
|
||
let mut host_funcs = Vec::<HostFn>::default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The functional style would be let host_funcs = items.iter().map(|i| HostFn::try_from(i.clone())).collect::<Result<Vec<_>, _>()?
. To be fair a lot of people do not like this (e.g. Sergei) 🙈
|
||
match *ret_ty { | ||
syn::Type::Path(tp) => { | ||
let result = &tp.path.segments.first().ok_or(err(span, &msg))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be last()
in case of fully qualified type e.g. ::core::result::Result
syn::Type::Path(tp) => Ok(tp | ||
.path | ||
.segments | ||
.first() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.first() | |
.last() |
syn::PathArguments::AngleBracketed(group) => { | ||
group.args.len().eq(&2).then_some(42).ok_or(err(span, &msg))?; | ||
|
||
let arg2 = group.args.last().ok_or(err(span, &msg))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could possibly simply the args extraction with slice pattern matching e,g, if let [arg1, arg2] = &group.args[..] { }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this would add up one more indent lvl 🙈
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could do something like:
let (arg1, arg2) = if let [arg1, arg2] = &group.args[..] {
Ok((arg1, arrg2))
} else {
Err("Expected exactly 2 args")
}?;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be great, but &group.args
is Punctuated
and even .iter().collect()
won't work on it (the trait FromIterator<GenericArgument>
is not implemented for GenericArgument
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Once you satisfied the CI (clippy) we can merge. |
bot merge |
* define_env proc macro basics + can_satisfy part ready * expand_impls part done * fix of the &FunctionType bug * pallet is compiled * updated host fn definition syntax * docs comments allowed to host fn definitions * all 53 host funcs re-defined by the new macro * unstable feat fix * cleanup * legacy mbe macros cleaned up * Added Env ident to macro attribute; all tests pass! * \#[v(..)] -> \#[version(..)] * some tiny corrections * save * builds with non-magic rt; tests fail * tests pass * refactored errors + added docs * merge err fixed * fixes on @ascjones review, all except moving away from `pub mod env` syntax * debug printing cleared * clippy fix
Resolves #11344