Skip to content

Commit

Permalink
Basic support for dyn Trait to allow cross-contract calls only with…
Browse files Browse the repository at this point in the history
… trait (#1673)

* Added `contract_ref!` macro rule that allows to create a wrapper around the trait defined via `#[ink::trait_definition]`.
Added `From<AccountId>` for the contract builder and forwarder to simplify the usage.
Added `AsRev<AccountId>` and `AsMut<AccountId>` for builder, forwarder, and contract_ref to provide the way modify the wrapper.

* Added comments for the method in the example of the `contract_ref!`

* Make clippy happy

* Make CI happy

* Changed the default behaviour to use alias generated by the `ink::contract`.
Added more examples into documentation

* Apply suggestions from code review

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Apply comments from the PR

* Missed the comment

* Remove error from the example

* Apply suggestions from code review

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Fixed comments from PR

* Update comments around `AccountIdGuard`

* Apply suggestions from code review

Co-authored-by: Michael Müller <mich@elmueller.net>

* Mentioned the PR in the `Unreleased` section

---------

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
Co-authored-by: Hernando Castano <hernando@hcastano.com>
Co-authored-by: Michael Müller <mich@elmueller.net>
  • Loading branch information
4 people authored Mar 3, 2023
1 parent fd0a45d commit f5f3ebe
Show file tree
Hide file tree
Showing 17 changed files with 636 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Basic support for `dyn Trait` to allow cross-contract calls only with trait - [#1673](https://github.com/paritytech/ink/pull/1673)

## Version 4.0.1

Expand Down
2 changes: 2 additions & 0 deletions crates/env/src/call/create_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ pub mod state {
///
/// This is needed because of conflicting implementations of `From<T> for T`
/// in the generated code of `ink`.
///
/// But it is possible to use `From<AccountId> for T` with [`crate::AccountIdGuard`] bound.
pub trait FromAccountId<T>
where
T: Environment,
Expand Down
1 change: 1 addition & 0 deletions crates/env/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ pub use self::{
},
topics::Topics,
types::{
AccountIdGuard,
DefaultEnvironment,
Environment,
FromLittleEndian,
Expand Down
11 changes: 11 additions & 0 deletions crates/env/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ impl FromLittleEndian for u128 {
}
}

/// A trait to enforce that a type should be an [`Environment::AccountId`].
///
/// If you have an [`Environment`] which uses an [`Environment::AccountId`] type other than the ink!
/// provided [`AccountId`](https://docs.rs/ink_primitives/latest/ink_primitives/struct.AccountId.html)
/// you will need to implement this trait for your [`Environment::AccountId`] concrete type.
pub trait AccountIdGuard {}

/// The ink! provided [`AccountId`](https://docs.rs/ink_primitives/latest/ink_primitives/struct.AccountId.html)
/// used in the [`DefaultEnvironment`].
impl AccountIdGuard for AccountId {}

/// The environmental types usable by contracts defined with ink!.
pub trait Environment {
/// The maximum number of supported event topics provided by the runtime.
Expand Down
12 changes: 12 additions & 0 deletions crates/ink/codegen/src/generator/as_dependency/call_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@ impl CallBuilder<'_> {
<AccountId as ::core::clone::Clone>::clone(&self.account_id)
}
}

impl ::core::convert::AsRef<AccountId> for #cb_ident {
fn as_ref(&self) -> &AccountId {
&self.account_id
}
}

impl ::core::convert::AsMut<AccountId> for #cb_ident {
fn as_mut(&mut self) -> &mut AccountId {
&mut self.account_id
}
}
)
}

Expand Down
12 changes: 12 additions & 0 deletions crates/ink/codegen/src/generator/as_dependency/contract_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,18 @@ impl ContractRef<'_> {
as ::ink::ToAccountId<Environment>>::to_account_id(&self.inner)
}
}

impl ::core::convert::AsRef<AccountId> for #ref_ident {
fn as_ref(&self) -> &AccountId {
<_ as ::core::convert::AsRef<AccountId>>::as_ref(&self.inner)
}
}

impl ::core::convert::AsMut<AccountId> for #ref_ident {
fn as_mut(&mut self) -> &mut AccountId {
<_ as ::core::convert::AsMut<AccountId>>::as_mut(&mut self.inner)
}
}
)
}

Expand Down
42 changes: 42 additions & 0 deletions crates/ink/codegen/src/generator/trait_def/call_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,20 @@ impl CallBuilder<'_> {
.finish()
}
}

#[cfg(feature = "std")]
/// We require this manual implementation since the derive produces incorrect trait bounds.
impl<E> ::scale_info::TypeInfo for #call_builder_ident<E>
where
E: ::ink::env::Environment,
<E as ::ink::env::Environment>::AccountId: ::scale_info::TypeInfo + 'static,
{
type Identity = <E as ::ink::env::Environment>::AccountId;

fn type_info() -> ::scale_info::Type {
<<E as ::ink::env::Environment>::AccountId as ::scale_info::TypeInfo>::type_info()
}
}
)
}

Expand All @@ -219,6 +233,16 @@ impl CallBuilder<'_> {
}
}

impl<E, AccountId> ::core::convert::From<AccountId> for #call_builder_ident<E>
where
E: ::ink::env::Environment<AccountId = AccountId>,
AccountId: ::ink::env::AccountIdGuard,
{
fn from(value: AccountId) -> Self {
<Self as ::ink::env::call::FromAccountId<E>>::from_account_id(value)
}
}

impl<E> ::ink::ToAccountId<E> for #call_builder_ident<E>
where
E: ::ink::env::Environment,
Expand All @@ -228,6 +252,24 @@ impl CallBuilder<'_> {
<<E as ::ink::env::Environment>::AccountId as ::core::clone::Clone>::clone(&self.account_id)
}
}

impl<E, AccountId> ::core::convert::AsRef<AccountId> for #call_builder_ident<E>
where
E: ::ink::env::Environment<AccountId = AccountId>,
{
fn as_ref(&self) -> &AccountId {
&self.account_id
}
}

impl<E, AccountId> ::core::convert::AsMut<AccountId> for #call_builder_ident<E>
where
E: ::ink::env::Environment<AccountId = AccountId>,
{
fn as_mut(&mut self) -> &mut AccountId {
&mut self.account_id
}
}
)
}

Expand Down
48 changes: 48 additions & 0 deletions crates/ink/codegen/src/generator/trait_def/call_forwarder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ impl CallForwarder<'_> {
let span = self.span();
let call_forwarder_ident = self.ident();
quote_spanned!(span=>
/// We require this manual implementation since the derive produces incorrect trait bounds.
impl<E> ::core::clone::Clone for #call_forwarder_ident<E>
where
E: ::ink::env::Environment,
Expand All @@ -177,6 +178,7 @@ impl CallForwarder<'_> {
}
}

/// We require this manual implementation since the derive produces incorrect trait bounds.
impl<E> ::core::fmt::Debug for #call_forwarder_ident<E>
where
E: ::ink::env::Environment,
Expand All @@ -188,6 +190,24 @@ impl CallForwarder<'_> {
.finish()
}
}

#[cfg(feature = "std")]
/// We require this manual implementation since the derive produces incorrect trait bounds.
impl<E> ::scale_info::TypeInfo for #call_forwarder_ident<E>
where
E: ::ink::env::Environment,
<E as ::ink::env::Environment>::AccountId: ::scale_info::TypeInfo + 'static,
{
type Identity = <
<Self as ::ink::codegen::TraitCallBuilder>::Builder as ::scale_info::TypeInfo
>::Identity;

fn type_info() -> ::scale_info::Type {
<
<Self as ::ink::codegen::TraitCallBuilder>::Builder as ::scale_info::TypeInfo
>::type_info()
}
}
)
}

Expand All @@ -213,6 +233,16 @@ impl CallForwarder<'_> {
}
}

impl<E, AccountId> ::core::convert::From<AccountId> for #call_forwarder_ident<E>
where
E: ::ink::env::Environment<AccountId = AccountId>,
AccountId: ::ink::env::AccountIdGuard,
{
fn from(value: AccountId) -> Self {
<Self as ::ink::env::call::FromAccountId<E>>::from_account_id(value)
}
}

impl<E> ::ink::ToAccountId<E> for #call_forwarder_ident<E>
where
E: ::ink::env::Environment,
Expand All @@ -223,6 +253,24 @@ impl CallForwarder<'_> {
as ::ink::ToAccountId<E>>::to_account_id(&self.builder)
}
}

impl<E, AccountId> ::core::convert::AsRef<AccountId> for #call_forwarder_ident<E>
where
E: ::ink::env::Environment<AccountId = AccountId>,
{
fn as_ref(&self) -> &AccountId {
<_ as ::core::convert::AsRef<AccountId>>::as_ref(&self.builder)
}
}

impl<E, AccountId> ::core::convert::AsMut<AccountId> for #call_forwarder_ident<E>
where
E: ::ink::env::Environment<AccountId = AccountId>,
{
fn as_mut(&mut self) -> &mut AccountId {
<_ as ::core::convert::AsMut<AccountId>>::as_mut(&mut self.builder)
}
}
)
}

Expand Down
Loading

0 comments on commit f5f3ebe

Please sign in to comment.