Skip to content

Commit

Permalink
Implement ink! chain extensions (#592)
Browse files Browse the repository at this point in the history
* add new tests for #[ink(namespace = ..)] and #[ink(selector = ..)] attrs

* [lang] implement new errors for ink! attributes: namespace, selector

* add #[ink(extension = N: u32)] attribute

* apply rustfmt

* [lang] add initial implementation of chain extension proc. macro

* [lang] rename AttributeArg -> AttributeFrag

* rename AttributeFrag::kind field to arg

* rename AttributeArgKind -> AttributeArg

Also introduce a new AttributeArgKind type and AttributeArg::kind method.

* [lang] apply rustfmt

* add Display impl for AttributeArgKind

* [lang] use AttributeArgKind in sanitize_attributes and ensure_first methods

* [lang/ir] improve error reporting for duplicate ink! attributes

* [lang/ir] refactoring and improvements to chain extension IR impl

* [lang/ir] add tests for IR implementation of chain extensions

* [lang/ir] remove some code dupe

* [lang/ir] add getters to ChainExtension

* [lang/ir] add re-exports for ChainExtension definitions

* [lang/codegen] add initial impl for ChainExtensions

* [env] add ChainExtension assoc type to the Environment trait

* [lang] initial impl to make it possible to use chain extension syntax

* [env] improvements to chain extensions API

Also removes the unstable crate feature guarding the feature.

* [lang/macro] add UI test for chain extension

* [lang/macro] register new UI test

* [lang/codegen] fix some codegen bugs with new chain extension feature

* [lang, env] apply rustfmt

* [lang/ir] apply clippy suggestions and fix outdated error messages

* [lang/ir] fix some tests and incorrect error messages

* [examples] apply clippy suggestion

* add ErrorCode to ink! chain extension trait

* add FromStatusCode trait to ink_lang

* add #[ink(expect_output)] and #[ink(expect_ok)] attributes

Also add their handling for the #[ink::chain_extension] proc. macro.

* add ink_lang::IsResultType trait

* add ChainExtensionMethodInputs iterator

* hide docs for IsResultType trait

* add some docs to chain extension codegen

* implement expect_ok and expect_output where bounds in codegen

* apply code review suggestions by (cmichi)

* add ReturnCode::into_u32 getter

* change return type of ext::call_chain_extension: RetCode -> u32

Chain extensions do not follow the general scheme of error return code because they have their own set of errors that is custom defined by the author of the chain extension.

* [lang] add ChainExtension trait

Not yet sure we need it.

* change EnvBackend::call_chain_extension signature

The new signature is much more low-level and supports all the different ways to call a chain extension method.
This commit already implements the chain extension call on the on-chain environment.
More work needs to be done to properly support this for the off-chain environment.

* remove old high-level API for calling chain extension methods

* [env] add new high-level module to handle chain extension calls

* rename ChainExtensionMethodInstance -> ChainExtensionMethod

* [env] add doc examples to chain extension method API

* apply rustfmt

* [env] clippy: allow complex type in ChainExtensionMethod type state

* silence some warnings

* re-export IsResultType from ink_lang crate

* [lang] remove FromStatusCode trait

This trait already exists in the ink_env crate.

* [lang] update codegen for chain extensions

Not yet done but close.

* [lang] update simple chain extension test

Compiles now again.

* apply rustfmt

* update some license headers

* [env] fix where bound

* extend chain extension test case to cover all cases

* add messages for read_small, access and unlock_access

* fix some bugs with chain extension method signatures in test

* fix some bugs and docs in chain extension test

* fix test

* update quickcheck to 1.0

* [env] implement chain extension calling for off-chain env

The new interface is much more lower-level and it is still impossible to use chain state from within the chain extension call. The latter must be fixed as soon as the off-chain environment receives its rework.

* apply rustfmt

* add docs to #[ink::chain_extension] proc. macro

* rename env_types -> env everywhere

* make doc examples for #[ink::chain_extension] compile

* add yet another technical limitation

* make link to simple.rs test case more stable (point to revision)

* fix docs (code suggestion)

Co-authored-by: Michael Müller <michi@parity.io>

* fix docs (code suggestion)

Co-authored-by: Michael Müller <michi@parity.io>

* fix docs (code suggestion)

Co-authored-by: Michael Müller <michi@parity.io>

* fix docs (code suggestion)

Co-authored-by: Michael Müller <michi@parity.io>

* add dev. note to Backend::call_chain_extension

* fix docs example (code suggestion)

Co-authored-by: Andrew Jones <ascjones@gmail.com>

* [env] chain extension: make doc examples/tests compile

* fix some doc comments according to review suggestions

* review suggestion: telling -> meaning

* fix docs (review suggestion)

Co-authored-by: Andrew Jones <ascjones@gmail.com>

* fix docs (review suggestion)

Co-authored-by: Andrew Jones <ascjones@gmail.com>

* improve docs (review suggestion)

Co-authored-by: Andrew Jones <ascjones@gmail.com>

* rename chain extension test file

* analyse_error_code add doc comments for possible errors

* rename expect_ok -> returns_result and expect_output -> handle_status

Some examples and docs might be invalidated or outdated.

* [lang/ir] improve error reporting for ink! namespace attribute with missing parameter

* [lang/*] implement new handle_status and returns_result attributes

* [env] apply rustfmt

Co-authored-by: Michael Müller <michi@parity.io>
Co-authored-by: Andrew Jones <ascjones@gmail.com>
  • Loading branch information
3 people committed Jan 12, 2021
1 parent abd5cf1 commit 59a7f5e
Show file tree
Hide file tree
Showing 41 changed files with 3,026 additions and 271 deletions.
1 change: 0 additions & 1 deletion crates/env/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,3 @@ std = [
"sha3",
"blake2",
]
ink-unstable-chain-extensions = []
21 changes: 0 additions & 21 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,27 +436,6 @@ where
})
}

/// Calls the chain extension with the given ID and inputs.
///
/// Returns the given output type.
///
/// # Errors
///
/// - If the given function ID does not exist in the runtime.
/// - If the given inputs cannot be properly decoded by the runtime.
/// - If the given output type cannot be properly decoded by the contract.
/// - If some chain extension specific conditions are not met.
#[cfg(feature = "ink-unstable-chain-extensions")]
pub fn call_chain_extension<I, O>(func_id: u32, input: &I) -> Result<O>
where
I: scale::Codec + 'static,
O: scale::Codec + 'static,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
EnvBackend::call_chain_extension(instance, func_id, input)
})
}

/// Returns the execution input to the executed contract and decodes it as `T`.
///
/// # Note
Expand Down
28 changes: 23 additions & 5 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub trait EnvBackend {
H: CryptoHash,
T: scale::Encode;

/// Calls the chain extension with the given ID and inputs.
/// Low-level interface to call a chain extension method.
///
/// Returns the output of the chain extension of the specified type.
///
Expand All @@ -138,11 +138,29 @@ pub trait EnvBackend {
/// - If the inputs had an unexpected encoding.
/// - If the output could not be properly decoded.
/// - If some extension specific condition has not been met.
#[cfg(feature = "ink-unstable-chain-extensions")]
fn call_chain_extension<I, O>(&mut self, func_id: u32, input: &I) -> Result<O>
///
/// # Dev. Note
///
/// A valid implementation applies the `status_to_result` closure on
/// the status code returned by the actual call to the chain extension
/// method.
/// Only if the closure finds that the given status code indicates a
/// successful call to the chain extension method is the resulting
/// output buffer passed to the `decode_to_result` closure, in order to
/// drive the decoding and error management process from the outside.
fn call_chain_extension<I, T, E, ErrorCode, F, D>(
&mut self,
func_id: u32,
input: &I,
status_to_result: F,
decode_to_result: D,
) -> ::core::result::Result<T, E>
where
I: scale::Codec + 'static,
O: scale::Codec + 'static;
I: scale::Encode,
T: scale::Decode,
E: From<ErrorCode>,
F: FnOnce(u32) -> ::core::result::Result<(), ErrorCode>,
D: FnOnce(&[u8]) -> ::core::result::Result<T, E>;
}

/// Environmental contract functionality.
Expand Down
14 changes: 7 additions & 7 deletions crates/env/src/call/call_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ where
E: Environment,
{
CallBuilder {
env_types: Default::default(),
env: Default::default(),
callee: Default::default(),
gas_limit: Default::default(),
transferred_value: Default::default(),
Expand All @@ -220,7 +220,7 @@ pub struct CallBuilder<E, Callee, GasLimit, TransferredValue, Args, RetType>
where
E: Environment,
{
env_types: PhantomData<fn() -> E>,
env: PhantomData<fn() -> E>,
/// The current parameters that have been built up so far.
callee: Callee,
gas_limit: GasLimit,
Expand All @@ -242,7 +242,7 @@ where
) -> CallBuilder<E, Set<E::AccountId>, GasLimit, TransferredValue, Args, RetType>
{
CallBuilder {
env_types: Default::default(),
env: Default::default(),
callee: Set(callee),
gas_limit: self.gas_limit,
transferred_value: self.transferred_value,
Expand All @@ -264,7 +264,7 @@ where
gas_limit: u64,
) -> CallBuilder<E, Callee, Set<u64>, TransferredValue, Args, RetType> {
CallBuilder {
env_types: Default::default(),
env: Default::default(),
callee: self.callee,
gas_limit: Set(gas_limit),
transferred_value: self.transferred_value,
Expand All @@ -286,7 +286,7 @@ where
transferred_value: E::Balance,
) -> CallBuilder<E, Callee, GasLimit, Set<E::Balance>, Args, RetType> {
CallBuilder {
env_types: Default::default(),
env: Default::default(),
callee: self.callee,
gas_limit: self.gas_limit,
transferred_value: Set(transferred_value),
Expand Down Expand Up @@ -327,7 +327,7 @@ where
R: IndicateReturnType,
{
CallBuilder {
env_types: Default::default(),
env: Default::default(),
callee: self.callee,
gas_limit: self.gas_limit,
transferred_value: self.transferred_value,
Expand Down Expand Up @@ -362,7 +362,7 @@ where
RetType,
> {
CallBuilder {
env_types: Default::default(),
env: Default::default(),
callee: self.callee,
gas_limit: self.gas_limit,
transferred_value: self.transferred_value,
Expand Down
12 changes: 6 additions & 6 deletions crates/env/src/call/create_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ pub struct CreateBuilder<E, CodeHash, GasLimit, Endowment, Args, R>
where
E: Environment,
{
env_types: PhantomData<fn() -> E>,
env: PhantomData<fn() -> E>,
code_hash: CodeHash,
gas_limit: GasLimit,
endowment: Endowment,
Expand Down Expand Up @@ -181,7 +181,7 @@ where
R: FromAccountId<E>,
{
CreateBuilder {
env_types: Default::default(),
env: Default::default(),
code_hash: Default::default(),
gas_limit: Default::default(),
endowment: Default::default(),
Expand All @@ -202,7 +202,7 @@ where
code_hash: E::Hash,
) -> CreateBuilder<E, Set<E::Hash>, GasLimit, Endowment, Args, R> {
CreateBuilder {
env_types: Default::default(),
env: Default::default(),
code_hash: Set(code_hash),
gas_limit: self.gas_limit,
endowment: self.endowment,
Expand All @@ -224,7 +224,7 @@ where
gas_limit: u64,
) -> CreateBuilder<E, CodeHash, Set<u64>, Endowment, Args, R> {
CreateBuilder {
env_types: Default::default(),
env: Default::default(),
code_hash: self.code_hash,
gas_limit: Set(gas_limit),
endowment: self.endowment,
Expand All @@ -246,7 +246,7 @@ where
endowment: E::Balance,
) -> CreateBuilder<E, CodeHash, GasLimit, Set<E::Balance>, Args, R> {
CreateBuilder {
env_types: Default::default(),
env: Default::default(),
code_hash: self.code_hash,
gas_limit: self.gas_limit,
endowment: Set(endowment),
Expand Down Expand Up @@ -276,7 +276,7 @@ where
) -> CreateBuilder<E, CodeHash, GasLimit, Endowment, Set<ExecutionInput<Args>>, R>
{
CreateBuilder {
env_types: Default::default(),
env: Default::default(),
code_hash: self.code_hash,
gas_limit: self.gas_limit,
endowment: self.endowment,
Expand Down

0 comments on commit 59a7f5e

Please sign in to comment.