Misc changes (#2)

* Remove dependency on tokio, submit returns a future
* Enable logging in tests
* Add fetch, fetch_or, fetch_or_default
This commit is contained in:
David Craven
2019-08-06 16:26:11 +02:00
committed by Andrew Jones
parent 5a046d043e
commit 6522bb08d0
4 changed files with 132 additions and 41 deletions
+2 -2
View File
@@ -14,7 +14,6 @@ include = ["/Cargo.toml", "src/**/*.rs", "/README.md", "/LICENSE"]
[dependencies] [dependencies]
derive_more = "0.14.0" derive_more = "0.14.0"
env_logger = "0.6"
log = "0.4" log = "0.4"
futures = "0.1.28" futures = "0.1.28"
jsonrpc-core-client = { version = "12.1.0", features = ["ws"] } 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-rpc = { git = "https://github.com/paritytech/substrate/", package = "substrate-rpc" }
substrate-primitives = { git = "https://github.com/paritytech/substrate/", package = "substrate-primitives" } substrate-primitives = { git = "https://github.com/paritytech/substrate/", package = "substrate-primitives" }
transaction_pool = { git = "https://github.com/paritytech/substrate/", package = "substrate-transaction-pool" } transaction_pool = { git = "https://github.com/paritytech/substrate/", package = "substrate-transaction-pool" }
tokio = "0.1.21"
url = "1.7" url = "1.7"
[dev-dependencies] [dev-dependencies]
env_logger = "0.6"
node_runtime = { git = "https://github.com/paritytech/substrate/", package = "node-runtime" } node_runtime = { git = "https://github.com/paritytech/substrate/", package = "node-runtime" }
srml_balances = { git = "https://github.com/paritytech/substrate/", package = "srml-balances" } srml_balances = { git = "https://github.com/paritytech/substrate/", package = "srml-balances" }
substrate-keyring = { git = "https://github.com/paritytech/substrate/", package = "substrate-keyring" } substrate-keyring = { git = "https://github.com/paritytech/substrate/", package = "substrate-keyring" }
tokio = "0.1"
+7 -9
View File
@@ -20,16 +20,14 @@ use substrate_primitives::crypto::SecretStringError;
#[derive(Debug, derive_more::From)] #[derive(Debug, derive_more::From)]
pub enum Error { pub enum Error {
Io(IoError), Io(IoError),
Rpc(RpcError), Rpc(RpcError),
SecretString(SecretStringError), SecretString(SecretStringError),
Other(String), Other(String),
} }
impl From<&str> for Error { impl From<&str> for Error {
fn from(error: &str) -> Self { fn from(error: &str) -> Self {
Error::Other(error.into()) Error::Other(error.into())
} }
} }
pub type Result<T> = std::result::Result<T, Error>;
+64 -11
View File
@@ -14,10 +14,12 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with substrate-subxt. If not, see <http://www.gnu.org/licenses/>. // along with substrate-subxt. If not, see <http://www.gnu.org/licenses/>.
use crate::error::Result;
use futures::future::Future; use futures::future::Future;
use jsonrpc_core_client::transports::ws; use jsonrpc_core_client::transports::ws;
use parity_codec::Codec; use parity_codec::{
Codec,
Decode,
};
use runtime_primitives::traits::SignedExtension; use runtime_primitives::traits::SignedExtension;
use substrate_primitives::Pair; use substrate_primitives::Pair;
@@ -40,7 +42,7 @@ pub fn submit<T, P, C, E, SE>(
signer: P, signer: P,
call: C, call: C,
extra: E, extra: E,
) -> Result<ExtrinsicSuccess<T>> ) -> impl Future<Item = ExtrinsicSuccess<T>, Error = error::Error>
where where
T: srml_system::Trait, T: srml_system::Trait,
P: Pair, P: Pair,
@@ -50,26 +52,65 @@ where
E: Fn(T::Index) -> SE + Send + 'static, E: Fn(T::Index) -> SE + Send + 'static,
SE: SignedExtension + 'static, SE: SignedExtension + 'static,
{ {
let submit = ws::connect(url.as_str()) ws::connect(url.as_str())
.expect("Url is a valid url; qed") .expect("Url is a valid url; qed")
.map_err(Into::into) .map_err(Into::into)
.and_then(|rpc: rpc::Rpc<T, C, P, E, SE>| { .and_then(|rpc: rpc::Rpc<T, C, P, E, SE>| {
rpc.create_and_submit_extrinsic(signer, call, extra) rpc.create_and_submit_extrinsic(signer, call, extra)
}); })
}
let mut rt = tokio::runtime::Runtime::new()?; /// Fetches a storage key from a substrate node.
rt.block_on(submit) pub fn fetch<T: srml_system::Trait, P, C, E, SE, V: Decode>(
url: &Url,
key: Vec<u8>,
) -> impl Future<Item = Option<V>, Error = error::Error> {
ws::connect(url.as_str())
.expect("Url is a valid url; qed")
.map_err(Into::into)
.and_then(|rpc: rpc::Rpc<T, P, C, E, SE>| rpc.fetch::<V>(key))
.map_err(Into::into)
}
/// Fetches a storage key from a substrate node
pub fn fetch_or<T: srml_system::Trait, P, C, E, SE, V: Decode>(
url: &Url,
key: Vec<u8>,
default: V,
) -> impl Future<Item = V, Error = error::Error> {
fetch::<T, P, C, E, SE, V>(url, key).map(|value| value.unwrap_or(default))
}
/// Fetches a storage key from a substrate node.
pub fn fetch_or_default<T: srml_system::Trait, P, C, E, SE, V: Decode + Default>(
url: &Url,
key: Vec<u8>,
) -> impl Future<Item = V, Error = error::Error> {
fetch::<T, P, C, E, SE, V>(url, key).map(|value| value.unwrap_or_default())
} }
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use node_runtime::Runtime; use node_runtime::Runtime;
use runtime_primitives::generic::Era; use runtime_primitives::generic::Era;
use runtime_support::StorageMap;
use substrate_primitives::crypto::Pair as _; use substrate_primitives::crypto::Pair as _;
#[test] #[ignore] // requires locally running substrate node fn run<F>(f: F) -> Result<F::Item, F::Error>
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() { 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 signer = substrate_keyring::AccountKeyring::Alice.pair();
let dest = substrate_keyring::AccountKeyring::Bob.pair().public(); let dest = substrate_keyring::AccountKeyring::Bob.pair().public();
@@ -85,7 +126,19 @@ pub mod tests {
srml_balances::TakeFees::<Runtime>::from(0), srml_balances::TakeFees::<Runtime>::from(0),
) )
}; };
let result = super::submit::<Runtime, _, _, _, _>(&url, signer, call, extra); let future = super::submit::<Runtime, _, _, _, _>(&url, signer, call, extra);
assert!(result.is_ok()) 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 = <srml_balances::FreeBalance<Runtime>>::key_for(&account);
type Balance = <Runtime as srml_balances::Trait>::Balance;
let future = super::fetch::<Runtime, (), (), (), (), Balance>(&url, key);
run(future).unwrap();
} }
} }
+59 -19
View File
@@ -14,31 +14,60 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with substrate-subxt. If not, see <http://www.gnu.org/licenses/>. // along with substrate-subxt. If not, see <http://www.gnu.org/licenses/>.
use crate::{error::Error, ExtrinsicSuccess}; use crate::{
error::Error,
ExtrinsicSuccess,
};
use futures::{ use futures::{
future::{self, Future, IntoFuture}, future::{
self,
Future,
IntoFuture,
},
stream::Stream, stream::Stream,
}; };
use jsonrpc_core_client::{RpcChannel, RpcError, TypedSubscriptionStream}; use jsonrpc_core_client::{
RpcChannel,
RpcError,
TypedSubscriptionStream,
};
use log; use log;
use num_traits::bounds::Bounded; use num_traits::bounds::Bounded;
use parity_codec::{Codec, Decode, Encode}; use parity_codec::{
Codec,
Decode,
Encode,
};
use runtime_primitives::{ use runtime_primitives::{
generic::UncheckedExtrinsic, generic::UncheckedExtrinsic,
traits::{Hash as _, SignedExtension}, traits::{
Hash as _,
SignedExtension,
},
}; };
use runtime_support::StorageMap; 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 std::marker::PhantomData;
use substrate_primitives::{ use substrate_primitives::{
blake2_256, blake2_256,
storage::{StorageChangeSet, StorageKey}, storage::{
twox_128, Pair, StorageChangeSet,
StorageKey,
},
twox_128,
Pair,
}; };
use substrate_rpc::{ use substrate_rpc::{
author::AuthorClient, author::AuthorClient,
chain::{number::NumberOrHex, ChainClient}, chain::{
number::NumberOrHex,
ChainClient,
},
state::StateClient, state::StateClient,
}; };
use transaction_pool::txpool::watcher::Status; use transaction_pool::txpool::watcher::Status;
@@ -106,6 +135,25 @@ where
} }
} }
impl<T, C, P, E, SE> Rpc<T, C, P, E, SE>
where
T: srml_system::Trait,
{
/// Fetch a storage key
pub fn fetch<V: Decode>(
&self,
key: Vec<u8>,
) -> impl Future<Item = Option<V>, 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<T, C, P, E, SE> Rpc<T, C, P, E, SE> impl<T, C, P, E, SE> Rpc<T, C, P, E, SE>
where where
T: srml_system::Trait, T: srml_system::Trait,
@@ -122,16 +170,8 @@ where
account: &T::AccountId, account: &T::AccountId,
) -> impl Future<Item = <T as srml_system::Trait>::Index, Error = RpcError> { ) -> impl Future<Item = <T as srml_system::Trait>::Index, Error = RpcError> {
let account_nonce_key = <srml_system::AccountNonce<T>>::key_for(account); let account_nonce_key = <srml_system::AccountNonce<T>>::key_for(account);
let storage_key = blake2_256(&account_nonce_key).to_vec(); self.fetch::<<T as srml_system::Trait>::Index>(account_nonce_key)
.map(|value| value.unwrap_or_default())
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)
} }
/// Fetch the genesis hash /// Fetch the genesis hash