Skip to content

Commit

Permalink
Make internal struct private
Browse files Browse the repository at this point in the history
  • Loading branch information
smiasojed committed Nov 15, 2023
1 parent 7fbf8c8 commit 9a3e1bb
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 56 deletions.
2 changes: 1 addition & 1 deletion crates/extrinsics/src/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ pub struct CallRequest {
/// A raw call to `pallet-contracts`'s `call`.
#[derive(scale_encode::EncodeAsType)]
#[encode_as_type(crate_path = "subxt::ext::scale_encode")]
pub struct Call {
struct Call {
dest: MultiAddress<<DefaultConfig as Config>::AccountId, ()>,
#[codec(compact)]
value: Balance,
Expand Down
157 changes: 111 additions & 46 deletions crates/extrinsics/src/contract_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,6 @@ async fn get_account_balance(
Ok(data)
}

/// Decode the deposit account from the contract info
fn get_deposit_account_id(contract_info: &DecodedValueThunk) -> Result<AccountId32> {
let account = contract_info.as_type::<DepositAccount>()?;
Ok(account.deposit_account)
}

/// Fetch the contract info from the storage using the provided client.
pub async fn fetch_contract_info(
contract: &AccountId32,
Expand All @@ -80,7 +74,7 @@ pub async fn fetch_contract_info(
"ContractInfoOf",
vec![Value::from_bytes(contract)],
);
let contract_info = client
let contract_info_value = client
.storage()
.at(best_block)
.fetch(&contract_info_address)
Expand All @@ -92,31 +86,74 @@ pub async fn fetch_contract_info(
)
})?;

// 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
// `deposit_account` field is present in a contract info structure,
// the contract's deposit is in this account.
let total_balance: Balance = match get_deposit_account_id(&contract_info) {
Ok(deposit_account) => {
get_account_balance(&deposit_account, rpc, client)
.await?
.free
}
Err(_) => get_account_balance(contract, rpc, client).await?.reserved,
let contract_info_raw = ContractInfoRaw::new(contract, contract_info_value)?;
let deposit_account = match contract_info_raw {
ContractInfoRaw::MainAccountDeposit(ref account, _)
| ContractInfoRaw::SecondaryAccountDeposit(ref account, _) => account,
};

let info = contract_info.as_type::<ContractInfoOf>()?;
Ok(ContractInfo {
trie_id: hex::encode(info.trie_id.0),
code_hash: info.code_hash,
storage_items: info.storage_items,
storage_items_deposit: info.storage_item_deposit,
storage_total_deposit: total_balance,
})
let deposit_account_data = get_account_balance(deposit_account, rpc, client).await?;
Ok(contract_info_raw.into_contract_info(deposit_account_data))
}

/// Enum representing different types of contract info, distinguishing between
/// main account deposit and secondary account deposit.
pub enum ContractInfoRaw {
MainAccountDeposit(AccountId32, ContractInfoOf),
SecondaryAccountDeposit(AccountId32, ContractInfoOf),
}

impl ContractInfoRaw {
/// 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: &AccountId32,
contract_info_value: DecodedValueThunk,
) -> Result<Self> {
let info = contract_info_value.as_type::<ContractInfoOf>()?;
// 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
// `deposit_account` field is present in a contract info structure,
// the contract's deposit is in this account.
match Self::get_deposit_account_id(&contract_info_value) {
Ok(deposit_account) => {
Ok(Self::SecondaryAccountDeposit(deposit_account, info))
}
Err(_) => Ok(Self::MainAccountDeposit(contract.clone(), info)),
}
}

/// Convert `ContractInfoRaw` to `ContractInfo`
pub fn into_contract_info(self, deposit: AccountData) -> ContractInfo {
let total_deposit = match self {
Self::MainAccountDeposit(_, _) => deposit.free,

Self::SecondaryAccountDeposit(_, _) => deposit.reserved,
};

match self {
Self::MainAccountDeposit(_, ref info)
| Self::SecondaryAccountDeposit(_, ref info) => {
ContractInfo {
trie_id: hex::encode(&info.trie_id.0),
code_hash: info.code_hash,
storage_items: info.storage_items,
storage_items_deposit: info.storage_item_deposit,
storage_total_deposit: total_deposit,
}
}
}
}

/// Decode the deposit account from the contract info
fn get_deposit_account_id(contract_info: &DecodedValueThunk) -> Result<AccountId32> {
let account = contract_info.as_type::<DepositAccount>()?;
Ok(account.deposit_account)
}
}

#[derive(serde::Serialize)]
#[derive(Debug, serde::Serialize, std::cmp::PartialEq)]
pub struct ContractInfo {
trie_id: String,
code_hash: CodeHash,
Expand Down Expand Up @@ -230,11 +267,11 @@ struct AccountInfo {
}

/// A struct used in the storage reads to access account data.
#[derive(Debug, DecodeAsType)]
#[derive(Clone, Debug, DecodeAsType)]
#[decode_as_type(crate_path = "subxt::ext::scale_decode")]
struct AccountData {
pub free: Balance,
pub reserved: Balance,
pub struct AccountData {
free: Balance,
reserved: Balance,
}

/// A struct representing `Vec`` used in the storage reads.
Expand All @@ -245,7 +282,7 @@ 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 {
pub struct ContractInfoOf {
trie_id: BoundedVec<u8>,
code_hash: CodeHash,
storage_items: u32,
Expand Down Expand Up @@ -297,7 +334,7 @@ mod tests {
}

#[test]
fn deposit_decode_works() {
fn contract_info_v11_decode_works() {
// This version of metadata includes the deposit_account field in ContractInfo
#[subxt::subxt(runtime_metadata_path = "src/runtime_api/metadata_v11.scale")]
mod api_v11 {}
Expand All @@ -321,7 +358,7 @@ mod tests {
)
.expect("the contract info type must be present in the metadata");

let contract_info = ContractInfoV11 {
let contract_info_v11 = ContractInfoV11 {
trie_id: BoundedVec(vec![]),
deposit_account: DepositAccount(AccountId32([7u8; 32])),
code_hash: Default::default(),
Expand All @@ -333,20 +370,35 @@ mod tests {
};

let contract_info_thunk = DecodedValueThunk::decode_with_metadata(
&mut &*contract_info.encode(),
&mut &*contract_info_v11.encode(),
contract_info_type_id as u32,
&metadata.into(),
)
.expect("the contract info must be decoded");

let deposit = get_deposit_account_id(&contract_info_thunk)
.expect("the deposit account must be decoded from contract info");
let contract = AccountId32([0u8; 32]);
let contract_info_raw = ContractInfoRaw::new(&contract, contract_info_thunk)
.expect("the conatract info raw must be created");
let account_data = AccountData {
free: 1,
reserved: 10,
};

assert_eq!(deposit, contract_info.deposit_account.0);
let contract_info = contract_info_raw.into_contract_info(account_data.clone());
assert_eq!(
contract_info,
ContractInfo {
trie_id: hex::encode(contract_info_v11.trie_id.0),
code_hash: contract_info_v11.code_hash,
storage_items: contract_info_v11.storage_items,
storage_items_deposit: contract_info_v11.storage_item_deposit,
storage_total_deposit: account_data.reserved,
}
);
}

#[test]
fn deposit_decode_fails() {
fn contract_info_v15_decode_works() {
// This version of metadata does not include the deposit_account field in
// ContractInfo
#[subxt::subxt(runtime_metadata_path = "src/runtime_api/metadata.scale")]
Expand All @@ -371,7 +423,7 @@ mod tests {
)
.expect("the contract info type must be present in the metadata");

let contract_info = ContractInfoV15 {
let contract_info_v15 = ContractInfoV15 {
trie_id: BoundedVec(vec![]),
code_hash: Default::default(),
storage_bytes: 1,
Expand All @@ -383,17 +435,30 @@ mod tests {
};

let contract_info_thunk = DecodedValueThunk::decode_with_metadata(
&mut &*contract_info.encode(),
&mut &*contract_info_v15.encode(),
contract_info_type_id as u32,
&metadata.into(),
)
.expect("the contract info must be decoded");

let res = get_deposit_account_id(&contract_info_thunk)
.expect_err("decoding the deposit account must fail");
let contract = AccountId32([0u8; 32]);
let contract_info_raw = ContractInfoRaw::new(&contract, contract_info_thunk)
.expect("the conatract info raw must be created");
let account_data = AccountData {
free: 1,
reserved: 10,
};

let contract_info = contract_info_raw.into_contract_info(account_data.clone());
assert_eq!(
res.to_string(),
"Error at : Field deposit_account does not exist in our encoded data"
contract_info,
ContractInfo {
trie_id: hex::encode(contract_info_v15.trie_id.0),
code_hash: contract_info_v15.code_hash,
storage_items: contract_info_v15.storage_items,
storage_items_deposit: contract_info_v15.storage_item_deposit,
storage_total_deposit: account_data.free,
}
);
}
}
4 changes: 2 additions & 2 deletions crates/extrinsics/src/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ pub enum Code {
/// A raw call to `pallet-contracts`'s `instantiate_with_code`.
#[derive(Debug, scale_encode::EncodeAsType)]
#[encode_as_type(crate_path = "subxt::ext::scale_encode")]
pub struct InstantiateWithCode {
struct InstantiateWithCode {
#[codec(compact)]
value: Balance,
gas_limit: Weight,
Expand All @@ -597,7 +597,7 @@ pub struct InstantiateWithCode {
/// A raw call to `pallet-contracts`'s `instantiate_with_code_hash`.
#[derive(Debug, scale_encode::EncodeAsType)]
#[encode_as_type(crate_path = "subxt::ext::scale_encode")]
pub struct Instantiate {
struct Instantiate {
#[codec(compact)]
value: Balance,
gas_limit: Weight,
Expand Down
12 changes: 7 additions & 5 deletions crates/extrinsics/src/remove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,6 @@ impl RemoveCommandBuilder<state::ExtrinsicOptions> {
})
}
}
#[derive(scale_encode::EncodeAsType)]
#[encode_as_type(crate_path = "subxt::ext::scale_encode")]
pub struct RemoveCode {
code_hash: CodeHash,
}

pub struct RemoveExec {
final_code_hash: [u8; 32],
Expand Down Expand Up @@ -225,3 +220,10 @@ pub struct RemoveResult {
pub code_removed: Option<CodeRemoved>,
pub display_events: DisplayEvents,
}

/// A raw call to `pallet-contracts`'s `remove_code`.
#[derive(scale_encode::EncodeAsType)]
#[encode_as_type(crate_path = "subxt::ext::scale_encode")]
struct RemoveCode {
code_hash: CodeHash,
}
4 changes: 2 additions & 2 deletions crates/extrinsics/src/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,10 @@ pub enum Determinism {
Relaxed,
}

/// A raw call to `pallet-contracts`'s `upload`.
/// A raw call to `pallet-contracts`'s `upload_code`.
#[derive(Debug, scale_encode::EncodeAsType)]
#[encode_as_type(crate_path = "subxt::ext::scale_encode")]
pub struct UploadCode {
struct UploadCode {
code: Vec<u8>,
storage_deposit_limit: Option<Compact<Balance>>,
determinism: Determinism,
Expand Down

0 comments on commit 9a3e1bb

Please sign in to comment.