Skip to content

Commit

Permalink
Add raw RPC calls (#1458)
Browse files Browse the repository at this point in the history
  • Loading branch information
smiasojed authored Jan 31, 2024
1 parent 75de3c0 commit 6ef21d3
Show file tree
Hide file tree
Showing 9 changed files with 385 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- Add a user-friendly view of contract storage data in the form of a table - [#1414](https://github.com/paritytech/cargo-contract/pull/1414)
- Add `rpc` command - [#1458](https://github.com/paritytech/cargo-contract/pull/1458)

### Changed
- Mandatory dylint-based lints - [#1412](https://github.com/paritytech/cargo-contract/pull/1412)
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ Verify a metadata file or a contract bundle containing metadata against the sche

Fetch and display the storage of a contract on chain.

##### `cargo contract rpc`

Invoke an RPC call to the node. See [rpc](docs/rpc.md).


## Publishing

Expand Down
2 changes: 2 additions & 0 deletions crates/cargo-contract/src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub mod encode;
pub mod info;
pub mod instantiate;
pub mod remove;
pub mod rpc;
pub mod schema;
pub mod storage;
pub mod upload;
Expand All @@ -39,6 +40,7 @@ pub(crate) use self::{
},
instantiate::InstantiateCommand,
remove::RemoveCommand,
rpc::RpcCommand,
schema::{
GenerateSchemaCommand,
VerifySchemaCommand,
Expand Down
74 changes: 74 additions & 0 deletions crates/cargo-contract/src/cmd/rpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of cargo-contract.
//
// cargo-contract is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// cargo-contract is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// 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 contract_build::name_value_println;
use contract_extrinsics::{
ErrorVariant,
RawParams,
RpcRequest,
};
use subxt::ext::scale_value;

use super::MAX_KEY_COL_WIDTH;

#[derive(Debug, clap::Args)]
#[clap(name = "rpc", about = "Make a raw RPC call")]
pub struct RpcCommand {
/// The name of the method to call.
method: String,
/// The arguments of the method to call.
#[clap(num_args = 0..)]
params: Vec<String>,
/// Websockets url of a substrate node.
#[clap(
name = "url",
long,
value_parser,
default_value = "ws://localhost:9944"
)]
url: url::Url,
/// Export the call output in JSON format.
#[clap(long)]
output_json: bool,
}

impl RpcCommand {
pub async fn run(&self) -> Result<(), ErrorVariant> {
let request = RpcRequest::new(&self.url).await?;
let params = RawParams::new(&self.params)?;

let result = request.raw_call(&self.method, params).await;

match (result, self.output_json) {
(Err(err), false) => Err(anyhow::anyhow!("Method call failed: {}", err))?,
(Err(err), true) => {
Err(anyhow::anyhow!(serde_json::to_string_pretty(
&ErrorVariant::from(err)
)?))?
}
(Ok(res), false) => {
let output: scale_value::Value = serde_json::from_str(res.get())?;
name_value_println!("Result", output, MAX_KEY_COL_WIDTH);
Ok(())
}
(Ok(res), true) => {
let json: serde_json::Value = serde_json::from_str(res.get())?;
println!("{}", serde_json::to_string_pretty(&json)?);
Ok(())
}
}
}
}
7 changes: 7 additions & 0 deletions crates/cargo-contract/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use self::cmd::{
InfoCommand,
InstantiateCommand,
RemoveCommand,
RpcCommand,
StorageCommand,
UploadCommand,
VerifyCommand,
Expand Down Expand Up @@ -154,6 +155,9 @@ enum Command {
/// Verify schema from the current metadata specification.
#[clap(name = "verify-schema")]
VerifySchema(VerifySchemaCommand),
/// Make a raw RPC call.
#[clap(name = "rpc")]
Rpc(RpcCommand),
}

fn main() {
Expand Down Expand Up @@ -260,6 +264,9 @@ fn exec(cmd: Command) -> Result<()> {
}
Ok(())
}
Command::Rpc(rpc) => {
runtime.block_on(async { rpc.run().await.map_err(format_err) })
}
}
}

Expand Down
45 changes: 45 additions & 0 deletions crates/extrinsics/src/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,51 @@ async fn api_build_upload_remove() {
let _ = node_process;
}

/// Sanity test the RPC API
#[tokio::test]
async fn api_rpc_call() {
init_tracing_subscriber();

let tmp_dir = tempfile::Builder::new()
.prefix("cargo-contract.cli.test.")
.tempdir()
.expect("temporary directory creation failed");

let node_process = ContractsNodeProcess::spawn(CONTRACTS_NODE)
.await
.expect("Error spawning contracts node");

cargo_contract(tmp_dir.path())
.arg("rpc")
.arg("author_insertKey")
.arg("\"sr25\"")
.arg("\"//ALICE\"")
.arg("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
.assert()
.success();

let output = cargo_contract(tmp_dir.path())
.arg("rpc")
.arg("author_hasKey")
.arg("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY")
.arg("\"sr25\"")
.arg("--output-json")
.output()
.expect("failed to execute process");

let stdout = str::from_utf8(&output.stdout).unwrap();
let stderr = str::from_utf8(&output.stderr).unwrap();
assert!(
output.status.success(),
"rpc method execution failed: {stderr}"
);

assert_eq!(stdout.trim_end(), "true", "{stdout:?}");

// prevent the node_process from being dropped and killed
let _ = node_process;
}

/// Sanity test the whole lifecycle of:
/// new -> build -> upload -> instantiate -> storage
///
Expand Down
6 changes: 6 additions & 0 deletions crates/extrinsics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mod extrinsic_opts;
mod instantiate;
pub mod pallet_contracts_primitives;
mod remove;
mod rpc;
mod upload;

#[cfg(test)]
Expand Down Expand Up @@ -112,6 +113,11 @@ pub use upload::{
UploadResult,
};

pub use rpc::{
RawParams,
RpcRequest,
};

pub type Client = OnlineClient<DefaultConfig>;
pub type Balance = u128;
pub type CodeHash = <DefaultConfig as Config>::Hash;
Expand Down
Loading

0 comments on commit 6ef21d3

Please sign in to comment.