From 6243b3e1bce96c0066f6747a7b37160833826811 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sun, 31 May 2020 18:58:17 +0200 Subject: [PATCH 1/2] Fix optional store items. --- proc-macro/src/store.rs | 22 ++++++++++++++++------ proc-macro/src/test.rs | 10 +++++----- proc-macro/src/utils.rs | 28 ++++++++++++++++++++++++++++ src/lib.rs | 28 ++++++++++++++++++++++------ src/rpc.rs | 17 +++++------------ src/signer.rs | 7 ++++++- 6 files changed, 82 insertions(+), 30 deletions(-) diff --git a/proc-macro/src/store.rs b/proc-macro/src/store.rs index cb5e2cc79e..d247050430 100644 --- a/proc-macro/src/store.rs +++ b/proc-macro/src/store.rs @@ -49,11 +49,16 @@ impl Parse for StoreAttr { type StoreAttrs = utils::Attrs; -fn parse_returns_attr(attr: &syn::Attribute) -> Option { +fn parse_returns_attr(attr: &syn::Attribute) -> Option<(syn::Type, syn::Type, bool)> { let attrs: StoreAttrs = syn::parse2(attr.tokens.clone()).unwrap(); attrs.attrs.into_iter().next().map(|attr| { let StoreAttr::Returns(attr) = attr; - attr.value + let ty = attr.value; + if let Some(inner) = utils::parse_option(&ty) { + (ty, inner, false) + } else { + (ty.clone(), ty, true) + } }) } @@ -72,11 +77,16 @@ pub fn store(s: Structure) -> TokenStream { let filtered_fields = utils::filter_fields(&fields, &marker); let args = utils::fields_to_args(&filtered_fields); let build_struct = utils::build_struct(ident, &fields); - let ret = bindings + let (ret, store_ret, uses_default) = bindings .iter() .filter_map(|bi| bi.ast().attrs.iter().filter_map(parse_returns_attr).next()) .next() .expect("#[store(returns = ..)] needs to be specified."); + let fetch = if uses_default { + quote!(fetch_or_default) + } else { + quote!(fetch) + }; let store_ty = format_ident!( "{}", match filtered_fields.len() { @@ -94,7 +104,7 @@ pub fn store(s: Structure) -> TokenStream { impl#generics #subxt::Store for #ident<#(#params),*> { const MODULE: &'static str = MODULE; const FIELD: &'static str = #store_name; - type Returns = #ret; + type Returns = #store_ret; fn key( &self, metadata: &#subxt::Metadata, @@ -127,7 +137,7 @@ pub fn store(s: Structure) -> TokenStream { #args ) -> core::pin::Pin> + Send + 'a>> { let #marker = core::marker::PhantomData::; - Box::pin(self.fetch(#build_struct, None)) + Box::pin(self.#fetch(#build_struct, None)) } } } @@ -184,7 +194,7 @@ mod tests { ) -> core::pin::Pin, substrate_subxt::Error>> + Send + 'a>> { let _ = core::marker::PhantomData::; - Box::pin(self.fetch(AccountStore { account_id, }, None)) + Box::pin(self.fetch_or_default(AccountStore { account_id, }, None)) } } }; diff --git a/proc-macro/src/test.rs b/proc-macro/src/test.rs index f625ad68c6..bef72e0eb3 100644 --- a/proc-macro/src/test.rs +++ b/proc-macro/src/test.rs @@ -330,7 +330,7 @@ impl Step { }; let build_struct = quote! { #( - let #state_name = client.fetch(#state, None).await.unwrap(); + let #state_name = client.fetch_or_default(#state, None).await.unwrap(); )* State { #(#state_name),* } }; @@ -477,11 +477,11 @@ mod tests { let pre = { let alice = client - .fetch(AccountStore { account_id: &alice }, None) + .fetch_or_default(AccountStore { account_id: &alice }, None) .await .unwrap(); let bob = client - .fetch(AccountStore { account_id: &bob }, None) + .fetch_or_default(AccountStore { account_id: &bob }, None) .await .unwrap(); State { alice, bob } @@ -510,11 +510,11 @@ mod tests { let post = { let alice = client - .fetch(AccountStore { account_id: &alice }, None) + .fetch_or_default(AccountStore { account_id: &alice }, None) .await .unwrap(); let bob = client - .fetch(AccountStore { account_id: &bob }, None) + .fetch_or_default(AccountStore { account_id: &bob }, None) .await .unwrap(); State { alice, bob } diff --git a/proc-macro/src/utils.rs b/proc-macro/src/utils.rs index 8d74cde62a..25a9198eae 100644 --- a/proc-macro/src/utils.rs +++ b/proc-macro/src/utils.rs @@ -167,6 +167,21 @@ pub fn type_params(generics: &syn::Generics) -> Vec { .collect() } +pub fn parse_option(ty: &syn::Type) -> Option { + if let syn::Type::Path(ty_path) = ty { + if let Some(seg) = ty_path.path.segments.first() { + if seg.ident.to_string() == "Option" { + if let syn::PathArguments::AngleBracketed(args) = &seg.arguments { + if let Some(syn::GenericArgument::Type(ty)) = args.args.first() { + return Some(ty.clone()) + } + } + } + } + } + None +} + #[derive(Debug)] pub struct Attrs { pub paren: syn::token::Paren, @@ -209,3 +224,16 @@ pub(crate) fn assert_proc_macro( let expected = expected.to_string(); pretty_assertions::assert_eq!(result, expected); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_option() { + let option_t: syn::Type = syn::parse2(quote!(Option)).unwrap(); + let t: syn::Type = syn::parse2(quote!(T)).unwrap(); + assert_eq!(parse_option(&option_t), Some(t.clone())); + assert_eq!(parse_option(&t), None); + } +} diff --git a/src/lib.rs b/src/lib.rs index 5c28706056..e6e28aaafb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,10 @@ extern crate substrate_subxt_proc_macro; pub use sp_core; pub use sp_runtime; -use codec::Encode; +use codec::{ + Decode, + Encode, +}; use futures::future; use jsonrpsee::client::Subscription; use sc_rpc_api::state::ReadProof; @@ -200,21 +203,34 @@ impl Client { &self.metadata } - /// Fetch a StorageKey. - pub async fn fetch>( + /// Fetch a StorageKey with default value. + pub async fn fetch_or_default>( &self, store: F, hash: Option, ) -> Result { let key = store.key(&self.metadata)?; - let value = self.rpc.storage::(key, hash).await?; - if let Some(v) = value { - Ok(v) + if let Some(data) = self.rpc.storage(key, hash).await? { + Ok(Decode::decode(&mut &data.0[..])?) } else { Ok(store.default(&self.metadata)?) } } + /// Fetch a StorageKey an optional storage key. + pub async fn fetch>( + &self, + store: F, + hash: Option, + ) -> Result, Error> { + let key = store.key(&self.metadata)?; + if let Some(data) = self.rpc.storage(key, hash).await? { + Ok(Some(Decode::decode(&mut &data.0[..])?)) + } else { + Ok(None) + } + } + /// Query historical storage entries pub async fn query_storage( &self, diff --git a/src/rpc.rs b/src/rpc.rs index c5898bf9b5..1a7c88443a 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -132,22 +132,15 @@ impl Rpc { } /// Fetch a storage key - pub async fn storage( + pub async fn storage( &self, key: StorageKey, hash: Option, - ) -> Result, Error> { + ) -> Result, Error> { let params = Params::Array(vec![to_json_value(key)?, to_json_value(hash)?]); - let data: Option = - self.client.request("state_getStorage", params).await?; - match data { - Some(data) => { - log::debug!("state_getStorage {:?}", data.0); - let value = Decode::decode(&mut &data.0[..])?; - Ok(Some(value)) - } - None => Ok(None), - } + let data = self.client.request("state_getStorage", params).await?; + log::debug!("state_getStorage {:?}", data); + Ok(data) } /// Query historical storage entries diff --git a/src/signer.rs b/src/signer.rs index ec60b195e4..d10dc9a3ba 100644 --- a/src/signer.rs +++ b/src/signer.rs @@ -104,10 +104,15 @@ where self.nonce = Some(nonce); } - /// Increment the nonce + /// Increment the nonce. pub fn increment_nonce(&mut self) { self.nonce = self.nonce.map(|nonce| nonce + 1.into()); } + + /// Returns the signer. + pub fn signer(&self) -> &P { + &self.signer + } } impl Signer for PairSigner From 217113fb1ee804da77072c252146d1b3d6577177 Mon Sep 17 00:00:00 2001 From: David Craven Date: Mon, 1 Jun 2020 03:25:45 +0200 Subject: [PATCH 2/2] Support querying a block hash. --- proc-macro/src/store.rs | 8 ++++++-- proc-macro/tests/balances.rs | 8 ++++---- src/frame/balances.rs | 4 ++-- src/lib.rs | 4 ++-- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/proc-macro/src/store.rs b/proc-macro/src/store.rs index d247050430..db528c61ac 100644 --- a/proc-macro/src/store.rs +++ b/proc-macro/src/store.rs @@ -123,6 +123,7 @@ pub fn store(s: Structure) -> TokenStream { fn #store<'a>( &'a self, #args + hash: Option, ) -> core::pin::Pin> + Send + 'a>>; } @@ -135,9 +136,10 @@ pub fn store(s: Structure) -> TokenStream { fn #store<'a>( &'a self, #args + hash: Option, ) -> core::pin::Pin> + Send + 'a>> { let #marker = core::marker::PhantomData::; - Box::pin(self.#fetch(#build_struct, None)) + Box::pin(self.#fetch(#build_struct, hash)) } } } @@ -179,6 +181,7 @@ mod tests { fn account<'a>( &'a self, account_id: &'a ::AccountId, + hash: Option, ) -> core::pin::Pin, substrate_subxt::Error>> + Send + 'a>>; } @@ -191,10 +194,11 @@ mod tests { fn account<'a>( &'a self, account_id: &'a ::AccountId, + hash: Option, ) -> core::pin::Pin, substrate_subxt::Error>> + Send + 'a>> { let _ = core::marker::PhantomData::; - Box::pin(self.fetch_or_default(AccountStore { account_id, }, None)) + Box::pin(self.fetch_or_default(AccountStore { account_id, }, hash)) } } }; diff --git a/proc-macro/tests/balances.rs b/proc-macro/tests/balances.rs index 062d4be74f..ea8c5ae6ec 100644 --- a/proc-macro/tests/balances.rs +++ b/proc-macro/tests/balances.rs @@ -117,8 +117,8 @@ async fn transfer_balance_example() -> Result<(), Box> { let alice = AccountKeyring::Alice.to_account_id(); let bob = AccountKeyring::Bob.to_account_id(); - let alice_account = client.account(&alice).await?; - let bob_account = client.account(&bob).await?; + let alice_account = client.account(&alice, None).await?; + let bob_account = client.account(&bob, None).await?; let pre = (alice_account, bob_account); let _hash = client @@ -138,8 +138,8 @@ async fn transfer_balance_example() -> Result<(), Box> { }) ); - let alice_account = client.account(&alice).await?; - let bob_account = client.account(&bob).await?; + let alice_account = client.account(&alice, None).await?; + let bob_account = client.account(&bob, None).await?; let post = (alice_account, bob_account); assert_eq!(pre.0.free, post.0.free - 10_000); diff --git a/src/frame/balances.rs b/src/frame/balances.rs index 02e41d9342..d3b0e45aff 100644 --- a/src/frame/balances.rs +++ b/src/frame/balances.rs @@ -146,7 +146,7 @@ mod tests { async fn test_state_total_issuance() { env_logger::try_init().ok(); let client = test_client().await; - let total_issuance = client.total_issuance().await.unwrap(); + let total_issuance = client.total_issuance(None).await.unwrap(); assert_ne!(total_issuance, 0); } @@ -156,7 +156,7 @@ mod tests { env_logger::try_init().ok(); let client = test_client().await; let account = AccountKeyring::Alice.to_account_id(); - let info = client.account(&account).await.unwrap(); + let info = client.account(&account, None).await.unwrap(); assert_ne!(info.data.free, 0); } } diff --git a/src/lib.rs b/src/lib.rs index e6e28aaafb..ed60910784 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -328,7 +328,7 @@ where let account_nonce = if let Some(nonce) = nonce { nonce } else { - self.account(account_id).await?.nonce + self.account(account_id, None).await?.nonce }; let spec_version = self.runtime_version.spec_version; let tx_version = self.runtime_version.transaction_version; @@ -469,7 +469,7 @@ mod tests { let client = test_client().await; let nonce = client - .account(&AccountKeyring::Alice.to_account_id()) + .account(&AccountKeyring::Alice.to_account_id(), None) .await .unwrap() .nonce;