Skip to content

Commit

Permalink
Add generics for info and storage commands
Browse files Browse the repository at this point in the history
  • Loading branch information
smiasojed committed Jan 22, 2024
1 parent 990b64b commit 3a2359e
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 66 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/cargo-contract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
crossterm = "0.27.0"

# dependencies for extrinsics (deploying and calling a contract)
Expand Down
39 changes: 26 additions & 13 deletions crates/cargo-contract/src/cmd/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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::<DefaultConfig, DefaultEnvironment>(
contract, &rpc, &client,
)
.await?;

let wasm_code =
fetch_wasm_code(&client, &rpc, info_to_json.code_hash()).await?;
Expand All @@ -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::<
<DefaultConfig as Config>::Hash,
<DefaultEnvironment as Environment>::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::<
<DefaultConfig as Config>::Hash,
<DefaultEnvironment as Environment>::Balance,
>::new(
info_to_json, &wasm_code
))
}
Ok(())
Expand All @@ -139,17 +148,21 @@ impl InfoCommand {
}

#[derive(serde::Serialize)]
pub struct ExtendedContractInfo {
pub struct ExtendedContractInfo<Hash, Balance> {
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<Hash, Balance> ExtendedContractInfo<Hash, Balance>
where
Hash: serde::Serialize + Copy,
Balance: serde::Serialize + Copy,
{
pub fn new(contract_info: ContractInfo<Hash, Balance>, code: &[u8]) -> Self {
let language = match determine_language(code).ok() {
Some(lang) => lang.to_string(),
None => "Unknown".to_string(),
Expand Down
7 changes: 6 additions & 1 deletion crates/cargo-contract/src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ use contract_extrinsics::{
Balance,
BalanceVariant,
};
use core::fmt;
use pallet_contracts_primitives::ContractResult;
use std::io::{
self,
Expand Down Expand Up @@ -224,7 +225,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<Hash>(
info: &ExtendedContractInfo<Hash, Balance>,
) where
Hash: fmt::Debug,
{
name_value_println!("TrieId", info.trie_id, MAX_KEY_COL_WIDTH);
name_value_println!(
"Code Hash",
Expand Down
7 changes: 5 additions & 2 deletions crates/cargo-contract/src/cmd/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use contract_extrinsics::{
ErrorVariant,
};
use crossterm::terminal;
use ink_env::DefaultEnvironment;
use std::{
cmp,
path::PathBuf,
Expand Down Expand Up @@ -65,8 +66,10 @@ pub struct StorageCommand {

impl StorageCommand {
pub async fn run(&self) -> Result<(), ErrorVariant> {
let rpc = ContractStorageRpc::<DefaultConfig>::new(&self.url).await?;
let storage_layout = ContractStorage::<DefaultConfig>::new(rpc);
let rpc = ContractStorageRpc::<DefaultConfig, DefaultEnvironment>::new(&self.url)
.await?;
let storage_layout =
ContractStorage::<DefaultConfig, DefaultEnvironment>::new(rpc);

if self.raw {
let storage_data = storage_layout
Expand Down
1 change: 1 addition & 0 deletions crates/extrinsics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ subxt = "0.33.0"
subxt-signer = { version = "0.33.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"
Expand Down
94 changes: 54 additions & 40 deletions crates/extrinsics/src/contract_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with cargo-contract. If not, see <http://www.gnu.org/licenses/>.

use super::{
get_best_block,
Balance,
Client,
CodeHash,
DefaultConfig,
};
use super::get_best_block;
use anyhow::{
anyhow,
Result,
Expand All @@ -31,6 +25,7 @@ use std::fmt::{
Formatter,
};

use ink_env::Environment;
use scale::Decode;
use std::option::Option;
use subxt::{
Expand All @@ -52,13 +47,14 @@ use subxt::{
};

/// Return the account data for an account ID.
async fn get_account_balance<C: Config>(
async fn get_account_balance<C: Config, E: Environment>(
account: &C::AccountId,
rpc: &LegacyRpcMethods<C>,
client: &OnlineClient<C>,
) -> Result<AccountData>
) -> Result<AccountData<E::Balance>>
where
C::AccountId: AsRef<[u8]>,
E::Balance: IntoVisitor,
{
let storage_query =
subxt::dynamic::storage("System", "Account", vec![Value::from_bytes(account)]);
Expand All @@ -71,19 +67,21 @@ where
.await?
.ok_or_else(|| anyhow::anyhow!("Failed to fetch account data"))?;

let data = account.as_type::<AccountInfo>()?.data;
let data = account.as_type::<AccountInfo<E::Balance>>()?.data;
Ok(data)
}

/// Fetch the contract info from the storage using the provided client.
pub async fn fetch_contract_info<C: Config>(
pub async fn fetch_contract_info<C: Config, E: Environment>(
contract: &C::AccountId,
rpc: &LegacyRpcMethods<C>,
client: &OnlineClient<C>,
) -> Result<ContractInfo>
) -> Result<ContractInfo<C::Hash, E::Balance>>
where
C::AccountId: AsRef<[u8]> + Display + IntoVisitor,
C::Hash: IntoVisitor,
DecodeError: From<<<C::AccountId as IntoVisitor>::Visitor as Visitor>::Error>,
E::Balance: IntoVisitor,
{
let best_block = get_best_block(rpc).await?;

Expand All @@ -105,34 +103,37 @@ where
})?;

let contract_info_raw =
ContractInfoRaw::<C>::new(contract.clone(), contract_info_value)?;
ContractInfoRaw::<C, E>::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::<C, E>(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<C: Config> {
struct ContractInfoRaw<C: Config, E: Environment> {
deposit_account: C::AccountId,
contract_info: ContractInfoOf,
contract_info: ContractInfoOf<C::Hash, E::Balance>,
deposit_on_main_account: bool,
}

impl<C> ContractInfoRaw<C>
impl<C: Config, E: Environment> ContractInfoRaw<C, E>
where
C: Config,
C::AccountId: IntoVisitor,
C::Hash: IntoVisitor,
DecodeError: From<<<C::AccountId as IntoVisitor>::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.
pub fn new(
contract_account: C::AccountId,
contract_info_value: DecodedValueThunk,
) -> Result<Self> {
let contract_info = contract_info_value.as_type::<ContractInfoOf>()?;
let contract_info =
contract_info_value.as_type::<ContractInfoOf<C::Hash, E::Balance>>()?;
// 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
Expand Down Expand Up @@ -161,7 +162,10 @@ where
}

/// Convert `ContractInfoRaw` to `ContractInfo`
pub fn into_contract_info(self, deposit: AccountData) -> ContractInfo {
pub fn into_contract_info(
self,
deposit: AccountData<E::Balance>,
) -> ContractInfo<C::Hash, E::Balance> {
let total_deposit = if self.deposit_on_main_account {
deposit.reserved
} else {
Expand All @@ -185,15 +189,19 @@ where
}

#[derive(Debug, PartialEq, serde::Serialize)]
pub struct ContractInfo {
pub struct ContractInfo<Hash, Balance> {
trie_id: TrieId,
code_hash: CodeHash,
code_hash: Hash,
storage_items: u32,
storage_items_deposit: Balance,
storage_total_deposit: Balance,
}

impl ContractInfo {
impl<Hash, Balance> ContractInfo<Hash, Balance>
where
Hash: serde::Serialize,
Balance: serde::Serialize + Copy,
{
/// Convert and return contract info in JSON format.
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string_pretty(self)?)
Expand All @@ -205,7 +213,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
}

Expand Down Expand Up @@ -255,11 +263,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<DefaultConfig>,
hash: &CodeHash,
) -> Result<Vec<u8>> {
pub async fn fetch_wasm_code<C: Config>(
client: &OnlineClient<C>,
rpc: &LegacyRpcMethods<C>,
hash: &C::Hash,
) -> Result<Vec<u8>>
where
C::Hash: AsRef<[u8]> + Display + IntoVisitor,
{
let best_block = get_best_block(rpc).await?;

let pristine_code_address =
Expand Down Expand Up @@ -292,9 +303,9 @@ fn parse_contract_account_address(
}

/// Fetch all contract addresses from the storage using the provided client.
pub async fn fetch_all_contracts(
client: &Client,
rpc: &LegacyRpcMethods<DefaultConfig>,
pub async fn fetch_all_contracts<C: Config>(
client: &OnlineClient<C>,
rpc: &LegacyRpcMethods<C>,
) -> Result<Vec<AccountId32>> {
let best_block = get_best_block(rpc).await?;
let root_key = subxt::dynamic::storage(
Expand Down Expand Up @@ -322,14 +333,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<Balance> {
data: AccountData<Balance>,
}

/// 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<Balance> {
free: Balance,
reserved: Balance,
}
Expand All @@ -342,9 +353,9 @@ struct BoundedVec<T>(pub ::std::vec::Vec<T>);
/// 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<Hash, Balance> {
trie_id: BoundedVec<u8>,
code_hash: CodeHash,
code_hash: Hash,
storage_items: u32,
storage_item_deposit: Balance,
}
Expand All @@ -364,9 +375,12 @@ mod tests {
IntoPortable,
Path,
};
use subxt::metadata::{
types::Metadata,
DecodeWithMetadata,
use subxt::{
metadata::{
types::Metadata,
DecodeWithMetadata,
},
PolkadotConfig as DefaultConfig,
};

// Find the type index in the metadata.
Expand Down
Loading

0 comments on commit 3a2359e

Please sign in to comment.