diff --git a/Cargo.lock b/Cargo.lock index 0508c2e2fceac6a1b2c4c47df4dade7af50682c1..538eec2ca8d240c0448745810852d1a659746c93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -554,12 +554,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chameleon" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bd83544cd11113170ce1eee45383928f3f720bc8b305af18c2a3da3547e1ae" - [[package]] name = "chrono" version = "0.4.19" @@ -782,9 +776,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.13.1" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" +checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02" dependencies = [ "darling_core", "darling_macro", @@ -792,9 +786,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.1" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" +checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f" dependencies = [ "fnv", "ident_case", @@ -806,9 +800,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.13.1" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" +checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5" dependencies = [ "darling_core", "quote", @@ -1674,12 +1668,12 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d0b8cc1959f8c05256ace093b2317482da9127f1d9227564f47e7e6bf9bda8" +checksum = "91dc760c341fa81173f9a434931aaf32baad5552b0230cc6c93e8fb7eaad4c19" dependencies = [ - "jsonrpsee-client-transport 0.9.0", - "jsonrpsee-core 0.9.0", + "jsonrpsee-client-transport 0.10.1", + "jsonrpsee-core 0.10.1", ] [[package]] @@ -1695,21 +1689,21 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa370c2c717d798c3c0a315ae3f0a707a388c6963c11f9da7dbbe1d3f7392f5f" +checksum = "765f7a36d5087f74e3b3b47805c2188fef8eb54afcb587b078d9f8ebfe9c7220" dependencies = [ "futures", "http", - "jsonrpsee-core 0.9.0", - "jsonrpsee-types 0.9.0", + "jsonrpsee-core 0.10.1", + "jsonrpsee-types 0.10.1", "pin-project", "rustls-native-certs", "soketto", "thiserror", "tokio", "tokio-rustls", - "tokio-util 0.6.9", + "tokio-util", "tracing", "webpki-roots", ] @@ -1730,16 +1724,16 @@ dependencies = [ "thiserror", "tokio", "tokio-rustls", - "tokio-util 0.7.1", + "tokio-util", "tracing", "webpki-roots", ] [[package]] name = "jsonrpsee-core" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22abc3274b265dcefe2e26c4beecf9fda4fffa48cf94930443a6c73678f020d5" +checksum = "82ef77ecd20c2254d54f5da8c0738eacca61e6b6511268a8f2753e3148c6c706" dependencies = [ "anyhow", "arrayvec 0.7.2", @@ -1748,7 +1742,7 @@ dependencies = [ "futures-channel", "futures-util", "hyper", - "jsonrpsee-types 0.9.0", + "jsonrpsee-types 0.10.1", "rustc-hash", "serde", "serde_json", @@ -1782,9 +1776,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f4c45d2e2aa1db4c7d7d7dbaabc10a5b5258d99cd9d42fbfd5260b76f80c324" +checksum = "38b6aa52f322cbf20c762407629b8300f39bcc0cf0619840d9252a2f65fd2dd9" dependencies = [ "anyhow", "beef", @@ -2182,7 +2176,7 @@ version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c45ed1f39709f5a89338fab50e59816b2e8815f5bb58276e7ddf9afd495f73f8" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -2391,15 +2385,6 @@ dependencies = [ "uint", ] -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - [[package]] name = "proc-macro-crate" version = "1.1.3" @@ -2436,18 +2421,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -2725,7 +2710,7 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4260c630e8a8a33429d1688eff2f163f24c65a4e1b1578ef6b565061336e4b6f" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -3221,7 +3206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ecb916b9664ed9f90abef0ff5a3e61454c1efea5861b2997e03f39b59b955f" dependencies = [ "Inflector", - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -3375,68 +3360,71 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "subxt" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc99c89f8e581c6e8b3e6923e66512041d908180efee7cb026b2ccd5f0334218" +checksum = "4ab902b8d1bf5ecdc16c78e1f7fdef77665d5ce77004b2be1f6ac4b4f679d987" dependencies = [ - "async-trait", "bitvec", - "chameleon", "derivative", "frame-metadata", "futures", "hex", - "jsonrpsee 0.9.0", + "jsonrpsee 0.10.1", "log", "parity-scale-codec", + "parking_lot", "scale-info", "serde", "serde_json", "sp-core", "sp-runtime", "subxt-macro", + "subxt-metadata", "thiserror", ] [[package]] name = "subxt-codegen" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74283176932f38c579311f65f4138ff2817a3bd1040250055fbd1f3857027cbb" +checksum = "2ac3c4e3565338616f009bc40419f45fa7d9472a5717fa8cce129777c709d1a1" dependencies = [ - "async-trait", "darling", "frame-metadata", "heck", "parity-scale-codec", - "proc-macro-crate 0.1.5", "proc-macro-error", "proc-macro2", "quote", "scale-info", + "subxt-metadata", "syn", ] [[package]] name = "subxt-macro" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb844cf84cdae36fc337810569cc39e3e022c17cc2ed11031c66d0e09b73726" +checksum = "078edfe8f06cb00848e2e64e923fe809f345042c3d7ec13edcd7f0e617656a9b" dependencies = [ - "async-trait", "darling", - "frame-metadata", - "heck", - "parity-scale-codec", - "proc-macro-crate 0.1.5", "proc-macro-error", - "proc-macro2", - "quote", - "scale-info", "subxt-codegen", "syn", ] +[[package]] +name = "subxt-metadata" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819a10a1a13bd9645419f59ac9d7cc8deb51052566b9d0c2157354ea44513d5" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", + "sp-core", +] + [[package]] name = "syn" version = "1.0.92" @@ -3610,21 +3598,6 @@ dependencies = [ "webpki", ] -[[package]] -name = "tokio-util" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" -dependencies = [ - "bytes", - "futures-core", - "futures-io", - "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.1" diff --git a/Cargo.toml b/Cargo.toml index 709a9d67c35d547cee6a0a2976de5a819b894ab2..929b06932d72767a1242e977a7b14b347662d26b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" sp-core = "6.0.0" sp-runtime = "6.0.0" pallet-contracts-primitives = "6.0.0" -subxt = "0.20.0" +subxt = "0.21.0" futures = "0.3.19" hex = "0.4.3" jsonrpsee = { version = "0.11.0", features = ["ws-client"] } diff --git a/src/cmd/extrinsics/call.rs b/src/cmd/extrinsics/call.rs index cf7ce7cb799b7acfc946209a3641794d1a6cdbcb..279c20c24a8138f3c1eb9e3235d0a8900bc6ecf2 100644 --- a/src/cmd/extrinsics/call.rs +++ b/src/cmd/extrinsics/call.rs @@ -17,6 +17,7 @@ use super::{ display_contract_exec_result, display_events, + dry_run_error_details, load_metadata, parse_balance, wait_for_success_and_handle_error, @@ -25,6 +26,7 @@ use super::{ ExtrinsicOpts, PairSigner, RuntimeApi, + RuntimeDispatchError, EXEC_RESULT_MAX_KEY_COL_WIDTH, }; use crate::name_value_println; @@ -34,9 +36,16 @@ use jsonrpsee::{ rpc_params, ws_client::WsClientBuilder, }; +use pallet_contracts_primitives::{ + ContractResult, + ExecReturnValue, +}; use serde::Serialize; use sp_core::Bytes; -use std::fmt::Debug; +use std::{ + fmt::Debug, + result, +}; use subxt::{ rpc::NumberOrHex, ClientBuilder, @@ -44,7 +53,8 @@ use subxt::{ DefaultConfig, }; -type ContractExecResult = pallet_contracts_primitives::ContractExecResult; +type ContractExecResult = + ContractResult, Balance>; #[derive(Debug, clap::Args)] #[clap(name = "call", about = "Call a contract")] @@ -79,16 +89,24 @@ impl CallCommand { let signer = super::pair_signer(self.extrinsic_opts.signer()?); async_std::task::block_on(async { + let url = self.extrinsic_opts.url.to_string(); + let api = ClientBuilder::new() + .set_url(&url) + .build() + .await? + .to_runtime_api::(); + if self.extrinsic_opts.dry_run { - self.call_rpc(call_data, &signer, &transcoder).await + self.call_rpc(&api, call_data, &signer, &transcoder).await } else { - self.call(call_data, &signer, &transcoder).await + self.call(&api, call_data, &signer, &transcoder).await } }) } async fn call_rpc( &self, + api: &RuntimeApi, data: Vec, signer: &PairSigner, transcoder: &ContractMessageTranscoder<'_>, @@ -131,12 +149,9 @@ impl CallCommand { EXEC_RESULT_MAX_KEY_COL_WIDTH ); } - Err(err) => { - name_value_println!( - "Result", - format!("Error: {:?}", err), - EXEC_RESULT_MAX_KEY_COL_WIDTH - ); + Err(ref err) => { + let err = dry_run_error_details(api, err).await?; + name_value_println!("Result", err, EXEC_RESULT_MAX_KEY_COL_WIDTH); } } display_contract_exec_result(&result)?; @@ -145,17 +160,11 @@ impl CallCommand { async fn call( &self, + api: &RuntimeApi, data: Vec, signer: &PairSigner, transcoder: &ContractMessageTranscoder<'_>, ) -> Result<()> { - let url = self.extrinsic_opts.url.to_string(); - let api = ClientBuilder::new() - .set_url(&url) - .build() - .await? - .to_runtime_api::(); - log::debug!("calling contract {:?}", self.contract); let tx_progress = api .tx() @@ -166,7 +175,7 @@ impl CallCommand { self.gas_limit, self.extrinsic_opts.storage_deposit_limit, data, - ) + )? .sign_and_submit_then_watch_default(signer) .await?; diff --git a/src/cmd/extrinsics/instantiate.rs b/src/cmd/extrinsics/instantiate.rs index 4330b83e2a9ed9495fb95b4407125d44aeed8a01..41a3354c5c9faf0c5b894c42410c64fc483931de 100644 --- a/src/cmd/extrinsics/instantiate.rs +++ b/src/cmd/extrinsics/instantiate.rs @@ -17,6 +17,7 @@ use super::{ display_contract_exec_result, display_events, + dry_run_error_details, parse_balance, runtime_api::api, wait_for_success_and_handle_error, @@ -27,6 +28,7 @@ use super::{ ExtrinsicOpts, PairSigner, RuntimeApi, + RuntimeDispatchError, EXEC_RESULT_MAX_KEY_COL_WIDTH, }; use crate::{ @@ -44,6 +46,10 @@ use jsonrpsee::{ rpc_params, ws_client::WsClientBuilder, }; +use pallet_contracts_primitives::{ + ContractResult, + InstantiateReturnValue, +}; use serde::Serialize; use sp_core::{ crypto::Ss58Codec, @@ -55,6 +61,7 @@ use std::{ Path, PathBuf, }, + result, }; use subxt::{ rpc::NumberOrHex, @@ -63,8 +70,10 @@ use subxt::{ DefaultConfig, }; -type ContractInstantiateResult = - pallet_contracts_primitives::ContractInstantiateResult; +type ContractInstantiateResult = ContractResult< + result::Result, RuntimeDispatchError>, + Balance, +>; #[derive(Debug, clap::Args)] pub struct InstantiateCommand { @@ -228,12 +237,10 @@ impl<'a> Exec<'a> { EXEC_RESULT_MAX_KEY_COL_WIDTH ); } - Err(err) => { - name_value_println!( - "Result", - format!("Error: {:?}", err), - EXEC_RESULT_MAX_KEY_COL_WIDTH - ); + Err(ref err) => { + let err = + dry_run_error_details(&self.subxt_api().await?, err).await?; + name_value_println!("Result", err, EXEC_RESULT_MAX_KEY_COL_WIDTH); } } display_contract_exec_result(&result)?; @@ -270,7 +277,7 @@ impl<'a> Exec<'a> { code.to_vec(), self.args.data.clone(), self.args.salt.0.clone(), - ) + )? .sign_and_submit_then_watch_default(&self.signer) .await?; @@ -302,7 +309,7 @@ impl<'a> Exec<'a> { code_hash, self.args.data.clone(), self.args.salt.0.clone(), - ) + )? .sign_and_submit_then_watch_default(&self.signer) .await?; @@ -340,6 +347,7 @@ impl<'a> Exec<'a> { .request("contracts_instantiate", params) .await .context("contracts_instantiate RPC error")?; + Ok(result) } } diff --git a/src/cmd/extrinsics/mod.rs b/src/cmd/extrinsics/mod.rs index cb3d5b5aece896e94d114fb31f7e2d5067347d76..9224ad74d5e7f3b0dbeea705a33531898281ac60 100644 --- a/src/cmd/extrinsics/mod.rs +++ b/src/cmd/extrinsics/mod.rs @@ -51,6 +51,7 @@ use sp_core::{ use subxt::{ Config, DefaultConfig, + HasModuleError as _, }; pub use self::transcode::ContractMessageTranscoder; @@ -229,3 +230,25 @@ where .await .map_err(Into::into) } + +/// Extract and display error details for an RPC `--dry-run` result. +async fn dry_run_error_details( + api: &RuntimeApi, + error: &RuntimeDispatchError, +) -> Result { + let error = if let Some(error_data) = error.module_error_data() { + let details = api + .client + .metadata() + .error(error_data.pallet_index, error_data.error_index())?; + format!( + "ModuleError: {}::{}: {:?}", + details.pallet(), + details.error(), + details.description() + ) + } else { + format!("{:?}", error) + }; + Ok(error) +} diff --git a/src/cmd/extrinsics/runtime_api/contracts_runtime.scale b/src/cmd/extrinsics/runtime_api/contracts_runtime.scale index ea4c3d12132f81ea151d28eb195d8f982fdf2714..50bb0e04480029c489c484107a8f1455490a719b 100644 Binary files a/src/cmd/extrinsics/runtime_api/contracts_runtime.scale and b/src/cmd/extrinsics/runtime_api/contracts_runtime.scale differ diff --git a/src/cmd/extrinsics/runtime_api/mod.rs b/src/cmd/extrinsics/runtime_api/mod.rs index db48cff3f279893fd68e96e0179bdb8d3f3a8ed5..5268b8d3d7337e5b2e83ee9c3ec37bb1890eabbf 100644 --- a/src/cmd/extrinsics/runtime_api/mod.rs +++ b/src/cmd/extrinsics/runtime_api/mod.rs @@ -15,6 +15,17 @@ // along with cargo-contract. If not, see . #[subxt::subxt( - runtime_metadata_path = "src/cmd/extrinsics/runtime_api/contracts_runtime.scale" + runtime_metadata_path = "src/cmd/extrinsics/runtime_api/contracts_runtime.scale", + derive_for_type(type = "sp_runtime::DispatchError", derive = "::serde::Deserialize"), + derive_for_type(type = "sp_runtime::ModuleError", derive = "::serde::Deserialize"), + derive_for_type(type = "sp_runtime::TokenError", derive = "::serde::Deserialize"), + derive_for_type( + type = "sp_runtime::ArithmeticError", + derive = "::serde::Deserialize" + ), + derive_for_type( + type = "sp_runtime::TransactionalError", + derive = "::serde::Deserialize" + ) )] pub mod api {} diff --git a/src/cmd/extrinsics/upload.rs b/src/cmd/extrinsics/upload.rs index 29f09a5aff0a574eda0eff3e43af9b0480261ac3..8fd5f792cb2349d962f9cc5379e485c8d38dc129 100644 --- a/src/cmd/extrinsics/upload.rs +++ b/src/cmd/extrinsics/upload.rs @@ -16,6 +16,7 @@ use super::{ display_events, + dry_run_error_details, runtime_api::api, wait_for_success_and_handle_error, Balance, @@ -24,6 +25,7 @@ use super::{ ExtrinsicOpts, PairSigner, RuntimeApi, + RuntimeDispatchError, }; use crate::name_value_println; use anyhow::{ @@ -40,6 +42,7 @@ use sp_core::Bytes; use std::{ fmt::Debug, path::PathBuf, + result, }; use subxt::{ rpc::NumberOrHex, @@ -48,7 +51,7 @@ use subxt::{ DefaultConfig, }; -type CodeUploadResult = pallet_contracts_primitives::CodeUploadResult; +type CodeUploadResult = result::Result; type CodeUploadReturnValue = pallet_contracts_primitives::CodeUploadReturnValue; @@ -79,15 +82,32 @@ impl UploadCommand { .context(format!("Failed to read from {}", wasm_path.display()))?; async_std::task::block_on(async { - if self.extrinsic_opts.dry_run { - let result = self.upload_code_rpc(code, &signer).await?; - - name_value_println!("Code hash", format!("{:?}", result.code_hash)); - name_value_println!("Deposit", format!("{:?}", result.deposit)); + let url = self.extrinsic_opts.url.to_string(); + let api = ClientBuilder::new() + .set_url(&url) + .build() + .await? + .to_runtime_api::(); + if self.extrinsic_opts.dry_run { + match self.upload_code_rpc(code, &signer).await? { + Ok(result) => { + name_value_println!("Result", String::from("Success!")); + name_value_println!( + "Code hash", + format!("{:?}", result.code_hash) + ); + name_value_println!("Deposit", format!("{:?}", result.deposit)); + } + Err(err) => { + let err = dry_run_error_details(&api, &err).await?; + name_value_println!("Result", err); + } + } Ok(()) } else { - let code_stored = self.upload_code(code, &signer, &transcoder).await?; + let code_stored = + self.upload_code(&api, code, &signer, &transcoder).await?; name_value_println!("Code hash", format!("{:?}", code_stored.code_hash)); @@ -100,7 +120,7 @@ impl UploadCommand { &self, code: Vec, signer: &PairSigner, - ) -> Result { + ) -> Result { let url = self.extrinsic_opts.url.to_string(); let cli = WsClientBuilder::default().build(&url).await?; let storage_deposit_limit = self @@ -115,29 +135,25 @@ impl UploadCommand { }; let params = rpc_params!(call_request); - let result: CodeUploadResult = - cli.request("contracts_upload_code", params).await?; + let result: CodeUploadResult = cli + .request("contracts_upload_code", params) + .await + .context("contracts_upload_code RPC error")?; - result.map_err(|e| anyhow::anyhow!("Failed to execute call via rpc: {:?}", e)) + Ok(result) } async fn upload_code( &self, + api: &RuntimeApi, code: Vec, signer: &PairSigner, transcoder: &ContractMessageTranscoder<'_>, ) -> Result { - let url = self.extrinsic_opts.url.to_string(); - let api = ClientBuilder::new() - .set_url(&url) - .build() - .await? - .to_runtime_api::(); - let tx_progress = api .tx() .contracts() - .upload_code(code, self.extrinsic_opts.storage_deposit_limit) + .upload_code(code, self.extrinsic_opts.storage_deposit_limit)? .sign_and_submit_then_watch_default(signer) .await?;