Skip to content

Commit

Permalink
[ink_e2e] method to generate and fund unique accounts (#1615)
Browse files Browse the repository at this point in the history
* Handle `LangError` from instantiate (fails for success case)

This commit lets us grab what's in the output buffer after our call to
`instantiate`, however we are unable to succesfully decode the
`AccountId` from the success case.

* Change generic in `CreateBuilder` to be more consistent

* Remove extra generic parameter

I accidently introduced this not knowing that the generic `C` was for
the return type

* Remove generic return type parameter from `CreateBuidler` codegen

* Hardcode assumption that `instantiate` returns a `ConstructorResult`

* Update `CreateBuilder` codegen to just return `Self`

* Remove generic usage to fix formatting

* Unwrap `ConstructorResult` in `contract-ref` E2E test

* Clean up some comments

* Bring back the assumption that we expect an `AccountId`

Is supposed to help give better error messages if somebody uses a wrong
type with the builder

* Remove unused method

* Update doc tests for new builder pattern

* Clean up some comments

* Fix Clippy warning

* Fix typo

* Add `try_instantiate` method to `CreateBuilder`

* Remove unneeded `unwrap`

* Remove debug logging

* Update doc test

* Fix some typos

Co-authored-by: Andrew Jones <[email protected]>

* Mention panicking behaviour of `instantiate` methods

* Improve error messages from wrong `returns()` type

* Actually check return values from `call_instantiate`

* Add test showing a reverting constructor with `Ok` in error buffer

* Check that we're only returning `LangError`s if the contract reverted

* Clean up the manual encoding test a bit

* Add test for constructors which return a contract level error

* Add `CreateBuilder` message which calls a fallible constructor

* Add test which calls falliable constructor for success case

* Get verbose `instantiate_contract_with_result` decoding past typechecker

* Add `try_instantiate_with_result` to `CreateBuilder`

* Clean up decoding logic for output from `seal_instatiate`

* Small cleanups in `call-builder` E2E tests

* RustFmt `env_access`

* Remove unused import

* Flip decoding logic so that it's more strict initially

Otherwise we may end up decoding a `Result` too eagerly and end up in a
wrong branch.

* Add test which revert a fallible constructor

* Remove note about removing `assert` statement

We still need this to prevent someone from manually encoding an `Ok`
value into the return buffer.

* Check return value from fallible constructor tests

* Update E2E Builder typedef to match changes

* Update E2E test for new call syntax

* Use `selector_bytes!` macro in more places

* Change order to accounts used in tests

The tests started failing due to nonce issues, re-ordering the accounts
seems to help with that.

* Update function names to use `fallible`

* Add note about docs

* Update `ContractRef` codegen to use fallible constructor return types

* Stop returning an `AccountId` directly from `CreateBuilder::try_instantiate_fallible`

This matches the behaviour of the other intantiate methods

* Add panicking version of `try_instantiate_fallible`

* Add test for using fallible constructors through ContractRefs

* Add test for instantiation failure too

* Add `instantiate_fallible` to `CreateParams`

* Add a couple of missing docs

* Convert `call-builder` test return type to `AccountId`

* Extract reverted fallible constructor fn for testing

* Fmt

* Add fallible_constructor_reverted_lang_error FAILs

* Rename tests

* Add test for a decode error

* Rename some tests

* Make `Result` types more explicit

* Add another test

* Clean up decoding match statement

* Andrew was right

* Small cleanups to naming and imports

* Couple more import and comment fixes

* Use decode trait method directly

* Fix `call-builder` E2E tests

This now accounts for the better error handling in the `CalleeReverted`
case

* Remove leading colons from non-codegen contexts

* Add doc test for `instantiate_fallible_contract`

* Add doc test to `build_create` function

* Remove leftover trait bound

We can't use this with fallible constructors

* Remove a few more leading colons

* Panic in case where we get `Ok` encoded into error buffer

* Add some links to env docs

* Add more docs to `call-builder` E2E tests

* Use correct path in `call-builder` docs

* Remove fallible create_builder.rs methods

* WIP experiment

* InstantiateResult blanket impl for T and Result

* Introduce ContractRef type parameter

* Fix up env access

* WIP...

* Make it compile

* Add ContractStorage parameter

* Remove commented out instantiate_fallible_contract

* Convert to env Error in helper

* Return Decode errors in case of invalid Result first byte

* Fix impls::instantiate_contract

* Remove ContractStorage generic parameter

* Fix env access

* Use generated constructor ref, introduces update_selector

* Fix e2e

* Use return_value() method in e2e test

* Remove commented out code

* Typos

* Clippy

* Rename some instantiate_fallible

* Restore `returns` method

* Remove ContractReference Result impl

* WIP implementing ConstructorReturnType

* Reorder ContractRef parameter, move ContractRef and ContractEnv trait to env crate

* Fmt and fix

* Remove E param from build_create

* Fix up build_create

* Fix up e2e creat builder

* Implement ContstructorReturnType for the storage_ident

* Fmt

* Fix envaccess test

* Fully qualify Result in macro

* More fully qualify Result in macro

* Fix up build_create examples

* Add test for different combos of Self and struct name

* Fix ui test

* Fmt

* Remove unused assoc type

* Change error fn to return Option<Result>

* Remove commented out code

* Fmt

* Fix `call-builder` E2E test compilation

* Fix `contract-ref` E2E test compilation

* ConstructorReturnType comments

* Fix up return types after merge

* Fmt

* Clippy

* Fix create_builder tests

* Fix some of the comment links

* Unwrap errors from default `instantiate_fallible` codepath

* Fix `contract-ref` E2E test

* Wrap long line

* Remove TODO

* Fix instatiation doc test

* Fix cross-contract compile test

* Clean up some comments

* Fix `contract-ref` compilation

* Remove outdated doc

* Update comment

* Another comment fix

* Bump `contract-metadata`

Fixes some inconsistent errors between Clippy and `rustc`

* Remove fallible create_builder.rs methods

* WIP experiment

* InstantiateResult blanket impl for T and Result

* Introduce ContractRef type parameter

* Fix up env access

* WIP...

* Make it compile

* Add ContractStorage parameter

* Remove commented out instantiate_fallible_contract

* Convert to env Error in helper

* Return Decode errors in case of invalid Result first byte

* Fix impls::instantiate_contract

* Remove ContractStorage generic parameter

* Fix env access

* Use generated constructor ref, introduces update_selector

* Fix e2e

* Remove commented out code

* Typos

* Clippy

* Rename some instantiate_fallible

* Restore `returns` method

* Remove ContractReference Result impl

* WIP implementing ConstructorReturnType

* Reorder ContractRef parameter, move ContractRef and ContractEnv trait to env crate

* Fmt and fix

* Remove E param from build_create

* Fix up build_create

* Fix up e2e creat builder

* Implement ContstructorReturnType for the storage_ident

* Fmt

* Fix envaccess test

* Fully qualify Result in macro

* More fully qualify Result in macro

* Fix up build_create examples

* Add test for different combos of Self and struct name

* Fix ui test

* Fmt

* Remove unused assoc type

* Change error fn to return Option<Result>

* Remove commented out code

* Fmt

* ConstructorReturnType comments

* Fix `contract-ref` E2E test compilation

* Fix up return types after merge

* Fmt

* Clippy

* Fix create_builder tests

* Fix cross-contract compile test

* Clean up some comments

* Remove outdated doc

* Update comment

* Another comment fix

* Wrap long line

* Remove TODO

* Bump `contract-metadata`

Fixes some inconsistent errors between Clippy and `rustc`

* Fix `CreateBuilder` compilation

* Fix one of the doc tests

* Clean up doc tests a bit

* WIP create accounts

* Try transfer balance

* WIP try creating and funding account for single test.

* Update all tests to use create_and_fund_account

* Fix error

* Fmt

* SP

* Clippy

* Remove commented out code

* Update crates/e2e/src/xts.rs

Co-authored-by: Michael Müller <[email protected]>

Co-authored-by: Hernando Castano <[email protected]>
Co-authored-by: Hernando Castano <[email protected]>
Co-authored-by: Michael Müller <[email protected]>
  • Loading branch information
4 people authored Jan 24, 2023
1 parent 59bbd36 commit 8321e6f
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 54 deletions.
61 changes: 52 additions & 9 deletions crates/e2e/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ use super::{
log_error,
log_info,
sr25519,
xts::{
Call,
InstantiateWithCode,
},
CodeUploadResult,
ContractExecResult,
ContractInstantiateResult,
Expand All @@ -35,6 +31,7 @@ use contract_metadata::ContractMetadata;
use ink_env::Environment;
use ink_primitives::MessageResult;

use sp_core::Pair;
use sp_runtime::traits::{
IdentifyAccount,
Verify,
Expand All @@ -55,7 +52,10 @@ use subxt::{
ValueDef,
},
},
tx::ExtrinsicParams,
tx::{
ExtrinsicParams,
PairSigner,
},
};

/// Result of a contract instantiation.
Expand Down Expand Up @@ -300,11 +300,8 @@ where

E: Environment,
E::AccountId: Debug,
E::Balance: Debug + scale::Encode + serde::Serialize,
E::Balance: Debug + scale::HasCompact + serde::Serialize,
E::Hash: Debug + scale::Encode,

Call<E, E::Balance>: scale::Encode,
InstantiateWithCode<E::Balance>: scale::Encode,
{
/// Creates a new [`Client`] instance.
pub async fn new(url: &str, contracts: impl IntoIterator<Item = &str>) -> Self {
Expand Down Expand Up @@ -342,6 +339,52 @@ where
}
}

/// Generate a new keypair and fund with the given amount from the origin account.
///
/// Because many tests may execute this in parallel, transfers may fail due to a race condition
/// with account indices. Therefore this will reattempt transfers a number of times.
pub async fn create_and_fund_account(
&self,
origin: &Signer<C>,
amount: E::Balance,
) -> Signer<C>
where
E::Balance: Clone,
C::AccountId: Clone + core::fmt::Display,
{
let (pair, _, _) = <sr25519::Pair as Pair>::generate_with_phrase(None);
let account_id =
<C::Signature as Verify>::Signer::from(pair.public()).into_account();

for _ in 0..6 {
let transfer_result = self
.api
.try_transfer_balance(origin, account_id.clone(), amount)
.await;
match transfer_result {
Ok(_) => {
log_info(&format!(
"transfer from {} to {} succeeded",
origin.account_id(),
account_id,
));
break
}
Err(err) => {
log_info(&format!(
"transfer from {} to {} failed with {:?}",
origin.account_id(),
account_id,
err
));
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
}
}
}

PairSigner::new(pair)
}

/// This function extracts the metadata of the contract at the file path
/// `target/ink/$contract_name.contract`.
///
Expand Down
58 changes: 54 additions & 4 deletions crates/e2e/src/xts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,25 @@ pub struct Call<E: Environment, B> {
data: Vec<u8>,
}

/// A raw call to `pallet-contracts`'s `call`.
#[derive(Debug, scale::Encode, scale::Decode)]
pub struct Call2<E: Environment, B> {
dest: sp_runtime::MultiAddress<E::AccountId, ()>,
#[codec(compact)]
value: B,
gas_limit: Weight,
storage_deposit_limit: Option<B>,
data: Vec<u8>,
}

/// A raw call to `pallet-contracts`'s `call`.
#[derive(Debug, scale::Encode, scale::Decode)]
pub struct Transfer<E: Environment, C: subxt::Config> {
dest: C::Address,
#[codec(compact)]
value: E::Balance,
}

#[derive(
Debug, Clone, Copy, scale::Encode, scale::Decode, PartialEq, Eq, serde::Serialize,
)]
Expand Down Expand Up @@ -167,10 +186,7 @@ where
sr25519::Signature: Into<C::Signature>,

E: Environment,
E::Balance: scale::Encode + serde::Serialize,

Call<E, E::Balance>: scale::Encode,
InstantiateWithCode<E::Balance>: scale::Encode,
E::Balance: scale::HasCompact + serde::Serialize,
{
/// Creates a new [`ContractsApi`] instance.
pub async fn new(client: OnlineClient<C>, url: &str) -> Self {
Expand All @@ -189,6 +205,40 @@ where
}
}

/// Attempt to transfer the `value` from `origin` to `dest`.
///
/// Returns `Ok` on success, and a [`subxt::Error`] if the extrinsic is
/// invalid (e.g. out of date nonce)
pub async fn try_transfer_balance(
&self,
origin: &Signer<C>,
dest: C::AccountId,
value: E::Balance,
) -> Result<(), subxt::Error> {
let call = subxt::tx::StaticTxPayload::new(
"Balances",
"transfer",
Transfer::<E, C> {
dest: dest.into(),
value,
},
Default::default(),
)
.unvalidated();

let tx_progress = self
.client
.tx()
.sign_and_submit_then_watch_default(&call, origin)
.await?;

tx_progress.wait_for_in_block().await.unwrap_or_else(|err| {
panic!("error on call `wait_for_in_block`: {:?}", err);
});

Ok(())
}

/// Dry runs the instantiation of the given `code`.
pub async fn instantiate_with_code_dry_run(
&self,
Expand Down
Loading

0 comments on commit 8321e6f

Please sign in to comment.