Skip to content

Commit

Permalink
Merge pull request #4954 from nymtech/feature/contract-state-tools
Browse files Browse the repository at this point in the history
Feature/contract state tools
  • Loading branch information
jstuczyn authored Oct 8, 2024
2 parents 143b336 + 5e0d1bb commit 27ac345
Show file tree
Hide file tree
Showing 19 changed files with 782 additions and 17 deletions.
36 changes: 36 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ members = [
"tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract",
"tools/echo-server",
"tools/internal/contract-state-importer/importer-cli",
"tools/internal/contract-state-importer/importer-contract",
]

default-members = [
Expand Down
1 change: 1 addition & 0 deletions common/client-libs/validator-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ nym-coconut-bandwidth-contract-common = { path = "../../cosmwasm-smart-contracts
nym-ecash-contract-common = { path = "../../cosmwasm-smart-contracts/ecash-contract" }
nym-multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig-contract" }
nym-group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" }
nym-serde-helpers = { path = "../../serde-helpers", features = ["hex", "base64"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
nym-http-api-client = { path = "../../../common/http-api-client" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::nyxd;
use crate::nyxd::coin::Coin;
use crate::nyxd::cosmwasm_client::helpers::{create_pagination, next_page_key};
use crate::nyxd::cosmwasm_client::types::{
Account, CodeDetails, Contract, ContractCodeId, SequenceResponse, SimulateResponse,
Account, CodeDetails, Contract, ContractCodeId, Model, SequenceResponse, SimulateResponse,
};
use crate::nyxd::error::NyxdError;
use crate::nyxd::Query;
Expand All @@ -21,11 +21,11 @@ use cosmrs::proto::cosmos::tx::v1beta1::{
SimulateRequest, SimulateResponse as ProtoSimulateResponse,
};
use cosmrs::proto::cosmwasm::wasm::v1::{
QueryCodeRequest, QueryCodeResponse, QueryCodesRequest, QueryCodesResponse,
QueryContractHistoryRequest, QueryContractHistoryResponse, QueryContractInfoRequest,
QueryContractInfoResponse, QueryContractsByCodeRequest, QueryContractsByCodeResponse,
QueryRawContractStateRequest, QueryRawContractStateResponse, QuerySmartContractStateRequest,
QuerySmartContractStateResponse,
QueryAllContractStateRequest, QueryAllContractStateResponse, QueryCodeRequest,
QueryCodeResponse, QueryCodesRequest, QueryCodesResponse, QueryContractHistoryRequest,
QueryContractHistoryResponse, QueryContractInfoRequest, QueryContractInfoResponse,
QueryContractsByCodeRequest, QueryContractsByCodeResponse, QueryRawContractStateRequest,
QueryRawContractStateResponse, QuerySmartContractStateRequest, QuerySmartContractStateResponse,
};
use cosmrs::tendermint::{block, chain, Hash};
use cosmrs::{AccountId, Coin as CosmosCoin, Tx};
Expand Down Expand Up @@ -444,6 +444,38 @@ pub trait CosmWasmClient: TendermintRpcClient {
.collect::<Result<_, _>>()?)
}

async fn query_all_contract_state(&self, address: &AccountId) -> Result<Vec<Model>, NyxdError> {
let path = Some("/cosmwasm.wasm.v1.Query/AllContractState".to_owned());

let mut models = Vec::new();
let mut pagination = None;

loop {
let req = QueryAllContractStateRequest {
address: address.to_string(),
pagination,
};

let mut res = self
.make_abci_query::<_, QueryAllContractStateResponse>(path.clone(), req)
.await?;

let empty_response = res.models.is_empty();
models.append(&mut res.models);

if empty_response {
break;
}
if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key))
} else {
break;
}
}

Ok(models.into_iter().map(Into::into).collect())
}

async fn query_contract_raw(
&self,
address: &AccountId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,34 @@ use cosmrs::vesting::{
};
use cosmrs::{AccountId, Any, Coin as CosmosCoin};
use prost::Message;
use serde::Serialize;
use serde::{Deserialize, Serialize};

pub use cosmrs::abci::GasInfo;
pub use cosmrs::abci::MsgResponse;

pub type ContractCodeId = u64;

// yet another thing to put in cosmrs
#[derive(Serialize, Deserialize)]
pub struct Model {
#[serde(with = "nym_serde_helpers::hex")]
pub key: Vec<u8>,

#[serde(with = "nym_serde_helpers::base64")]
pub value: Vec<u8>,
}

// follow the cosmwasm serialisation format, i.e. hex for key and base64 for value

impl From<cosmrs::proto::cosmwasm::wasm::v1::Model> for Model {
fn from(model: cosmrs::proto::cosmwasm::wasm::v1::Model) -> Self {
Model {
key: model.key,
value: model.value,
}
}
}

#[derive(Serialize)]
pub struct EmptyMsg {}

Expand Down
5 changes: 4 additions & 1 deletion common/commands/src/validator/cosmwasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ pub mod execute_contract;
pub mod generators;
pub mod init_contract;
pub mod migrate_contract;
pub mod raw_contract_state;
pub mod upload_contract;

#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Cosmwasm {
#[clap(subcommand)]
pub command: Option<CosmwasmCommands>,
pub command: CosmwasmCommands,
}

#[derive(Debug, Subcommand)]
Expand All @@ -28,4 +29,6 @@ pub enum CosmwasmCommands {
Migrate(crate::validator::cosmwasm::migrate_contract::Args),
/// Execute a WASM smart contract method
Execute(crate::validator::cosmwasm::execute_contract::Args),
/// Obtain raw contract state of a cosmwasm smart contract
RawContractState(crate::validator::cosmwasm::raw_contract_state::Args),
}
39 changes: 39 additions & 0 deletions common/commands/src/validator/cosmwasm/raw_contract_state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2024 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: Apache-2.0

use crate::context::QueryClient;
use clap::Parser;
use cosmrs::AccountId;
use log::trace;
use nym_validator_client::nyxd::CosmWasmClient;
use std::fs;
use std::fs::File;
use std::path::PathBuf;

#[derive(Debug, Parser)]
pub struct Args {
#[clap(long, value_parser)]
#[clap(help = "The address of contract to get the state of")]
pub contract: AccountId,

#[clap(short, long)]
#[clap(help = "Output file for the retrieved contract state")]
pub output: PathBuf,
}

pub async fn execute(args: Args, client: QueryClient) -> anyhow::Result<()> {
trace!("args: {args:?}");

let output = File::create(&args.output)?;
let raw = client.query_all_contract_state(&args.contract).await?;

serde_json::to_writer(output, &raw)?;
println!(
"wrote {} key-value from {} pairs into '{}'",
raw.len(),
args.contract,
fs::canonicalize(args.output)?.display()
);

Ok(())
}
2 changes: 2 additions & 0 deletions common/serde-helpers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ license.workspace = true
[dependencies]

serde = { workspace = true }
hex = { workspace = true, optional = true }
bs58 = { workspace = true, optional = true }
base64 = { workspace = true, optional = true }
time = { workspace = true, features = ["formatting", "parsing"], optional = true }

[features]
hex = ["dep:hex"]
bs58 = ["dep:bs58"]
base64 = ["dep:base64"]
date = ["time"]
14 changes: 14 additions & 0 deletions common/serde-helpers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ pub mod bs58 {
}
}

#[cfg(feature = "hex")]
pub mod hex {
use serde::{Deserialize, Deserializer, Serializer};

pub fn serialize<S: Serializer>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&::hex::encode(bytes))
}

pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
let s = String::deserialize(deserializer)?;
::hex::decode(&s).map_err(serde::de::Error::custom)
}
}

#[cfg(feature = "date")]
pub mod date {
use serde::ser::Error;
Expand Down
2 changes: 2 additions & 0 deletions nym-wallet/Cargo.lock

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

2 changes: 2 additions & 0 deletions tools/internal/contract-state-importer/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build-importer-contract:
$(MAKE) -C importer-contract build
26 changes: 26 additions & 0 deletions tools/internal/contract-state-importer/importer-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "importer-cli"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license.workspace = true
rust-version.workspace = true
readme.workspace = true

[dependencies]
anyhow = { workspace = true }
bip39 = { workspace = true }
clap = { workspace = true, features = ["derive"] }
dirs = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] }
tracing = { workspace = true }

importer-contract = { path = "../importer-contract" }
nym-validator-client = { path = "../../../../common/client-libs/validator-client" }
nym-bin-common = { path = "../../../../common/bin-common", features = ["basic_tracing"] }
nym-network-defaults = { path = "../../../../common/network-defaults" }
Loading

0 comments on commit 27ac345

Please sign in to comment.