diff --git a/Cargo.lock b/Cargo.lock index c114f976..384a11e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1556,8 +1556,10 @@ dependencies = [ "array-bytes", "clap", "cmd-impl", + "serde_json", "subalfred-core", "subhasher", + "subrpcer", "substorager", "tokio", "tracing-subscriber", diff --git a/bin/subalfred/Cargo.toml b/bin/subalfred/Cargo.toml index 55194562..644d7523 100644 --- a/bin/subalfred/Cargo.toml +++ b/bin/subalfred/Cargo.toml @@ -22,6 +22,7 @@ vergen = { version = "7.4" } anyhow = { version = "1.0" } array-bytes = { version = "4.1" } clap = { version = "4.0", features = ["cargo", "derive", "wrap_help"] } +serde_json = { version = "1.0" } tokio = { version = "1.21", features = ["macros", "rt-multi-thread"] } tracing-subscriber = { version = "0.3" } unescaper = { version = "0.1" } @@ -29,4 +30,5 @@ unescaper = { version = "0.1" } cmd-impl = { version = "0.9.0-rc13", path = "src/command/impl" } subalfred-core = { version = "0.9.0-rc13", path = "../../lib/core", features = ["clap"] } subhasher = { version = "0.9.0-rc13", path = "../../substrate-minimal/subhasher" } +subrpcer = { version = "0.9.0-rc13", path = "../../substrate-minimal/subrpcer" } substorager = { version = "0.9.0-rc13", path = "../../substrate-minimal/substorager" } diff --git a/bin/subalfred/src/command/mod.rs b/bin/subalfred/src/command/mod.rs index a93c02f8..b015519a 100644 --- a/bin/subalfred/src/command/mod.rs +++ b/bin/subalfred/src/command/mod.rs @@ -13,6 +13,9 @@ use hash::HashCmd; mod key; use key::KeyCmd; +mod rpc; +use rpc::RpcCmd; + mod state; use state::StateCmd; @@ -33,6 +36,7 @@ pub(crate) enum Cmd { Get, Hash, Key, + Rpc, #[command(subcommand)] State, StorageKey, diff --git a/bin/subalfred/src/command/rpc.rs b/bin/subalfred/src/command/rpc.rs new file mode 100644 index 00000000..463c28d2 --- /dev/null +++ b/bin/subalfred/src/command/rpc.rs @@ -0,0 +1,52 @@ +// crates.io +use clap::Args; +use serde_json::Value; +// hack-ink +use crate::prelude::*; +use subalfred_core::http::CLIENT; + +/// Send a RPC request to the node's HTTP RPC endpoint. +/// +/// Example: +/// Get the Polkadot's block zero's hash: +/// ``` +/// # Normal output +/// subalfred rpc https://rpc.polkadot.io --method chain_getBlockHash --params '[[0,1,2]]' +/// # Beautiful output +/// subalfred rpc https://rpc.polkadot.io --method chain_getBlockHash --params '[[0,1,2]]' | jq +/// ``` +#[derive(Debug, Args)] +pub(crate) struct RpcCmd { + /// Node's HTTP RPC endpoint. + #[arg(required = true, value_name = "URI", default_value = "http://localhost:9933")] + uri: String, + /// JSONRPC method name. + #[arg(long, required = true, value_name = "METHOD")] + method: String, + /// JSONRPC parameters. + #[arg(long, value_name = "PARAMETERS")] + params: Option, +} +impl RpcCmd { + #[tokio::main] + pub(crate) async fn run(&self) -> Result<()> { + let Self { method, params, uri } = self; + let params = if let Some(params) = params.as_ref() { + serde_json::from_str(params)? + } else { + Value::Null + }; + let result = CLIENT + .post(uri) + .json(&subrpcer::rpc(0, method, params)) + .send() + .await? + .json::() + .await?; + let result = serde_json::to_string(&result)?; + + println!("{result}"); + + Ok(()) + } +}