Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[E2E] Call builders and extra gas margin option #1917

Merged
merged 52 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
bc27b10
add extra arg to specify extra gas portion
Sep 16, 2023
313d351
changelog
Sep 16, 2023
2578e5a
fmt
Sep 16, 2023
116caf6
fix the test
Sep 18, 2023
024405b
add call builders
Sep 25, 2023
e7b9c0e
Update changelog
Sep 25, 2023
da053c6
fix spelling
Sep 25, 2023
e872567
introduce bare calls alongside builder api
Sep 27, 2023
9df632f
add docs
Sep 27, 2023
86fab73
add upload builder
Sep 27, 2023
9e7814e
remove async in upload
Sep 27, 2023
2b3260f
ignore doctest
Sep 27, 2023
3bef64c
update integration tests
Sep 27, 2023
ad43cce
`submit_dry_run()` -> `dry_run()`
Sep 27, 2023
5109e64
format tests
Sep 27, 2023
9e5b311
fixes
Sep 27, 2023
7e7a02e
fmt
Sep 27, 2023
8e8713f
another fmt
Sep 27, 2023
8cdf350
Make env cloneable and take constructor as mut ref
Sep 28, 2023
505e582
one more fix
Sep 28, 2023
48e9543
remove unnecessary trait bound
Sep 28, 2023
93221db
remove more trait bounds
Sep 28, 2023
a8ccedf
fix tests and fmt
Sep 28, 2023
3c600b4
fix tests and tweak drink backend
Sep 28, 2023
0c076f4
move margin call to separate trait
Sep 28, 2023
3d3e04d
update docs
Sep 28, 2023
f1a3228
add BuilderClient as supertrait of E2EBackend and fix docs
Sep 28, 2023
bb332ad
fix more tests and docs
Sep 28, 2023
975762a
one last doc fix
Sep 28, 2023
714d7d8
Merge branch 'master' into gn/extra_gas_config
Sep 28, 2023
2855db2
UI tests
Sep 28, 2023
c091243
Remove unecessary trait bounds
Sep 29, 2023
5f11cbc
remove move unecessary trait bounds
Sep 29, 2023
62b1608
one more missing trait
Sep 29, 2023
d96fed4
Revert "UI tests"
Sep 29, 2023
61a0fa0
keep Clone with custom env in UI tests
Sep 29, 2023
6af9c46
remove duplicate derive
Sep 29, 2023
02bb3ec
add proper dry-run in drink
Oct 3, 2023
2d62be8
reformat the trait and add gas limit option
Oct 3, 2023
6be1cdc
fmt example
Oct 3, 2023
8036919
update docs
Oct 3, 2023
1bebfc9
Merge branch 'master' into gn/extra_gas_config
Oct 3, 2023
d7c6be4
fix CI by adding necessary trait bounds
Oct 4, 2023
7d6aafa
fix CI
Oct 4, 2023
3d8f9ba
Update integration-tests/call-builder-return-value/lib.rs
Oct 7, 2023
d3560c3
Merge branch 'master' into gn/extra_gas_config
Oct 7, 2023
7542d5a
Suggestions for removing code duplication in #1917 (#1938)
ascjones Oct 17, 2023
aef2dcd
add dummy error struct to drink
Oct 17, 2023
c5b78de
Merge branch 'master' into gn/extra_gas_config
Oct 17, 2023
c649b58
remove default
Oct 17, 2023
c5c1de5
pass args to instantiate dry run correctly
Oct 18, 2023
ccac9ff
add license files
Oct 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

## Changed
- [E2E] E2E call builders and extra gas margin option - [#1917](https://github.com/paritytech/ink/pull/1917)
- Make `set_code_hash` generic - [#1906](https://github.com/paritytech/ink/pull/1906)

## Version 5.0.0-alpha
Expand Down
30 changes: 29 additions & 1 deletion crates/e2e/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

use super::Keypair;
use crate::{
backend_calls::InstantiateBuilder,
builders::CreateBuilderPartial,
CallBuilder,
CallBuilderFinal,
CallDryRunResult,
CallResult,
Expand Down Expand Up @@ -42,7 +44,7 @@ pub trait ChainBackend {
/// Account type.
type AccountId;
/// Balance type.
type Balance: Send;
type Balance: Send + From<u32>;
pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved
/// Error type.
type Error;
/// Event log type.
Expand Down Expand Up @@ -93,6 +95,18 @@ pub trait ContractsBackend<E: Environment> {
/// Event log type.
type EventLog;

fn create_instantiate_call<'a, Contract, Args: Send + scale::Encode, R>(
&'a mut self,
contract_name: &'a str,
caller: &'a Keypair,
Copy link
Member

Choose a reason for hiding this comment

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

just wondering... maybe alice() should be moved to default as well (similarly to value, storage deposit and margin)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IMHO, the caller should be specified explicitly. I don't want to hide this information from the developer per se

constructor: CreateBuilderPartial<E, Contract, Args, R>,
) -> InstantiateBuilder<'a, E, Contract, Args, R, Self>
where
Self: Sized,
{
InstantiateBuilder::new(self, caller, contract_name, constructor)
}

/// The function subsequently uploads and instantiates an instance of the contract.
///
/// This function extracts the metadata of the contract at the file path
Expand All @@ -107,6 +121,7 @@ pub trait ContractsBackend<E: Environment> {
caller: &Keypair,
constructor: CreateBuilderPartial<E, Contract, Args, R>,
value: E::Balance,
extra_gas_portion: Option<usize>,
storage_deposit_limit: Option<E::Balance>,
) -> Result<InstantiationResult<E, Self::EventLog>, Self::Error>;

Expand Down Expand Up @@ -134,6 +149,18 @@ pub trait ContractsBackend<E: Environment> {
storage_deposit_limit: Option<E::Balance>,
) -> Result<UploadResult<E, Self::EventLog>, Self::Error>;

/// Creates a call builder then can later be submitted.
fn create_call<'a, Args: Sync + scale::Encode, RetType: Send + scale::Decode>(
&'a mut self,
caller: &'a Keypair,
message: &'a CallBuilderFinal<E, Args, RetType>,
) -> CallBuilder<'a, E, Args, RetType, Self>
where
Self: Sized,
{
CallBuilder::new(self, caller, message)
}

/// Executes a `call` for the contract at `account_id`.
///
/// Returns when the transaction is included in a block. The return value
Expand All @@ -143,6 +170,7 @@ pub trait ContractsBackend<E: Environment> {
caller: &Keypair,
message: &CallBuilderFinal<E, Args, RetType>,
value: E::Balance,
extra_gas_portion: Option<usize>,
storage_deposit_limit: Option<E::Balance>,
) -> Result<CallResult<E, RetType, Self::EventLog>, Self::Error>
where
Expand Down
229 changes: 229 additions & 0 deletions crates/e2e/src/backend_calls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
use ink_env::Environment;
use pallet_contracts_primitives::ContractInstantiateResult;
use scale::{
Decode,
Encode,
};

use crate::{
builders::CreateBuilderPartial,
CallBuilderFinal,
CallDryRunResult,
CallResult,
ContractsBackend,
InstantiationResult,
};

use super::Keypair;

pub struct CallBuilder<'a, E, Args, RetType, CB>
where
E: Environment,
Args: Sync + Encode,
RetType: Send + Decode,

CB: ContractsBackend<E>,
{
client: &'a mut CB,
caller: &'a Keypair,
message: &'a CallBuilderFinal<E, Args, RetType>,
value: E::Balance,
extra_gas_portion: Option<usize>,
storage_deposit_limit: Option<E::Balance>,
}

impl<'a, E, Args, RetType, CB> CallBuilder<'a, E, Args, RetType, CB>
where
E: Environment,
Args: Sync + Encode,
RetType: Send + Decode,
E::Balance: Clone,

pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved
CB: ContractsBackend<E>,
{
/// Initialize a call builder with essential values.
pub fn new(
client: &'a mut CB,
caller: &'a Keypair,
message: &'a CallBuilderFinal<E, Args, RetType>,
) -> CallBuilder<'a, E, Args, RetType, CB>
where
E::Balance: From<u32>,
{
Self {
client,
caller,
message,
value: 0u32.into(),
extra_gas_portion: None,
storage_deposit_limit: None,
}
}

/// Provide value with a call
pub fn value(&mut self, value: E::Balance) {
self.value = value;
}

/// Increases the gas limit marginally by a specified percent.
/// Useful when the message's gas usage depends on the runtime state
/// and the dry run does not produce an accurate gas estimate.
///
/// # Example
///
/// With dry run gas estimate of `100` units and `5`% extra gas portion specified,
/// the set gas limit becomes `105` units
pub fn extra_gas_portion(&mut self, per_cent: usize) {
if per_cent == 0 {
self.extra_gas_portion = None
} else {
self.extra_gas_portion = Some(per_cent)
}
}

/// Specify the max amount of funds that can be charged for storage.
pub fn storage_deposit_limit(&mut self, storage_deposit_limit: E::Balance) {
if storage_deposit_limit == 0u32.into() {
self.storage_deposit_limit = None
} else {
self.storage_deposit_limit = Some(storage_deposit_limit)
}
}

/// Submit the call for the on-chain execution.
pub async fn submit(
&mut self,
) -> Result<CallResult<E, RetType, CB::EventLog>, CB::Error>
where
CallBuilderFinal<E, Args, RetType>: Clone,
{
CB::call(
self.client,
self.caller,
self.message,
self.value,
self.extra_gas_portion,
self.storage_deposit_limit,
)
.await
}

/// Dry run the call.
pub async fn submit_dry_run(&mut self) -> CallDryRunResult<E, RetType>
where
CallBuilderFinal<E, Args, RetType>: Clone,
{
CB::call_dry_run(
self.client,
self.caller,
self.message,
self.value,
self.storage_deposit_limit,
)
.await
}
}

pub struct InstantiateBuilder<'a, E, Contract, Args, R, CB>
where
E: Environment,
Args: Send + Encode,

CB: ContractsBackend<E>,
{
client: &'a mut CB,
caller: &'a Keypair,
contract_name: &'a str,
constructor: CreateBuilderPartial<E, Contract, Args, R>,
value: E::Balance,
extra_gas_portion: Option<usize>,
storage_deposit_limit: Option<E::Balance>,
}

impl<'a, E, Contract, Args, R, CB> InstantiateBuilder<'a, E, Contract, Args, R, CB>
where
E: Environment,
Args: Send + Encode,

CB: ContractsBackend<E>,
{
/// Initialize a call builder with essential values.
pub fn new(
client: &'a mut CB,
caller: &'a Keypair,
contract_name: &'a str,
constructor: CreateBuilderPartial<E, Contract, Args, R>,
) -> InstantiateBuilder<'a, E, Contract, Args, R, CB>
where
E::Balance: From<u32>,
{
Self {
client,
caller,
contract_name,
constructor,
value: 0u32.into(),
extra_gas_portion: None,
storage_deposit_limit: None,
}
}

/// Provide value with a call
pub fn value(&mut self, value: E::Balance) {
self.value = value;
}

/// Increases the gas limit marginally by a specified percent.
/// Useful when the message's gas usage depends on the runtime state
/// and the dry run does not produce an accurate gas estimate.
///
/// # Example
///
/// With dry run gas estimate of `100` units and `5`% extra gas portion specified,
/// the set gas limit becomes `105` units
pub fn extra_gas_portion(&mut self, per_cent: usize) {
if per_cent == 0 {
self.extra_gas_portion = None
} else {
self.extra_gas_portion = Some(per_cent)
}
}

/// Specify the max amount of funds that can be charged for storage.
pub fn storage_deposit_limit(&mut self, storage_deposit_limit: E::Balance) {
if storage_deposit_limit == 0u32.into() {
self.storage_deposit_limit = None
} else {
self.storage_deposit_limit = Some(storage_deposit_limit)
}
}

/// Submit the instantiate call for the on-chain execution.
pub async fn submit(self) -> Result<InstantiationResult<E, CB::EventLog>, CB::Error> {
CB::instantiate(
self.client,
self.contract_name,
self.caller,
self.constructor,
self.value,
self.extra_gas_portion,
self.storage_deposit_limit,
)
.await
}

/// Dry run the instantiate call.
pub async fn submit_dry_run(
self,
) -> ContractInstantiateResult<E::AccountId, E::Balance, ()> {
CB::instantiate_dry_run(
self.client,
self.contract_name,
self.caller,
self.constructor,
self.value,
self.storage_deposit_limit,
)
.await
}
}
16 changes: 14 additions & 2 deletions crates/e2e/src/drink_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,18 +195,24 @@ where
caller: &Keypair,
constructor: CreateBuilderPartial<E, Contract, Args, R>,
value: E::Balance,
extra_gas_portion: Option<usize>,
storage_deposit_limit: Option<E::Balance>,
) -> Result<InstantiationResult<E, Self::EventLog>, Self::Error> {
let code = self.contracts.load_code(contract_name);
let data = constructor_exec_input(constructor);

let mut gas_limit = DEFAULT_GAS_LIMIT;
if let Some(gas_portion) = extra_gas_portion {
gas_limit += gas_limit / 100 * (gas_portion as u64);
}

let result = self.sandbox.deploy_contract(
code,
value,
data,
salt(),
keypair_to_account(caller),
DEFAULT_GAS_LIMIT,
gas_limit,
storage_deposit_limit,
);

Expand Down Expand Up @@ -291,6 +297,7 @@ where
caller: &Keypair,
message: &CallBuilderFinal<E, Args, RetType>,
value: E::Balance,
extra_gas_portion: Option<usize>,
storage_deposit_limit: Option<E::Balance>,
) -> Result<CallResult<E, RetType, Self::EventLog>, Self::Error>
where
Expand All @@ -300,12 +307,17 @@ where
let exec_input = Encode::encode(message.clone().params().exec_input());
let account_id = (*account_id.as_ref()).into();

let mut gas_limit = DEFAULT_GAS_LIMIT;
if let Some(gas_portion) = extra_gas_portion {
gas_limit += gas_limit / 100 * (gas_portion as u64);
}

let result = self.sandbox.call_contract(
account_id,
value,
exec_input,
keypair_to_account(caller),
DEFAULT_GAS_LIMIT,
gas_limit,
storage_deposit_limit,
);

Expand Down
5 changes: 5 additions & 0 deletions crates/e2e/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
)]

mod backend;
mod backend_calls;
mod builders;
mod client_utils;
mod contract_build;
Expand All @@ -41,6 +42,10 @@ pub use backend::{
ContractsBackend,
E2EBackend,
};
pub use backend_calls::{
CallBuilder,
InstantiateBuilder,
};
pub use contract_results::{
CallDryRunResult,
CallResult,
Expand Down
Loading