ink_e2e/
lib.rs

1// Copyright (C) Use Ink (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Module for the logic behind ink!'s End-to-End testing framework.
16
17#![doc(
18    html_logo_url = "https://use.ink/img/crate-docs/logo.png",
19    html_favicon_url = "https://use.ink/crate-docs/favicon.png"
20)]
21
22mod backend;
23mod backend_calls;
24mod builders;
25mod client_utils;
26mod contract_build;
27mod contract_results;
28mod error;
29pub mod events;
30mod node_proc;
31#[cfg(feature = "sandbox")]
32mod sandbox_client;
33mod subxt_client;
34mod xts;
35
36pub use crate::contract_build::build_root_and_contract_dependencies;
37pub use backend::{
38    BuilderClient,
39    ChainBackend,
40    ContractsBackend,
41    E2EBackend,
42};
43pub use backend_calls::{
44    CallBuilder,
45    InstantiateBuilder,
46};
47pub use client_utils::ContractsRegistry;
48pub use contract_results::{
49    CallDryRunResult,
50    CallResult,
51    InstantiateDryRunResult,
52    InstantiationResult,
53    UploadResult,
54};
55pub use ink_e2e_macro::test;
56pub use node_proc::{
57    TestNodeProcess,
58    TestNodeProcessBuilder,
59};
60pub use pallet_revive::evm::CallTrace;
61#[cfg(feature = "sandbox")]
62pub use sandbox_client::{
63    Client as SandboxClient,
64    preset,
65};
66pub use sp_keyring::Sr25519Keyring;
67pub use subxt::{
68    self,
69    backend::rpc::RpcClient,
70};
71pub use subxt_client::{
72    CallBuilderFinal,
73    Client,
74    Error,
75};
76pub use subxt_signer::{
77    self,
78    sr25519::{
79        self,
80        Keypair,
81        dev::*,
82    },
83};
84pub use tokio;
85pub use tracing;
86pub use tracing_subscriber;
87
88#[cfg(feature = "sandbox")]
89pub use ink_sandbox::DefaultSandbox;
90
91use ink::codegen::ContractCallBuilder;
92use ink_env::{
93    ContractEnv,
94    Environment,
95    call::FromAddr,
96};
97use ink_primitives::{
98    Address,
99    DepositLimit,
100    H256,
101    types::AccountIdMapper,
102};
103pub use sp_weights::Weight;
104use std::{
105    cell::RefCell,
106    sync::Once,
107};
108use xts::ReviveApi;
109
110pub use subxt::PolkadotConfig;
111
112/// We use this to only initialize `env_logger` once.
113pub static INIT: Once = Once::new();
114
115// We save the name of the currently executing test here as a mean
116// of prefixing log entries to make it easier pinning them to tests.
117thread_local! {
118    /// This prefix will be used for log output. It is set by each
119    /// `#[ink_e2e::test]` with the function name as String.
120    /// This way it is possible to distinguish the lines in stdout
121    /// and stderr, to still know which line belongs to which test.
122    pub static LOG_PREFIX: RefCell<String> = RefCell::new(String::from("no prefix set"));
123}
124
125/// Returns the name of the test which is currently executed.
126pub fn log_prefix() -> String {
127    LOG_PREFIX.with(|log_prefix| log_prefix.borrow().clone())
128}
129
130/// Writes `msg` to stdout.
131pub fn log_info(msg: &str) {
132    tracing::info!("[{}] {}", log_prefix(), msg);
133}
134
135/// Writes `msg` to stderr.
136pub fn log_error(msg: &str) {
137    tracing::error!("[{}] {}", log_prefix(), msg);
138}
139
140/// Get an ink! [`ink_primitives::AccountId`] for a given keyring account.
141pub fn account_id(account: Sr25519Keyring) -> ink_primitives::AccountId {
142    ink_primitives::AccountId::try_from(account.to_account_id().as_ref())
143        .expect("account keyring has a valid account id")
144}
145
146/// Returns the [`ink::Address`] for a given keyring account.
147///
148/// # Developer Note
149///
150/// We take the `AccountId` and return only the first twenty bytes, this
151/// is what `pallet-revive` does as well.
152pub fn address<E: Environment>(account: Sr25519Keyring) -> Address {
153    AccountIdMapper::to_address(account.to_account_id().as_ref())
154}
155
156/// Returns the [`ink::Address`] for a given account id.
157///
158/// # Developer Note
159///
160/// We take the `AccountId` and return only the first twenty bytes, this
161/// is what `pallet-revive` does as well.
162pub fn address_from_account_id<AccountId: AsRef<[u8]>>(account_id: AccountId) -> Address {
163    AccountIdMapper::to_address(account_id.as_ref())
164}
165
166/// Returns the [`ink::Address`] for a given `Keypair`.
167///
168/// # Developer Note
169///
170/// We take the `AccountId` and return only the first twenty bytes, this
171/// is what `pallet-revive` does as well.
172pub fn address_from_keypair<AccountId: From<[u8; 32]> + AsRef<[u8]>>(
173    keypair: &Keypair,
174) -> Address {
175    let account_id: AccountId = keypair_to_account(keypair);
176    address_from_account_id(account_id)
177}
178
179/// Transforms a `Keypair` into an account id.
180pub fn keypair_to_account<AccountId: From<[u8; 32]>>(keypair: &Keypair) -> AccountId {
181    AccountId::from(keypair.public_key().0)
182}
183
184/// Creates a call builder for `Contract`, based on an account id.
185pub fn create_call_builder<Contract>(
186    acc_id: Address,
187) -> <Contract as ContractCallBuilder>::Type<ink::env::DefaultAbi>
188where
189    <Contract as ContractEnv>::Env: Environment,
190    Contract: ContractCallBuilder + ContractEnv,
191    <Contract as ContractCallBuilder>::Type<ink::env::DefaultAbi>: FromAddr,
192{
193    <<Contract as ContractCallBuilder>::Type<ink::env::DefaultAbi> as FromAddr>::from_addr(
194        acc_id,
195    )
196}
197
198/// Creates a call builder for `Contract` for the specified ABI, based on an account id.
199pub fn create_call_builder_abi<Contract, Abi>(
200    acc_id: Address,
201) -> <Contract as ContractCallBuilder>::Type<Abi>
202where
203    <Contract as ContractEnv>::Env: Environment,
204    Contract: ContractCallBuilder + ContractEnv,
205    <Contract as ContractCallBuilder>::Type<Abi>: FromAddr,
206{
207    <<Contract as ContractCallBuilder>::Type<Abi> as FromAddr>::from_addr(acc_id)
208}
209
210/// Transforms `Option<<E as Environment>::Balance>>` into `DepositLimit`.
211///
212/// This function must only be used for dry-runs, a `None` will
213/// become an unrestricted deposit limit (`DepositLimit::UnsafeOnlyForDryRun`).
214fn balance_to_deposit_limit_dry_run<E: Environment>(
215    b: Option<<E as Environment>::Balance>,
216) -> DepositLimit<<E as Environment>::Balance> {
217    match b {
218        Some(v) => DepositLimit::Balance(v),
219        None => DepositLimit::UnsafeOnlyForDryRun,
220    }
221}
222
223/// Transforms `Option<<E as Environment>::Balance>>` into `DepositLimit`.
224/// This function must be used for submitting extrinsics on-chain.
225///
226/// Panics if `limit` is `None`. Make sure to execute a dry-run
227/// beforehand and use the `storage_deposit_limit` result of it here.
228fn balance_to_deposit_limit<E: Environment>(
229    limit: Option<<E as Environment>::Balance>,
230) -> DepositLimit<<E as Environment>::Balance> {
231    match limit {
232        Some(val) => DepositLimit::Balance(val),
233        None => panic!("Deposit limit must be specified for on-chain submissions."),
234    }
235}
236
237/// Transforms `DepositLimit<<E as Environment>::Balance>` into `<E as
238/// Environment>::Balance>`.
239///
240/// Panics if `limit` is unrestricted (`DepositLimit::UnsafeOnlyForDryRun`).
241fn deposit_limit_to_balance<E: Environment>(
242    limit: DepositLimit<<E as Environment>::Balance>,
243) -> <E as Environment>::Balance {
244    match limit {
245        DepositLimit::Balance(val) => val,
246        DepositLimit::UnsafeOnlyForDryRun => {
247            panic!("Unrestricted deposit limit not allowed for balance conversion!")
248        }
249    }
250}