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

[contracts] define_env! re-write as a proc macro #11888

Merged
merged 26 commits into from
Aug 22, 2022

Conversation

agryaznov
Copy link
Contributor

@agryaznov agryaznov commented Jul 21, 2022

Resolves #11344

@github-actions github-actions bot added the A3-in_progress Pull request is in progress. No review needed at this stage. label Jul 21, 2022
@agryaznov agryaznov added A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C1-low PR touches the given topic and has a low impact on builders. and removed A3-in_progress Pull request is in progress. No review needed at this stage. labels Jul 22, 2022
@agryaznov agryaznov marked this pull request as ready for review July 22, 2022 17:56
@agryaznov agryaznov requested a review from athei as a code owner July 22, 2022 17:56
@agryaznov agryaznov added D2-notlive 💤 PR contains changes in a runtime directory that is not deployed to a chain that requires an audit. D5-nicetohaveaudit ⚠️ PR contains trivial changes to logic that should be properly reviewed. and removed D2-notlive 💤 PR contains changes in a runtime directory that is not deployed to a chain that requires an audit. labels Jul 22, 2022
frame/contracts/src/wasm/env_def/macros.rs Show resolved Hide resolved
frame/contracts/proc-macro/src/lib.rs Show resolved Hide resolved
frame/contracts/src/wasm/runtime.rs Outdated Show resolved Hide resolved
frame/contracts/src/wasm/runtime.rs Outdated Show resolved Hide resolved
@agryaznov agryaznov requested a review from athei August 1, 2022 16:58
Copy link
Member

@athei athei left a 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.

@agryaznov
Copy link
Contributor Author

agryaznov commented Aug 12, 2022

but that can be confusing because we actually call .into() on it in the macro

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 TrapReason to the runtime as it is, and returns the sp_sandbox::HostError

@agryaznov agryaznov requested a review from athei August 12, 2022 16:01
Copy link
Member

@athei athei left a 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 ?.

@athei athei added D2-notlive 💤 PR contains changes in a runtime directory that is not deployed to a chain that requires an audit. and removed D5-nicetohaveaudit ⚠️ PR contains trivial changes to logic that should be properly reviewed. labels Aug 15, 2022
@athei athei requested review from ascjones and cmichi August 15, 2022 09:10
frame/contracts/proc-macro/src/lib.rs Outdated Show resolved Hide resolved
frame/contracts/proc-macro/src/lib.rs Outdated Show resolved Hide resolved
.ok_or(err("Invalid environment definition, expected `mod` to be inlined."))?
.1;

let mut host_funcs = Vec::<HostFn>::default();
Copy link
Contributor

@ascjones ascjones Aug 18, 2022

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))?;
Copy link
Contributor

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()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.first()
.last()

frame/contracts/proc-macro/src/lib.rs Outdated Show resolved Hide resolved
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))?;
Copy link
Contributor

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[..] { }

Copy link
Contributor Author

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 🙈

Copy link
Contributor

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")
}?;

Copy link
Contributor Author

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)

frame/contracts/proc-macro/src/lib.rs Outdated Show resolved Hide resolved
frame/contracts/src/wasm/runtime.rs Show resolved Hide resolved
Copy link
Contributor

@ascjones ascjones left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@athei
Copy link
Member

athei commented Aug 22, 2022

Once you satisfied the CI (clippy) we can merge.

@athei
Copy link
Member

athei commented Aug 22, 2022

bot merge

@paritytech-processbot paritytech-processbot bot merged commit 1498d86 into master Aug 22, 2022
@paritytech-processbot paritytech-processbot bot deleted the ag-macro-rewrite branch August 22, 2022 13:06
ark0f pushed a commit to gear-tech/substrate that referenced this pull request Feb 27, 2023
* 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
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C1-low PR touches the given topic and has a low impact on builders. D2-notlive 💤 PR contains changes in a runtime directory that is not deployed to a chain that requires an audit.
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Rewrite define_env! as a procedural macro
3 participants