diff --git a/Cargo.lock b/Cargo.lock index 524c846ee..804a48954 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -900,6 +900,7 @@ dependencies = [ "contract-transcode", "current_platform", "hex", + "ink_env", "ink_metadata", "jsonschema", "predicates", @@ -1211,6 +1212,7 @@ dependencies = [ "futures", "hex", "ink", + "ink_env", "ink_metadata", "itertools 0.12.1", "pallet-contracts-uapi", diff --git a/crates/cargo-contract/Cargo.toml b/crates/cargo-contract/Cargo.toml index bf8c5e57f..6b3266ad0 100644 --- a/crates/cargo-contract/Cargo.toml +++ b/crates/cargo-contract/Cargo.toml @@ -38,6 +38,7 @@ semver = "1.0" jsonschema = "0.17" schemars = "0.8" ink_metadata = "5.0.0-rc" +ink_env = "5.0.0-rc" comfy-table = "7.1.0" # dependencies for extrinsics (deploying and calling a contract) diff --git a/crates/cargo-contract/src/cmd/info.rs b/crates/cargo-contract/src/cmd/info.rs index 4bf72a047..e9e19f49b 100644 --- a/crates/cargo-contract/src/cmd/info.rs +++ b/crates/cargo-contract/src/cmd/info.rs @@ -26,12 +26,14 @@ use contract_extrinsics::{ fetch_contract_info, fetch_wasm_code, url_to_string, - Balance, - CodeHash, ContractInfo, ErrorVariant, TrieId, }; +use ink_env::{ + DefaultEnvironment, + Environment, +}; use std::{ fmt::Debug, io::Write, @@ -103,7 +105,10 @@ impl InfoCommand { .as_ref() .expect("Contract argument was not provided"); - let info_to_json = fetch_contract_info(contract, &rpc, &client).await?; + let info_to_json = fetch_contract_info::( + contract, &rpc, &client, + ) + .await?; let wasm_code = fetch_wasm_code(&client, &rpc, info_to_json.code_hash()).await?; @@ -122,15 +127,19 @@ impl InfoCommand { } else if self.output_json { println!( "{}", - serde_json::to_string_pretty(&ExtendedContractInfo::new( - info_to_json, - &wasm_code + serde_json::to_string_pretty(&ExtendedContractInfo::< + ::Hash, + ::Balance, + >::new( + info_to_json, &wasm_code ))? ) } else { - basic_display_format_extended_contract_info(&ExtendedContractInfo::new( - info_to_json, - &wasm_code, + basic_display_format_extended_contract_info(&ExtendedContractInfo::< + ::Hash, + ::Balance, + >::new( + info_to_json, &wasm_code )) } Ok(()) @@ -139,17 +148,21 @@ impl InfoCommand { } #[derive(serde::Serialize)] -pub struct ExtendedContractInfo { +pub struct ExtendedContractInfo { pub trie_id: TrieId, - pub code_hash: CodeHash, + pub code_hash: Hash, pub storage_items: u32, pub storage_items_deposit: Balance, pub storage_total_deposit: Balance, pub source_language: String, } -impl ExtendedContractInfo { - pub fn new(contract_info: ContractInfo, code: &[u8]) -> Self { +impl ExtendedContractInfo +where + Hash: serde::Serialize + Copy, + Balance: serde::Serialize + Copy, +{ + pub fn new(contract_info: ContractInfo, code: &[u8]) -> Self { let language = match determine_language(code).ok() { Some(lang) => lang.to_string(), None => "Unknown".to_string(), diff --git a/crates/cargo-contract/src/cmd/mod.rs b/crates/cargo-contract/src/cmd/mod.rs index 5d4a20c09..3e660fa8c 100644 --- a/crates/cargo-contract/src/cmd/mod.rs +++ b/crates/cargo-contract/src/cmd/mod.rs @@ -72,6 +72,7 @@ use contract_extrinsics::{ Balance, BalanceVariant, }; +use core::fmt; use std::io::{ self, Write, @@ -226,7 +227,11 @@ pub fn print_gas_required_success(gas: Weight) { } /// Display contract information in a formatted way -pub fn basic_display_format_extended_contract_info(info: &ExtendedContractInfo) { +pub fn basic_display_format_extended_contract_info( + info: &ExtendedContractInfo, +) where + Hash: fmt::Debug, +{ name_value_println!("TrieId", info.trie_id, MAX_KEY_COL_WIDTH); name_value_println!( "Code Hash", diff --git a/crates/cargo-contract/src/cmd/storage.rs b/crates/cargo-contract/src/cmd/storage.rs index bd8d095ea..73d198f7a 100644 --- a/crates/cargo-contract/src/cmd/storage.rs +++ b/crates/cargo-contract/src/cmd/storage.rs @@ -28,6 +28,7 @@ use contract_extrinsics::{ ContractStorageRpc, ErrorVariant, }; +use ink_env::DefaultEnvironment; use std::path::PathBuf; use subxt::Config; @@ -63,7 +64,8 @@ pub struct StorageCommand { impl StorageCommand { pub async fn run(&self) -> Result<(), ErrorVariant> { let rpc = ContractStorageRpc::::new(&self.url).await?; - let storage_layout = ContractStorage::::new(rpc); + let storage_layout = + ContractStorage::::new(rpc); if self.raw { let storage_data = storage_layout diff --git a/crates/extrinsics/Cargo.toml b/crates/extrinsics/Cargo.toml index 5b6dac742..968670000 100644 --- a/crates/extrinsics/Cargo.toml +++ b/crates/extrinsics/Cargo.toml @@ -41,6 +41,7 @@ subxt = "0.34.0" subxt-signer = { version = "0.34.0", features = ["subxt", "sr25519"] } hex = "0.4.3" ink_metadata = "5.0.0-rc" +ink_env = "5.0.0-rc" [dev-dependencies] ink = "5.0.0-rc" diff --git a/crates/extrinsics/src/contract_info.rs b/crates/extrinsics/src/contract_info.rs index 73f4f91d0..84f325b96 100644 --- a/crates/extrinsics/src/contract_info.rs +++ b/crates/extrinsics/src/contract_info.rs @@ -14,13 +14,7 @@ // You should have received a copy of the GNU General Public License // along with cargo-contract. If not, see . -use super::{ - get_best_block, - Balance, - Client, - CodeHash, - DefaultConfig, -}; +use super::get_best_block; use anyhow::{ anyhow, Result, @@ -31,6 +25,7 @@ use std::fmt::{ Formatter, }; +use ink_env::Environment; use scale::Decode; use std::option::Option; use subxt::{ @@ -46,19 +41,19 @@ use subxt::{ scale_value::Value, }, storage::dynamic, - utils::AccountId32, Config, OnlineClient, }; /// Return the account data for an account ID. -async fn get_account_balance( +async fn get_account_balance( account: &C::AccountId, rpc: &LegacyRpcMethods, client: &OnlineClient, -) -> Result +) -> Result> where C::AccountId: AsRef<[u8]>, + E::Balance: IntoVisitor, { let storage_query = subxt::dynamic::storage("System", "Account", vec![Value::from_bytes(account)]); @@ -71,19 +66,21 @@ where .await? .ok_or_else(|| anyhow::anyhow!("Failed to fetch account data"))?; - let data = account.as_type::()?.data; + let data = account.as_type::>()?.data; Ok(data) } /// Fetch the contract info from the storage using the provided client. -pub async fn fetch_contract_info( +pub async fn fetch_contract_info( contract: &C::AccountId, rpc: &LegacyRpcMethods, client: &OnlineClient, -) -> Result +) -> Result> where C::AccountId: AsRef<[u8]> + Display + IntoVisitor, + C::Hash: IntoVisitor, DecodeError: From<<::Visitor as Visitor>::Error>, + E::Balance: IntoVisitor, { let best_block = get_best_block(rpc).await?; @@ -105,26 +102,28 @@ where })?; let contract_info_raw = - ContractInfoRaw::::new(contract.clone(), contract_info_value)?; + ContractInfoRaw::::new(contract.clone(), contract_info_value)?; let deposit_account = contract_info_raw.get_deposit_account(); - let deposit_account_data = get_account_balance(deposit_account, rpc, client).await?; + let deposit_account_data = + get_account_balance::(deposit_account, rpc, client).await?; Ok(contract_info_raw.into_contract_info(deposit_account_data)) } /// Struct representing contract info, supporting deposit on either the main or secondary /// account. -struct ContractInfoRaw { +struct ContractInfoRaw { deposit_account: C::AccountId, - contract_info: ContractInfoOf, + contract_info: ContractInfoOf, deposit_on_main_account: bool, } -impl ContractInfoRaw +impl ContractInfoRaw where - C: Config, C::AccountId: IntoVisitor, + C::Hash: IntoVisitor, DecodeError: From<<::Visitor as Visitor>::Error>, + E::Balance: IntoVisitor, { /// Create a new instance of `ContractInfoRaw` based on the provided contract and /// contract info value. Determines whether it's a main or secondary account deposit. @@ -132,7 +131,8 @@ where contract_account: C::AccountId, contract_info_value: DecodedValueThunk, ) -> Result { - let contract_info = contract_info_value.as_type::()?; + let contract_info = + contract_info_value.as_type::>()?; // Pallet-contracts [>=10, <15] store the contract's deposit as a free balance // in a secondary account (deposit account). Other versions store it as // reserved balance on the main contract's account. If the @@ -161,7 +161,10 @@ where } /// Convert `ContractInfoRaw` to `ContractInfo` - pub fn into_contract_info(self, deposit: AccountData) -> ContractInfo { + pub fn into_contract_info( + self, + deposit: AccountData, + ) -> ContractInfo { let total_deposit = if self.deposit_on_main_account { deposit.reserved } else { @@ -185,15 +188,19 @@ where } #[derive(Debug, PartialEq, serde::Serialize)] -pub struct ContractInfo { +pub struct ContractInfo { trie_id: TrieId, - code_hash: CodeHash, + code_hash: Hash, storage_items: u32, storage_items_deposit: Balance, storage_total_deposit: Balance, } -impl ContractInfo { +impl ContractInfo +where + Hash: serde::Serialize, + Balance: serde::Serialize + Copy, +{ /// Convert and return contract info in JSON format. pub fn to_json(&self) -> Result { Ok(serde_json::to_string_pretty(self)?) @@ -205,7 +212,7 @@ impl ContractInfo { } /// Return the code_hash of the contract. - pub fn code_hash(&self) -> &CodeHash { + pub fn code_hash(&self) -> &Hash { &self.code_hash } @@ -255,11 +262,14 @@ impl Display for TrieId { } /// Fetch the contract wasm code from the storage using the provided client and code hash. -pub async fn fetch_wasm_code( - client: &Client, - rpc: &LegacyRpcMethods, - hash: &CodeHash, -) -> Result> { +pub async fn fetch_wasm_code( + client: &OnlineClient, + rpc: &LegacyRpcMethods, + hash: &C::Hash, +) -> Result> +where + C::Hash: AsRef<[u8]> + Display + IntoVisitor, +{ let best_block = get_best_block(rpc).await?; let pristine_code_address = @@ -278,31 +288,34 @@ pub async fn fetch_wasm_code( /// Parse a contract account address from a storage key. Returns error if a key is /// malformated. -fn parse_contract_account_address( +fn parse_contract_account_address( storage_contract_account_key: &[u8], storage_contract_root_key_len: usize, -) -> Result { +) -> Result +where + C::AccountId: Decode, +{ // storage_contract_account_key is a concatenation of contract_info_of root key and // Twox64Concat(AccountId) let mut account = storage_contract_account_key .get(storage_contract_root_key_len + 8..) .ok_or(anyhow!("Unexpected storage key size"))?; - AccountId32::decode(&mut account) + Decode::decode(&mut account) .map_err(|err| anyhow!("AccountId deserialization error: {}", err)) } /// Fetch all contract addresses from the storage using the provided client. -pub async fn fetch_all_contracts( - client: &Client, - rpc: &LegacyRpcMethods, -) -> Result> { +pub async fn fetch_all_contracts( + client: &OnlineClient, + rpc: &LegacyRpcMethods, +) -> Result> +where + C::AccountId: Decode, +{ let best_block = get_best_block(rpc).await?; - let root_key = subxt::dynamic::storage( - "Contracts", - "ContractInfoOf", - vec![Value::from_bytes(AccountId32([0u8; 32]))], - ) - .to_root_bytes(); + let root_key = + subxt::dynamic::storage("Contracts", "ContractInfoOf", Vec::<()>::new()) + .to_root_bytes(); let mut keys = client .storage() .at(best_block) @@ -312,7 +325,7 @@ pub async fn fetch_all_contracts( let mut contract_accounts = Vec::new(); while let Some(result) = keys.next().await { let key = result?; - let contract_account = parse_contract_account_address(&key, root_key.len())?; + let contract_account = parse_contract_account_address::(&key, root_key.len())?; contract_accounts.push(contract_account); } @@ -322,14 +335,14 @@ pub async fn fetch_all_contracts( /// A struct used in the storage reads to access account info. #[derive(DecodeAsType, Debug)] #[decode_as_type(crate_path = "subxt::ext::scale_decode")] -struct AccountInfo { - data: AccountData, +struct AccountInfo { + data: AccountData, } /// A struct used in the storage reads to access account data. #[derive(Clone, Debug, DecodeAsType)] #[decode_as_type(crate_path = "subxt::ext::scale_decode")] -struct AccountData { +struct AccountData { free: Balance, reserved: Balance, } @@ -342,9 +355,9 @@ struct BoundedVec(pub ::std::vec::Vec); /// A struct used in the storage reads to access contract info. #[derive(Debug, DecodeAsType)] #[decode_as_type(crate_path = "subxt::ext::scale_decode")] -struct ContractInfoOf { +struct ContractInfoOf { trie_id: BoundedVec, - code_hash: CodeHash, + code_hash: Hash, storage_items: u32, storage_item_deposit: Balance, } @@ -359,14 +372,19 @@ struct DepositAccount { #[cfg(test)] mod tests { use super::*; + use ink_env::DefaultEnvironment; use scale::Encode; use scale_info::{ IntoPortable, Path, }; - use subxt::metadata::{ - types::Metadata, - DecodeWithMetadata, + use subxt::{ + metadata::{ + types::Metadata, + DecodeWithMetadata, + }, + utils::AccountId32, + PolkadotConfig as DefaultConfig, }; // Find the type index in the metadata. @@ -438,8 +456,11 @@ mod tests { let contract = AccountId32([0u8; 32]); let contract_info_raw = - ContractInfoRaw::::new(contract, contract_info_thunk) - .expect("the conatract info raw must be created"); + ContractInfoRaw::::new( + contract, + contract_info_thunk, + ) + .expect("the conatract info raw must be created"); let account_data = AccountData { free: 1, reserved: 10, @@ -504,8 +525,11 @@ mod tests { let contract = AccountId32([0u8; 32]); let contract_info_raw = - ContractInfoRaw::::new(contract, contract_info_thunk) - .expect("the conatract info raw must be created"); + ContractInfoRaw::::new( + contract, + contract_info_thunk, + ) + .expect("the conatract info raw must be created"); let account_data = AccountData { free: 1, reserved: 10, diff --git a/crates/extrinsics/src/contract_storage.rs b/crates/extrinsics/src/contract_storage.rs index ca9f4ee53..1c31a2c97 100644 --- a/crates/extrinsics/src/contract_storage.rs +++ b/crates/extrinsics/src/contract_storage.rs @@ -22,6 +22,7 @@ use contract_transcode::{ ContractMessageTranscoder, Value, }; +use ink_env::Environment; use ink_metadata::layout::{ Layout, StructLayout, @@ -50,6 +51,7 @@ use std::{ Display, Formatter, }, + marker::PhantomData, }; use subxt::{ backend::{ @@ -75,21 +77,26 @@ use super::{ fetch_contract_info, url_to_string, ContractInfo, - DefaultConfig, TrieId, }; -pub struct ContractStorage { +pub struct ContractStorage { rpc: ContractStorageRpc, + _phantom: PhantomData E>, } -impl ContractStorage +impl ContractStorage where C::AccountId: AsRef<[u8]> + Display + IntoVisitor, + C::Hash: IntoVisitor, DecodeError: From<<::Visitor as Visitor>::Error>, + E::Balance: IntoVisitor + Serialize, { pub fn new(rpc: ContractStorageRpc) -> Self { - Self { rpc } + Self { + rpc, + _phantom: Default::default(), + } } /// Load the raw key/value storage for a given contract. @@ -97,7 +104,7 @@ where &self, contract_account: &C::AccountId, ) -> Result { - let contract_info = self.rpc.fetch_contract_info(contract_account).await?; + let contract_info = self.rpc.fetch_contract_info::(contract_account).await?; let trie_id = contract_info.trie_id(); let mut storage_keys = Vec::new(); @@ -596,6 +603,7 @@ pub struct ContractStorageRpc { impl ContractStorageRpc where C::AccountId: AsRef<[u8]> + Display + IntoVisitor, + C::Hash: IntoVisitor, DecodeError: From<<::Visitor as Visitor>::Error>, { /// Create a new instance of the ContractsRpc. @@ -612,11 +620,14 @@ where } /// Fetch the contract info to access the trie id for querying storage. - pub async fn fetch_contract_info( + pub async fn fetch_contract_info( &self, contract: &C::AccountId, - ) -> Result { - fetch_contract_info(contract, &self.rpc_methods, &self.client).await + ) -> Result> + where + E::Balance: IntoVisitor, + { + fetch_contract_info::(contract, &self.rpc_methods, &self.client).await } /// Fetch the contract storage at the given key.