Skip to content

Commit

Permalink
Improve error handling in proc-macros, handle DispatchError etc. (par…
Browse files Browse the repository at this point in the history
…itytech#123)

* Improve error handling.

* Fix build.

* Handle runtime errors.

* Add runtime trait for better type inference.

* Use runtime trait part 1.

* wip

* Add support for sudo.

* Finish error handling.

* Fix tests.

* Fix clippy warnings.
  • Loading branch information
dvc94ch authored Jun 22, 2020
1 parent 21d07c6 commit 3080ec9
Show file tree
Hide file tree
Showing 23 changed files with 561 additions and 377 deletions.
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ client = ["substrate-subxt-client"]

[dependencies]
log = "0.4.8"
thiserror = "1.0.19"
thiserror = "1.0.20"
futures = "0.3.5"
jsonrpsee = { version = "0.1.0", features = ["ws"] }
num-traits = { version = "0.2.11", default-features = false }
serde = { version = "1.0.111", features = ["derive"] }
serde_json = "1.0.53"
num-traits = { version = "0.2.12", default-features = false }
serde = { version = "1.0.113", features = ["derive"] }
serde_json = "1.0.55"
url = "2.1.1"
codec = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive", "full"] }

Expand Down
4 changes: 2 additions & 2 deletions client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ jsonrpsee = "0.1.0"
log = "0.4.8"
sc-network = { version = "0.8.0-rc3", default-features = false }
sc-service = { version = "0.8.0-rc3", default-features = false }
serde_json = "1.0.53"
serde_json = "1.0.55"
sp-keyring = "2.0.0-rc3"
thiserror = "1.0.19"
thiserror = "1.0.20"

[dev-dependencies]
async-std = { version = "=1.5.0", features = ["attributes"] }
Expand Down
1 change: 1 addition & 0 deletions client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ fn start_subxt_client<C: ChainSpec + 'static, S: AbstractService>(
pruning: Default::default(),
rpc_cors: Default::default(),
rpc_http: Default::default(),
rpc_ipc: Default::default(),
rpc_ws: Default::default(),
rpc_ws_max_connections: Default::default(),
rpc_methods: Default::default(),
Expand Down
5 changes: 3 additions & 2 deletions proc-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ proc-macro = true
heck = "0.3.1"
proc-macro2 = "1.0.18"
proc-macro-crate = "0.1.4"
proc-macro-error = "1.0.2"
quote = "1.0.7"
syn = "1.0.30"
syn = "1.0.31"
synstructure = "0.12.4"

[dev-dependencies]
Expand All @@ -29,7 +30,7 @@ env_logger = "0.7.1"
pretty_assertions = "0.6.1"
sp-keyring = "2.0.0-rc3"
substrate-subxt = { path = ".." }
trybuild = "1.0.28"
trybuild = "1.0.30"

[[test]]
name = "balances"
Expand Down
35 changes: 14 additions & 21 deletions proc-macro/src/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ use synstructure::Structure;

pub fn call(s: Structure) -> TokenStream {
let subxt = utils::use_crate("substrate-subxt");
let codec = utils::use_crate("parity-scale-codec");
let ident = &s.ast().ident;
let generics = &s.ast().generics;
let params = utils::type_params(generics);
Expand Down Expand Up @@ -60,32 +59,29 @@ pub fn call(s: Structure) -> TokenStream {
}

/// Call extension trait.
pub trait #call_trait<T: #module, S: #codec::Encode, E: #subxt::SignedExtra<T>> {
pub trait #call_trait<T: #subxt::Runtime + #module> {
/// Create and submit an extrinsic.
fn #call<'a>(
&'a self,
signer: &'a (dyn #subxt::Signer<T, S, E> + Send + Sync),
signer: &'a (dyn #subxt::Signer<T> + Send + Sync),
#args
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<T::Hash, #subxt::Error>> + Send + 'a>>;

/// Create, submit and watch an extrinsic.
fn #call_and_watch<'a>(
&'a self,
signer: &'a (dyn #subxt::Signer<T, S, E> + Send + Sync),
signer: &'a (dyn #subxt::Signer<T> + Send + Sync),
#args
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<#subxt::ExtrinsicSuccess<T>, #subxt::Error>> + Send + 'a>>;
}

impl<T, S, E> #call_trait<T, S, E> for #subxt::Client<T, S, E>
impl<T: #subxt::Runtime + #module> #call_trait<T> for #subxt::Client<T>
where
T: #module + #subxt::system::System + Send + Sync + 'static,
S: #codec::Encode + Send + Sync + 'static,
E: #subxt::SignedExtra<T> + #subxt::sp_runtime::traits::SignedExtension + Send + Sync + 'static,
<<E as #subxt::SignedExtra<T>>::Extra as #subxt::sp_runtime::traits::SignedExtension>::AdditionalSigned: Send + Sync,
<<T::Extra as #subxt::SignedExtra<T>>::Extra as #subxt::SignedExtension>::AdditionalSigned: Send + Sync,
{
fn #call<'a>(
&'a self,
signer: &'a (dyn #subxt::Signer<T, S, E> + Send + Sync),
signer: &'a (dyn #subxt::Signer<T> + Send + Sync),
#args
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<T::Hash, #subxt::Error>> + Send + 'a>> {
let #marker = core::marker::PhantomData::<T>;
Expand All @@ -94,7 +90,7 @@ pub fn call(s: Structure) -> TokenStream {

fn #call_and_watch<'a>(
&'a self,
signer: &'a (dyn #subxt::Signer<T, S, E> + Send + Sync),
signer: &'a (dyn #subxt::Signer<T> + Send + Sync),
#args
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<#subxt::ExtrinsicSuccess<T>, #subxt::Error>> + Send + 'a>> {
let #marker = core::marker::PhantomData::<T>;
Expand Down Expand Up @@ -130,34 +126,31 @@ mod tests {
}

/// Call extension trait.
pub trait TransferCallExt<T: Balances, S: codec::Encode, E: substrate_subxt::SignedExtra<T>> {
pub trait TransferCallExt<T: substrate_subxt::Runtime + Balances> {
/// Create and submit an extrinsic.
fn transfer<'a>(
&'a self,
signer: &'a (dyn substrate_subxt::Signer<T, S, E> + Send + Sync),
signer: &'a (dyn substrate_subxt::Signer<T> + Send + Sync),
to: &'a <T as System>::Address,
amount: T::Balance,
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<T::Hash, substrate_subxt::Error>> + Send + 'a>>;

/// Create, submit and watch an extrinsic.
fn transfer_and_watch<'a>(
&'a self,
signer: &'a (dyn substrate_subxt::Signer<T, S, E> + Send + Sync),
signer: &'a (dyn substrate_subxt::Signer<T> + Send + Sync),
to: &'a <T as System>::Address,
amount: T::Balance,
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<substrate_subxt::ExtrinsicSuccess<T>, substrate_subxt::Error>> + Send + 'a>>;
}

impl<T, S, E> TransferCallExt<T, S, E> for substrate_subxt::Client<T, S, E>
impl<T: substrate_subxt::Runtime + Balances> TransferCallExt<T> for substrate_subxt::Client<T>
where
T: Balances + substrate_subxt::system::System + Send + Sync + 'static,
S: codec::Encode + Send + Sync + 'static,
E: substrate_subxt::SignedExtra<T> + substrate_subxt::sp_runtime::traits::SignedExtension + Send + Sync + 'static,
<<E as substrate_subxt::SignedExtra<T>>::Extra as substrate_subxt::sp_runtime::traits::SignedExtension>::AdditionalSigned: Send + Sync,
<<T::Extra as substrate_subxt::SignedExtra<T>>::Extra as substrate_subxt::SignedExtension>::AdditionalSigned: Send + Sync,
{
fn transfer<'a>(
&'a self,
signer: &'a (dyn substrate_subxt::Signer<T, S, E> + Send + Sync),
signer: &'a (dyn substrate_subxt::Signer<T> + Send + Sync),
to: &'a <T as System>::Address,
amount: T::Balance,
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<T::Hash, substrate_subxt::Error>> + Send + 'a>> {
Expand All @@ -167,7 +160,7 @@ mod tests {

fn transfer_and_watch<'a>(
&'a self,
signer: &'a (dyn substrate_subxt::Signer<T, S, E> + Send + Sync),
signer: &'a (dyn substrate_subxt::Signer<T> + Send + Sync),
to: &'a <T as System>::Address,
amount: T::Balance,
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<substrate_subxt::ExtrinsicSuccess<T>, substrate_subxt::Error>> + Send + 'a>> {
Expand Down
6 changes: 2 additions & 4 deletions proc-macro/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn event(s: Structure) -> TokenStream {
let event = format_ident!("{}", event_name.to_snake_case());
let event_trait = format_ident!("{}EventExt", event_name);

let expanded = quote! {
quote! {
impl<T: #module> #subxt::Event<T> for #ident<T> {
const MODULE: &'static str = MODULE;
const EVENT: &'static str = #event_name;
Expand All @@ -53,9 +53,7 @@ pub fn event(s: Structure) -> TokenStream {
self.find_event()
}
}
};

TokenStream::from(expanded)
}
}

#[cfg(test)]
Expand Down
9 changes: 6 additions & 3 deletions proc-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,35 @@ mod test;
mod utils;

use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
use synstructure::{
decl_derive,
Structure,
};

#[proc_macro_attribute]
#[proc_macro_error]
pub fn module(args: TokenStream, input: TokenStream) -> TokenStream {
module::module(args.into(), input.into()).into()
}

decl_derive!([Call] => call);
decl_derive!([Call] => #[proc_macro_error] call);
fn call(s: Structure) -> TokenStream {
call::call(s).into()
}

decl_derive!([Event] => event);
decl_derive!([Event] => #[proc_macro_error] event);
fn event(s: Structure) -> TokenStream {
event::event(s).into()
}

decl_derive!([Store, attributes(store)] => store);
decl_derive!([Store, attributes(store)] => #[proc_macro_error] store);
fn store(s: Structure) -> TokenStream {
store::store(s).into()
}

#[proc_macro]
#[proc_macro_error]
pub fn subxt_test(input: TokenStream) -> TokenStream {
test::test(input.into()).into()
}
15 changes: 10 additions & 5 deletions proc-macro/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use crate::utils;
use heck::SnakeCase;
use proc_macro2::TokenStream;
use proc_macro_error::abort;
use quote::{
format_ident,
quote,
Expand Down Expand Up @@ -48,8 +49,10 @@ type ModuleAttrs = utils::Attrs<ModuleAttr>;
fn ignore(attrs: &[syn::Attribute]) -> bool {
for attr in attrs {
if let Some(ident) = attr.path.get_ident() {
if ident.to_string() == "module" {
let attrs: ModuleAttrs = syn::parse2(attr.tokens.clone()).unwrap();
if ident == "module" {
let attrs: ModuleAttrs = syn::parse2(attr.tokens.clone())
.map_err(|err| abort!("{}", err))
.unwrap();
if !attrs.attrs.is_empty() {
return true
}
Expand All @@ -69,10 +72,12 @@ fn with_module_ident(module: &syn::Ident) -> syn::Ident {

pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
let input: Result<syn::ItemTrait, _> = syn::parse2(tokens.clone());
if input.is_err() {
let input = if let Ok(input) = input {
input
} else {
// handle #[module(ignore)] by just returning the tokens
return tokens
}
let input = input.unwrap();
};

let subxt = utils::use_crate("substrate-subxt");
let module = &input.ident;
Expand Down
31 changes: 16 additions & 15 deletions proc-macro/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use heck::{
SnakeCase,
};
use proc_macro2::TokenStream;
use proc_macro_error::abort;
use quote::{
format_ident,
quote,
Expand Down Expand Up @@ -50,7 +51,9 @@ impl Parse for StoreAttr {
type StoreAttrs = utils::Attrs<StoreAttr>;

fn parse_returns_attr(attr: &syn::Attribute) -> Option<(syn::Type, syn::Type, bool)> {
let attrs: StoreAttrs = syn::parse2(attr.tokens.clone()).unwrap();
let attrs: StoreAttrs = syn::parse2(attr.tokens.clone())
.map_err(|err| abort!("{}", err))
.unwrap();
attrs.attrs.into_iter().next().map(|attr| {
let StoreAttr::Returns(attr) = attr;
let ty = attr.value;
Expand Down Expand Up @@ -81,7 +84,9 @@ pub fn store(s: Structure) -> TokenStream {
.iter()
.filter_map(|bi| bi.ast().attrs.iter().filter_map(parse_returns_attr).next())
.next()
.expect("#[store(returns = ..)] needs to be specified.");
.unwrap_or_else(|| {
abort!(ident, "#[store(returns = ..)] needs to be specified.")
});
let fetch = if uses_default {
quote!(fetch_or_default)
} else {
Expand All @@ -93,7 +98,13 @@ pub fn store(s: Structure) -> TokenStream {
0 => "plain",
1 => "map",
2 => "double_map",
_ => panic!("invalid number of arguments"),
_ => {
abort!(
ident,
"Expected 0-2 fields but found {}",
filtered_fields.len()
);
}
}
);
let keys = filtered_fields
Expand Down Expand Up @@ -127,12 +138,7 @@ pub fn store(s: Structure) -> TokenStream {
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<#ret, #subxt::Error>> + Send + 'a>>;
}

impl<T, S, E> #store_trait<T> for #subxt::Client<T, S, E>
where
T: #module + Send + Sync,
S: 'static,
E: Send + Sync + 'static,
{
impl<T: #subxt::Runtime + #module> #store_trait<T> for #subxt::Client<T> {
fn #store<'a>(
&'a self,
#args
Expand Down Expand Up @@ -185,12 +191,7 @@ mod tests {
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<AccountData<T::Balance>, substrate_subxt::Error>> + Send + 'a>>;
}

impl<T, S, E> AccountStoreExt<T> for substrate_subxt::Client<T, S, E>
where
T: Balances + Send + Sync,
S: 'static,
E: Send + Sync + 'static,
{
impl<T: substrate_subxt::Runtime + Balances> AccountStoreExt<T> for substrate_subxt::Client<T> {
fn account<'a>(
&'a self,
account_id: &'a <T as System>::AccountId,
Expand Down
Loading

0 comments on commit 3080ec9

Please sign in to comment.