diff --git a/CHANGELOG.md b/CHANGELOG.md index 48b7c66570..3973b334da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# Version 0.12.0 + +* Only return an error if the extrinsic failed. [#156](https://github.com/paritytech/substrate-subxt/pull/156) +* Update to rc6. [#155](https://github.com/paritytech/substrate-subxt/pull/155) +* Different assert. [#153](https://github.com/paritytech/substrate-subxt/pull/153) +* Add a method to fetch an unhashed key, close #100 [#152](https://github.com/paritytech/substrate-subxt/pull/152) +* Fix port number. [#151](https://github.com/paritytech/substrate-subxt/pull/151) +* Implement the `concat` in `twox_64_concat` [#150](https://github.com/paritytech/substrate-subxt/pull/150) +* Storage map iter [#148](https://github.com/paritytech/substrate-subxt/pull/148) + # Version 0.11.0 * Fix build error, wabt 0.9.2 is yanked [#146](https://github.com/paritytech/substrate-subxt/pull/146) @@ -29,7 +39,7 @@ # Version 0.8.0 (2020-05-26) * Update to Substrate release candidate [#116](https://github.com/paritytech/substrate-subxt/pull/116) -* Update to alpha.8 [#114]c +* Update to alpha.8 [#114](https://github.com/paritytech/substrate-subxt/pull/114) * Refactors the api [#113](https://github.com/paritytech/substrate-subxt/pull/113) # Version 0.7.0 (2020-05-13) diff --git a/Cargo.toml b/Cargo.toml index fb9adb372e..99e19dee93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = [".", "client", "proc-macro", "test-node"] [package] name = "substrate-subxt" -version = "0.11.0" +version = "0.12.0" authors = ["Parity Technologies "] edition = "2018" @@ -50,8 +50,8 @@ sp-rpc = { version = "2.0.0-rc6", package = "sp-rpc" } sp-core = { version = "2.0.0-rc6", package = "sp-core" } sc-rpc-api = { version = "0.8.0-rc6", package = "sc-rpc-api" } sp-transaction-pool = { version = "2.0.0-rc6", package = "sp-transaction-pool" } -substrate-subxt-client = { version = "0.3.0", path = "client", optional = true } -substrate-subxt-proc-macro = { version = "0.11.0", path = "proc-macro" } +substrate-subxt-client = { version = "0.4.0", path = "client", optional = true } +substrate-subxt-proc-macro = { version = "0.12.0", path = "proc-macro" } [dev-dependencies] async-std = { version = "1.6.3", features = ["attributes"] } @@ -59,7 +59,7 @@ env_logger = "0.7.1" frame-system = { version = "2.0.0-rc6", package = "frame-system" } pallet-balances = { version = "2.0.0-rc6", package = "pallet-balances" } sp-keyring = { version = "2.0.0-rc6", package = "sp-keyring" } -substrate-subxt-client = { version = "0.3.0", path = "client" } +substrate-subxt-client = { version = "0.4.0", path = "client" } tempdir = "0.3.7" test-node = { path = "test-node" } wabt = "0.10.0" diff --git a/client/Cargo.toml b/client/Cargo.toml index 8bd0a919f5..f8fe327f73 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "substrate-subxt-client" -version = "0.3.0" +version = "0.4.0" authors = ["David Craven ", "Parity Technologies "] edition = "2018" diff --git a/proc-macro/Cargo.toml b/proc-macro/Cargo.toml index 0a112230f2..47072b398b 100644 --- a/proc-macro/Cargo.toml +++ b/proc-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "substrate-subxt-proc-macro" -version = "0.11.0" +version = "0.12.0" authors = ["David Craven ", "Parity Technologies "] edition = "2018" autotests = false diff --git a/src/error.rs b/src/error.rs index cbadeb35f5..195a2d22da 100644 --- a/src/error.rs +++ b/src/error.rs @@ -62,13 +62,7 @@ pub enum Error { TypeSizeUnavailable(String), /// Runtime error. #[error("Runtime error: {0}")] - Runtime(RuntimeError), - /// Bad origin. - #[error("Bad origin: throw by ensure_signed, ensure_root or ensure_none.")] - BadOrigin, - /// Cannot lookup. - #[error("Cannot lookup some information required to validate the transaction.")] - CannotLookup, + Runtime(#[from] RuntimeError), /// Other error. #[error("Other error: {0}")] Other(String), @@ -98,9 +92,29 @@ impl From for Error { } } -impl Error { +/// Runtime error. +#[derive(Clone, Debug, Eq, Error, PartialEq)] +pub enum RuntimeError { + /// Module error. + #[error("Runtime module error: {0}")] + Module(ModuleError), + /// Bad origin. + #[error("Bad origin: throw by ensure_signed, ensure_root or ensure_none.")] + BadOrigin, + /// Cannot lookup. + #[error("Cannot lookup some information required to validate the transaction.")] + CannotLookup, + /// Other error. + #[error("Other error: {0}")] + Other(String), +} + +impl RuntimeError { /// Converts a `DispatchError` into a subxt error. - pub fn from_dispatch(metadata: &Metadata, error: DispatchError) -> Result<(), Self> { + pub fn from_dispatch( + metadata: &Metadata, + error: DispatchError, + ) -> Result { match error { DispatchError::Module { index, @@ -109,22 +123,22 @@ impl Error { } => { let module = metadata.module_with_errors(index)?; let error = module.error(error)?; - Err(Error::Runtime(RuntimeError { + Ok(Self::Module(ModuleError { module: module.name().to_string(), error: error.to_string(), })) } - DispatchError::BadOrigin => Err(Error::BadOrigin), - DispatchError::CannotLookup => Err(Error::CannotLookup), - DispatchError::Other(msg) => Err(Error::Other(msg.into())), + DispatchError::BadOrigin => Ok(Self::BadOrigin), + DispatchError::CannotLookup => Ok(Self::CannotLookup), + DispatchError::Other(msg) => Ok(Self::Other(msg.into())), } } } -/// Runtime errors. +/// Module error. #[derive(Clone, Debug, Eq, Error, PartialEq)] #[error("{error} from {module}")] -pub struct RuntimeError { +pub struct ModuleError { pub module: String, pub error: String, } diff --git a/src/events.rs b/src/events.rs index d5f75c9b8c..e8ae9146c5 100644 --- a/src/events.rs +++ b/src/events.rs @@ -39,7 +39,10 @@ use std::{ }; use crate::{ - error::Error, + error::{ + Error, + RuntimeError, + }, metadata::{ EventArg, Metadata, @@ -151,6 +154,17 @@ impl EventsDecoder { self.decode_raw_bytes(&[*arg.clone()], input, output)? } } + EventArg::Option(arg) => { + match input.read_byte()? { + 0 => (), + 1 => self.decode_raw_bytes(&[*arg.clone()], input, output)?, + _ => { + return Err(Error::Other( + "unexpected first byte decoding Option".into(), + )) + } + } + } EventArg::Tuple(args) => self.decode_raw_bytes(args, input, output)?, EventArg::Primitive(name) => { let result = match name.as_str() { @@ -168,7 +182,9 @@ impl EventsDecoder { } }; if let Err(error) = result { - Error::from_dispatch(&self.metadata, error)?; + return Err( + RuntimeError::from_dispatch(&self.metadata, error)?.into() + ) } } } @@ -177,10 +193,7 @@ impl EventsDecoder { } /// Decode events. - pub fn decode_events( - &self, - input: &mut &[u8], - ) -> Result, Error> { + pub fn decode_events(&self, input: &mut &[u8]) -> Result, Error> { let compact_len = >::decode(input)?; let len = compact_len.0 as usize; @@ -201,20 +214,36 @@ impl EventsDecoder { ); let mut event_data = Vec::::new(); - self.decode_raw_bytes(&event_metadata.arguments(), input, &mut event_data)?; + let result = self.decode_raw_bytes( + &event_metadata.arguments(), + input, + &mut event_data, + ); + let raw = match result { + Ok(()) => { + log::debug!("raw bytes: {}", hex::encode(&event_data),); - log::debug!("raw bytes: {}", hex::encode(&event_data),); + let event = RawEvent { + module: module.name().to_string(), + variant: event_metadata.name.clone(), + data: event_data, + }; - let event = RawEvent { - module: module.name().to_string(), - variant: event_metadata.name.clone(), - data: event_data, + // topics come after the event data in EventRecord + let _topics = Vec::::decode(input)?; + Raw::Event(event) + } + Err(Error::Runtime(err)) => Raw::Error(err), + Err(err) => return Err(err), }; - // topics come after the event data in EventRecord - let _topics = Vec::::decode(input)?; - r.push((phase, event)); + r.push((phase, raw)); } Ok(r) } } + +pub enum Raw { + Event(RawEvent), + Error(RuntimeError), +} diff --git a/src/frame/balances.rs b/src/frame/balances.rs index edf146dc26..9ebf6d6388 100644 --- a/src/frame/balances.rs +++ b/src/frame/balances.rs @@ -112,6 +112,7 @@ mod tests { use crate::{ error::{ Error, + ModuleError, RuntimeError, }, events::EventsDecoder, @@ -193,8 +194,8 @@ mod tests { let res = client .transfer_and_watch(&hans, alice.account_id(), 100_000_000_000) .await; - if let Err(Error::Runtime(error)) = res { - let error2 = RuntimeError { + if let Err(Error::Runtime(RuntimeError::Module(error))) = res { + let error2 = ModuleError { module: "Balances".into(), error: "InsufficientBalance".into(), }; diff --git a/src/frame/sudo.rs b/src/frame/sudo.rs index 8efb336b7d..733e1290d8 100644 --- a/src/frame/sudo.rs +++ b/src/frame/sudo.rs @@ -43,7 +43,10 @@ pub struct SudoCall<'a, T: Sudo> { mod tests { use super::*; use crate::{ - error::Error, + error::{ + Error, + RuntimeError, + }, extrinsic::PairSigner, frame::balances::TransferCall, tests::{ @@ -68,7 +71,7 @@ mod tests { let res = client.sudo_and_watch(&alice, &call).await; assert!( - if let Err(Error::BadOrigin) = res { + if let Err(Error::Runtime(RuntimeError::BadOrigin)) = res { true } else { false diff --git a/src/metadata.rs b/src/metadata.rs index 3ef160cfc9..176db3aa99 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -398,6 +398,7 @@ pub enum EventArg { Primitive(String), Vec(Box), Tuple(Vec), + Option(Box), } impl FromStr for EventArg { @@ -413,6 +414,15 @@ impl FromStr for EventArg { "Expected closing `>` for `Vec`", )) } + } else if s.starts_with("Option<") { + if s.ends_with('>') { + Ok(EventArg::Option(Box::new(s[7..s.len() - 1].parse()?))) + } else { + Err(ConversionError::InvalidEventArg( + s.to_string(), + "Expected closing `>` for `Option`", + )) + } } else if s.starts_with('(') { if s.ends_with(')') { let mut args = Vec::new(); @@ -439,6 +449,7 @@ impl EventArg { match self { EventArg::Primitive(p) => vec![p.clone()], EventArg::Vec(arg) => arg.primitives(), + EventArg::Option(arg) => arg.primitives(), EventArg::Tuple(args) => { let mut primitives = Vec::new(); for arg in args { diff --git a/src/subscription.rs b/src/subscription.rs index 6208ce6f7b..6f352edeb8 100644 --- a/src/subscription.rs +++ b/src/subscription.rs @@ -22,6 +22,7 @@ use crate::{ error::Error, events::{ EventsDecoder, + Raw, RawEvent, }, frame::{ @@ -99,13 +100,17 @@ impl EventSubscription { Ok(events) => events, Err(error) => return Some(Err(error)), }; - for (phase, event) in raw_events { + for (phase, raw) in raw_events { if let Phase::ApplyExtrinsic(i) = phase { if let Some(ext_index) = self.extrinsic { if i as usize != ext_index { continue } } + let event = match raw { + Raw::Event(event) => event, + Raw::Error(err) => return Some(Err(err.into())), + }; if let Some((module, variant)) = self.event { if event.module != module || event.variant != variant { continue