From 0b570fdc0202df7d19cb93207d576a8dbf2cacc6 Mon Sep 17 00:00:00 2001 From: Sebastian Miasojed Date: Tue, 16 Jan 2024 15:30:06 +0100 Subject: [PATCH] Code refactored --- Cargo.lock | 1 + crates/cargo-contract/Cargo.toml | 1 + crates/cargo-contract/src/cmd/rpc.rs | 63 ++++++++++++++------- crates/extrinsics/src/rpc.rs | 85 +++++++++++++++++++++++----- crates/transcode/src/scon/mod.rs | 4 ++ 5 files changed, 121 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2be388dcc..7f90474c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -796,6 +796,7 @@ dependencies = [ "predicates", "primitive-types", "regex", + "scale-value", "schemars", "semver", "serde", diff --git a/crates/cargo-contract/Cargo.toml b/crates/cargo-contract/Cargo.toml index 2f492333c..0893d1b4e 100644 --- a/crates/cargo-contract/Cargo.toml +++ b/crates/cargo-contract/Cargo.toml @@ -39,6 +39,7 @@ jsonschema = "0.17" schemars = "0.8" ink_metadata = "5.0.0-rc" crossterm = "0.27.0" +scale-value = "0.13.0" # dependencies for extrinsics (deploying and calling a contract) tokio = { version = "1", features = ["macros", "rt-multi-thread"] } diff --git a/crates/cargo-contract/src/cmd/rpc.rs b/crates/cargo-contract/src/cmd/rpc.rs index 9422f2329..3cfb46cc2 100644 --- a/crates/cargo-contract/src/cmd/rpc.rs +++ b/crates/cargo-contract/src/cmd/rpc.rs @@ -19,8 +19,14 @@ use contract_extrinsics::{ Rpc, RpcRequest, }; -use contract_transcode::scon::parse_value; -use serde_json::value::RawValue; +use scale_value::{ + stringify::{ + from_str_custom, + ParseError, + }, + Value, +}; +use subxt::backend::rpc::RpcParams; #[derive(Debug, clap::Args)] #[clap(name = "rpc", about = "Make a raw RPC call")] @@ -51,27 +57,46 @@ impl RpcCommand { pub async fn run(&self) -> Result<(), ErrorVariant> { let rpc = Rpc::new(&self.url).await?; let request = RpcRequest::new(rpc); + let str_parser = from_str_custom(); + let str_parser = str_parser.add_custom_parser(custom_parse_hex); + + let params = self + .params + .iter() + .map(|e| str_parser.parse(e).0) + .collect::, ParseError>>() + .map_err(|e| anyhow::anyhow!("Function arguments parsing failed: {e}"))?; - let mut params = None; - if !self.params.is_empty() { - let mut json = String::new(); - for i in &self.params { - let p = parse_value(i).unwrap(); - json = format!("{json}, {}", serde_json::to_string(&p)?); + let params = match params.is_empty() { + true => None, + false => { + params + .iter() + .try_fold(RpcParams::new(), |mut v, e| { + v.push(e)?; + Ok(v) + }) + .map_err(|e: subxt::Error| { + anyhow::anyhow!("Method arguments parsing failed: {e}") + })? + .build() } - json = format!("[{json}]"); - println!("{json}"); - params = Some( - RawValue::from_string(json) - .map_err(|e| anyhow::anyhow!("Raw Value creation failed: {e}"))?, - ); - } - println!("{:?}", self.params); + }; + + // println!("params: {:?}", params); let res = request - .exec(&self.method, params) + .raw_call(&self.method, params) .await - .map_err(|e| anyhow::anyhow!("Err: {}", e))?; - println!("{res}"); + .map_err(|e| anyhow::anyhow!("Method call failed: {}", e))?; + let json: serde_json::Value = serde_json::from_str(res.get())?; + println!("{}", serde_json::to_string_pretty(&json)?); Ok(()) } } + +pub fn custom_parse_hex(s: &mut &str) -> Option, ParseError>> { + if !s.starts_with("0x") { + return None + } + Some(Ok(Value::string(s.to_string()))) +} diff --git a/crates/extrinsics/src/rpc.rs b/crates/extrinsics/src/rpc.rs index 143237c54..9226925b8 100644 --- a/crates/extrinsics/src/rpc.rs +++ b/crates/extrinsics/src/rpc.rs @@ -14,43 +14,100 @@ // You should have received a copy of the GNU General Public License // along with cargo-contract. If not, see . -use subxt::backend::rpc::{ - RawRpcFuture, - RawValue, - RpcClient, +use subxt::{ + backend::{ + legacy::LegacyRpcMethods, + rpc::{ + RawValue, + RpcClient, + }, + }, + Config, + OnlineClient, + PolkadotConfig, }; use crate::url_to_string; - -use anyhow::Result; +use anyhow::{ + anyhow, + bail, + Result, +}; pub struct RpcRequest { - rpc: Rpc, + rpc: Rpc, } impl RpcRequest { - pub fn new(rpc: Rpc) -> Self { + pub fn new(rpc: Rpc) -> Self { Self { rpc } } - pub fn exec<'a>( + pub async fn raw_call<'a>( &'a self, method: &'a str, params: Option>, - ) -> RawRpcFuture<'a, Box> { - self.rpc.rpc_client.request_raw(method, params) + ) -> Result> { + let methods = self.get_supported_methods().await?; + if !methods.iter().any(|e| e == method) { + bail!( + "Method not found, supported methods: {}", + methods.join(", ") + ); + } + self.rpc + .rpc_client + .request_raw(method, params) + .await + .map_err(|e| anyhow!("Raw RPC call failed: {e}")) + } + + pub async fn get_supported_methods(&self) -> Result> { + let raw_value = self + .rpc + .rpc_client + .request_raw("rpc_methods", None) + .await + .map_err(|e| anyhow!("Rpc method call failed: {e}"))?; + + let value: serde_json::Value = serde_json::from_str(raw_value.get())?; + + let methods = value + .get("methods") + .and_then(|v| v.as_array()) + .ok_or_else(|| anyhow!("Methods parsing failed!"))?; + let patterns = ["watch", "unstable", "subscribe"]; + let filtered_methods: Vec = methods + .iter() + .filter_map(|v| v.as_str().map(String::from)) + .filter(|s| { + patterns + .iter() + .all(|&pattern| !s.to_lowercase().contains(pattern)) + }) + .collect(); + + Ok(filtered_methods) } } /// Methods for querying over RPC. -pub struct Rpc { +pub struct Rpc { rpc_client: RpcClient, + _rpc_methods: LegacyRpcMethods, + _client: OnlineClient, } -impl Rpc { +impl Rpc { /// Create a new instance of the Rpc. pub async fn new(url: &url::Url) -> Result { let rpc_client = RpcClient::from_url(url_to_string(url)).await?; - Ok(Self { rpc_client }) + let _client = OnlineClient::from_rpc_client(rpc_client.clone()).await?; + let _rpc_methods = LegacyRpcMethods::new(rpc_client.clone()); + Ok(Self { + rpc_client, + _rpc_methods, + _client, + }) } } diff --git a/crates/transcode/src/scon/mod.rs b/crates/transcode/src/scon/mod.rs index cb5727b03..a05c58414 100644 --- a/crates/transcode/src/scon/mod.rs +++ b/crates/transcode/src/scon/mod.rs @@ -221,6 +221,10 @@ impl Seq { pub fn len(&self) -> usize { self.elems.len() } + + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } } #[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]