Staking support (#99)

* Initial Staking API

* Add more staking types

* Reformat

* Remove dead code

* Fix missing documentation

* Reformat

* Staking: use proc macros

* Add partial session support

* Reformat

* Try to implement nomination

This currently fails with compilation errors I do not understand.

* Use the #[module] macro

This fixes a compile error

* Explain undefined method diagnostics

* Use ‘#[module]’ and implement session for Kusama

* Don’t impl ‘Staking’ for all ‘T: System’

* Add staking payout support

* Fix compilation errors and remove useless lifetimes

* Respond to code review

This fixes most of the issues found during review, with the exception of
tests.

* Make signing fallable and asynchronous

This is needed for hardware wallets, which require human confirmation to
sign transactions.  Blocking on a human to sign transactions is not a
good idea, and the signing might fail for many reasons (device
unplugged, authorization not granted, etc).

* Reformat

* Refactor as suggested by Andrew Jones (@ascjones).

* Reformat

* Refactor as suggested by Andrew Jones (@ascjones).

* Trait cleanups

* Make the `Signer` impl require Send + Sync

This is what Ledgeracio needs.

* Use the correct key for staking maps

They use the key type, not ‘PhantomData’.

* Implement set_payee call

* Switch to associated types for Staking

* Implement `set_keys`

This is needed for Ledgeracio.

* Remove impl of Signer for Box<dyn Signer + Send + Sync>

It isn’t needed, since Box implements Deref.

* Fix Polkadot and Kusama ‘SessionKey’ structs

I had failed to include the ‘Parachains’ component, which the default
Substrate runtime doesn’t have.

* Include a copy of `ValidatorId`

This avoids needing to depend on Polkadot.

* Fix syntax error in Cargo.toml

* Fix compile errors

* Add Debug impls

* Fix return type of `BondedStore`

* Use some upstream type definitions

Also add `Default` impls.

* Bump deps and fix build

* Remove last reference to Kusama feature

* Fix compilation errors

* Implement the `concat` in `twox_64_concat`

* Expose properties and per-era preferences

* Era rewards point support

I also did some refactoring.

* Expose clipped exposure

* Era reward points support

* Make `PayoutStakersCall` public

* Add in all default features for debugging

* Chill support and update to latest Substrate

* If property fetch fails, use dummy values

* Fix tests

* Fix header

* Remove some code Ledgeracio does not need

* More deletions

* Remove more code not needed for Ledgeracio

* Remove a pointless change in Cargo.toml

w.r.t. upstream.

* Remove more junk

* Revert contracts put_code test to pure code (not using the macro)

* Test contract instantiate

* Fmt

* WIP

* Add some more submission tests

* Reformat

* More tests

* Cleanup

* Hopefully fix CI

* Remove dead code

* Test chill

* Add missing docs

* Remove unnecessary use

* Revert "Remove unnecessary use"

This reverts commit bc8bc36bde581f1892ea88a778dfe0fe5bff24d7.

* Retry on temporary failures

* Ignore the staking tests on CI

* Obey the fmt

* Run CI with at most one test thread

* Implement tests for staking

* More tests

* Remove unhelpful println!

* Revert changes in contract tests

* Reformat

* Remove spurious diff

* More tests

Co-authored-by: Demi M. Obenour <demiobenour@gmail.com>
Co-authored-by: David Palm <dvdplm@gmail.com>
Co-authored-by: Andrew Jones <ascjones@gmail.com>
This commit is contained in:
Demi Obenour
2020-09-21 17:15:46 +00:00
committed by GitHub
parent 0c7454dfcd
commit f9f69b8c3b
12 changed files with 606 additions and 4 deletions
+1 -1
View File
@@ -26,4 +26,4 @@ jobs:
run: cargo build --workspace --verbose
- name: test
run: cargo test --workspace --verbose
run: cargo test --workspace --verbose -- --test-threads=1
+12 -1
View File
@@ -17,6 +17,8 @@ keywords = ["parity", "substrate", "blockchain"]
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"]
[features]
kusama = []
default = ["kusama"]
client = ["substrate-subxt-client"]
# enable this feature to run tests which require a local dev chain node
@@ -31,7 +33,7 @@ num-traits = { version = "0.2.12", default-features = false }
serde = { version = "1.0.115", features = ["derive"] }
serde_json = "1.0.57"
url = "2.1.1"
codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive", "full"] }
codec = { package = "parity-scale-codec", version = "1.3.5", default-features = false, features = ["derive", "full"] }
frame-metadata = { version = "11.0.0-rc6", package = "frame-metadata" }
frame-support = { version = "2.0.0-rc6", package = "frame-support" }
@@ -39,6 +41,14 @@ sp-runtime = { version = "2.0.0-rc6", package = "sp-runtime" }
sp-version = { version = "2.0.0-rc6", package = "sp-version" }
pallet-indices = { version = "2.0.0-rc6", package = "pallet-indices" }
hex = "0.4.2"
sp-std = "2.0.0-rc6"
application-crypto = { version = "2.0.0-rc6", package = "sp-application-crypto" }
sp-finality-grandpa = "2.0.0-rc6"
sp-consensus-babe = "0.8.0-rc6"
pallet-im-online = "2.0.0-rc6"
sp-authority-discovery = "2.0.0-rc6"
pallet-staking = "2.0.0-rc6"
sp-rpc = { version = "2.0.0-rc6", package = "sp-rpc" }
sp-core = { version = "2.0.0-rc6", package = "sp-core" }
sc-rpc-api = { version = "0.8.0-rc6", package = "sc-rpc-api" }
@@ -56,3 +66,4 @@ substrate-subxt-client = { version = "0.4.0", path = "client" }
tempdir = "0.3.7"
test-node = { path = "test-node" }
wabt = "0.10.0"
assert_matches = "1.3"
+3
View File
@@ -6,6 +6,9 @@ A library to **sub**mit e**xt**rinsics to a [substrate](https://github.com/parit
See [examples](./examples).
If you use `#[derive(Call)]` without `#[module]` in the same module, you will get errors
complaining about an undefined method with a name starting with `with_`.
**Alternatives**
[substrate-api-client](https://github.com/scs/substrate-api-client) provides similar functionality.
+1
View File
@@ -54,6 +54,7 @@ pub trait Signer<T: Runtime> {
}
/// Extrinsic signer using a private key.
#[derive(Debug)]
pub struct PairSigner<T: Runtime, P: Pair> {
account_id: T::AccountId,
nonce: Option<T::Index>,
+2
View File
@@ -31,6 +31,8 @@ use sp_core::storage::StorageKey;
pub mod balances;
pub mod contracts;
pub mod session;
pub mod staking;
pub mod sudo;
pub mod system;
+75
View File
@@ -0,0 +1,75 @@
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
// This file is part of substrate-subxt.
//
// subxt is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// subxt is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with substrate-subxt. If not, see <http://www.gnu.org/licenses/>.
//! Session support
use crate::frame::system::{
System,
SystemEventsDecoder as _,
};
use codec::Encode;
use frame_support::Parameter;
use sp_runtime::traits::{
Member,
OpaqueKeys,
};
use std::{
fmt::Debug,
marker::PhantomData,
};
use substrate_subxt_proc_macro::Store;
/// Impls `Default::default` for some types that have a `_runtime` field of type
/// `PhantomData` as their only field.
macro_rules! default_impl {
($name:ident) => {
impl<T: Session> Default for $name<T> {
fn default() -> Self {
Self {
_runtime: PhantomData,
}
}
}
};
}
/// The trait needed for this module.
#[module]
pub trait Session: System {
/// The validator account identifier type for the runtime.
type ValidatorId: Parameter + Debug + Ord + Default + Send + Sync + 'static;
/// The keys.
type Keys: OpaqueKeys + Member + Parameter + Default;
}
/// The current set of validators.
#[derive(Encode, Store, Debug)]
pub struct ValidatorsStore<T: Session> {
#[store(returns = Vec<<T as Session>::ValidatorId>)]
/// Marker for the runtime
pub _runtime: PhantomData<T>,
}
default_impl!(ValidatorsStore);
/// Set the session keys for a validator.
#[derive(Encode, Call, Debug)]
pub struct SetKeysCall<T: Session> {
/// The keys
pub keys: T::Keys,
/// The proof. This is not currently used and can be set to an empty vector.
pub proof: Vec<u8>,
}
+371
View File
@@ -0,0 +1,371 @@
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
// This file is part of substrate-subxt.
//
// subxt is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// subxt is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with substrate-subxt. If not, see <http://www.gnu.org/licenses/>.
//! Implements support for the pallet_staking module.
use super::balances::{
Balances,
BalancesEventsDecoder as _,
};
use codec::{
Decode,
Encode,
};
use std::{
collections::BTreeMap,
fmt::Debug,
marker::PhantomData,
};
pub use pallet_staking::{
ActiveEraInfo,
EraIndex,
Exposure,
Nominations,
RewardDestination,
RewardPoint,
StakingLedger,
ValidatorPrefs,
};
/// Rewards for the last `HISTORY_DEPTH` eras.
/// If reward hasn't been set or has been removed then 0 reward is returned.
#[derive(Clone, Encode, Decode, Debug, Store)]
pub struct ErasRewardPointsStore<T: Staking> {
#[store(returns = EraRewardPoints<T::AccountId>)]
/// Era index
pub index: EraIndex,
/// Marker for the runtime
pub _phantom: PhantomData<T>,
}
/// Preference of what happens regarding validation.
#[derive(Clone, Encode, Decode, Debug, Call)]
pub struct SetPayeeCall<T: Staking> {
/// The payee
pub payee: RewardDestination,
/// Marker for the runtime
pub _runtime: PhantomData<T>,
}
/// The subset of the `frame::Trait` that a client must implement.
#[module]
pub trait Staking: Balances {}
/// Number of eras to keep in history.
///
/// Information is kept for eras in `[current_era - history_depth; current_era]`.
///
/// Must be more than the number of eras delayed by session otherwise.
/// I.e. active era must always be in history.
/// I.e. `active_era > current_era - history_depth` must be guaranteed.
#[derive(Encode, Decode, Copy, Clone, Debug, Default, Store)]
pub struct HistoryDepthStore<T: Staking> {
#[store(returns = u32)]
/// Marker for the runtime
pub _runtime: PhantomData<T>,
}
/// Map from all locked "stash" accounts to the controller account.
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store)]
pub struct BondedStore<T: Staking> {
#[store(returns = Option<T::AccountId>)]
/// Tٗhe stash account
pub stash: T::AccountId,
}
/// Map from all (unlocked) "controller" accounts to the info regarding the staking.
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store)]
pub struct LedgerStore<T: Staking> {
#[store(returns = Option<StakingLedger<T::AccountId, T::Balance>>)]
/// The controller account
pub controller: T::AccountId,
}
/// Where the reward payment should be made. Keyed by stash.
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store)]
pub struct PayeeStore<T: Staking> {
#[store(returns = RewardDestination)]
/// Tٗhe stash account
pub stash: T::AccountId,
}
/// The map from (wannabe) validator stash key to the preferences of that validator.
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd, Store)]
pub struct ValidatorsStore<T: Staking> {
#[store(returns = ValidatorPrefs)]
/// Tٗhe stash account
pub stash: T::AccountId,
}
/// The map from nominator stash key to the set of stash keys of all validators to nominate.
#[derive(Encode, Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Store)]
pub struct NominatorsStore<T: Staking> {
#[store(returns = Option<Nominations<T::AccountId>>)]
/// Tٗhe stash account
pub stash: T::AccountId,
}
/// The current era index.
///
/// This is the latest planned era, depending on how the Session pallet queues the validator
/// set, it might be active or not.
#[derive(Encode, Copy, Clone, Debug, Store)]
pub struct CurrentEraStore<T: Staking> {
#[store(returns = Option<EraIndex>)]
/// Marker for the runtime
pub _runtime: PhantomData<T>,
}
/// Reward points of an era. Used to split era total payout between validators.
///
/// This points will be used to reward validators and their respective nominators.
#[derive(PartialEq, Encode, Decode, Default, Debug)]
pub struct EraRewardPoints<AccountId: Ord> {
/// Total number of points. Equals the sum of reward points for each validator.
pub total: RewardPoint,
/// The reward points earned by a given validator.
pub individual: BTreeMap<AccountId, RewardPoint>,
}
/// Declare no desire to either validate or nominate.
///
/// Effective at the beginning of the next era.
///
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
/// Can only be called when [`EraElectionStatus`] is `Closed`.
#[derive(Debug, Call, Encode)]
pub struct ChillCall<T: Staking> {
/// Runtime marker
pub _runtime: PhantomData<T>,
}
impl<T: Staking> Default for ChillCall<T> {
fn default() -> Self {
Self {
_runtime: PhantomData,
}
}
}
impl<T: Staking> Clone for ChillCall<T> {
fn clone(&self) -> Self {
Self {
_runtime: self._runtime,
}
}
}
impl<T: Staking> Copy for ChillCall<T> {}
/// Declare the desire to validate for the origin controller.
///
/// Effective at the beginning of the next era.
///
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
/// Can only be called when [`EraElectionStatus`] is `Closed`.
#[derive(Clone, Debug, PartialEq, Call, Encode)]
pub struct ValidateCall<T: Staking> {
/// Runtime marker
pub _runtime: PhantomData<T>,
/// Validation preferences
pub prefs: ValidatorPrefs,
}
/// Declare the desire to nominate `targets` for the origin controller.
///
/// Effective at the beginning of the next era.
///
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
/// Can only be called when [`EraElectionStatus`] is `Closed`.
#[derive(Call, Encode, Debug)]
pub struct NominateCall<T: Staking> {
/// The targets that are being nominated
pub targets: Vec<T::Address>,
}
#[cfg(test)]
#[cfg(feature = "integration-tests")]
mod tests {
use super::*;
use crate::{
error::RuntimeError,
extrinsic::{
PairSigner,
Signer,
},
frame::balances::*,
runtimes::KusamaRuntime as RT,
ClientBuilder,
Error,
ExtrinsicSuccess,
};
use assert_matches::assert_matches;
use sp_core::{
sr25519,
Pair,
};
use sp_keyring::AccountKeyring;
/// Helper function to generate a crypto pair from seed
fn get_from_seed(seed: &str) -> sr25519::Pair {
sr25519::Pair::from_string(&format!("//{}", seed), None)
.expect("static values are valid; qed")
}
#[async_std::test]
async fn test_validate_with_controller_account() -> Result<(), Error> {
env_logger::try_init().ok();
let alice = PairSigner::<RT, _>::new(AccountKeyring::Alice.pair());
let client = ClientBuilder::<RT>::new().build().await?;
let announce_validator = client
.validate_and_watch(&alice, ValidatorPrefs::default())
.await;
assert_matches!(announce_validator, Ok(ExtrinsicSuccess {block: _, extrinsic: _, events}) => {
// TOOD: this is unsatisfying can we do better?
assert_eq!(events.len(), 3);
});
Ok(())
}
#[async_std::test]
async fn test_validate_not_possible_for_stash_account() -> Result<(), Error> {
env_logger::try_init().ok();
let alice_stash = PairSigner::<RT, _>::new(get_from_seed("Alice//stash"));
let client = ClientBuilder::<RT>::new().build().await?;
let announce_validator = client
.validate_and_watch(&alice_stash, ValidatorPrefs::default())
.await;
assert_matches!(announce_validator, Err(Error::Runtime(RuntimeError::Module(module_err))) => {
assert_eq!(module_err.module, "Staking");
assert_eq!(module_err.error, "NotController");
});
Ok(())
}
#[async_std::test]
async fn test_nominate_with_controller_account() -> Result<(), Error> {
env_logger::try_init().ok();
let alice = PairSigner::<RT, _>::new(AccountKeyring::Alice.pair());
let bob = PairSigner::<RT, _>::new(AccountKeyring::Bob.pair());
let client = ClientBuilder::<RT>::new().build().await?;
let nomination = client
.nominate_and_watch(&alice, vec![bob.account_id().clone()])
.await;
assert_matches!(nomination, Ok(ExtrinsicSuccess {block: _, extrinsic: _, events}) => {
// TOOD: this is unsatisfying can we do better?
assert_eq!(events.len(), 3);
});
Ok(())
}
#[async_std::test]
async fn test_nominate_not_possible_for_stash_account() -> Result<(), Error> {
env_logger::try_init().ok();
let alice_stash =
PairSigner::<RT, sr25519::Pair>::new(get_from_seed("Alice//stash"));
let bob = PairSigner::<RT, _>::new(AccountKeyring::Bob.pair());
let client = ClientBuilder::<RT>::new().build().await?;
let nomination = client
.nominate_and_watch(&alice_stash, vec![bob.account_id().clone()])
.await;
assert_matches!(nomination, Err(Error::Runtime(RuntimeError::Module(module_err))) => {
assert_eq!(module_err.module, "Staking");
assert_eq!(module_err.error, "NotController");
});
Ok(())
}
#[async_std::test]
async fn test_chill_works_for_controller_only() -> Result<(), Error> {
env_logger::try_init().ok();
let alice_stash =
PairSigner::<RT, sr25519::Pair>::new(get_from_seed("Alice//stash"));
let bob_stash = PairSigner::<RT, sr25519::Pair>::new(get_from_seed("Bob//stash"));
let alice = PairSigner::<RT, _>::new(AccountKeyring::Alice.pair());
let client = ClientBuilder::<RT>::new().build().await?;
// this will fail the second time, which is why this is one test, not two
client
.nominate_and_watch(&alice, vec![bob_stash.account_id().clone()])
.await?;
let store = LedgerStore {
controller: alice.account_id().clone(),
};
let StakingLedger { stash, .. } = client.fetch(&store, None).await?.unwrap();
assert_eq!(alice_stash.account_id(), &stash);
let chill = client.chill_and_watch(&alice_stash).await;
assert_matches!(chill, Err(Error::Runtime(RuntimeError::Module(module_err))) => {
assert_eq!(module_err.module, "Staking");
assert_eq!(module_err.error, "NotController");
});
let chill = client.chill_and_watch(&alice).await;
assert_matches!(chill, Ok(ExtrinsicSuccess {block: _, extrinsic: _, events}) => {
// TOOD: this is unsatisfying can we do better?
assert_eq!(events.len(), 3);
});
Ok(())
}
#[async_std::test]
async fn test_total_issuance_is_okay() -> Result<(), Error> {
env_logger::try_init().ok();
let client = ClientBuilder::<RT>::new().build().await?;
let total_issuance = client.total_issuance(None).await?;
assert!(total_issuance > 1u128 << 32);
Ok(())
}
#[async_std::test]
async fn test_history_depth_is_okay() -> Result<(), Error> {
env_logger::try_init().ok();
let client = ClientBuilder::<RT>::new().build().await?;
let history_depth = client.history_depth(None).await?;
assert_eq!(history_depth, 84);
Ok(())
}
#[async_std::test]
async fn test_current_era_is_okay() -> Result<(), Error> {
env_logger::try_init().ok();
let client = ClientBuilder::<RT>::new().build().await?;
let _current_era = client
.current_era(None)
.await?
.expect("current era always exists");
Ok(())
}
#[async_std::test]
async fn test_era_reward_points_is_okay() -> Result<(), Error> {
env_logger::try_init().ok();
let client = ClientBuilder::<RT>::new().build().await?;
let store = ErasRewardPointsStore {
_phantom: PhantomData,
index: 0,
};
let _current_era = client
.fetch(&store, None)
.await?
.expect("current era always exists");
Ok(())
}
}
+2
View File
@@ -101,6 +101,8 @@ pub trait System {
+ MaybeSerialize
+ Debug
+ MaybeDisplay
+ Encode
+ Decode
+ Ord
+ Default;
+13 -2
View File
@@ -35,7 +35,8 @@
while_true,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates
unused_extern_crates,
clippy::all
)]
#![allow(clippy::type_complexity)]
@@ -93,6 +94,7 @@ pub use crate::{
rpc::{
BlockNumber,
ExtrinsicSuccess,
SystemProperties,
},
runtimes::*,
subscription::*,
@@ -161,16 +163,18 @@ impl<T: Runtime> ClientBuilder<T> {
}
};
let rpc = Rpc::new(client);
let (metadata, genesis_hash, runtime_version) = future::join3(
let (metadata, genesis_hash, runtime_version, properties) = future::join4(
rpc.metadata(),
rpc.genesis_hash(),
rpc.runtime_version(None),
rpc.system_properties(),
)
.await;
Ok(Client {
rpc,
genesis_hash: genesis_hash?,
metadata: metadata?,
properties: properties.unwrap_or_else(|_| Default::default()),
runtime_version: runtime_version?,
_marker: PhantomData,
page_size: self.page_size.unwrap_or(10),
@@ -183,6 +187,7 @@ pub struct Client<T: Runtime> {
rpc: Rpc<T>,
genesis_hash: T::Hash,
metadata: Metadata,
properties: SystemProperties,
runtime_version: RuntimeVersion,
_marker: PhantomData<(fn() -> T::Signature, T::Extra)>,
page_size: u32,
@@ -194,6 +199,7 @@ impl<T: Runtime> Clone for Client<T> {
rpc: self.rpc.clone(),
genesis_hash: self.genesis_hash,
metadata: self.metadata.clone(),
properties: self.properties.clone(),
runtime_version: self.runtime_version.clone(),
_marker: PhantomData,
page_size: self.page_size,
@@ -258,6 +264,11 @@ impl<T: Runtime> Client<T> {
&self.metadata
}
/// Returns the system properties
pub fn properties(&self) -> &SystemProperties {
&self.properties
}
/// Fetch the value under an unhashed storage key
pub async fn fetch_unhashed<V: Decode>(
&self,
+20
View File
@@ -96,6 +96,18 @@ impl From<u32> for BlockNumber {
}
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, Default)]
#[serde(rename_all = "camelCase")]
/// System properties for a Substrate-based runtime
pub struct SystemProperties {
/// The address format
pub ss58_format: u8,
/// The number of digits after the decimal point in the native token
pub token_decimals: u8,
/// The symbol of the native token
pub token_symbol: String,
}
/// Client for substrate rpc interfaces
pub struct Rpc<T: Runtime> {
client: Client,
@@ -208,6 +220,14 @@ impl<T: Runtime> Rpc<T> {
Ok(metadata)
}
/// Fetch system properties
pub async fn system_properties(&self) -> Result<SystemProperties, Error> {
Ok(self
.client
.request("system_properties", Params::None)
.await?)
}
/// Get a header
pub async fn header(
&self,
+105
View File
@@ -15,8 +15,10 @@
// along with substrate-subxt. If not, see <http://www.gnu.org/licenses/>.
use codec::Encode;
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use sp_runtime::{
generic::Header,
impl_opaque_keys,
traits::{
BlakeTwo256,
IdentifyAccount,
@@ -25,6 +27,88 @@ use sp_runtime::{
MultiSignature,
OpaqueExtrinsic,
};
use sp_std::prelude::*;
/// BABE marker struct
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Babe;
impl sp_runtime::BoundToRuntimeAppPublic for Babe {
type Public = sp_consensus_babe::AuthorityId;
}
/// ImOnline marker struct
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ImOnline;
impl sp_runtime::BoundToRuntimeAppPublic for ImOnline {
type Public = ImOnlineId;
}
/// GRANDPA marker struct
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Grandpa;
impl sp_runtime::BoundToRuntimeAppPublic for Grandpa {
type Public = sp_finality_grandpa::AuthorityId;
}
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
#[cfg(feature = "kusama")]
mod validator_app {
use application_crypto::{
app_crypto,
sr25519,
};
app_crypto!(sr25519, sp_core::crypto::KeyTypeId(*b"para"));
}
/// Parachain marker struct
#[cfg(feature = "kusama")]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Parachains;
#[cfg(feature = "kusama")]
impl sp_runtime::BoundToRuntimeAppPublic for Parachains {
type Public = validator_app::Public;
}
/// Authority discovery marker struct
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AuthorityDiscovery;
impl sp_runtime::BoundToRuntimeAppPublic for AuthorityDiscovery {
type Public = AuthorityDiscoveryId;
}
impl_opaque_keys! {
/// Substrate base runtime keys
pub struct BasicSessionKeys {
/// GRANDPA session key
pub grandpa: Grandpa,
/// BABE session key
pub babe: Babe,
/// ImOnline session key
pub im_online: ImOnline,
/// Parachain validation session key
pub parachains: Parachains,
/// AuthorityDiscovery session key
pub authority_discovery: AuthorityDiscovery,
}
}
impl_opaque_keys! {
/// Polkadot/Kusama runtime keys
pub struct SessionKeys {
/// GRANDPA session key
pub grandpa: Grandpa,
/// BABE session key
pub babe: Babe,
/// ImOnline session key
pub im_online: ImOnline,
/// ParachainValidator session key
pub parachain_validator: Parachains,
/// AuthorityDiscovery session key
pub authority_discovery: AuthorityDiscovery,
}
}
use crate::{
extrinsic::{
@@ -37,6 +121,8 @@ use crate::{
Balances,
},
contracts::Contracts,
session::Session,
staking::Staking,
sudo::Sudo,
system::System,
},
@@ -59,6 +145,8 @@ pub trait Runtime: System + Sized + Send + Sync + 'static {
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct DefaultNodeRuntime;
impl Staking for DefaultNodeRuntime {}
impl Runtime for DefaultNodeRuntime {
type Signature = MultiSignature;
type Extra = DefaultExtra<Self>;
@@ -80,6 +168,11 @@ impl Balances for DefaultNodeRuntime {
type Balance = u128;
}
impl Session for DefaultNodeRuntime {
type ValidatorId = <Self as System>::AccountId;
type Keys = BasicSessionKeys;
}
impl Contracts for DefaultNodeRuntime {}
impl Sudo for DefaultNodeRuntime {}
@@ -114,6 +207,11 @@ impl Balances for NodeTemplateRuntime {
type Balance = u128;
}
impl Session for NodeTemplateRuntime {
type ValidatorId = <Self as System>::AccountId;
type Keys = BasicSessionKeys;
}
impl Sudo for NodeTemplateRuntime {}
/// Concrete type definitions compatible with the node template, with the
@@ -175,6 +273,13 @@ impl System for KusamaRuntime {
type AccountData = AccountData<<Self as Balances>::Balance>;
}
impl Session for KusamaRuntime {
type ValidatorId = <Self as System>::AccountId;
type Keys = SessionKeys;
}
impl Staking for KusamaRuntime {}
impl Balances for KusamaRuntime {
type Balance = u128;
}
+1
View File
@@ -20,6 +20,7 @@ pallet-aura = { version = "2.0.0-rc6", default-features = false }
pallet-balances = { version = "2.0.0-rc6", default-features = false }
pallet-grandpa = { version = "2.0.0-rc6", default-features = false }
pallet-randomness-collective-flip = { version = "2.0.0-rc6", default-features = false }
pallet-staking = { version = "2.0.0-rc6", default-features = false }
pallet-sudo = { version = "2.0.0-rc6", default-features = false }
pallet-timestamp = { version = "2.0.0-rc6", default-features = false }
pallet-transaction-payment = { version = "2.0.0-rc6", default-features = false }