From 6522bb08d05b0ebfb906c2bde729f5d3b91c9418 Mon Sep 17 00:00:00 2001 From: David Craven Date: Tue, 6 Aug 2019 16:26:11 +0200 Subject: [PATCH] Misc changes (#2) * Remove dependency on tokio, submit returns a future * Enable logging in tests * Add fetch, fetch_or, fetch_or_default --- Cargo.toml | 4 +-- src/error.rs | 16 +++++------ src/lib.rs | 75 ++++++++++++++++++++++++++++++++++++++++++-------- src/rpc.rs | 78 +++++++++++++++++++++++++++++++++++++++------------- 4 files changed, 132 insertions(+), 41 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index accecaea14d1d..1e1c0241fd766 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ include = ["/Cargo.toml", "src/**/*.rs", "/README.md", "/LICENSE"] [dependencies] derive_more = "0.14.0" -env_logger = "0.6" log = "0.4" futures = "0.1.28" jsonrpc-core-client = { version = "12.1.0", features = ["ws"] } @@ -27,10 +26,11 @@ srml-system = { git = "https://github.com/paritytech/substrate/", package = "srm substrate-rpc = { git = "https://github.com/paritytech/substrate/", package = "substrate-rpc" } substrate-primitives = { git = "https://github.com/paritytech/substrate/", package = "substrate-primitives" } transaction_pool = { git = "https://github.com/paritytech/substrate/", package = "substrate-transaction-pool" } -tokio = "0.1.21" url = "1.7" [dev-dependencies] +env_logger = "0.6" node_runtime = { git = "https://github.com/paritytech/substrate/", package = "node-runtime" } srml_balances = { git = "https://github.com/paritytech/substrate/", package = "srml-balances" } substrate-keyring = { git = "https://github.com/paritytech/substrate/", package = "substrate-keyring" } +tokio = "0.1" diff --git a/src/error.rs b/src/error.rs index cc2d90d637ece..95b9adfeaee3a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -20,16 +20,14 @@ use substrate_primitives::crypto::SecretStringError; #[derive(Debug, derive_more::From)] pub enum Error { - Io(IoError), - Rpc(RpcError), - SecretString(SecretStringError), - Other(String), + Io(IoError), + Rpc(RpcError), + SecretString(SecretStringError), + Other(String), } impl From<&str> for Error { - fn from(error: &str) -> Self { - Error::Other(error.into()) - } + fn from(error: &str) -> Self { + Error::Other(error.into()) + } } - -pub type Result = std::result::Result; \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 906ba61762f89..913821cc371c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,10 +14,12 @@ // You should have received a copy of the GNU General Public License // along with substrate-subxt. If not, see . -use crate::error::Result; use futures::future::Future; use jsonrpc_core_client::transports::ws; -use parity_codec::Codec; +use parity_codec::{ + Codec, + Decode, +}; use runtime_primitives::traits::SignedExtension; use substrate_primitives::Pair; @@ -40,7 +42,7 @@ pub fn submit( signer: P, call: C, extra: E, -) -> Result> +) -> impl Future, Error = error::Error> where T: srml_system::Trait, P: Pair, @@ -50,26 +52,65 @@ where E: Fn(T::Index) -> SE + Send + 'static, SE: SignedExtension + 'static, { - let submit = ws::connect(url.as_str()) + ws::connect(url.as_str()) .expect("Url is a valid url; qed") .map_err(Into::into) .and_then(|rpc: rpc::Rpc| { rpc.create_and_submit_extrinsic(signer, call, extra) - }); + }) +} + +/// Fetches a storage key from a substrate node. +pub fn fetch( + url: &Url, + key: Vec, +) -> impl Future, Error = error::Error> { + ws::connect(url.as_str()) + .expect("Url is a valid url; qed") + .map_err(Into::into) + .and_then(|rpc: rpc::Rpc| rpc.fetch::(key)) + .map_err(Into::into) +} - let mut rt = tokio::runtime::Runtime::new()?; - rt.block_on(submit) +/// Fetches a storage key from a substrate node +pub fn fetch_or( + url: &Url, + key: Vec, + default: V, +) -> impl Future { + fetch::(url, key).map(|value| value.unwrap_or(default)) +} + +/// Fetches a storage key from a substrate node. +pub fn fetch_or_default( + url: &Url, + key: Vec, +) -> impl Future { + fetch::(url, key).map(|value| value.unwrap_or_default()) } #[cfg(test)] pub mod tests { use node_runtime::Runtime; use runtime_primitives::generic::Era; + use runtime_support::StorageMap; use substrate_primitives::crypto::Pair as _; - #[test] #[ignore] // requires locally running substrate node + fn run(f: F) -> Result + where + F: futures::Future + Send + 'static, + F::Item: Send + 'static, + F::Error: Send + 'static, + { + let mut rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(f) + } + + #[test] + #[ignore] // requires locally running substrate node fn node_runtime_balance_transfer() { - let url = url::Url::parse("ws://localhost:9944").unwrap(); + env_logger::try_init().ok(); + let url = url::Url::parse("ws://127.0.0.1:9944").unwrap(); let signer = substrate_keyring::AccountKeyring::Alice.pair(); let dest = substrate_keyring::AccountKeyring::Bob.pair().public(); @@ -85,7 +126,19 @@ pub mod tests { srml_balances::TakeFees::::from(0), ) }; - let result = super::submit::(&url, signer, call, extra); - assert!(result.is_ok()) + let future = super::submit::(&url, signer, call, extra); + run(future).unwrap(); + } + + #[test] + #[ignore] // requires locally running substrate node + fn node_runtime_fetch_account_balance() { + env_logger::try_init().ok(); + let url = url::Url::parse("ws://127.0.0.1:9944").unwrap(); + let account = substrate_keyring::AccountKeyring::Alice.pair().public(); + let key = >::key_for(&account); + type Balance = ::Balance; + let future = super::fetch::(&url, key); + run(future).unwrap(); } } diff --git a/src/rpc.rs b/src/rpc.rs index 91885f1b8afcc..0c9920a1e65de 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -14,31 +14,60 @@ // You should have received a copy of the GNU General Public License // along with substrate-subxt. If not, see . -use crate::{error::Error, ExtrinsicSuccess}; +use crate::{ + error::Error, + ExtrinsicSuccess, +}; use futures::{ - future::{self, Future, IntoFuture}, + future::{ + self, + Future, + IntoFuture, + }, stream::Stream, }; -use jsonrpc_core_client::{RpcChannel, RpcError, TypedSubscriptionStream}; +use jsonrpc_core_client::{ + RpcChannel, + RpcError, + TypedSubscriptionStream, +}; use log; use num_traits::bounds::Bounded; -use parity_codec::{Codec, Decode, Encode}; +use parity_codec::{ + Codec, + Decode, + Encode, +}; use runtime_primitives::{ generic::UncheckedExtrinsic, - traits::{Hash as _, SignedExtension}, + traits::{ + Hash as _, + SignedExtension, + }, }; use runtime_support::StorageMap; -use serde::{self, de::Error as DeError, Deserialize}; +use serde::{ + self, + de::Error as DeError, + Deserialize, +}; use std::marker::PhantomData; use substrate_primitives::{ blake2_256, - storage::{StorageChangeSet, StorageKey}, - twox_128, Pair, + storage::{ + StorageChangeSet, + StorageKey, + }, + twox_128, + Pair, }; use substrate_rpc::{ author::AuthorClient, - chain::{number::NumberOrHex, ChainClient}, + chain::{ + number::NumberOrHex, + ChainClient, + }, state::StateClient, }; use transaction_pool::txpool::watcher::Status; @@ -106,6 +135,25 @@ where } } +impl Rpc +where + T: srml_system::Trait, +{ + /// Fetch a storage key + pub fn fetch( + &self, + key: Vec, + ) -> impl Future, Error = RpcError> { + let storage_key = StorageKey(blake2_256(&key).to_vec()); + self.state + .storage(storage_key, None) + .map(|data| { + data.map(|d| Decode::decode(&mut &d.0[..]).expect("Valid storage key")) + }) + .map_err(Into::into) + } +} + impl Rpc where T: srml_system::Trait, @@ -122,16 +170,8 @@ where account: &T::AccountId, ) -> impl Future::Index, Error = RpcError> { let account_nonce_key = >::key_for(account); - let storage_key = blake2_256(&account_nonce_key).to_vec(); - - self.state - .storage(StorageKey(storage_key), None) - .map(|data| { - data.map_or(Default::default(), |d| { - Decode::decode(&mut &d.0[..]).expect("Account nonce is valid Index") - }) - }) - .map_err(Into::into) + self.fetch::<::Index>(account_nonce_key) + .map(|value| value.unwrap_or_default()) } /// Fetch the genesis hash