From 87eee37a1d1a848f51be939a3a5d566c33870eaa Mon Sep 17 00:00:00 2001 From: haerdib Date: Tue, 27 Feb 2024 08:50:29 +0100 Subject: [PATCH 1/6] add some renaming --- src/extrinsic/contracts.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/extrinsic/contracts.rs b/src/extrinsic/contracts.rs index 4727252eb..c2dd4bf3a 100644 --- a/src/extrinsic/contracts.rs +++ b/src/extrinsic/contracts.rs @@ -31,7 +31,8 @@ use alloc::vec::Vec; use codec::{Compact, Encode}; pub const CONTRACTS_MODULE: &str = "Contracts"; -pub const PUT_CODE: &str = "put_code"; +pub const UPLOAD_CODE: &str = "upload_code"; +pub const REMOVE_CODE: &str = "remove_code"; pub const INSTANTIATE: &str = "instantiate"; pub const INSTANTIATE_WITH_CODE: &str = "instantiate_with_code"; pub const CALL: &str = "call"; @@ -45,8 +46,8 @@ pub type SaltFor = ::Salt; pub type HashFor = ::Hash; pub type AddressFor = ::Address; -/// Call for putting code in a contract. -pub type PutCodeFor = (CallIndex, GasLimitFor, DataFor); +/// Call for uploading code in a contract. +pub type UploadCodeFor = (CallIndex, GasLimitFor, DataFor); /// Call for instantiating a contract with the code hash. pub type InstantiateWithHashFor = @@ -70,11 +71,17 @@ pub trait ContractsExtrinsics { type Address; type Extrinsic; - async fn contract_put_code( + async fn contract_upload_code( &self, - gas_limit: Self::Gas, code: Self::Code, - ) -> Option>>; + storage_deposit_limit: Option, + determinism: Self::Determinism, + ) -> Option>>; + + async fn contract_remove_code( + &self, + code_hash: Self::CodeHash, + ) -> Option>>; async fn contract_instantiate( &self, @@ -124,12 +131,12 @@ where >::SignedExtra, >; - async fn contract_put_code( + async fn contract_upload_code( &self, gas_limit: Self::Gas, code: Self::Code, - ) -> Option>> { - compose_extrinsic!(self, CONTRACTS_MODULE, PUT_CODE, Compact(gas_limit), code) + ) -> Option>> { + compose_extrinsic!(self, CONTRACTS_MODULE, UPLOAD_CODE, Compact(gas_limit), code) } async fn contract_instantiate( From 8eb8bd34add80aabc1da772312b5136e1b70b38f Mon Sep 17 00:00:00 2001 From: haerdib Date: Tue, 27 Feb 2024 14:37:49 +0100 Subject: [PATCH 2/6] update contracts module and add to ci --- .github/workflows/ci.yml | 1 + .../contract_instantiate_with_code.rs | 14 +- primitives/src/types.rs | 21 +- src/extrinsic/contracts.rs | 306 ++++++++++++++---- 4 files changed, 269 insertions(+), 73 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b4a4d75a..cb0257cfc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -165,6 +165,7 @@ jobs: example: [ benchmark_bulk_xt, compose_extrinsic, + contract_instantiate_with_code, custom_nonce, check_extrinsic_events, get_account_identity, diff --git a/examples/async/examples/contract_instantiate_with_code.rs b/examples/async/examples/contract_instantiate_with_code.rs index 538a3da0f..2e0ec1d6e 100644 --- a/examples/async/examples/contract_instantiate_with_code.rs +++ b/examples/async/examples/contract_instantiate_with_code.rs @@ -62,7 +62,14 @@ async fn main() { let wasm = wabt::wat2wasm(CONTRACT).expect("invalid wabt"); let xt = api - .contract_instantiate_with_code(1_000_000_000_000_000, 500_000, wasm, vec![1u8], vec![1u8]) + .contract_instantiate_with_code( + 1_000_000_000_000_000, + 500_000.into(), + None, + wasm.into(), + vec![1u8].into(), + vec![1u8].into(), + ) .await .unwrap(); @@ -84,7 +91,10 @@ async fn main() { let contract = contract_instantiated_events[0].contract.clone(); println!("[+] Event was received. Contract deployed at: {contract:?}\n"); - let xt = api.contract_call(contract.into(), 500_000, 500_000, vec![0u8]).await.unwrap(); + let xt = api + .contract_call(contract.into(), 500_000, 500_000.into(), None, vec![0u8].into()) + .await + .unwrap(); println!("[+] Calling the contract with extrinsic Extrinsic:\n{:?}\n\n", xt); let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::Finalized).await.unwrap(); diff --git a/primitives/src/types.rs b/primitives/src/types.rs index dff686230..ad3170fec 100644 --- a/primitives/src/types.rs +++ b/primitives/src/types.rs @@ -336,7 +336,7 @@ pub type NodeIndex = u64; /// Merkle Mountain Range operation error. // https://github.com/paritytech/polkadot-sdk/blob/a190e0e9253562fdca9c1b6e9541a7ea0a50c018/substrate/primitives/merkle-mountain-range/src/lib.rs#L362-L396 -#[derive(codec::Encode, codec::Decode, PartialEq, Eq, TypeInfo, RuntimeDebug)] +#[derive(Encode, Decode, PartialEq, Eq, TypeInfo, RuntimeDebug)] pub enum MmrError { /// Error during translation of a block number into a leaf index. InvalidNumericOp, @@ -359,3 +359,22 @@ pub enum MmrError { /// The provided best know block number is invalid. InvalidBestKnownBlock, } + +/// Defines the required determinism level of a wasm blob when either running or uploading code. +#[derive(Clone, Copy, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug, PartialEq, Eq)] +pub enum Determinism { + /// The execution should be deterministic and hence no indeterministic instructions are + /// allowed. + /// + /// Dispatchables always use this mode in order to make on-chain execution deterministic. + Enforced, + /// Allow calling or uploading an indeterministic code. + /// + /// This is only possible when calling into `pallet-contracts` directly via + /// [`crate::Pallet::bare_call`]. + /// + /// # Note + /// + /// **Never** use this mode for on-chain execution. + Relaxed, +} diff --git a/src/extrinsic/contracts.rs b/src/extrinsic/contracts.rs index c2dd4bf3a..0b05e2248 100644 --- a/src/extrinsic/contracts.rs +++ b/src/extrinsic/contracts.rs @@ -24,89 +24,216 @@ use crate::{api::Api, rpc::Request}; use ac_compose_macros::compose_extrinsic; use ac_primitives::{ - config::Config, extrinsic_params::ExtrinsicParams, extrinsics::CallIndex, SignExtrinsic, - UncheckedExtrinsicV4, + config::Config, extrinsic_params::ExtrinsicParams, extrinsics::CallIndex, Determinism, + SignExtrinsic, UncheckedExtrinsicV4, Weight, }; -use alloc::vec::Vec; use codec::{Compact, Encode}; +use sp_core::Bytes; pub const CONTRACTS_MODULE: &str = "Contracts"; pub const UPLOAD_CODE: &str = "upload_code"; pub const REMOVE_CODE: &str = "remove_code"; -pub const INSTANTIATE: &str = "instantiate"; -pub const INSTANTIATE_WITH_CODE: &str = "instantiate_with_code"; +pub const SET_CODE: &str = "set_code"; pub const CALL: &str = "call"; +pub const INSTANTIATE_WITH_CODE: &str = "instantiate_with_code"; +pub const INSTANTIATE: &str = "instantiate"; +pub const MIGRATE: &str = "migrate"; -pub type GasLimitFor = Compact<::Gas>; -pub type ValueFor = Compact<::Currency>; -pub type EndowmentFor = Compact<::Currency>; -pub type DataFor = ::Data; -pub type CodeFor = ::Code; -pub type SaltFor = ::Salt; -pub type HashFor = ::Hash; -pub type AddressFor = ::Address; +/// Upload new `code` without instantiating a contract from it.. +pub type UploadCodeCall

= (CallIndex, CodeFor

, Option>, DeterminismFor

); -/// Call for uploading code in a contract. -pub type UploadCodeFor = (CallIndex, GasLimitFor, DataFor); +/// Remove the code stored under `code_hash` and refund the deposit to its owner. +pub type RemoveCodeCall

= (CallIndex, CodeHashFor

); -/// Call for instantiating a contract with the code hash. -pub type InstantiateWithHashFor = - (CallIndex, EndowmentFor, GasLimitFor, HashFor, DataFor); +/// Privileged function that changes the code of an existing contract. +pub type SetCodeCall

= (CallIndex, AddressFor

, CodeHashFor

); -/// Call for instantiating a contract with code and salt. -pub type InstantiateWithCodeFor = - (CallIndex, EndowmentFor, GasLimitFor, CodeFor, DataFor, SaltFor); +/// Makes a call to an account, optionally transferring some balance. +pub type ContractCall

= + (CallIndex, AddressFor

, CurrencyFor

, WeightFor

, Option>, DataFor

); -/// Call for calling a function inside a contract. -pub type ContractCallFor = (CallIndex, AddressFor, ValueFor, GasLimitFor, DataFor); +/// Instantiates a new contract from the supplied `code` optionally transferring +/// some balance. +pub type InstantiateWithCodeCall

= ( + CallIndex, + CurrencyFor

, + WeightFor

, + Option>, + CodeFor

, + DataFor

, + SaltFor

, +); +/// Instantiates a contract from a previously deployed wasm binary. +pub type InstantiateCall

= ( + CallIndex, + CurrencyFor

, + WeightFor

, + Option>, + CodeHashFor

, + DataFor

, + SaltFor

, +); + +/// Calls that contribute to advancing the migration have their fees waived, as it's helpful +/// for the chain. +pub type MigrateCall

= (CallIndex, WeightFor

); + +pub type WeightFor

=

::Weight; +pub type DeterminismFor

=

::Determinism; +pub type DataFor

=

::Data; +pub type CodeFor

=

::Code; +pub type SaltFor

=

::Salt; +pub type CodeHashFor

=

::CodeHash; +pub type AddressFor

=

::Address; +pub type CurrencyFor

= Compact<

::Currency>; #[maybe_async::maybe_async(?Send)] pub trait ContractsExtrinsics { - type Gas; + type Weight; type Currency; - type Hash; + type Determinism; + type CodeHash; type Code; type Data; type Salt; type Address; type Extrinsic; + /// Upload new `code` without instantiating a contract from it. + /// + /// If the code does not already exist a deposit is reserved from the caller + /// and unreserved only when [`Self::remove_code`] is called. The size of the reserve + /// depends on the size of the supplied `code`. + /// + /// If the code already exists in storage it will still return `Ok` and upgrades + /// the in storage version to the current + /// [`InstructionWeights::version`](InstructionWeights). + /// + /// - `determinism`: If this is set to any other value but [`Determinism::Enforced`] then + /// the only way to use this code is to delegate call into it from an offchain execution. + /// Set to [`Determinism::Enforced`] if in doubt. + /// + /// # Note + /// + /// Anyone can instantiate a contract from any uploaded code and thus prevent its removal. + /// To avoid this situation a constructor could employ access control so that it can + /// only be instantiated by permissioned entities. The same is true when uploading + /// through [`Self::instantiate_with_code`]. async fn contract_upload_code( &self, code: Self::Code, - storage_deposit_limit: Option, + storage_deposit_limit: Option, determinism: Self::Determinism, - ) -> Option>>; + ) -> Option>>; + /// Remove the code stored under `code_hash` and refund the deposit to its owner. + /// + /// A code can only be removed by its original uploader (its owner) and only if it is + /// not used by any contract. async fn contract_remove_code( &self, code_hash: Self::CodeHash, - ) -> Option>>; + ) -> Option>>; - async fn contract_instantiate( + /// Privileged function that changes the code of an existing contract. + /// + /// This takes care of updating refcounts and all other necessary operations. Returns + /// an error if either the `code_hash` or `dest` do not exist. + /// + /// # Note + /// + /// This does **not** change the address of the contract in question. This means + /// that the contract address is no longer derived from its code hash after calling + /// this dispatchable. + async fn contract_set_code( + &self, + dest: Self::Address, + code_hash: Self::CodeHash, + ) -> Option>>; + + /// Makes a call to an account, optionally transferring some balance. + /// + /// # Parameters + /// + /// * `dest`: Address of the contract to call. + /// * `value`: The balance to transfer from the `origin` to `dest`. + /// * `gas_limit`: The gas limit enforced when executing the constructor. + /// * `storage_deposit_limit`: The maximum amount of balance that can be charged from the + /// caller to pay for the storage consumed. + /// * `data`: The input data to pass to the contract. + /// + /// * If the account is a smart-contract account, the associated code will be + /// executed and any value will be transferred. + /// * If the account is a regular account, any value will be transferred. + /// * If no account exists and the call value is not less than `existential_deposit`, + /// a regular account will be created and any value will be transferred. + async fn contract_call( &self, - endowment: Self::Currency, - gas_limit: Self::Gas, - code_hash: Self::Hash, + dest: Self::Address, + value: Self::Currency, + gas_limit: Self::Weight, + storage_deposit_limit: Option, data: Self::Data, - ) -> Option>>; + ) -> Option>>; + /// Instantiates a new contract from the supplied `code` optionally transferring + /// some balance. + /// + /// This dispatchable has the same effect as calling [`Self::upload_code`] + + /// [`Self::instantiate`]. Bundling them together provides efficiency gains. Please + /// also check the documentation of [`Self::upload_code`]. + /// + /// # Parameters + /// + /// * `value`: The balance to transfer from the `origin` to the newly created contract. + /// * `gas_limit`: The gas limit enforced when executing the constructor. + /// * `storage_deposit_limit`: The maximum amount of balance that can be charged/reserved + /// from the caller to pay for the storage consumed. + /// * `code`: The contract code to deploy in raw bytes. + /// * `data`: The input data to pass to the contract constructor. + /// * `salt`: Used for the address derivation. See [`Pallet::contract_address`]. + /// + /// Instantiation is executed as follows: + /// + /// - The supplied `code` is deployed, and a `code_hash` is created for that code. + /// - If the `code_hash` already exists on the chain the underlying `code` will be shared. + /// - The destination address is computed based on the sender, code_hash and the salt. + /// - The smart-contract account is created at the computed address. + /// - The `value` is transferred to the new account. + /// - The `deploy` function is executed in the context of the newly-created account. async fn contract_instantiate_with_code( &self, - endowment: Self::Currency, - gas_limit: Self::Gas, + value: Self::Currency, + gas_limit: Self::Weight, + storage_deposit_limit: Option, code: Self::Code, data: Self::Data, salt: Self::Salt, - ) -> Option>>; + ) -> Option>>; - async fn contract_call( + /// Instantiates a contract from a previously deployed wasm binary. + /// + /// This function is identical to [`Self::instantiate_with_code`] but without the + /// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary + /// must be supplied. + async fn contract_instantiate( &self, - dest: Self::Address, value: Self::Currency, - gas_limit: Self::Gas, + gas_limit: Self::Weight, + storage_deposit_limit: Option, + code_hash: Self::CodeHash, data: Self::Data, - ) -> Option>>; + salt: Self::Salt, + ) -> Option>>; + + /// When a migration is in progress, this dispatchable can be used to run migration steps. + /// Calls that contribute to advancing the migration have their fees waived, as it's helpful + /// for the chain. Note that while the migration is in progress, the pallet will also + /// leverage the `on_idle` hooks to run migration steps. + async fn contract_migrate( + &self, + weight_limit: Self::Weight, + ) -> Option>>; } #[cfg(feature = "std")] @@ -117,12 +244,13 @@ where Client: Request, Compact: Encode + Clone, { - type Gas = u64; + type Weight = Weight; type Currency = T::ContractCurrency; - type Hash = T::Hash; - type Code = Vec; - type Data = Vec; - type Salt = Vec; + type Determinism = Determinism; + type CodeHash = T::Hash; + type Code = Bytes; + type Data = Bytes; + type Salt = Bytes; type Address = >::ExtrinsicAddress; type Extrinsic = UncheckedExtrinsicV4< Self::Address, @@ -133,65 +261,103 @@ where async fn contract_upload_code( &self, - gas_limit: Self::Gas, code: Self::Code, - ) -> Option>> { - compose_extrinsic!(self, CONTRACTS_MODULE, UPLOAD_CODE, Compact(gas_limit), code) + storage_deposit_limit: Option, + determinism: Self::Determinism, + ) -> Option>> { + compose_extrinsic!( + self, + CONTRACTS_MODULE, + UPLOAD_CODE, + code, + storage_deposit_limit.map(|limit| Compact(limit)), + determinism + ) } - async fn contract_instantiate( + async fn contract_remove_code( + &self, + code_hash: Self::CodeHash, + ) -> Option>> { + compose_extrinsic!(self, CONTRACTS_MODULE, REMOVE_CODE, code_hash) + } + + async fn contract_set_code( + &self, + dest: Self::Address, + code_hash: Self::CodeHash, + ) -> Option>> { + compose_extrinsic!(self, CONTRACTS_MODULE, SET_CODE, dest, code_hash) + } + + async fn contract_call( &self, - endowment: Self::Currency, - gas_limit: Self::Gas, - code_hash: Self::Hash, + dest: Self::Address, + value: Self::Currency, + gas_limit: Self::Weight, + storage_deposit_limit: Option, data: Self::Data, - ) -> Option>> { + ) -> Option>> { compose_extrinsic!( self, CONTRACTS_MODULE, - INSTANTIATE, - Compact(endowment), - Compact(gas_limit), - code_hash, + CALL, + dest, + Compact(value), + gas_limit, + storage_deposit_limit.map(|limit| Compact(limit)), data ) } async fn contract_instantiate_with_code( &self, - endowment: Self::Currency, - gas_limit: Self::Gas, + value: Self::Currency, + gas_limit: Self::Weight, + storage_deposit_limit: Option, code: Self::Code, data: Self::Data, salt: Self::Salt, - ) -> Option>> { + ) -> Option>> { compose_extrinsic!( self, CONTRACTS_MODULE, INSTANTIATE_WITH_CODE, - Compact(endowment), - Compact(gas_limit), + Compact(value), + gas_limit, + storage_deposit_limit.map(|limit| Compact(limit)), code, data, salt ) } - async fn contract_call( + async fn contract_instantiate( &self, - dest: Self::Address, value: Self::Currency, - gas_limit: Self::Gas, + gas_limit: Self::Weight, + storage_deposit_limit: Option, + code_hash: Self::CodeHash, data: Self::Data, - ) -> Option>> { + salt: Self::Salt, + ) -> Option>> { compose_extrinsic!( self, CONTRACTS_MODULE, - CALL, - dest, + INSTANTIATE, Compact(value), - Compact(gas_limit), - data + gas_limit, + storage_deposit_limit.map(|limit| Compact(limit)), + code_hash, + data, + salt ) } + + async fn contract_migrate( + &self, + weight_limit: Self::Weight, + ) -> Option>> { + compose_extrinsic!(self, CONTRACTS_MODULE, MIGRATE, weight_limit) + } } From 555b72c714a4376b2d01fd0d7c0ebcdfaf070784 Mon Sep 17 00:00:00 2001 From: haerdib Date: Tue, 27 Feb 2024 16:57:35 +0100 Subject: [PATCH 3/6] remove comment --- src/extrinsic/contracts.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/extrinsic/contracts.rs b/src/extrinsic/contracts.rs index 0b05e2248..68473b0cb 100644 --- a/src/extrinsic/contracts.rs +++ b/src/extrinsic/contracts.rs @@ -19,8 +19,6 @@ //! Contracts module is community maintained and not CI tested, therefore it may not work as is. //! https://polkadot.js.org/docs/substrate/extrinsics/#contracts -// FIXME: This module is currently outdated. See https://github.com/scs/substrate-api-client/issues/435. - use crate::{api::Api, rpc::Request}; use ac_compose_macros::compose_extrinsic; use ac_primitives::{ @@ -270,7 +268,7 @@ where CONTRACTS_MODULE, UPLOAD_CODE, code, - storage_deposit_limit.map(|limit| Compact(limit)), + storage_deposit_limit.map(Compact), determinism ) } @@ -305,7 +303,7 @@ where dest, Compact(value), gas_limit, - storage_deposit_limit.map(|limit| Compact(limit)), + storage_deposit_limit.map(Compact), data ) } @@ -325,7 +323,7 @@ where INSTANTIATE_WITH_CODE, Compact(value), gas_limit, - storage_deposit_limit.map(|limit| Compact(limit)), + storage_deposit_limit.map(Compact), code, data, salt @@ -347,7 +345,7 @@ where INSTANTIATE, Compact(value), gas_limit, - storage_deposit_limit.map(|limit| Compact(limit)), + storage_deposit_limit.map(Compact), code_hash, data, salt From a29815c5d98a779ec374803d58f89845015d5e38 Mon Sep 17 00:00:00 2001 From: haerdib Date: Tue, 27 Feb 2024 18:36:27 +0100 Subject: [PATCH 4/6] add missing files --- .../contract_instantiate_with_code.rs | 76 ++++++++++-------- examples/async/examples/flipper.wasm | Bin 0 -> 11354 bytes 2 files changed, 41 insertions(+), 35 deletions(-) create mode 100644 examples/async/examples/flipper.wasm diff --git a/examples/async/examples/contract_instantiate_with_code.rs b/examples/async/examples/contract_instantiate_with_code.rs index 2e0ec1d6e..51c76f4d9 100644 --- a/examples/async/examples/contract_instantiate_with_code.rs +++ b/examples/async/examples/contract_instantiate_with_code.rs @@ -20,7 +20,8 @@ use kitchensink_runtime::AccountId; use sp_keyring::AccountKeyring; use substrate_api_client::{ ac_compose_macros::primitives::AssetRuntimeConfig, ac_node_api::StaticEvent, - extrinsic::ContractsExtrinsics, rpc::JsonrpseeClient, Api, SubmitAndWatch, XtStatus, + ac_primitives::Determinism, error::FailedExtrinsicError, extrinsic::ContractsExtrinsics, + rpc::JsonrpseeClient, Api, SubmitAndWatch, XtStatus, }; // To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. @@ -52,51 +53,56 @@ async fn main() { println!("[+] Alice's Account Nonce is {}", api.get_nonce().await.unwrap()); - // contract to be deployed on the chain - const CONTRACT: &str = r#" -(module - (func (export "call")) - (func (export "deploy")) -) -"#; - let wasm = wabt::wat2wasm(CONTRACT).expect("invalid wabt"); + let wasm = include_bytes!("flipper.wasm").to_vec(); let xt = api .contract_instantiate_with_code( - 1_000_000_000_000_000, - 500_000.into(), + 0, + 500_000_000.into(), None, - wasm.into(), - vec![1u8].into(), - vec![1u8].into(), + wasm.clone().into(), + vec![0].into(), + vec![0].into(), ) .await .unwrap(); - println!("[+] Creating a contract instance with extrinsic:\n\n{:?}\n", xt); - let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock).await.unwrap(); - println!("[+] Extrinsic is in Block. Hash: {:?}\n", report.block_hash.unwrap()); - - println!("[+] Waiting for the contracts.Instantiated event"); - - let associated_contract_events = report.events.unwrap(); - - let contract_instantiated_events: Vec = - associated_contract_events - .iter() - .filter_map(|event| event.as_event().unwrap()) - .collect(); - // We only expect one instantiated event - assert_eq!(contract_instantiated_events.len(), 1); - let contract = contract_instantiated_events[0].contract.clone(); - println!("[+] Event was received. Contract deployed at: {contract:?}\n"); + println!("[+] Creating a contract instance \n"); + let result = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock).await; + // Ensure the contract is valid - just doesnt make any changes. + assert!(format!("{:?}", result).contains("ContractReverted")); let xt = api - .contract_call(contract.into(), 500_000, 500_000.into(), None, vec![0u8].into()) + .contract_upload_code(wasm.into(), None, Determinism::Enforced) .await .unwrap(); - println!("[+] Calling the contract with extrinsic Extrinsic:\n{:?}\n\n", xt); - let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::Finalized).await.unwrap(); - println!("[+] Extrinsic got finalized. Extrinsic Hash: {:?}", report.extrinsic_hash); + let _report = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock).await.unwrap(); + // + // println!("[+] Creating a contract instance \n"); + // let report = api.submit_and_watch_extrinsic_until(xt1, XtStatus::InBlock).await.unwrap(); + // println!("[+] Extrinsic is in Block. Hash: {:?}\n", report.block_hash.unwrap()); + // + // println!("[+] Waiting for the contracts.Instantiated event"); + // + // let associated_contract_events = report.events.unwrap(); + // + // let contract_instantiated_events: Vec = + // associated_contract_events + // .iter() + // .filter_map(|event| event.as_event().unwrap()) + // .collect(); + // // We only expect one instantiated event + // assert_eq!(contract_instantiated_events.len(), 1); + // let contract = contract_instantiated_events[0].contract.clone(); + // println!("[+] Event was received. Contract deployed at: {contract:?}\n"); + // + // let xt = api + // .contract_call(contract.into(), 500_000, 500_000.into(), None, vec![0u8].into()) + // .await + // .unwrap(); + // + // println!("[+] Calling the contract with extrinsic Extrinsic:\n{:?}\n\n", xt); + // let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::Finalized).await.unwrap(); + // println!("[+] Extrinsic got finalized. Extrinsic Hash: {:?}", report.extrinsic_hash); } diff --git a/examples/async/examples/flipper.wasm b/examples/async/examples/flipper.wasm new file mode 100644 index 0000000000000000000000000000000000000000..afd39d793655910a5b634a4d0bd74367c8861b8f GIT binary patch literal 11354 zcmcgyZERcDc|Pad%Ma<2@^z}TN~A4^jM~VJWqyjJoCMV|W-DImq(8R(*b3ORMA@Vy zQX(nE-qK1*>@>-`%v;jNLsKjmGUUh5Aq_fU0|wN^3ar42AsK?T!-6b8^P|{O)W8BP z83K6EbIzqKiDkHWr0)Z(_~%+D3oylwNF{-Z*n|wbAQww6uMSLGQyeqOHDivfJoyblbx78tu*a zYGbw2J+Gt+y<)*r-f+T`Dk0*^_mqnJaWAPnKdur|_(I~JucRD`C1XRldeV={H90a8 zPeMVnz3m5y{mNgcudIkq#}^xGE1mOVZ0J)`7#XBfrO#ES%D3Nf`{ZXcpC7(_PvM}H zTi%vd+B@cNX%W*xdo3;TXIhBE0#8P^GG0ms!L7mP(D`;@!sV=*6c~dJ`_NaJeJvxy zByPgiqzJw&y)8AT#gs~BeXUwqPx}w}bJ}B*pN-v@mb??%Z=ua!wo^R+tREJ*dPODo z1?I{(d^2IT(KsOj^op5FxDP~dLcwKUg%o-@D6{*FFCz3ST=>rm1pdvii=Fr_VABU{j4xQy6m@L&5An6X7l>saSD$rTAFuLSXyg2 zrAGN@3@yo4n9XpFJj?=(?{-4KvQ7wjmz=;PkN~}@_$d0m{R9LFaRV1Q(NeAOfC%QL ziohW;nKTw0ys_Zemla20V>vDMWmJGxBE>*EL($~1aRWKVwHOcX!8{Hqo>s@Rz8%Kp zp<|X{`|HaQQnXs8ORxq&1`h<d1`6fwLR%VOeG zI2?|O;MaBrTm6qjgVkWL;$Q#)k%F+mU>P$az*LZZXOfqtifu_E6wZuHK}k%{A%EHQUmGKcpQp*EsvPw4*9}-yLqEqT%_$gje8Ne5@m5H(AXeRC^I*5Vs zDzE`z!o==b0Jms#OxvNb7y>c$Z^cNuJ~#@;)6oo1?>>LdypHg@-CT*n4|EXO8nQ)h zpuxFRN`CZbrwa%%4S|8U4$ zlj|mSY`_LUyj6%ogjS1DfahWG1u4u0Mg*-Fi z{tG&#ez^{gpi0s`T@Lb-DlZDn9GmARg}om1}GY4GS5F^ zJ@Qfg-?9CnIHUz0pcKu`3E+wmc!8c$$I`y`(;mQsq-4P}2->|7ucC1s?4|XAkFxE zx0@#6-V}zgnP>je;utT9<2TUNk_RLkK}NH#olkqa>_?Vx>>YmCKhdC|Akzi1PBKM}3nq?_RL}ybVqR#_cRbumIyChy98O z_66auis0BzoZ3PV!Qi+JH2|ge9HpV)BSTH#V&jy4Wt=*|A@4jU-8_S`fZb9+|HMw% zTaK0HM~}g~A>KeoW_4*xHy8OS%s2&y52{}ySfdH^Q;xAD2@^P;j0&}gahWb%p?1B> zvxEr|g9+4U7f&qmQ2%=0#+Ncu8gyq6fT}5#Ag;89zq# z^iT_IX^ZwOBgUIjc>-1-#Bg5*boUF9_L)bq`GU4^Kn4ckywH`aAYR$1zzrS{q+|Of zU<>6DRSGVp-4iC($LItF{DPGa2;dwx*pramPUQs74rLT%wAg2z%L$SL;kYuQf0u9w zX6Zapw=T25ThrFfnC~IRvHI8H6q(R=;jnq-6oJ0KZ^b&&(|Y z7c%gKw8(*bRCo(u^s2%(c86MlXcz|)rdkmoP$JlEBRuTlcso2!-T-R-2jFJn_zUak z)IBUl>{DvfyvZkQ=kPARx$`=0JaQz{5X&?OjSAE)?L)Xh-a;+0H*dKFWXJ7EUxR%+ z@QV5f+98~|z;2P!10k+hk&JSreqH8$gAN~3V$k5GxM|ZQ*3DHniywry5P)`fN1}C! z^O8%P{~T9=+q_5NNL91yJDD`iyZb+;xb%+#yK-{}kdV%d5Sqq6o*sh7Zb23&YvANy z&9)dG+`GR!)e!1f8drkzAhJTEWSK>$bN8 zRv_?3j$He}PjbJ7;KIUMA*yuxMXdKTaRPo7MxpvoB?Bv3)XGp*s6efBEq31}hx+&> zX{%v(_<&L&o?^^n@|bH+BbY$}*XQL<9nM9N+ro3#ifXT}fy1l0;{;4NrNy$j1AkC; zAgCs?F(cQriSZ1ei>SkK$hs?WYzWe0_=I=z%%n@b6x<~ukqjPju*?|p0$vi;4d z2*Kqeix3)N5V9V*kpbrQ&4q8;o)vJZV3i8B zwLn1$J-`S@QTsy=o0BDzdzr5*NRvFUz@M-cX6O~Ldd4bWnb$H8tt0Z$ zD#C+VRNJnLKr^>?-g3)!6wlD0hxv@rzVu(W_sSh(NH46zj}``KZb1+Wnr zX+^=Dkb2lwB>^`|iA^0Kg?7!uk6cKiNE9GCxWXRph4Y|L6%5>Z>5pCX_$hA|zQHq3>Hxj|$BLZvJ1VjK!LJ~NE zaR1*IJCU}8i{tLAFd2@!BRIaf=V{w%5xu+O-q9-ILFRs!ax?kEt1&U1JKk}LIX3C#@!d*Kw;`NyLZ z5gx&;0EBR&XlamPhb7Sy;Toc1OQUMn9*+Z1uyalWH6prtIodwV5rZr%H8QDO9>EtP z0&03Z8%PV_!iR^ovJi2l3slN_00A=LCdl05g>NE@Jr{9kRBA>f2?SFpkP|MW5!kpO z&YfAz!F|{dQ)r^Ws$(lHyYF=75J3@pBDDqBa)5sf>g^P?>~eiPo0mas$AjO6#{9}< z4jst&@sB(Jjja4p2cYmn3U2(~rHGF3Jc+qbI>P}VBeEs(J{qncfWnDT;*yea`}GXY zDQsGY=Ac{}0J3veM-#TP*u@J4bAnK_*vaSvTjdcND3|XaDhu8lsUl37&kZdad%a$ zb4iaABsf7AqPbK{OhE;H;{?)L=Kc`nB0U1i#nuIRo24+!b-gTo=4lJ-zwuxZaDDXU z3o@qt& zL9PgkEZ!+5l-N}+xFU^E$g)4x2=C0sPQZ|g8#jq*V#_$k%NdFF zNb9?b9XzIh0Sq6_qEfs*c@|A}PsPmQ>WiUWk+4$#~eeEeE(45r3zo@G(it%i*xoa~#&pY#o4n^Mq)H5~b& z*8zo6f=i>A;>?3*?9%yWDw=M}en03ohCCKTm4J&iGtc!1fCHX5@`L|+@8>^$`sG*6 zMa+oF(Dc?De}D1PD;MAR%Eb#`0%B>Vy}}T=U`9)iz#!yvezm)CBaB2_2SC;*0j_@}bh9ydBbLpJ}!mxla4!!r6MWook%yAL{mm5K=7T?_2nM z2A>y2k*6m=LmGgSBvCvs;=shFFL+F18`tx7C-{&N{-_ffZEB)pg20hs9pVghsMt5nY z^C0>pY)@KSh$KEosSvJ1_@wah@fpS^h@L;-hwetNzp<9eX&V%jgm1cY6-1M3D2G!4T6t9E~@7dU`14H<&L}$S@*B?B&*;ug7z^^O> zW%>&UNjopp*Xj$+{`uW{JdQrVt{C*aOF6sVD0!{qkkl{T^gr!}ZUgAD`=bsncDB_nPf98b5ex_BD~&SOqxTobE>} zz+b)XAb6wHTw0By^IMR;4OtgqXN~KP5&)RUt#%eIE+%}3iwgiT?KXJ+PdpR9yYS!J zI1NKC^!MWbz+rJ^n8+96pD-8i2G`wj!MWG!?dHNVE#B9Mhb_>bwq zvkkq{XzOMV4#z7#yN+lXj!A2$&*OR%<~yv#&e~r@8_f6#+i;=NZP?I)4|DB}Rgw@m zIbY0|^5y(YzLKxzYx&tizECI>3#CH2FjJ@$s)br%wwNy#ip657ST4>KE5&NDR-7&6 zONCOgR4SEAGo?zYTB?<1%lUGlTr8K$9qQm&S3<=L71Okt)tQ<^Ey%*<3~sx!5j z*-E}rs1z%uO1UyqsZ^?!T4lDHuNJDsYN=YT&QvSaYPD9Kt>tTlTCrBDm1{G#O08O} z)n;cQ;w+Y*#niJHHjAcD7JPdQH^APX#HCn=&tf2N;$!gqES~dt9)JTsS3A>SJnP;{ zbD=@J03&BW!tPC@y%>Q+i2L!ovJhhr;+nB_xZ57%Eh1mI5{7#`$`YseYY?*sn+Wa{D58%y}PtIc;|;BqeU$vSBF^XLbj z3%i~hxF?>>8GQa9 Date: Thu, 29 Feb 2024 14:32:03 +0100 Subject: [PATCH 5/6] move example to tests --- .github/workflows/ci.yml | 2 +- .../async/examples/flipper.wasm | Bin .../async/examples/pallet_contract_tests.rs | 27 ------------------ 3 files changed, 1 insertion(+), 28 deletions(-) rename {examples => testing}/async/examples/flipper.wasm (100%) rename examples/async/examples/contract_instantiate_with_code.rs => testing/async/examples/pallet_contract_tests.rs (69%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d2ae7a39..9ab133514 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -165,7 +165,6 @@ jobs: example: [ benchmark_bulk_xt, compose_extrinsic, - contract_instantiate_with_code, custom_nonce, check_extrinsic_events, get_account_identity, @@ -185,6 +184,7 @@ jobs: jsonrpsee_tests, keystore_tests, pallet_balances_tests, + pallet_contract_tests, pallet_transaction_payment_tests, runtime_api_tests, tungstenite_client_test, diff --git a/examples/async/examples/flipper.wasm b/testing/async/examples/flipper.wasm similarity index 100% rename from examples/async/examples/flipper.wasm rename to testing/async/examples/flipper.wasm diff --git a/examples/async/examples/contract_instantiate_with_code.rs b/testing/async/examples/pallet_contract_tests.rs similarity index 69% rename from examples/async/examples/contract_instantiate_with_code.rs rename to testing/async/examples/pallet_contract_tests.rs index 51c76f4d9..5017c1c04 100644 --- a/examples/async/examples/contract_instantiate_with_code.rs +++ b/testing/async/examples/pallet_contract_tests.rs @@ -78,31 +78,4 @@ async fn main() { .unwrap(); let _report = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock).await.unwrap(); - // - // println!("[+] Creating a contract instance \n"); - // let report = api.submit_and_watch_extrinsic_until(xt1, XtStatus::InBlock).await.unwrap(); - // println!("[+] Extrinsic is in Block. Hash: {:?}\n", report.block_hash.unwrap()); - // - // println!("[+] Waiting for the contracts.Instantiated event"); - // - // let associated_contract_events = report.events.unwrap(); - // - // let contract_instantiated_events: Vec = - // associated_contract_events - // .iter() - // .filter_map(|event| event.as_event().unwrap()) - // .collect(); - // // We only expect one instantiated event - // assert_eq!(contract_instantiated_events.len(), 1); - // let contract = contract_instantiated_events[0].contract.clone(); - // println!("[+] Event was received. Contract deployed at: {contract:?}\n"); - // - // let xt = api - // .contract_call(contract.into(), 500_000, 500_000.into(), None, vec![0u8].into()) - // .await - // .unwrap(); - // - // println!("[+] Calling the contract with extrinsic Extrinsic:\n{:?}\n\n", xt); - // let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::Finalized).await.unwrap(); - // println!("[+] Extrinsic got finalized. Extrinsic Hash: {:?}", report.extrinsic_hash); } From 998e3a6f7ea2762f5e340cfdcb888c5ea36e30a0 Mon Sep 17 00:00:00 2001 From: haerdib Date: Thu, 29 Feb 2024 15:28:52 +0100 Subject: [PATCH 6/6] fix compilation error --- testing/async/examples/pallet_contract_tests.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/testing/async/examples/pallet_contract_tests.rs b/testing/async/examples/pallet_contract_tests.rs index 5017c1c04..46ff4c9c4 100644 --- a/testing/async/examples/pallet_contract_tests.rs +++ b/testing/async/examples/pallet_contract_tests.rs @@ -20,8 +20,8 @@ use kitchensink_runtime::AccountId; use sp_keyring::AccountKeyring; use substrate_api_client::{ ac_compose_macros::primitives::AssetRuntimeConfig, ac_node_api::StaticEvent, - ac_primitives::Determinism, error::FailedExtrinsicError, extrinsic::ContractsExtrinsics, - rpc::JsonrpseeClient, Api, SubmitAndWatch, XtStatus, + ac_primitives::Determinism, extrinsic::ContractsExtrinsics, rpc::JsonrpseeClient, Api, + SubmitAndWatch, XtStatus, }; // To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. @@ -43,8 +43,6 @@ impl StaticEvent for ContractInstantiatedEventArgs { #[tokio::main] async fn main() { - env_logger::init(); - // Initialize api and set the signer (sender) that is used to sign the extrinsics. let signer = AccountKeyring::Alice.pair(); let client = JsonrpseeClient::with_default_url().await.unwrap();