Skip to content

Commit

Permalink
[ink_e2e] resolve DispatchError error details for dry-runs (#1994)
Browse files Browse the repository at this point in the history
* Instantiate dry run dispatch error details

* Works now to display DispatchError details

* Fix up some examples to new dry-run API result

* CallDryRun error

* custom-allocator

* custom-environment

* e2e-call-runtime

* e2e-runtime-only-backend

* erc20

* lang-err-integration-tests 1

* Encapsulate InstantiateDryRunResult

* constructors-return-value

* contract-ref

* integration-flipper, mapping-integration-tests

* more integration-tests

* set-code-hash

* CHANGELOG.md

* fmt

* thiserror workspace dependency

* clippy

* Delete data method
  • Loading branch information
ascjones authored Nov 16, 2023
1 parent 6afc65a commit cd0670a
Show file tree
Hide file tree
Showing 29 changed files with 310 additions and 222 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed
- Fail when decoding from storage and not all bytes consumed - [#1897](https://github.com/paritytech/ink/pull/1897)
- [E2E] resolve DispatchError error details for dry-runs - [#1944](https://github.com/paritytech/ink/pull/1994)

### Added
- Linter: `storage_never_freed` lint - [#1932](https://github.com/paritytech/ink/pull/1932)
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ subxt-metadata = { version = "0.32.1" }
subxt-signer = { version = "0.32.1" }
syn = { version = "2" }
synstructure = { version = "0.13.0" }
thiserror = { version = "1.0.50" }
tokio = { version = "1.18.2" }
tracing = { version = "0.1.37" }
tracing-subscriber = { version = "0.3.17" }
Expand Down
1 change: 1 addition & 0 deletions crates/e2e/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ scale = { package = "parity-scale-codec", workspace = true }
subxt = { workspace = true }
subxt-metadata = { workspace = true, optional = true }
subxt-signer = { workspace = true, features = ["subxt", "sr25519"] }
thiserror = { workspace = true }
wasm-instrument = { workspace = true }
which = { workspace = true }

Expand Down
10 changes: 6 additions & 4 deletions crates/e2e/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ use crate::{
UploadBuilder,
},
builders::CreateBuilderPartial,
contract_results::BareInstantiationResult,
contract_results::{
BareInstantiationResult,
InstantiateDryRunResult,
},
CallBuilder,
CallBuilderFinal,
CallDryRunResult,
Expand All @@ -30,7 +33,6 @@ use ink_env::{
Environment,
};
use jsonrpsee::core::async_trait;
use pallet_contracts_primitives::ContractInstantiateResult;
use scale::{
Decode,
Encode,
Expand Down Expand Up @@ -219,7 +221,7 @@ pub trait BuilderClient<E: Environment>: ContractsBackend<E> {
message: &CallBuilderFinal<E, Args, RetType>,
value: E::Balance,
storage_deposit_limit: Option<E::Balance>,
) -> CallDryRunResult<E, RetType>
) -> Result<CallDryRunResult<E, RetType>, Self::Error>
where
CallBuilderFinal<E, Args, RetType>: Clone;

Expand Down Expand Up @@ -272,5 +274,5 @@ pub trait BuilderClient<E: Environment>: ContractsBackend<E> {
constructor: &mut CreateBuilderPartial<E, Contract, Args, R>,
value: E::Balance,
storage_deposit_limit: Option<E::Balance>,
) -> ContractInstantiateResult<E::AccountId, E::Balance, ()>;
) -> Result<InstantiateDryRunResult<E>, Self::Error>;
}
28 changes: 7 additions & 21 deletions crates/e2e/src/backend_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
// limitations under the License.

use ink_env::Environment;
use pallet_contracts_primitives::ContractInstantiateResult;
use scale::{
Decode,
Encode,
Expand All @@ -26,8 +25,8 @@ use crate::{
CallBuilderFinal,
CallDryRunResult,
CallResult,
ContractExecResult,
ContractsBackend,
InstantiateDryRunResult,
InstantiationResult,
UploadResult,
};
Expand Down Expand Up @@ -140,7 +139,6 @@ where
) -> Result<CallResult<E, RetType, B::EventLog>, B::Error>
where
CallBuilderFinal<E, Args, RetType>: Clone,
B::Error: From<ContractExecResult<E::Balance, ()>>,
{
let dry_run = B::bare_call_dry_run(
self.client,
Expand All @@ -149,8 +147,7 @@ where
self.value,
self.storage_deposit_limit,
)
.await
.to_result()?;
.await?;

let gas_limit = if let Some(limit) = self.gas_limit {
limit
Expand Down Expand Up @@ -180,7 +177,7 @@ where
}

/// Dry run the call.
pub async fn dry_run(&mut self) -> CallDryRunResult<E, RetType>
pub async fn dry_run(&mut self) -> Result<CallDryRunResult<E, RetType>, B::Error>
where
CallBuilderFinal<E, Args, RetType>: Clone,
{
Expand Down Expand Up @@ -301,10 +298,7 @@ where
/// to add a margin to the gas limit.
pub async fn submit(
&mut self,
) -> Result<InstantiationResult<E, B::EventLog>, B::Error>
where
B::Error: From<ContractInstantiateResult<E::AccountId, E::Balance, ()>>,
{
) -> Result<InstantiationResult<E, B::EventLog>, B::Error> {
let dry_run = B::bare_instantiate_dry_run(
self.client,
self.contract_name,
Expand All @@ -313,18 +307,12 @@ where
self.value,
self.storage_deposit_limit,
)
.await;

let dry_run = if dry_run.result.is_err() {
Err(B::Error::from(dry_run))
} else {
Ok(dry_run)
}?;
.await?;

let gas_limit = if let Some(limit) = self.gas_limit {
limit
} else {
let gas_required = dry_run.gas_required;
let gas_required = dry_run.contract_result.gas_required;
if let Some(m) = self.extra_gas_portion {
gas_required + (gas_required / 100 * m)
} else {
Expand All @@ -351,9 +339,7 @@ where
}

/// Dry run the instantiate call.
pub async fn dry_run(
&mut self,
) -> ContractInstantiateResult<E::AccountId, E::Balance, ()> {
pub async fn dry_run(&mut self) -> Result<InstantiateDryRunResult<E>, B::Error> {
B::bare_instantiate_dry_run(
self.client,
self.contract_name,
Expand Down
84 changes: 70 additions & 14 deletions crates/e2e/src/contract_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,19 @@ use ink_env::{
call::FromAccountId,
Environment,
};
use ink_primitives::MessageResult;
use ink_primitives::{
ConstructorResult,
MessageResult,
};
use pallet_contracts_primitives::{
CodeUploadResult,
ContractExecResult,
ContractInstantiateResult,
ExecReturnValue,
InstantiateReturnValue,
};
use std::{
fmt,
fmt::Debug,
marker::PhantomData,
};
Expand Down Expand Up @@ -72,7 +77,7 @@ pub struct InstantiationResult<E: Environment, EventLog> {
pub account_id: E::AccountId,
/// The result of the dry run, contains debug messages
/// if there were any.
pub dry_run: ContractInstantiateResult<E::AccountId, E::Balance, ()>,
pub dry_run: InstantiateDryRunResult<E>,
/// Events that happened with the contract instantiation.
pub events: EventLog,
}
Expand Down Expand Up @@ -204,18 +209,6 @@ impl<E: Environment, V: scale::Decode> CallDryRunResult<E, V> {
self.exec_result.result.is_err()
}

/// Converts the dry-run result into a `Result` type.
pub fn to_result<Error>(self) -> Result<Self, Error>
where
Error: From<ContractExecResult<E::Balance, ()>>,
{
if self.is_err() {
Err(Error::from(self.exec_result))
} else {
Ok(self)
}
}

/// Returns the [`ExecReturnValue`] resulting from the dry-run message call.
///
/// Panics if the dry-run message call failed to execute.
Expand Down Expand Up @@ -265,3 +258,66 @@ impl<E: Environment, V: scale::Decode> CallDryRunResult<E, V> {
String::from_utf8_lossy(&self.exec_result.debug_message).into()
}
}

/// Result of the dry run of a contract call.
pub struct InstantiateDryRunResult<E: Environment> {
/// The result of the dry run, contains debug messages if there were any.
pub contract_result: ContractInstantiateResult<E::AccountId, E::Balance, ()>,
}

impl<E: Environment> From<ContractInstantiateResult<E::AccountId, E::Balance, ()>>
for InstantiateDryRunResult<E>
{
fn from(
contract_result: ContractInstantiateResult<E::AccountId, E::Balance, ()>,
) -> Self {
Self { contract_result }
}
}

impl<E: Environment> InstantiateDryRunResult<E> {
/// Returns true if the dry-run execution resulted in an error.
pub fn is_err(&self) -> bool {
self.contract_result.result.is_err()
}

/// Returns the [`InstantiateReturnValue`] resulting from the dry-run message call.
///
/// Panics if the dry-run message call failed to execute.
pub fn instantiate_return_value(&self) -> &InstantiateReturnValue<E::AccountId> {
self.contract_result
.result
.as_ref()
.unwrap_or_else(|call_err| panic!("Instantiate dry-run failed: {call_err:?}"))
}

/// Returns the encoded return value from the constructor.
///
/// # Panics
/// - if the dry-run message instantiate failed to execute.
/// - if message result cannot be decoded into the expected return value type.
pub fn constructor_result<V: scale::Decode>(&self) -> ConstructorResult<V> {
let data = &self.instantiate_return_value().result.data;
scale::Decode::decode(&mut data.as_ref()).unwrap_or_else(|env_err| {
panic!("Decoding dry run result to constructor return type failed: {env_err}")
})
}

/// Returns any debug message output by the contract decoded as UTF-8.
pub fn debug_message(&self) -> String {
String::from_utf8_lossy(&self.contract_result.debug_message).into()
}
}

impl<E> Debug for InstantiateDryRunResult<E>
where
E: Environment,
E::AccountId: Debug,
E::Balance: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("InstantiateDryRunResult")
.field("contract_result", &self.contract_result)
.finish()
}
}
16 changes: 9 additions & 7 deletions crates/e2e/src/drink_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::{
ChainBackend,
ContractsBackend,
E2EBackend,
InstantiateDryRunResult,
UploadResult,
};
use drink::{
Expand Down Expand Up @@ -248,7 +249,7 @@ where
constructor: &mut CreateBuilderPartial<E, Contract, Args, R>,
value: E::Balance,
storage_deposit_limit: Option<E::Balance>,
) -> ContractInstantiateResult<E::AccountId, E::Balance, Self::EventLog> {
) -> Result<InstantiateDryRunResult<E>, Self::Error> {
let code = self.contracts.load_code(contract_name);
let data = constructor_exec_input(constructor.clone());
let result = self.sandbox.dry_run(|r| {
Expand All @@ -271,7 +272,7 @@ where
};
let account_id = AccountId::from(account_id_raw);

ContractInstantiateResult {
let result = ContractInstantiateResult {
gas_consumed: result.gas_consumed,
gas_required: result.gas_required,
storage_deposit: result.storage_deposit,
Expand All @@ -283,7 +284,8 @@ where
}
}),
events: None,
}
};
Ok(result.into())
}

async fn bare_upload(
Expand Down Expand Up @@ -338,7 +340,7 @@ where
let account_id = (*account_id.as_ref()).into();

self.bare_call_dry_run(caller, message, value, storage_deposit_limit)
.await;
.await?;

if self
.sandbox
Expand All @@ -365,7 +367,7 @@ where
message: &CallBuilderFinal<E, Args, RetType>,
value: E::Balance,
storage_deposit_limit: Option<E::Balance>,
) -> CallDryRunResult<E, RetType>
) -> Result<CallDryRunResult<E, RetType>, Self::Error>
where
CallBuilderFinal<E, Args, RetType>: Clone,
{
Expand All @@ -383,7 +385,7 @@ where
storage_deposit_limit,
)
});
CallDryRunResult {
Ok(CallDryRunResult {
exec_result: ContractResult {
gas_consumed: result.gas_consumed,
gas_required: result.gas_required,
Expand All @@ -393,7 +395,7 @@ where
events: None,
},
_marker: Default::default(),
}
})
}
}

Expand Down
Loading

0 comments on commit cd0670a

Please sign in to comment.