Merge branch 'master' into staking

This commit is contained in:
Demi M. Obenour
2020-07-08 18:06:11 -04:00
10 changed files with 284 additions and 24 deletions
+9 -5
View File
@@ -43,12 +43,14 @@ use jsonrpsee::{
};
use sc_network::config::TransportConfig;
pub use sc_service::{
config::DatabaseConfig,
config::{
DatabaseConfig,
KeystoreConfig,
},
Error as ServiceError,
};
use sc_service::{
config::{
KeystoreConfig,
NetworkConfiguration,
TaskType,
},
@@ -119,6 +121,8 @@ pub struct SubxtClientConfig<C: ChainSpec + 'static, S: AbstractService> {
pub copyright_start_year: i32,
/// Database configuration.
pub db: DatabaseConfig,
/// Keystore configuration.
pub keystore: KeystoreConfig,
/// Service builder.
pub builder: fn(Configuration) -> Result<S, sc_service::Error>,
/// Chain specification.
@@ -216,13 +220,11 @@ fn start_subxt_client<C: ChainSpec + 'static, S: AbstractService>(
})
.into(),
database: config.db,
keystore: KeystoreConfig::InMemory,
keystore: config.keystore,
max_runtime_instances: 8,
announce_block: true,
dev_key_seed: config.role.into(),
base_path: Default::default(),
informant_output_format: Default::default(),
telemetry_endpoints: Default::default(),
telemetry_external_transport: Default::default(),
default_heap_pages: Default::default(),
@@ -344,6 +346,7 @@ mod tests {
path: tmp.path().into(),
cache_size: 64,
},
keystore: KeystoreConfig::InMemory,
builder: test_node::service::new_light,
chain_spec,
role: Role::Light,
@@ -374,6 +377,7 @@ mod tests {
path: tmp.path().into(),
cache_size: 128,
},
keystore: KeystoreConfig::InMemory,
builder: test_node::service::new_full,
chain_spec: test_node::chain_spec::development_config(),
role: Role::Authority(AccountKeyring::Alice),
+4 -1
View File
@@ -16,7 +16,10 @@
use sp_keyring::AccountKeyring;
use substrate_subxt::{
balances::*,
balances::{
TransferCallExt,
TransferEventExt,
},
ClientBuilder,
DefaultNodeRuntime,
PairSigner,
+99 -1
View File
@@ -30,13 +30,111 @@ use synstructure::{
Structure,
};
/// Register type sizes for [EventsDecoder](struct.EventsDecoder.html) and set the `MODULE`.
///
/// The `module` macro registers the type sizes of the associated types of a trait so that [EventsDecoder](struct.EventsDecoder.html)
/// can decode events of that type when received from Substrate. It also sets the `MODULE` constant
/// to the name of the trait (must match the name of the Substrate pallet) that enables the [Call](), [Event]() and [Store]() macros to work.
///
/// If you do not want an associated type to be registered, likely because you never expect it as part of a response payload to be decoded, use `#[module(ignore)]` on the type.
///
/// Example:
///
/// ```ignore
/// #[module]
/// pub trait Herd: Husbandry {
/// type Hooves: HoofCounter;
/// type Wool: WoollyAnimal;
/// #[module(ignore)]
/// type Digestion: EnergyProducer + std::fmt::Debug;
/// }
/// ```
///
/// The above will produce the following code:
///
/// ```ignore
/// pub trait Herd: Husbandry {
/// type Hooves: HoofCounter;
/// type Wool: WoollyAnimal;
/// #[module(ignore)]
/// type Digestion: EnergyProducer + std::fmt::Debug;
/// }
///
/// const MODULE: &str = "Herd";
///
/// // `EventsDecoder` extension trait.
/// pub trait HerdEventsDecoder {
/// // Registers this modules types.
/// fn with_herd(&mut self);
/// }
///
/// impl<T: Herd> HerdEventsDecoder for
/// substrate_subxt::EventsDecoder<T>
/// {
/// fn with_herd(&mut self) {
/// self.with_husbandry();
/// self.register_type_size::<T::Hooves>("Hooves");
/// self.register_type_size::<T::Wool>("Wool");
/// }
/// }
/// ```
///
/// The following type sizes are registered by default: `bool, u8, u32, AccountId, AccountIndex,
/// AuthorityId, AuthorityIndex, AuthorityWeight, BlockNumber, DispatchInfo, Hash, Kind,
/// MemberCount, PhantomData, PropIndex, ProposalIndex, ReferendumIndex, SessionIndex, VoteThreshold`
#[proc_macro_attribute]
#[proc_macro_error]
pub fn module(args: TokenStream, input: TokenStream) -> TokenStream {
module::module(args.into(), input.into()).into()
}
decl_derive!([Call] => #[proc_macro_error] call);
decl_derive!(
[Call] =>
/// Derive macro that implements [substrate_subxt::Call](../substrate_subxt/trait.Call.html) for your struct
/// and defines&implements the calls as an extension trait.
///
/// Use the `Call` derive macro in tandem with the [#module](../substrate_subxt/attr.module.html) macro to extend
/// your struct to enable calls to substrate and to decode events. The struct maps to the corresponding Substrate runtime call, e.g.:
///
/// ```ignore
/// decl_module! {
/// /* … */
/// pub fn fun_stuff(origin, something: Vec<u8>) -> DispatchResult { /* … */ }
/// /* … */
/// }
///```
///
/// Implements [substrate_subxt::Call](../substrate_subxt/trait.Call.html) and adds an extension trait that
/// provides two methods named as your struct.
///
/// Example:
/// ```rust,ignore
/// pub struct MyRuntime;
///
/// impl System for MyRuntime { /* … */ }
/// impl Balances for MyRuntime { /* … */ }
///
/// #[module]
/// pub trait MyTrait: System + Balances {}
///
/// #[derive(Call)]
/// pub struct FunStuffCall<T: MyTrait> {
/// /// Runtime marker.
/// pub _runtime: PhantomData<T>,
/// /// The argument passed to the call..
/// pub something: Vec<u8>,
/// }
/// ```
///
/// When building a [Client](../substrate_subxt/struct.Client.html) parameterised to `MyRuntime`, you have access to
/// two new methods: `fun_stuff()` and `fun_stuff_and_watch()` by way of the derived `FunStuffExt`
/// trait. The `_and_watch` variant makes the call and waits for the result. The fields of the
/// input struct become arguments to the calls (ignoring the marker field).
///
/// Under the hood the implementation calls [submit()](../substrate_subxt/struct.Client.html#method.submit) and
/// [watch()](../substrate_subxt/struct.Client.html#method.watch) respectively.
#[proc_macro_error] call
);
fn call(s: Structure) -> TokenStream {
call::call(s).into()
}
+43 -1
View File
@@ -69,7 +69,7 @@ fn events_decoder_trait_name(module: &syn::Ident) -> syn::Ident {
fn with_module_ident(module: &syn::Ident) -> syn::Ident {
format_ident!("with_{}", module.to_string().to_snake_case())
}
/// Attribute macro that registers the type sizes used by the module; also sets the `MODULE` constant.
pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
let input: Result<syn::ItemTrait, _> = syn::parse2(tokens.clone());
let input = if let Ok(input) = input {
@@ -187,4 +187,46 @@ mod tests {
let result = module(attr, input);
utils::assert_proc_macro(result, expected);
}
#[test]
fn test_herd() {
let attr = quote!(#[module]);
let input = quote! {
pub trait Herd: Husbandry {
type Hoves: u8;
type Wool: bool;
#[module(ignore)]
type Digestion: EnergyProducer + fmt::Debug;
}
};
let expected = quote! {
pub trait Herd: Husbandry {
type Hoves: u8;
type Wool: bool;
#[module(ignore)]
type Digestion: EnergyProducer + fmt::Debug;
}
const MODULE: &str = "Herd";
/// `EventsDecoder` extension trait.
pub trait HerdEventsDecoder {
/// Registers this modules types.
fn with_herd(&mut self);
}
impl<T: Herd> HerdEventsDecoder for
substrate_subxt::EventsDecoder<T>
{
fn with_herd(&mut self) {
self.with_husbandry();
self.register_type_size::<T::Hoves>("Hoves");
self.register_type_size::<T::Wool>("Wool");
}
}
};
let result = module(attr, input);
utils::assert_proc_macro(result, expected);
}
}
+1 -1
View File
@@ -59,7 +59,7 @@ pub struct RawEvent {
pub data: Vec<u8>,
}
/// Event decoder.
/// Events decoder.
#[derive(Debug)]
pub struct EventsDecoder<T> {
metadata: Metadata,
+80 -11
View File
@@ -28,7 +28,6 @@
path_statements,
patterns_in_fns_without_body,
private_in_public,
missing_debug_implementations,
unconditional_recursion,
unused_allocation,
unused_comparisons,
@@ -36,8 +35,7 @@
while_true,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
clippy::all
unused_extern_crates
)]
#![allow(clippy::type_complexity)]
@@ -54,9 +52,12 @@ use codec::Decode;
use futures::future;
use jsonrpsee::client::Subscription;
use sc_rpc_api::state::ReadProof;
use sp_core::storage::{
StorageChangeSet,
StorageKey,
use sp_core::{
storage::{
StorageChangeSet,
StorageKey,
},
Bytes,
};
pub use sp_runtime::traits::SignedExtension;
use sp_version::RuntimeVersion;
@@ -107,7 +108,6 @@ use crate::{
/// ClientBuilder for constructing a Client.
#[derive(Default)]
#[allow(missing_debug_implementations)]
pub struct ClientBuilder<T: Runtime> {
_marker: std::marker::PhantomData<T>,
url: Option<String>,
@@ -166,7 +166,6 @@ impl<T: Runtime> ClientBuilder<T> {
}
/// Client to interface with a substrate node.
#[allow(missing_debug_implementations)]
pub struct Client<T: Runtime> {
rpc: Rpc<T>,
genesis_hash: T::Hash,
@@ -429,6 +428,41 @@ impl<T: Runtime> Client<T> {
let decoder = self.events_decoder::<C>();
self.submit_and_watch_extrinsic(extrinsic, decoder).await
}
/// Insert a key into the keystore.
pub async fn insert_key(
&self,
key_type: String,
suri: String,
public: Bytes,
) -> Result<(), Error> {
self.rpc.insert_key(key_type, suri, public).await
}
/// Generate new session keys and returns the corresponding public keys.
pub async fn rotate_keys(&self) -> Result<Bytes, Error> {
self.rpc.rotate_keys().await
}
/// Checks if the keystore has private keys for the given session public keys.
///
/// `session_keys` is the SCALE encoded session keys object from the runtime.
///
/// Returns `true` iff all private keys could be found.
pub async fn has_session_keys(&self, session_keys: Bytes) -> Result<bool, Error> {
self.rpc.has_session_keys(session_keys).await
}
/// Checks if the keystore has private keys for the given public key and key type.
///
/// Returns `true` if a private key could be found.
pub async fn has_key(
&self,
public_key: Bytes,
key_type: String,
) -> Result<bool, Error> {
self.rpc.has_key(public_key, key_type).await
}
}
/// Wraps an already encoded byte vector, prevents being encoded as a raw byte vector as part of
@@ -460,6 +494,7 @@ mod tests {
use sp_runtime::MultiSignature;
use substrate_subxt_client::{
DatabaseConfig,
KeystoreConfig,
Role,
SubxtClient,
SubxtClientConfig,
@@ -468,7 +503,9 @@ mod tests {
pub(crate) type TestRuntime = crate::NodeTemplateRuntime;
pub(crate) async fn test_client() -> (Client<TestRuntime>, TempDir) {
pub(crate) async fn test_client_with(
key: AccountKeyring,
) -> (Client<TestRuntime>, TempDir) {
env_logger::try_init().ok();
let tmp = TempDir::new("subxt-").expect("failed to create tempdir");
let config = SubxtClientConfig {
@@ -477,12 +514,16 @@ mod tests {
author: "substrate subxt",
copyright_start_year: 2020,
db: DatabaseConfig::RocksDb {
path: tmp.path().into(),
path: tmp.path().join("db"),
cache_size: 128,
},
keystore: KeystoreConfig::Path {
path: tmp.path().join("keystore"),
password: None,
},
builder: test_node::service::new_full,
chain_spec: test_node::chain_spec::development_config(),
role: Role::Authority(AccountKeyring::Alice),
role: Role::Authority(key),
};
let client = ClientBuilder::new()
.set_client(SubxtClient::new(config).expect("Error creating subxt client"))
@@ -492,6 +533,34 @@ mod tests {
(client, tmp)
}
pub(crate) async fn test_client() -> (Client<TestRuntime>, TempDir) {
test_client_with(AccountKeyring::Alice).await
}
#[async_std::test]
async fn test_insert_key() {
// Bob is not an authority, so block production should be disabled.
let (client, _tmp) = test_client_with(AccountKeyring::Bob).await;
let mut blocks = client.subscribe_blocks().await.unwrap();
// get the genesis block.
assert_eq!(blocks.next().await.number, 0);
let public = AccountKeyring::Alice.public().as_array_ref().to_vec();
client
.insert_key(
"aura".to_string(),
"//Alice".to_string(),
public.clone().into(),
)
.await
.unwrap();
assert!(client
.has_key(public.clone().into(), "aura".to_string())
.await
.unwrap());
// Alice is an authority, so blocks should be produced.
assert_eq!(blocks.next().await.number, 1);
}
#[async_std::test]
async fn test_tx_transfer_balance() {
let mut signer = PairSigner::new(AccountKeyring::Alice.pair());
+47
View File
@@ -396,6 +396,53 @@ impl<T: Runtime> Rpc<T> {
}
unreachable!()
}
/// Insert a key into the keystore.
pub async fn insert_key(
&self,
key_type: String,
suri: String,
public: Bytes,
) -> Result<(), Error> {
let params = Params::Array(vec![
to_json_value(key_type)?,
to_json_value(suri)?,
to_json_value(public)?,
]);
self.client.request("author_insertKey", params).await?;
Ok(())
}
/// Generate new session keys and returns the corresponding public keys.
pub async fn rotate_keys(&self) -> Result<Bytes, Error> {
Ok(self
.client
.request("author_rotateKeys", Params::None)
.await?)
}
/// Checks if the keystore has private keys for the given session public keys.
///
/// `session_keys` is the SCALE encoded session keys object from the runtime.
///
/// Returns `true` iff all private keys could be found.
pub async fn has_session_keys(&self, session_keys: Bytes) -> Result<bool, Error> {
let params = Params::Array(vec![to_json_value(session_keys)?]);
Ok(self.client.request("author_hasSessionKeys", params).await?)
}
/// Checks if the keystore has private keys for the given public key and key type.
///
/// Returns `true` if a private key could be found.
pub async fn has_key(
&self,
public_key: Bytes,
key_type: String,
) -> Result<bool, Error> {
let params =
Params::Array(vec![to_json_value(public_key)?, to_json_value(key_type)?]);
Ok(self.client.request("author_hasKey", params).await?)
}
}
/// Captures data for when an extrinsic is successfully included in a block
-1
View File
@@ -33,7 +33,6 @@ use crate::{
/// Event subscription simplifies filtering a storage change set stream for
/// events of interest.
#[allow(missing_debug_implementations)]
pub struct EventSubscription<T: Runtime> {
subscription: Subscription<StorageChangeSet<T::Hash>>,
decoder: EventsDecoder<T>,
+1 -1
View File
@@ -13,7 +13,7 @@ repository = "https://github.com/paritytech/substrate/"
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
futures = { version = "0.3.5", package = "futures" }
futures = "0.3.5"
log = "0.4.8"
structopt = "0.3.15"
parking_lot = "0.11.0"
-2
View File
@@ -235,8 +235,6 @@ impl system::Trait for Runtime {
type OnKilledAccount = ();
/// The data to be stored in an account.
type AccountData = balances::AccountData<Balance>;
/// The base call filter.
type BaseCallFilter = ();
}
impl aura::Trait for Runtime {