mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-24 20:41:14 +00:00
Use BABE instead of AuRa in node (#3171)
* babe: add babe module trait * babe: track current slot and epoch start slot * babe: implement ShouldEndSession based on epochs * babe: rename weight type to avoid ambiguities * babe: expose epoch start slot in Epoch digest * babe: use epoch start for validating epoch transitions * babe: make the epoch duration a parameter type * babe: remove unused fields from config * node: update runtime to use babe instead of aura * node: use babe instead of aura * core: generate sr25519 keys from seed and add to keystore * core: remove AuthorityKeyring * node: remove unused primitive types related to babe crypto * uniform babe primitives crate import name * wrap long lines * babe: fix find_epoch_digest * fork-tree: fix find_node_where * node: set babe epoch duration to "10 minutes" * babe: cleanup import key cache if authorities don't change * node: make integration test compile (but fail) * node: bump spec_version * node: fix import * babe: don't use constants in storage fields array sizes * babe: account for first epoch slot way in the past * babe: signal next epoch change (not current) * babe: calculate next epoch randomness with next epoch index * babe: track next epoch in node * babe: cache current epoch and authorities separately * babe: generate valid babe vrf proofs in integration test * babe: cleanup claim_slot * babe: perform threshold calculation according to spec * babe: compute relative weight in threshold * babe: more precise threshold calculation * babe: use floats for threshold exponent calculation * babe: update constant c
This commit is contained in:
committed by
DemiMarie-parity
parent
407970406d
commit
9f50c8fce4
Generated
+29
-4
@@ -2274,8 +2274,8 @@ dependencies = [
|
|||||||
"substrate-basic-authorship 2.0.0",
|
"substrate-basic-authorship 2.0.0",
|
||||||
"substrate-cli 2.0.0",
|
"substrate-cli 2.0.0",
|
||||||
"substrate-client 2.0.0",
|
"substrate-client 2.0.0",
|
||||||
"substrate-consensus-aura 2.0.0",
|
"substrate-consensus-babe 2.0.0",
|
||||||
"substrate-consensus-aura-primitives 2.0.0",
|
"substrate-consensus-babe-primitives 2.0.0",
|
||||||
"substrate-consensus-common 2.0.0",
|
"substrate-consensus-common 2.0.0",
|
||||||
"substrate-finality-grandpa 2.0.0",
|
"substrate-finality-grandpa 2.0.0",
|
||||||
"substrate-finality-grandpa-primitives 2.0.0",
|
"substrate-finality-grandpa-primitives 2.0.0",
|
||||||
@@ -2360,8 +2360,8 @@ dependencies = [
|
|||||||
"sr-primitives 2.0.0",
|
"sr-primitives 2.0.0",
|
||||||
"sr-std 2.0.0",
|
"sr-std 2.0.0",
|
||||||
"sr-version 2.0.0",
|
"sr-version 2.0.0",
|
||||||
"srml-aura 2.0.0",
|
|
||||||
"srml-authorship 0.1.0",
|
"srml-authorship 0.1.0",
|
||||||
|
"srml-babe 2.0.0",
|
||||||
"srml-balances 2.0.0",
|
"srml-balances 2.0.0",
|
||||||
"srml-collective 2.0.0",
|
"srml-collective 2.0.0",
|
||||||
"srml-contracts 2.0.0",
|
"srml-contracts 2.0.0",
|
||||||
@@ -2380,7 +2380,7 @@ dependencies = [
|
|||||||
"srml-timestamp 2.0.0",
|
"srml-timestamp 2.0.0",
|
||||||
"srml-treasury 2.0.0",
|
"srml-treasury 2.0.0",
|
||||||
"substrate-client 2.0.0",
|
"substrate-client 2.0.0",
|
||||||
"substrate-consensus-aura-primitives 2.0.0",
|
"substrate-consensus-babe-primitives 2.0.0",
|
||||||
"substrate-keyring 2.0.0",
|
"substrate-keyring 2.0.0",
|
||||||
"substrate-offchain-primitives 2.0.0",
|
"substrate-offchain-primitives 2.0.0",
|
||||||
"substrate-primitives 2.0.0",
|
"substrate-primitives 2.0.0",
|
||||||
@@ -2460,6 +2460,15 @@ dependencies = [
|
|||||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.41"
|
version = "0.1.41"
|
||||||
@@ -2469,6 +2478,17 @@ dependencies = [
|
|||||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
@@ -4335,6 +4355,9 @@ dependencies = [
|
|||||||
"futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"merlin 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"merlin 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -6153,7 +6176,9 @@ dependencies = [
|
|||||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||||
"checksum nohash-hasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d138afcce92d219ccb6eb53d9b1e8a96ac0d633cfd3c53cd9856d96d1741bb8"
|
"checksum nohash-hasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d138afcce92d219ccb6eb53d9b1e8a96ac0d633cfd3c53cd9856d96d1741bb8"
|
||||||
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||||
|
"checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718"
|
||||||
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
|
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
|
||||||
|
"checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454"
|
||||||
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||||
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
|
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
|
||||||
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||||
|
|||||||
@@ -431,15 +431,15 @@ struct KeyringTestAccountCliValues {
|
|||||||
help: String,
|
help: String,
|
||||||
conflicts_with: Vec<String>,
|
conflicts_with: Vec<String>,
|
||||||
name: String,
|
name: String,
|
||||||
variant: keyring::AuthorityKeyring,
|
variant: keyring::Sr25519Keyring,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
/// The Cli values for all test accounts.
|
/// The Cli values for all test accounts.
|
||||||
static ref TEST_ACCOUNTS_CLI_VALUES: Vec<KeyringTestAccountCliValues> = {
|
static ref TEST_ACCOUNTS_CLI_VALUES: Vec<KeyringTestAccountCliValues> = {
|
||||||
keyring::AuthorityKeyring::iter().map(|a| {
|
keyring::Sr25519Keyring::iter().map(|a| {
|
||||||
let help = format!("Shortcut for `--key //{} --name {}`.", a, a);
|
let help = format!("Shortcut for `--key //{} --name {}`.", a, a);
|
||||||
let conflicts_with = keyring::AuthorityKeyring::iter()
|
let conflicts_with = keyring::Sr25519Keyring::iter()
|
||||||
.filter(|b| a != *b)
|
.filter(|b| a != *b)
|
||||||
.map(|b| b.to_string().to_lowercase())
|
.map(|b| b.to_string().to_lowercase())
|
||||||
.chain(["name", "key"].iter().map(ToString::to_string))
|
.chain(["name", "key"].iter().map(ToString::to_string))
|
||||||
@@ -459,7 +459,7 @@ lazy_static::lazy_static! {
|
|||||||
/// Wrapper for exposing the keyring test accounts into the Cli.
|
/// Wrapper for exposing the keyring test accounts into the Cli.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Keyring {
|
pub struct Keyring {
|
||||||
pub account: Option<keyring::AuthorityKeyring>,
|
pub account: Option<keyring::Sr25519Keyring>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructOpt for Keyring {
|
impl StructOpt for Keyring {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ mod tests {
|
|||||||
use test_client::{
|
use test_client::{
|
||||||
runtime::genesismap::{GenesisConfig, additional_storage_with_genesis},
|
runtime::genesismap::{GenesisConfig, additional_storage_with_genesis},
|
||||||
runtime::{Hash, Transfer, Block, BlockNumber, Header, Digest},
|
runtime::{Hash, Transfer, Block, BlockNumber, Header, Digest},
|
||||||
AccountKeyring, AuthorityKeyring
|
AccountKeyring, Sr25519Keyring,
|
||||||
};
|
};
|
||||||
use runtime_primitives::traits::BlakeTwo256;
|
use runtime_primitives::traits::BlakeTwo256;
|
||||||
use primitives::Blake2Hasher;
|
use primitives::Blake2Hasher;
|
||||||
@@ -147,7 +147,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn construct_genesis_should_work_with_native() {
|
fn construct_genesis_should_work_with_native() {
|
||||||
let mut storage = GenesisConfig::new(false,
|
let mut storage = GenesisConfig::new(false,
|
||||||
vec![AuthorityKeyring::One.into(), AuthorityKeyring::Two.into()],
|
vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()],
|
||||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||||
1000
|
1000
|
||||||
).genesis_map();
|
).genesis_map();
|
||||||
@@ -176,7 +176,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn construct_genesis_should_work_with_wasm() {
|
fn construct_genesis_should_work_with_wasm() {
|
||||||
let mut storage = GenesisConfig::new(false,
|
let mut storage = GenesisConfig::new(false,
|
||||||
vec![AuthorityKeyring::One.into(), AuthorityKeyring::Two.into()],
|
vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()],
|
||||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||||
1000
|
1000
|
||||||
).genesis_map();
|
).genesis_map();
|
||||||
@@ -205,7 +205,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn construct_genesis_with_bad_transaction_should_panic() {
|
fn construct_genesis_with_bad_transaction_should_panic() {
|
||||||
let mut storage = GenesisConfig::new(false,
|
let mut storage = GenesisConfig::new(false,
|
||||||
vec![AuthorityKeyring::One.into(), AuthorityKeyring::Two.into()],
|
vec![Sr25519Keyring::One.into(), Sr25519Keyring::Two.into()],
|
||||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||||
68
|
68
|
||||||
).genesis_map();
|
).genesis_map();
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parity-codec = { version = "4.1.1", features = ["derive"] }
|
parity-codec = { version = "4.1.1", features = ["derive"] }
|
||||||
babe_primitives = { package = "substrate-consensus-babe-primitives", path = "primitives" }
|
babe-primitives = { package = "substrate-consensus-babe-primitives", path = "primitives" }
|
||||||
primitives = { package = "substrate-primitives", path = "../../primitives" }
|
primitives = { package = "substrate-primitives", path = "../../primitives" }
|
||||||
|
num-bigint = "0.2"
|
||||||
|
num-rational = "0.2"
|
||||||
|
num-traits = "0.2"
|
||||||
runtime_support = { package = "srml-support", path = "../../../srml/support" }
|
runtime_support = { package = "srml-support", path = "../../../srml/support" }
|
||||||
runtime_version = { package = "sr-version", path = "../../sr-version" }
|
runtime_version = { package = "sr-version", path = "../../sr-version" }
|
||||||
runtime_io = { package = "sr-io", path = "../../sr-io" }
|
runtime_io = { package = "sr-io", path = "../../sr-io" }
|
||||||
@@ -37,3 +40,6 @@ service = { package = "substrate-service", path = "../../service" }
|
|||||||
test-client = { package = "substrate-test-runtime-client", path = "../../test-runtime/client" }
|
test-client = { package = "substrate-test-runtime-client", path = "../../test-runtime/client" }
|
||||||
tokio = "0.1.18"
|
tokio = "0.1.18"
|
||||||
env_logger = "0.6.1"
|
env_logger = "0.6.1"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
test-helpers = []
|
||||||
|
|||||||
@@ -24,16 +24,21 @@ mod digest;
|
|||||||
use parity_codec::{Encode, Decode};
|
use parity_codec::{Encode, Decode};
|
||||||
use rstd::vec::Vec;
|
use rstd::vec::Vec;
|
||||||
use runtime_primitives::ConsensusEngineId;
|
use runtime_primitives::ConsensusEngineId;
|
||||||
use substrate_primitives::sr25519::Public;
|
use substrate_primitives::sr25519;
|
||||||
use substrate_client::decl_runtime_apis;
|
use substrate_client::decl_runtime_apis;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use digest::{BabePreDigest, CompatibleDigestItem};
|
pub use digest::{BabePreDigest, CompatibleDigestItem};
|
||||||
pub use digest::{BABE_VRF_PREFIX, RawBabePreDigest};
|
pub use digest::{BABE_VRF_PREFIX, RawBabePreDigest};
|
||||||
|
|
||||||
|
/// A Babe authority keypair. Necessarily equivalent to the schnorrkel public key used in
|
||||||
|
/// the main Babe module. If that ever changes, then this must, too.
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub type AuthorityPair = sr25519::Pair;
|
||||||
|
|
||||||
/// A Babe authority identifier. Necessarily equivalent to the schnorrkel public key used in
|
/// A Babe authority identifier. Necessarily equivalent to the schnorrkel public key used in
|
||||||
/// the main Babe module. If that ever changes, then this must, too.
|
/// the main Babe module. If that ever changes, then this must, too.
|
||||||
pub type AuthorityId = Public;
|
pub type AuthorityId = sr25519::Public;
|
||||||
|
|
||||||
/// The `ConsensusEngineId` of BABE.
|
/// The `ConsensusEngineId` of BABE.
|
||||||
pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE";
|
pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE";
|
||||||
@@ -54,20 +59,24 @@ pub type AuthorityIndex = u64;
|
|||||||
pub type SlotNumber = u64;
|
pub type SlotNumber = u64;
|
||||||
|
|
||||||
/// The weight of an authority.
|
/// The weight of an authority.
|
||||||
pub type Weight = u64;
|
// NOTE: we use a unique name for the weight to avoid conflicts with other
|
||||||
|
// `Weight` types, since the metadata isn't able to disambiguate.
|
||||||
|
pub type BabeWeight = u64;
|
||||||
|
|
||||||
/// BABE epoch information
|
/// BABE epoch information
|
||||||
#[derive(Decode, Encode, Default, PartialEq, Eq, Clone)]
|
#[derive(Decode, Encode, Default, PartialEq, Eq, Clone)]
|
||||||
#[cfg_attr(any(feature = "std", test), derive(Debug))]
|
#[cfg_attr(any(feature = "std", test), derive(Debug))]
|
||||||
pub struct Epoch {
|
pub struct Epoch {
|
||||||
/// The authorities and their weights
|
|
||||||
pub authorities: Vec<(AuthorityId, Weight)>,
|
|
||||||
/// The epoch index
|
/// The epoch index
|
||||||
pub epoch_index: u64,
|
pub epoch_index: u64,
|
||||||
/// Randomness for this epoch
|
/// The starting slot of the epoch,
|
||||||
pub randomness: [u8; VRF_OUTPUT_LENGTH],
|
pub start_slot: u64,
|
||||||
/// The duration of this epoch
|
/// The duration of this epoch
|
||||||
pub duration: SlotNumber,
|
pub duration: SlotNumber,
|
||||||
|
/// The authorities and their weights
|
||||||
|
pub authorities: Vec<(AuthorityId, BabeWeight)>,
|
||||||
|
/// Randomness for this epoch
|
||||||
|
pub randomness: [u8; VRF_OUTPUT_LENGTH],
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An consensus log item for BABE.
|
/// An consensus log item for BABE.
|
||||||
@@ -93,23 +102,10 @@ pub struct BabeConfiguration {
|
|||||||
/// Dynamic slot duration may be supported in the future.
|
/// Dynamic slot duration may be supported in the future.
|
||||||
pub slot_duration: u64,
|
pub slot_duration: u64,
|
||||||
|
|
||||||
/// The number of slots per BABE epoch. Currently, only
|
/// A constant value that is used in the threshold calculation formula.
|
||||||
/// the value provided by this type at genesis will be used.
|
/// Expressed as a fraction where the first member of the tuple is the
|
||||||
///
|
/// numerator and the second is the denominator.
|
||||||
/// Dynamic slot duration may be supported in the future.
|
pub c: (u64, u64),
|
||||||
pub slots_per_epoch: u64,
|
|
||||||
|
|
||||||
/// The expected block time in milliseconds for BABE. Currently,
|
|
||||||
/// only the value provided by this type at genesis will be used.
|
|
||||||
///
|
|
||||||
/// Dynamic expected block time may be supported in the future.
|
|
||||||
pub expected_block_time: u64,
|
|
||||||
|
|
||||||
/// The maximum permitted VRF output, or *threshold*, for BABE. Currently,
|
|
||||||
/// only the value provided by this type at genesis will be used.
|
|
||||||
///
|
|
||||||
/// Dynamic thresholds may be supported in the future.
|
|
||||||
pub threshold: u64,
|
|
||||||
|
|
||||||
/// The minimum number of blocks that must be received before running the
|
/// The minimum number of blocks that must be received before running the
|
||||||
/// median algorithm to compute the offset between the on-chain time and the
|
/// median algorithm to compute the offset between the on-chain time and the
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use consensus_common::import_queue::{
|
|||||||
BoxJustificationImport, BoxFinalityProofImport,
|
BoxJustificationImport, BoxFinalityProofImport,
|
||||||
};
|
};
|
||||||
use consensus_common::well_known_cache_keys::Id as CacheKeyId;
|
use consensus_common::well_known_cache_keys::Id as CacheKeyId;
|
||||||
use runtime_primitives::{generic, generic::BlockId, Justification};
|
use runtime_primitives::{generic, generic::{BlockId, OpaqueDigestItemId}, Justification};
|
||||||
use runtime_primitives::traits::{
|
use runtime_primitives::traits::{
|
||||||
Block as BlockT, Header, DigestItemFor, NumberFor, ProvideRuntimeApi,
|
Block as BlockT, Header, DigestItemFor, NumberFor, ProvideRuntimeApi,
|
||||||
SimpleBitOps, Zero,
|
SimpleBitOps, Zero,
|
||||||
@@ -114,9 +114,9 @@ impl Config {
|
|||||||
self.0.slot_duration
|
self.0.slot_duration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the threshold for BABE
|
/// Retrieve the threshold calculation constant `c`.
|
||||||
pub fn threshold(&self) -> u64 {
|
pub fn c(&self) -> (u64, u64) {
|
||||||
self.0.threshold
|
self.0.c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ pub fn start_babe<B, C, SC, E, I, SO, Error, H>(BabeParams {
|
|||||||
local_key,
|
local_key,
|
||||||
sync_oracle: sync_oracle.clone(),
|
sync_oracle: sync_oracle.clone(),
|
||||||
force_authoring,
|
force_authoring,
|
||||||
threshold: config.threshold(),
|
c: config.c(),
|
||||||
};
|
};
|
||||||
register_babe_inherent_data_provider(&inherent_data_providers, config.0.slot_duration())?;
|
register_babe_inherent_data_provider(&inherent_data_providers, config.0.slot_duration())?;
|
||||||
Ok(slots::start_slot_worker(
|
Ok(slots::start_slot_worker(
|
||||||
@@ -224,7 +224,7 @@ struct BabeWorker<C, E, I, SO> {
|
|||||||
local_key: Arc<sr25519::Pair>,
|
local_key: Arc<sr25519::Pair>,
|
||||||
sync_oracle: SO,
|
sync_oracle: SO,
|
||||||
force_authoring: bool,
|
force_authoring: bool,
|
||||||
threshold: u64,
|
c: (u64, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> where
|
impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> where
|
||||||
@@ -273,7 +273,7 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let Epoch { ref authorities, randomness, epoch_index, .. } = epoch;
|
let Epoch { ref authorities, .. } = epoch;
|
||||||
|
|
||||||
if authorities.is_empty() {
|
if authorities.is_empty() {
|
||||||
error!(target: "babe", "No authorities at block {:?}", chain_head.hash());
|
error!(target: "babe", "No authorities at block {:?}", chain_head.hash());
|
||||||
@@ -287,14 +287,14 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
|||||||
return Box::new(future::ok(()));
|
return Box::new(future::ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let proposal_work = if let Some(((inout, vrf_proof, _batchable_proof), authority_index)) = claim_slot(
|
let proposal_work = if let Some(claim) = claim_slot(
|
||||||
&randomness,
|
|
||||||
slot_info.number,
|
slot_info.number,
|
||||||
epoch_index,
|
|
||||||
epoch,
|
epoch,
|
||||||
&pair,
|
&pair,
|
||||||
self.threshold,
|
self.c,
|
||||||
) {
|
) {
|
||||||
|
let ((inout, vrf_proof, _batchable_proof), authority_index) = claim;
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
target: "babe", "Starting authorship at slot {}; timestamp = {}",
|
target: "babe", "Starting authorship at slot {}; timestamp = {}",
|
||||||
slot_number,
|
slot_number,
|
||||||
@@ -308,7 +308,11 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
|||||||
let proposer = match env.init(&chain_head) {
|
let proposer = match env.init(&chain_head) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!(target: "babe", "Unable to author block in slot {:?}: {:?}", slot_number, e);
|
warn!(target: "babe",
|
||||||
|
"Unable to author block in slot {:?}: {:?}",
|
||||||
|
slot_number,
|
||||||
|
e,
|
||||||
|
);
|
||||||
telemetry!(CONSENSUS_WARN; "babe.unable_authoring_block";
|
telemetry!(CONSENSUS_WARN; "babe.unable_authoring_block";
|
||||||
"slot" => slot_number, "err" => ?e
|
"slot" => slot_number, "err" => ?e
|
||||||
);
|
);
|
||||||
@@ -367,11 +371,6 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
|||||||
let signature = pair.sign(header_hash.as_ref());
|
let signature = pair.sign(header_hash.as_ref());
|
||||||
let signature_digest_item = DigestItemFor::<B>::babe_seal(signature);
|
let signature_digest_item = DigestItemFor::<B>::babe_seal(signature);
|
||||||
|
|
||||||
let cache = find_epoch_digest::<B>(&header)
|
|
||||||
.map(|epoch| vec![(well_known_cache_keys::AUTHORITIES, epoch.encode())])
|
|
||||||
.map(|keys| keys.into_iter().collect())
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let import_block = BlockImportParams::<B> {
|
let import_block = BlockImportParams::<B> {
|
||||||
origin: BlockOrigin::Own,
|
origin: BlockOrigin::Own,
|
||||||
header,
|
header,
|
||||||
@@ -396,7 +395,7 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
|||||||
"hash_previously" => ?header_hash,
|
"hash_previously" => ?header_hash,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Err(e) = block_import.lock().import_block(import_block, cache) {
|
if let Err(e) = block_import.lock().import_block(import_block, Default::default()) {
|
||||||
warn!(target: "babe", "Error with block built on {:?}: {:?}",
|
warn!(target: "babe", "Error with block built on {:?}: {:?}",
|
||||||
parent_hash, e);
|
parent_hash, e);
|
||||||
telemetry!(CONSENSUS_WARN; "babe.err_with_block_built_on";
|
telemetry!(CONSENSUS_WARN; "babe.err_with_block_built_on";
|
||||||
@@ -423,26 +422,34 @@ macro_rules! babe_err {
|
|||||||
fn find_pre_digest<B: BlockT>(header: &B::Header) -> Result<BabePreDigest, String>
|
fn find_pre_digest<B: BlockT>(header: &B::Header) -> Result<BabePreDigest, String>
|
||||||
where DigestItemFor<B>: CompatibleDigestItem,
|
where DigestItemFor<B>: CompatibleDigestItem,
|
||||||
{
|
{
|
||||||
|
let mut pre_digest: Option<_> = None;
|
||||||
for log in header.digest().logs() {
|
for log in header.digest().logs() {
|
||||||
if let Some(pre_digest) = log.as_babe_pre_digest() {
|
trace!(target: "babe", "Checking log {:?}, looking for pre runtime digest", log);
|
||||||
return Ok(pre_digest);
|
match (log.as_babe_pre_digest(), pre_digest.is_some()) {
|
||||||
|
(Some(_), true) => Err(babe_err!("Multiple BABE pre-runtime digests, rejecting!"))?,
|
||||||
|
(None, _) => trace!(target: "babe", "Ignoring digest not meant for us"),
|
||||||
|
(s, false) => pre_digest = s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pre_digest.ok_or_else(|| babe_err!("No BABE pre-runtime digest found"))
|
||||||
Err(babe_err!("No BABE pre-runtime digest found"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract the BABE epoch change digest from the given header, if it exists.
|
/// Extract the BABE epoch change digest from the given header, if it exists.
|
||||||
fn find_epoch_digest<B: BlockT>(header: &B::Header) -> Option<Epoch>
|
fn find_next_epoch_digest<B: BlockT>(header: &B::Header) -> Result<Option<Epoch>, String>
|
||||||
where DigestItemFor<B>: CompatibleDigestItem,
|
where DigestItemFor<B>: CompatibleDigestItem,
|
||||||
{
|
{
|
||||||
|
let mut epoch_digest: Option<_> = None;
|
||||||
for log in header.digest().logs() {
|
for log in header.digest().logs() {
|
||||||
if let Some(epoch_digest) = log.as_babe_epoch() {
|
trace!(target: "babe", "Checking log {:?}, looking for epoch change digest.", log);
|
||||||
return Some(epoch_digest);
|
let log = log.try_to::<ConsensusLog>(OpaqueDigestItemId::Consensus(&BABE_ENGINE_ID));
|
||||||
|
match (log, epoch_digest.is_some()) {
|
||||||
|
(Some(ConsensusLog::NextEpochData(_)), true) => Err(babe_err!("Multiple BABE epoch change digests, rejecting!"))?,
|
||||||
|
(Some(ConsensusLog::NextEpochData(epoch)), false) => epoch_digest = Some(epoch),
|
||||||
|
_ => trace!(target: "babe", "Ignoring digest not meant for us"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return None;
|
Ok(epoch_digest)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check a header has been signed by the right key. If the slot is too far in
|
/// Check a header has been signed by the right key. If the slot is too far in
|
||||||
@@ -459,10 +466,10 @@ fn check_header<B: BlockT + Sized, C: AuxStore>(
|
|||||||
slot_now: u64,
|
slot_now: u64,
|
||||||
mut header: B::Header,
|
mut header: B::Header,
|
||||||
hash: B::Hash,
|
hash: B::Hash,
|
||||||
authorities: &[AuthorityId],
|
authorities: &[(AuthorityId, BabeWeight)],
|
||||||
randomness: [u8; 32],
|
randomness: [u8; 32],
|
||||||
epoch_index: u64,
|
epoch_index: u64,
|
||||||
threshold: u64,
|
c: (u64, u64),
|
||||||
) -> Result<CheckedHeader<B::Header, (DigestItemFor<B>, DigestItemFor<B>)>, String>
|
) -> Result<CheckedHeader<B::Header, (DigestItemFor<B>, DigestItemFor<B>)>, String>
|
||||||
where DigestItemFor<B>: CompatibleDigestItem,
|
where DigestItemFor<B>: CompatibleDigestItem,
|
||||||
{
|
{
|
||||||
@@ -486,7 +493,7 @@ fn check_header<B: BlockT + Sized, C: AuxStore>(
|
|||||||
} else if authority_index > authorities.len() as u64 {
|
} else if authority_index > authorities.len() as u64 {
|
||||||
Err(babe_err!("Slot author not found"))
|
Err(babe_err!("Slot author not found"))
|
||||||
} else {
|
} else {
|
||||||
let (pre_hash, author) = (header.hash(), &authorities[authority_index as usize]);
|
let (pre_hash, author) = (header.hash(), &authorities[authority_index as usize].0);
|
||||||
|
|
||||||
if sr25519::Pair::verify(&sig, pre_hash, author.clone()) {
|
if sr25519::Pair::verify(&sig, pre_hash, author.clone()) {
|
||||||
let (inout, _batchable_proof) = {
|
let (inout, _batchable_proof) = {
|
||||||
@@ -503,6 +510,7 @@ fn check_header<B: BlockT + Sized, C: AuxStore>(
|
|||||||
})?
|
})?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let threshold = calculate_threshold(c, authorities, authority_index as usize);
|
||||||
if !check(&inout, threshold) {
|
if !check(&inout, threshold) {
|
||||||
return Err(babe_err!("VRF verification of block by author {:?} failed: \
|
return Err(babe_err!("VRF verification of block by author {:?} failed: \
|
||||||
threshold {} exceeded", author, threshold));
|
threshold {} exceeded", author, threshold));
|
||||||
@@ -562,7 +570,9 @@ impl<C> BabeVerifier<C> {
|
|||||||
if !inherent_res.ok() {
|
if !inherent_res.ok() {
|
||||||
inherent_res
|
inherent_res
|
||||||
.into_errors()
|
.into_errors()
|
||||||
.try_for_each(|(i, e)| Err(self.inherent_data_providers.error_to_string(&i, &e)))
|
.try_for_each(|(i, e)| {
|
||||||
|
Err(self.inherent_data_providers.error_to_string(&i, &e))
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -581,7 +591,9 @@ fn median_algorithm(
|
|||||||
let mut new_list: Vec<_> = time_source.1.iter().map(|&(t, sl)| {
|
let mut new_list: Vec<_> = time_source.1.iter().map(|&(t, sl)| {
|
||||||
let offset: u128 = u128::from(slot_duration)
|
let offset: u128 = u128::from(slot_duration)
|
||||||
.checked_mul(1_000_000u128) // self.config.get() returns *milliseconds*
|
.checked_mul(1_000_000u128) // self.config.get() returns *milliseconds*
|
||||||
.and_then(|x| x.checked_mul(u128::from(slot_number).saturating_sub(u128::from(sl))))
|
.and_then(|x| {
|
||||||
|
x.checked_mul(u128::from(slot_number).saturating_sub(u128::from(sl)))
|
||||||
|
})
|
||||||
.expect("we cannot have timespans long enough for this to overflow; qed");
|
.expect("we cannot have timespans long enough for this to overflow; qed");
|
||||||
|
|
||||||
const NANOS_PER_SEC: u32 = 1_000_000_000;
|
const NANOS_PER_SEC: u32 = 1_000_000_000;
|
||||||
@@ -640,8 +652,6 @@ impl<B: BlockT, C> Verifier<B> for BabeVerifier<C> where
|
|||||||
epoch(self.api.as_ref(), &BlockId::Hash(parent_hash))
|
epoch(self.api.as_ref(), &BlockId::Hash(parent_hash))
|
||||||
.map_err(|e| format!("Could not fetch epoch at {:?}: {:?}", parent_hash, e))?;
|
.map_err(|e| format!("Could not fetch epoch at {:?}: {:?}", parent_hash, e))?;
|
||||||
|
|
||||||
let authorities: Vec<_> = authorities.into_iter().map(|(s, _)| s).collect();
|
|
||||||
|
|
||||||
// We add one to allow for some small drift.
|
// We add one to allow for some small drift.
|
||||||
// FIXME #1019 in the future, alter this queue to allow deferring of headers
|
// FIXME #1019 in the future, alter this queue to allow deferring of headers
|
||||||
let checked_header = check_header::<B, C>(
|
let checked_header = check_header::<B, C>(
|
||||||
@@ -649,10 +659,10 @@ impl<B: BlockT, C> Verifier<B> for BabeVerifier<C> where
|
|||||||
slot_now + 1,
|
slot_now + 1,
|
||||||
header,
|
header,
|
||||||
hash,
|
hash,
|
||||||
&authorities[..],
|
&authorities,
|
||||||
randomness,
|
randomness,
|
||||||
epoch_index,
|
epoch_index,
|
||||||
self.config.threshold(),
|
self.config.c(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
match checked_header {
|
match checked_header {
|
||||||
@@ -683,12 +693,6 @@ impl<B: BlockT, C> Verifier<B> for BabeVerifier<C> where
|
|||||||
"babe.checked_and_importing";
|
"babe.checked_and_importing";
|
||||||
"pre_header" => ?pre_header);
|
"pre_header" => ?pre_header);
|
||||||
|
|
||||||
// `Consensus` is the Babe-specific authorities change log.
|
|
||||||
// It's an encoded `Epoch`, the same format as is stored in the
|
|
||||||
// cache, so no need to decode/re-encode.
|
|
||||||
let maybe_keys = find_epoch_digest::<B>(&pre_header)
|
|
||||||
.map(|epoch| vec![(well_known_cache_keys::AUTHORITIES, epoch.encode())]);
|
|
||||||
|
|
||||||
let import_block = BlockImportParams {
|
let import_block = BlockImportParams {
|
||||||
origin,
|
origin,
|
||||||
header: pre_header,
|
header: pre_header,
|
||||||
@@ -709,8 +713,7 @@ impl<B: BlockT, C> Verifier<B> for BabeVerifier<C> where
|
|||||||
&mut *self.time_source.0.lock(),
|
&mut *self.time_source.0.lock(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME #1019 extract authorities
|
Ok((import_block, Default::default()))
|
||||||
Ok((import_block, maybe_keys))
|
|
||||||
}
|
}
|
||||||
CheckedHeader::Deferred(a, b) => {
|
CheckedHeader::Deferred(a, b) => {
|
||||||
debug!(target: "babe", "Checking {:?} failed; {:?}, {:?}.", hash, a, b);
|
debug!(target: "babe", "Checking {:?} failed; {:?}, {:?}.", hash, a, b);
|
||||||
@@ -732,7 +735,7 @@ fn epoch<B, C>(client: &C, at: &BlockId<B>) -> Result<Epoch, ConsensusError> whe
|
|||||||
{
|
{
|
||||||
client
|
client
|
||||||
.cache()
|
.cache()
|
||||||
.and_then(|cache| cache.get_at(&well_known_cache_keys::AUTHORITIES, at)
|
.and_then(|cache| cache.get_at(&well_known_cache_keys::EPOCH, at)
|
||||||
.and_then(|v| Decode::decode(&mut &v[..])))
|
.and_then(|v| Decode::decode(&mut &v[..])))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
if client.runtime_api().has_api::<dyn BabeApi<B>>(at).unwrap_or(false) {
|
if client.runtime_api().has_api::<dyn BabeApi<B>>(at).unwrap_or(false) {
|
||||||
@@ -786,8 +789,33 @@ fn make_transcript(
|
|||||||
transcript
|
transcript
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(inout: &VRFInOut, threshold: u64) -> bool {
|
fn check(inout: &VRFInOut, threshold: u128) -> bool {
|
||||||
u64::from_le_bytes(inout.make_bytes::<[u8; 8]>(BABE_VRF_PREFIX)) < threshold
|
u128::from_le_bytes(inout.make_bytes::<[u8; 16]>(BABE_VRF_PREFIX)) < threshold
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_threshold(
|
||||||
|
c: (u64, u64),
|
||||||
|
authorities: &[(AuthorityId, BabeWeight)],
|
||||||
|
authority_index: usize,
|
||||||
|
) -> u128 {
|
||||||
|
use num_bigint::BigUint;
|
||||||
|
use num_rational::BigRational;
|
||||||
|
use num_traits::{cast::ToPrimitive, identities::One};
|
||||||
|
|
||||||
|
let c = c.0 as f64 / c.1 as f64;
|
||||||
|
|
||||||
|
let theta =
|
||||||
|
authorities[authority_index].1 as f64 /
|
||||||
|
authorities.iter().map(|(_, weight)| weight).sum::<u64>() as f64;
|
||||||
|
|
||||||
|
let calc = || {
|
||||||
|
let p = BigRational::from_float(1f64 - (1f64 - c).powf(theta))?;
|
||||||
|
let numer = p.numer().to_biguint()?;
|
||||||
|
let denom = p.denom().to_biguint()?;
|
||||||
|
((BigUint::one() << 128) * numer / denom).to_u128()
|
||||||
|
};
|
||||||
|
|
||||||
|
calc().unwrap_or(u128::max_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Claim a slot if it is our turn. Returns `None` if it is not our turn.
|
/// Claim a slot if it is our turn. Returns `None` if it is not our turn.
|
||||||
@@ -796,22 +824,20 @@ fn check(inout: &VRFInOut, threshold: u64) -> bool {
|
|||||||
/// the VRF. If the VRF produces a value less than `threshold`, it is our turn,
|
/// the VRF. If the VRF produces a value less than `threshold`, it is our turn,
|
||||||
/// so it returns `Some(_)`. Otherwise, it returns `None`.
|
/// so it returns `Some(_)`. Otherwise, it returns `None`.
|
||||||
fn claim_slot(
|
fn claim_slot(
|
||||||
randomness: &[u8],
|
|
||||||
slot_number: u64,
|
slot_number: u64,
|
||||||
epoch: u64,
|
Epoch { ref authorities, ref randomness, epoch_index, .. }: Epoch,
|
||||||
Epoch { ref authorities, .. }: Epoch,
|
|
||||||
key: &sr25519::Pair,
|
key: &sr25519::Pair,
|
||||||
threshold: u64,
|
c: (u64, u64),
|
||||||
) -> Option<((VRFInOut, VRFProof, VRFProofBatchable), usize)> {
|
) -> Option<((VRFInOut, VRFProof, VRFProofBatchable), usize)> {
|
||||||
let public = &key.public();
|
let public = &key.public();
|
||||||
let authority_index = authorities.iter().position(|s| &s.0 == public)?;
|
let authority_index = authorities.iter().position(|s| &s.0 == public)?;
|
||||||
let transcript = make_transcript(randomness, slot_number, epoch);
|
let transcript = make_transcript(randomness, slot_number, epoch_index);
|
||||||
|
|
||||||
// Compute the threshold we will use.
|
// Compute the threshold we will use.
|
||||||
//
|
//
|
||||||
// We already checked that authorities contains `key.public()`, so it can't
|
// We already checked that authorities contains `key.public()`, so it can't
|
||||||
// be empty. Therefore, this division is safe.
|
// be empty. Therefore, this division in `calculate_threshold` is safe.
|
||||||
let threshold = threshold / authorities.len() as u64;
|
let threshold = calculate_threshold(c, authorities, authority_index);
|
||||||
|
|
||||||
get_keypair(key)
|
get_keypair(key)
|
||||||
.vrf_sign_n_check(transcript, |inout| check(inout, threshold))
|
.vrf_sign_n_check(transcript, |inout| check(inout, threshold))
|
||||||
@@ -832,7 +858,7 @@ fn initialize_authorities_cache<B, C>(client: &C) -> Result<(), ConsensusError>
|
|||||||
// check if we already have initialized the cache
|
// check if we already have initialized the cache
|
||||||
let genesis_id = BlockId::Number(Zero::zero());
|
let genesis_id = BlockId::Number(Zero::zero());
|
||||||
let genesis_epoch: Option<Epoch> = cache
|
let genesis_epoch: Option<Epoch> = cache
|
||||||
.get_at(&well_known_cache_keys::AUTHORITIES, &genesis_id)
|
.get_at(&well_known_cache_keys::EPOCH, &genesis_id)
|
||||||
.and_then(|v| Decode::decode(&mut &v[..]));
|
.and_then(|v| Decode::decode(&mut &v[..]));
|
||||||
if genesis_epoch.is_some() {
|
if genesis_epoch.is_some() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -845,18 +871,17 @@ fn initialize_authorities_cache<B, C>(client: &C) -> Result<(), ConsensusError>
|
|||||||
)));
|
)));
|
||||||
|
|
||||||
let genesis_epoch = epoch(client, &genesis_id)?;
|
let genesis_epoch = epoch(client, &genesis_id)?;
|
||||||
cache.initialize(&well_known_cache_keys::AUTHORITIES, genesis_epoch.encode())
|
cache.initialize(&well_known_cache_keys::EPOCH, genesis_epoch.encode())
|
||||||
.map_err(map_err)
|
.map_err(map_err)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tree of all epoch changes across all *seen* forks. Data stored in tree is the
|
/// Tree of all epoch changes across all *seen* forks. Data stored in tree is
|
||||||
/// hash and block number of the block signaling the epoch change, the new epoch
|
/// the hash and block number of the block signaling the epoch change, and the
|
||||||
/// index and the minimum *slot number* when the next epoch should start (i.e.
|
/// epoch that was signalled at that block.
|
||||||
/// slot number begin + duration).
|
|
||||||
type EpochChanges<Block> = ForkTree<
|
type EpochChanges<Block> = ForkTree<
|
||||||
<Block as BlockT>::Hash,
|
<Block as BlockT>::Hash,
|
||||||
NumberFor<Block>,
|
NumberFor<Block>,
|
||||||
(u64, SlotNumber),
|
Epoch,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/// A shared epoch changes tree.
|
/// A shared epoch changes tree.
|
||||||
@@ -893,50 +918,56 @@ impl<Block: BlockT> From<EpochChanges<Block>> for SharedEpochChanges<Block> {
|
|||||||
/// it is missing.
|
/// it is missing.
|
||||||
///
|
///
|
||||||
/// The epoch change tree should be pruned as blocks are finalized.
|
/// The epoch change tree should be pruned as blocks are finalized.
|
||||||
pub struct BabeBlockImport<B, E, Block: BlockT, I, RA> {
|
pub struct BabeBlockImport<B, E, Block: BlockT, I, RA, PRA> {
|
||||||
inner: I,
|
inner: I,
|
||||||
client: Arc<Client<B, E, Block, RA>>,
|
client: Arc<Client<B, E, Block, RA>>,
|
||||||
|
api: Arc<PRA>,
|
||||||
epoch_changes: SharedEpochChanges<Block>,
|
epoch_changes: SharedEpochChanges<Block>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, E, Block: BlockT, I: Clone, RA> Clone for BabeBlockImport<B, E, Block, I, RA> {
|
impl<B, E, Block: BlockT, I: Clone, RA, PRA> Clone for BabeBlockImport<B, E, Block, I, RA, PRA> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
BabeBlockImport {
|
BabeBlockImport {
|
||||||
inner: self.inner.clone(),
|
inner: self.inner.clone(),
|
||||||
client: self.client.clone(),
|
client: self.client.clone(),
|
||||||
|
api: self.api.clone(),
|
||||||
epoch_changes: self.epoch_changes.clone(),
|
epoch_changes: self.epoch_changes.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, E, Block: BlockT, I, RA> BabeBlockImport<B, E, Block, I, RA> {
|
impl<B, E, Block: BlockT, I, RA, PRA> BabeBlockImport<B, E, Block, I, RA, PRA> {
|
||||||
fn new(
|
fn new(
|
||||||
client: Arc<Client<B, E, Block, RA>>,
|
client: Arc<Client<B, E, Block, RA>>,
|
||||||
|
api: Arc<PRA>,
|
||||||
epoch_changes: SharedEpochChanges<Block>,
|
epoch_changes: SharedEpochChanges<Block>,
|
||||||
block_import: I,
|
block_import: I,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
BabeBlockImport {
|
BabeBlockImport {
|
||||||
client,
|
client,
|
||||||
|
api,
|
||||||
inner: block_import,
|
inner: block_import,
|
||||||
epoch_changes,
|
epoch_changes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, E, Block, I, RA> BlockImport<Block> for BabeBlockImport<B, E, Block, I, RA> where
|
impl<B, E, Block, I, RA, PRA> BlockImport<Block> for BabeBlockImport<B, E, Block, I, RA, PRA> where
|
||||||
Block: BlockT<Hash=H256>,
|
Block: BlockT<Hash=H256>,
|
||||||
I: BlockImport<Block> + Send + Sync,
|
I: BlockImport<Block> + Send + Sync,
|
||||||
I::Error: Into<ConsensusError>,
|
I::Error: Into<ConsensusError>,
|
||||||
B: Backend<Block, Blake2Hasher> + 'static,
|
B: Backend<Block, Blake2Hasher> + 'static,
|
||||||
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
|
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
|
||||||
RA: Send + Sync,
|
RA: Send + Sync,
|
||||||
|
PRA: ProvideRuntimeApi + ProvideCache<Block>,
|
||||||
|
PRA::Api: BabeApi<Block>,
|
||||||
{
|
{
|
||||||
type Error = ConsensusError;
|
type Error = ConsensusError;
|
||||||
|
|
||||||
fn import_block(
|
fn import_block(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut block: BlockImportParams<Block>,
|
mut block: BlockImportParams<Block>,
|
||||||
new_cache: HashMap<well_known_cache_keys::Id, Vec<u8>>,
|
mut new_cache: HashMap<well_known_cache_keys::Id, Vec<u8>>,
|
||||||
) -> Result<ImportResult, Self::Error> {
|
) -> Result<ImportResult, Self::Error> {
|
||||||
let hash = block.post_header().hash();
|
let hash = block.post_header().hash();
|
||||||
let number = block.header.number().clone();
|
let number = block.header.number().clone();
|
||||||
@@ -965,21 +996,22 @@ impl<B, E, Block, I, RA> BlockImport<Block> for BabeBlockImport<B, E, Block, I,
|
|||||||
|
|
||||||
// check if there's any epoch change expected to happen at this slot
|
// check if there's any epoch change expected to happen at this slot
|
||||||
let mut epoch_changes = self.epoch_changes.lock();
|
let mut epoch_changes = self.epoch_changes.lock();
|
||||||
let epoch_change = epoch_changes.find_node_where(
|
let enacted_epoch = epoch_changes.find_node_where(
|
||||||
&hash,
|
&hash,
|
||||||
&number,
|
&number,
|
||||||
&is_descendent_of,
|
&is_descendent_of,
|
||||||
&|(_, expected_epoch_change_slot)| {
|
&|epoch| epoch.start_slot <= slot_number,
|
||||||
*expected_epoch_change_slot <= slot_number
|
|
||||||
}
|
|
||||||
).map_err(|e| ConsensusError::from(ConsensusError::ClientImport(e.to_string())))?;
|
).map_err(|e| ConsensusError::from(ConsensusError::ClientImport(e.to_string())))?;
|
||||||
|
|
||||||
let check_roots = || -> Result<bool, ConsensusError> {
|
let check_roots = || -> Result<bool, ConsensusError> {
|
||||||
// this can only happen when the chain starts, since there's no epoch change at genesis.
|
// this can only happen when the chain starts, since there's no
|
||||||
// afterwards every time we expect an epoch change it means we will import another one.
|
// epoch change at genesis. afterwards every time we expect an epoch
|
||||||
|
// change it means we will import another one.
|
||||||
for (root, _, _) in epoch_changes.roots() {
|
for (root, _, _) in epoch_changes.roots() {
|
||||||
let is_descendent_of = is_descendent_of(root, &hash)
|
let is_descendent_of = is_descendent_of(root, &hash)
|
||||||
.map_err(|e| ConsensusError::from(ConsensusError::ClientImport(e.to_string())))?;
|
.map_err(|e| {
|
||||||
|
ConsensusError::from(ConsensusError::ClientImport(e.to_string()))
|
||||||
|
})?;
|
||||||
|
|
||||||
if is_descendent_of {
|
if is_descendent_of {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
@@ -989,14 +1021,18 @@ impl<B, E, Block, I, RA> BlockImport<Block> for BabeBlockImport<B, E, Block, I,
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
};
|
};
|
||||||
|
|
||||||
let expected_epoch_change = epoch_change.is_some();
|
let expected_epoch_change = enacted_epoch.is_some();
|
||||||
|
let next_epoch_digest = find_next_epoch_digest::<Block>(&block.header)
|
||||||
|
.map_err(|e| ConsensusError::from(ConsensusError::ClientImport(e.to_string())))?;
|
||||||
|
|
||||||
match (expected_epoch_change, new_cache.contains_key(&well_known_cache_keys::AUTHORITIES)) {
|
match (expected_epoch_change, next_epoch_digest.is_some()) {
|
||||||
(true, true) => {},
|
(true, true) => {},
|
||||||
(false, false) => {},
|
(false, false) => {},
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
return Err(
|
return Err(
|
||||||
ConsensusError::ClientImport("Expected epoch change to happen by this block".into())
|
ConsensusError::ClientImport(
|
||||||
|
"Expected epoch change to happen by this block".into(),
|
||||||
|
)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
(false, true) => {
|
(false, true) => {
|
||||||
@@ -1010,40 +1046,55 @@ impl<B, E, Block, I, RA> BlockImport<Block> for BabeBlockImport<B, E, Block, I,
|
|||||||
// this way we can revert it if there's any error
|
// this way we can revert it if there's any error
|
||||||
let mut old_epoch_changes = None;
|
let mut old_epoch_changes = None;
|
||||||
|
|
||||||
if let Some(entry) = new_cache.get(&well_known_cache_keys::AUTHORITIES) {
|
if let Some(next_epoch) = next_epoch_digest {
|
||||||
if let Some(epoch) = Epoch::decode(&mut &entry[..]) {
|
if let Some(enacted_epoch) = enacted_epoch {
|
||||||
if let Some(last_epoch_change) = epoch_change {
|
let enacted_epoch = &enacted_epoch.data;
|
||||||
let last_epoch_index = last_epoch_change.data.0;
|
if next_epoch.epoch_index.checked_sub(enacted_epoch.epoch_index) != Some(1) {
|
||||||
if epoch.epoch_index.checked_sub(last_epoch_index) != Some(1) {
|
return Err(ConsensusError::ClientImport(format!(
|
||||||
return Err(ConsensusError::ClientImport(format!(
|
"Invalid BABE epoch change: expected next epoch to be {:?}, got {:?}",
|
||||||
"Invalid BABE epoch change: expected next epoch to be {:?}, got {:?}",
|
enacted_epoch.epoch_index.saturating_add(1),
|
||||||
last_epoch_index.saturating_add(1),
|
next_epoch.epoch_index,
|
||||||
epoch.epoch_index,
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
old_epoch_changes = Some(epoch_changes.clone());
|
// update the current epoch in the client cache
|
||||||
|
new_cache.insert(
|
||||||
// track the epoch change in the fork tree
|
well_known_cache_keys::EPOCH,
|
||||||
epoch_changes.import(
|
enacted_epoch.encode(),
|
||||||
hash,
|
|
||||||
number,
|
|
||||||
(epoch.epoch_index, slot_number + epoch.duration),
|
|
||||||
&is_descendent_of,
|
|
||||||
).map_err(|e| ConsensusError::from(ConsensusError::ClientImport(e.to_string())))?;
|
|
||||||
|
|
||||||
crate::aux_schema::write_epoch_changes::<Block, _, _>(
|
|
||||||
&*epoch_changes,
|
|
||||||
|insert| block.auxiliary.extend(
|
|
||||||
insert.iter().map(|(k, v)| (k.to_vec(), Some(v.to_vec())))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Err(
|
|
||||||
ConsensusError::ClientImport("Failed to decode epoch change digest".into())
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let current_epoch = epoch(&*self.api, &BlockId::Hash(parent_hash))?;
|
||||||
|
|
||||||
|
// if the authorities have changed then we populate the
|
||||||
|
// `AUTHORITIES` key with the enacted epoch, so that the inner
|
||||||
|
// `ImportBlock` can process it (`EPOCH` is specific to BABE).
|
||||||
|
// e.g. in the case of GRANDPA it would require a justification
|
||||||
|
// for the block, expecting that the authorities actually
|
||||||
|
// changed.
|
||||||
|
if current_epoch.authorities != enacted_epoch.authorities {
|
||||||
|
new_cache.insert(
|
||||||
|
well_known_cache_keys::AUTHORITIES,
|
||||||
|
enacted_epoch.encode(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
old_epoch_changes = Some(epoch_changes.clone());
|
||||||
|
|
||||||
|
// track the epoch change in the fork tree
|
||||||
|
epoch_changes.import(
|
||||||
|
hash,
|
||||||
|
number,
|
||||||
|
next_epoch,
|
||||||
|
&is_descendent_of,
|
||||||
|
).map_err(|e| ConsensusError::from(ConsensusError::ClientImport(e.to_string())))?;
|
||||||
|
|
||||||
|
crate::aux_schema::write_epoch_changes::<Block, _, _>(
|
||||||
|
&*epoch_changes,
|
||||||
|
|insert| block.auxiliary.extend(
|
||||||
|
insert.iter().map(|(k, v)| (k.to_vec(), Some(v.to_vec())))
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let import_result = self.inner.import_block(block, new_cache);
|
let import_result = self.inner.import_block(block, new_cache);
|
||||||
@@ -1085,7 +1136,7 @@ pub fn import_queue<B, E, Block: BlockT<Hash=H256>, I, RA, PRA>(
|
|||||||
) -> ClientResult<(
|
) -> ClientResult<(
|
||||||
BabeImportQueue<Block>,
|
BabeImportQueue<Block>,
|
||||||
BabeLink,
|
BabeLink,
|
||||||
BabeBlockImport<B, E, Block, I, RA>,
|
BabeBlockImport<B, E, Block, I, RA, PRA>,
|
||||||
impl Future<Item = (), Error = ()>,
|
impl Future<Item = (), Error = ()>,
|
||||||
)> where
|
)> where
|
||||||
B: Backend<Block, Blake2Hasher> + 'static,
|
B: Backend<Block, Blake2Hasher> + 'static,
|
||||||
@@ -1100,7 +1151,7 @@ pub fn import_queue<B, E, Block: BlockT<Hash=H256>, I, RA, PRA>(
|
|||||||
initialize_authorities_cache(&*api)?;
|
initialize_authorities_cache(&*api)?;
|
||||||
|
|
||||||
let verifier = BabeVerifier {
|
let verifier = BabeVerifier {
|
||||||
api,
|
api: api.clone(),
|
||||||
inherent_data_providers,
|
inherent_data_providers,
|
||||||
time_source: Default::default(),
|
time_source: Default::default(),
|
||||||
config,
|
config,
|
||||||
@@ -1111,6 +1162,7 @@ pub fn import_queue<B, E, Block: BlockT<Hash=H256>, I, RA, PRA>(
|
|||||||
|
|
||||||
let block_import = BabeBlockImport::new(
|
let block_import = BabeBlockImport::new(
|
||||||
client.clone(),
|
client.clone(),
|
||||||
|
api,
|
||||||
epoch_changes.clone(),
|
epoch_changes.clone(),
|
||||||
block_import,
|
block_import,
|
||||||
);
|
);
|
||||||
@@ -1123,7 +1175,9 @@ pub fn import_queue<B, E, Block: BlockT<Hash=H256>, I, RA, PRA>(
|
|||||||
¬ification.hash,
|
¬ification.hash,
|
||||||
*notification.header.number(),
|
*notification.header.number(),
|
||||||
&is_descendent_of,
|
&is_descendent_of,
|
||||||
).map_err(|e| debug!(target: "babe", "Error pruning epoch changes fork tree: {:?}", e))?;
|
).map_err(|e| {
|
||||||
|
debug!(target: "babe", "Error pruning epoch changes fork tree: {:?}", e)
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
@@ -1138,3 +1192,39 @@ pub fn import_queue<B, E, Block: BlockT<Hash=H256>, I, RA, PRA>(
|
|||||||
|
|
||||||
Ok((queue, timestamp_core, block_import, pruning_task))
|
Ok((queue, timestamp_core, block_import, pruning_task))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// BABE test helpers. Utility methods for manually authoring blocks.
|
||||||
|
#[cfg(feature = "test-helpers")]
|
||||||
|
pub mod test_helpers {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Try to claim the given slot and return a `BabePreDigest` if
|
||||||
|
/// successful.
|
||||||
|
pub fn claim_slot<B, C>(
|
||||||
|
client: &C,
|
||||||
|
at: &BlockId<B>,
|
||||||
|
slot_number: u64,
|
||||||
|
key: &sr25519::Pair,
|
||||||
|
c: (u64, u64),
|
||||||
|
) -> Option<BabePreDigest> where
|
||||||
|
B: BlockT,
|
||||||
|
C: ProvideRuntimeApi + ProvideCache<B>,
|
||||||
|
C::Api: BabeApi<B>,
|
||||||
|
{
|
||||||
|
let epoch = epoch(client, at).unwrap();
|
||||||
|
|
||||||
|
super::claim_slot(
|
||||||
|
slot_number,
|
||||||
|
epoch,
|
||||||
|
key,
|
||||||
|
c,
|
||||||
|
).map(|((inout, vrf_proof, _), authority_index)| {
|
||||||
|
BabePreDigest {
|
||||||
|
vrf_proof,
|
||||||
|
vrf_output: inout.to_output(),
|
||||||
|
authority_index: authority_index as u64,
|
||||||
|
slot_number,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -64,7 +64,12 @@ impl Proposer<TestBlock> for DummyProposer {
|
|||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Create = Result<TestBlock, Error>;
|
type Create = Result<TestBlock, Error>;
|
||||||
|
|
||||||
fn propose(&self, _: InherentData, digests: DigestFor<TestBlock>, _: Duration) -> Result<TestBlock, Error> {
|
fn propose(
|
||||||
|
&self,
|
||||||
|
_: InherentData,
|
||||||
|
digests: DigestFor<TestBlock>,
|
||||||
|
_: Duration,
|
||||||
|
) -> Result<TestBlock, Error> {
|
||||||
self.1.new_block(digests).unwrap().bake().map_err(|e| e.into())
|
self.1.new_block(digests).unwrap().bake().map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,7 +237,10 @@ fn run_one_test() {
|
|||||||
// wait for all finalized on each.
|
// wait for all finalized on each.
|
||||||
let wait_for = futures::future::join_all(import_notifications);
|
let wait_for = futures::future::join_all(import_notifications);
|
||||||
|
|
||||||
let drive_to_completion = futures::future::poll_fn(|| { net.lock().poll(); Ok(Async::NotReady) });
|
let drive_to_completion = futures::future::poll_fn(|| {
|
||||||
|
net.lock().poll();
|
||||||
|
Ok(Async::NotReady)
|
||||||
|
});
|
||||||
let _ = runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap();
|
let _ = runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,17 +314,17 @@ fn sig_is_not_pre_digest() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn can_author_block() {
|
fn can_author_block() {
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
let randomness = &[];
|
|
||||||
let (pair, _) = sr25519::Pair::generate();
|
let (pair, _) = sr25519::Pair::generate();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let epoch = Epoch {
|
let epoch = Epoch {
|
||||||
authorities: vec![(pair.public(), 0)],
|
start_slot: 0,
|
||||||
|
authorities: vec![(pair.public(), 1)],
|
||||||
randomness: [0; 32],
|
randomness: [0; 32],
|
||||||
epoch_index: 1,
|
epoch_index: 1,
|
||||||
duration: 100,
|
duration: 100,
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
match claim_slot(randomness, i, 0, epoch.clone(), &pair, u64::MAX / 10) {
|
match claim_slot(i, epoch.clone(), &pair, (3, 10)) {
|
||||||
None => i += 1,
|
None => i += 1,
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
debug!(target: "babe", "Authored block {:?}", s);
|
debug!(target: "babe", "Authored block {:?}", s);
|
||||||
|
|||||||
@@ -123,4 +123,7 @@ pub mod well_known_cache_keys {
|
|||||||
|
|
||||||
/// A list of authorities.
|
/// A list of authorities.
|
||||||
pub const AUTHORITIES: Id = *b"auth";
|
pub const AUTHORITIES: Id = *b"auth";
|
||||||
|
|
||||||
|
/// Current Epoch data.
|
||||||
|
pub const EPOCH: Id = *b"epch";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1331,7 +1331,7 @@ mod tests {
|
|||||||
|
|
||||||
use runtime_primitives::testing::{Block as GenericTestBlock, Header as TestHeader};
|
use runtime_primitives::testing::{Block as GenericTestBlock, Header as TestHeader};
|
||||||
use primitives::H256;
|
use primitives::H256;
|
||||||
use keyring::AuthorityKeyring;
|
use keyring::Ed25519Keyring;
|
||||||
|
|
||||||
type TestBlock = GenericTestBlock<()>;
|
type TestBlock = GenericTestBlock<()>;
|
||||||
|
|
||||||
@@ -1436,7 +1436,7 @@ mod tests {
|
|||||||
start_round: 0,
|
start_round: 0,
|
||||||
})),
|
})),
|
||||||
round_timeout_multiplier: 10,
|
round_timeout_multiplier: 10,
|
||||||
key: Arc::new(AuthorityKeyring::One.into()),
|
key: Arc::new(Ed25519Keyring::One.into()),
|
||||||
factory: DummyFactory
|
factory: DummyFactory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1462,10 +1462,10 @@ mod tests {
|
|||||||
fn future_gets_preempted() {
|
fn future_gets_preempted() {
|
||||||
let client = FakeClient {
|
let client = FakeClient {
|
||||||
authorities: vec![
|
authorities: vec![
|
||||||
AuthorityKeyring::One.into(),
|
Ed25519Keyring::One.into(),
|
||||||
AuthorityKeyring::Two.into(),
|
Ed25519Keyring::Two.into(),
|
||||||
AuthorityKeyring::Alice.into(),
|
Ed25519Keyring::Alice.into(),
|
||||||
AuthorityKeyring::Eve.into(),
|
Ed25519Keyring::Eve.into(),
|
||||||
],
|
],
|
||||||
imported_heights: Mutex::new(HashSet::new()),
|
imported_heights: Mutex::new(HashSet::new()),
|
||||||
};
|
};
|
||||||
@@ -1509,17 +1509,17 @@ mod tests {
|
|||||||
let hash = [0xff; 32].into();
|
let hash = [0xff; 32].into();
|
||||||
|
|
||||||
let authorities = vec![
|
let authorities = vec![
|
||||||
AuthorityKeyring::One.into(),
|
Ed25519Keyring::One.into(),
|
||||||
AuthorityKeyring::Two.into(),
|
Ed25519Keyring::Two.into(),
|
||||||
AuthorityKeyring::Alice.into(),
|
Ed25519Keyring::Alice.into(),
|
||||||
AuthorityKeyring::Eve.into(),
|
Ed25519Keyring::Eve.into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let authorities_keys = vec![
|
let authorities_keys = vec![
|
||||||
AuthorityKeyring::One.into(),
|
Ed25519Keyring::One.into(),
|
||||||
AuthorityKeyring::Two.into(),
|
Ed25519Keyring::Two.into(),
|
||||||
AuthorityKeyring::Alice.into(),
|
Ed25519Keyring::Alice.into(),
|
||||||
AuthorityKeyring::Eve.into(),
|
Ed25519Keyring::Eve.into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let unchecked = UncheckedJustification(rhododendron::UncheckedJustification {
|
let unchecked = UncheckedJustification(rhododendron::UncheckedJustification {
|
||||||
@@ -1570,8 +1570,8 @@ mod tests {
|
|||||||
let parent_hash = Default::default();
|
let parent_hash = Default::default();
|
||||||
|
|
||||||
let authorities = vec![
|
let authorities = vec![
|
||||||
AuthorityKeyring::Alice.into(),
|
Ed25519Keyring::Alice.into(),
|
||||||
AuthorityKeyring::Eve.into(),
|
Ed25519Keyring::Eve.into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let block = TestBlock {
|
let block = TestBlock {
|
||||||
@@ -1579,7 +1579,11 @@ mod tests {
|
|||||||
extrinsics: Default::default()
|
extrinsics: Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let proposal = sign_message(rhododendron::Message::Propose(1, block.clone()), &AuthorityKeyring::Alice.pair(), parent_hash);;
|
let proposal = sign_message(
|
||||||
|
rhododendron::Message::Propose(1, block.clone()),
|
||||||
|
&Ed25519Keyring::Alice.pair(),
|
||||||
|
parent_hash,
|
||||||
|
);
|
||||||
if let rhododendron::LocalizedMessage::Propose(proposal) = proposal {
|
if let rhododendron::LocalizedMessage::Propose(proposal) = proposal {
|
||||||
assert!(check_proposal(&authorities, &parent_hash, &proposal).is_ok());
|
assert!(check_proposal(&authorities, &parent_hash, &proposal).is_ok());
|
||||||
let mut invalid_round = proposal.clone();
|
let mut invalid_round = proposal.clone();
|
||||||
@@ -1593,7 +1597,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Not an authority
|
// Not an authority
|
||||||
let proposal = sign_message::<TestBlock>(rhododendron::Message::Propose(1, block), &AuthorityKeyring::Bob.pair(), parent_hash);;
|
let proposal = sign_message::<TestBlock>(
|
||||||
|
rhododendron::Message::Propose(1, block),
|
||||||
|
&Ed25519Keyring::Bob.pair(),
|
||||||
|
parent_hash,
|
||||||
|
);
|
||||||
if let rhododendron::LocalizedMessage::Propose(proposal) = proposal {
|
if let rhododendron::LocalizedMessage::Propose(proposal) = proposal {
|
||||||
assert!(check_proposal(&authorities, &parent_hash, &proposal).is_err());
|
assert!(check_proposal(&authorities, &parent_hash, &proposal).is_err());
|
||||||
} else {
|
} else {
|
||||||
@@ -1607,8 +1615,8 @@ mod tests {
|
|||||||
let hash: H256 = [0xff; 32].into();
|
let hash: H256 = [0xff; 32].into();
|
||||||
|
|
||||||
let authorities = vec![
|
let authorities = vec![
|
||||||
AuthorityKeyring::Alice.into(),
|
Ed25519Keyring::Alice.into(),
|
||||||
AuthorityKeyring::Eve.into(),
|
Ed25519Keyring::Eve.into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let vote = sign_message::<TestBlock>(rhododendron::Message::Vote(rhododendron::Vote::Prepare(1, hash)), &Keyring::Alice.pair(), parent_hash);;
|
let vote = sign_message::<TestBlock>(rhododendron::Message::Vote(rhododendron::Vote::Prepare(1, hash)), &Keyring::Alice.pair(), parent_hash);;
|
||||||
@@ -1634,10 +1642,10 @@ mod tests {
|
|||||||
fn drop_bft_future_does_not_deadlock() {
|
fn drop_bft_future_does_not_deadlock() {
|
||||||
let client = FakeClient {
|
let client = FakeClient {
|
||||||
authorities: vec![
|
authorities: vec![
|
||||||
AuthorityKeyring::One.into(),
|
Ed25519Keyring::One.into(),
|
||||||
AuthorityKeyring::Two.into(),
|
Ed25519Keyring::Two.into(),
|
||||||
AuthorityKeyring::Alice.into(),
|
Ed25519Keyring::Alice.into(),
|
||||||
AuthorityKeyring::Eve.into(),
|
Ed25519Keyring::Eve.into(),
|
||||||
],
|
],
|
||||||
imported_heights: Mutex::new(HashSet::new()),
|
imported_heights: Mutex::new(HashSet::new()),
|
||||||
};
|
};
|
||||||
@@ -1659,10 +1667,10 @@ mod tests {
|
|||||||
fn bft_can_build_though_skipped() {
|
fn bft_can_build_though_skipped() {
|
||||||
let client = FakeClient {
|
let client = FakeClient {
|
||||||
authorities: vec![
|
authorities: vec![
|
||||||
AuthorityKeyring::One.into(),
|
Ed25519Keyring::One.into(),
|
||||||
AuthorityKeyring::Two.into(),
|
Ed25519Keyring::Two.into(),
|
||||||
AuthorityKeyring::Alice.into(),
|
Ed25519Keyring::Alice.into(),
|
||||||
AuthorityKeyring::Eve.into(),
|
Ed25519Keyring::Eve.into(),
|
||||||
],
|
],
|
||||||
imported_heights: Mutex::new(HashSet::new()),
|
imported_heights: Mutex::new(HashSet::new()),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ pub fn evaluate_misbehavior<B: Codec, H: Codec + Copy>(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use keyring::AuthorityKeyring;
|
use keyring::Ed25519Keyring;
|
||||||
use rhododendron;
|
use rhododendron;
|
||||||
|
|
||||||
use runtime_primitives::testing::{H256, Block as RawBlock};
|
use runtime_primitives::testing::{H256, Block as RawBlock};
|
||||||
@@ -109,7 +109,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn evaluates_double_prepare() {
|
fn evaluates_double_prepare() {
|
||||||
let key = AuthorityKeyring::One.pair();
|
let key = Ed25519Keyring::One.pair();
|
||||||
let parent_hash = [0xff; 32].into();
|
let parent_hash = [0xff; 32].into();
|
||||||
let hash_1 = [0; 32].into();
|
let hash_1 = [0; 32].into();
|
||||||
let hash_2 = [1; 32].into();
|
let hash_2 = [1; 32].into();
|
||||||
@@ -138,7 +138,7 @@ mod tests {
|
|||||||
|
|
||||||
// misbehavior has wrong target.
|
// misbehavior has wrong target.
|
||||||
assert!(!evaluate_misbehavior::<Block, H256>(
|
assert!(!evaluate_misbehavior::<Block, H256>(
|
||||||
&AuthorityKeyring::Two.into(),
|
&Ed25519Keyring::Two.into(),
|
||||||
parent_hash,
|
parent_hash,
|
||||||
&MisbehaviorKind::BftDoublePrepare(
|
&MisbehaviorKind::BftDoublePrepare(
|
||||||
1,
|
1,
|
||||||
@@ -150,7 +150,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn evaluates_double_commit() {
|
fn evaluates_double_commit() {
|
||||||
let key = AuthorityKeyring::One.pair();
|
let key = Ed25519Keyring::One.pair();
|
||||||
let parent_hash = [0xff; 32].into();
|
let parent_hash = [0xff; 32].into();
|
||||||
let hash_1 = [0; 32].into();
|
let hash_1 = [0; 32].into();
|
||||||
let hash_2 = [1; 32].into();
|
let hash_2 = [1; 32].into();
|
||||||
@@ -179,7 +179,7 @@ mod tests {
|
|||||||
|
|
||||||
// misbehavior has wrong target.
|
// misbehavior has wrong target.
|
||||||
assert!(!evaluate_misbehavior::<Block, H256>(
|
assert!(!evaluate_misbehavior::<Block, H256>(
|
||||||
&AuthorityKeyring::Two.into(),
|
&Ed25519Keyring::Two.into(),
|
||||||
parent_hash,
|
parent_hash,
|
||||||
&MisbehaviorKind::BftDoubleCommit(
|
&MisbehaviorKind::BftDoubleCommit(
|
||||||
1,
|
1,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use network::test::{Block, Hash};
|
|||||||
use network_gossip::Validator;
|
use network_gossip::Validator;
|
||||||
use tokio::runtime::current_thread;
|
use tokio::runtime::current_thread;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use keyring::AuthorityKeyring;
|
use keyring::Ed25519Keyring;
|
||||||
use parity_codec::Encode;
|
use parity_codec::Encode;
|
||||||
|
|
||||||
use crate::environment::SharedVoterSetState;
|
use crate::environment::SharedVoterSetState;
|
||||||
@@ -202,7 +202,7 @@ fn make_test_network() -> (
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_ids(keys: &[AuthorityKeyring]) -> Vec<(AuthorityId, u64)> {
|
fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> {
|
||||||
keys.iter()
|
keys.iter()
|
||||||
.map(|key| AuthorityId(key.to_raw_public()))
|
.map(|key| AuthorityId(key.to_raw_public()))
|
||||||
.map(|id| (id, 1))
|
.map(|id| (id, 1))
|
||||||
@@ -220,7 +220,7 @@ impl network_gossip::ValidatorContext<Block> for NoopContext {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn good_commit_leads_to_relay() {
|
fn good_commit_leads_to_relay() {
|
||||||
let private = [AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let private = [Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let public = make_ids(&private[..]);
|
let public = make_ids(&private[..]);
|
||||||
let voter_set = Arc::new(public.iter().cloned().collect::<VoterSet<AuthorityId>>());
|
let voter_set = Arc::new(public.iter().cloned().collect::<VoterSet<AuthorityId>>());
|
||||||
|
|
||||||
@@ -335,7 +335,7 @@ fn good_commit_leads_to_relay() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bad_commit_leads_to_report() {
|
fn bad_commit_leads_to_report() {
|
||||||
let private = [AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let private = [Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let public = make_ids(&private[..]);
|
let public = make_ids(&private[..]);
|
||||||
let voter_set = Arc::new(public.iter().cloned().collect::<VoterSet<AuthorityId>>());
|
let voter_set = Arc::new(public.iter().cloned().collect::<VoterSet<AuthorityId>>());
|
||||||
|
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA, SC> BlockImport<Block>
|
|||||||
|
|
||||||
// we don't want to finalize on `inner.import_block`
|
// we don't want to finalize on `inner.import_block`
|
||||||
let mut justification = block.justification.take();
|
let mut justification = block.justification.take();
|
||||||
let enacts_consensus_change = !new_cache.is_empty();
|
let enacts_consensus_change = new_cache.contains_key(&well_known_cache_keys::AUTHORITIES);
|
||||||
let import_result = (&*self.inner).import_block(block, new_cache);
|
let import_result = (&*self.inner).import_block(block, new_cache);
|
||||||
|
|
||||||
let mut imported_aux = {
|
let mut imported_aux = {
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ fn do_import_block<B, E, Block: BlockT<Hash=H256>, RA, J>(
|
|||||||
|
|
||||||
// we don't want to finalize on `inner.import_block`
|
// we don't want to finalize on `inner.import_block`
|
||||||
let justification = block.justification.take();
|
let justification = block.justification.take();
|
||||||
let enacts_consensus_change = !new_cache.is_empty();
|
let enacts_consensus_change = new_cache.contains_key(&well_known_cache_keys::AUTHORITIES);
|
||||||
let import_result = BlockImport::import_block(&mut client, block, new_cache);
|
let import_result = BlockImport::import_block(&mut client, block, new_cache);
|
||||||
|
|
||||||
let mut imported_aux = match import_result {
|
let mut imported_aux = match import_result {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use network::config::{ProtocolConfig, Roles, BoxFinalityProofRequestBuilder};
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use futures03::{StreamExt as _, TryStreamExt as _};
|
use futures03::{StreamExt as _, TryStreamExt as _};
|
||||||
use tokio::runtime::current_thread;
|
use tokio::runtime::current_thread;
|
||||||
use keyring::ed25519::{Keyring as AuthorityKeyring};
|
use keyring::Ed25519Keyring;
|
||||||
use client::{
|
use client::{
|
||||||
error::Result,
|
error::Result,
|
||||||
runtime_api::{Core, RuntimeVersion, ApiExt},
|
runtime_api::{Core, RuntimeVersion, ApiExt},
|
||||||
@@ -342,7 +342,7 @@ impl AuthoritySetForFinalityChecker<Block> for TestApi {
|
|||||||
|
|
||||||
const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500);
|
const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500);
|
||||||
|
|
||||||
fn make_ids(keys: &[AuthorityKeyring]) -> Vec<(substrate_primitives::ed25519::Public, u64)> {
|
fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(substrate_primitives::ed25519::Public, u64)> {
|
||||||
keys.iter()
|
keys.iter()
|
||||||
.map(|key| AuthorityId::from_raw(key.to_raw_public()))
|
.map(|key| AuthorityId::from_raw(key.to_raw_public()))
|
||||||
.map(|id| (id, 1))
|
.map(|id| (id, 1))
|
||||||
@@ -355,7 +355,7 @@ fn run_to_completion_with<F>(
|
|||||||
runtime: &mut current_thread::Runtime,
|
runtime: &mut current_thread::Runtime,
|
||||||
blocks: u64,
|
blocks: u64,
|
||||||
net: Arc<Mutex<GrandpaTestNet>>,
|
net: Arc<Mutex<GrandpaTestNet>>,
|
||||||
peers: &[AuthorityKeyring],
|
peers: &[Ed25519Keyring],
|
||||||
with: F,
|
with: F,
|
||||||
) -> u64 where
|
) -> u64 where
|
||||||
F: FnOnce(current_thread::Handle) -> Option<Box<dyn Future<Item=(), Error=()>>>
|
F: FnOnce(current_thread::Handle) -> Option<Box<dyn Future<Item=(), Error=()>>>
|
||||||
@@ -437,7 +437,7 @@ fn run_to_completion(
|
|||||||
runtime: &mut current_thread::Runtime,
|
runtime: &mut current_thread::Runtime,
|
||||||
blocks: u64,
|
blocks: u64,
|
||||||
net: Arc<Mutex<GrandpaTestNet>>,
|
net: Arc<Mutex<GrandpaTestNet>>,
|
||||||
peers: &[AuthorityKeyring]
|
peers: &[Ed25519Keyring]
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
run_to_completion_with(runtime, blocks, net, peers, |_| None)
|
run_to_completion_with(runtime, blocks, net, peers, |_| None)
|
||||||
}
|
}
|
||||||
@@ -446,7 +446,7 @@ fn run_to_completion(
|
|||||||
fn finalize_3_voters_no_observers() {
|
fn finalize_3_voters_no_observers() {
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||||
let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let voters = make_ids(peers);
|
let voters = make_ids(peers);
|
||||||
|
|
||||||
let mut net = GrandpaTestNet::new(TestApi::new(voters), 3);
|
let mut net = GrandpaTestNet::new(TestApi::new(voters), 3);
|
||||||
@@ -470,7 +470,7 @@ fn finalize_3_voters_no_observers() {
|
|||||||
fn finalize_3_voters_1_full_observer() {
|
fn finalize_3_voters_1_full_observer() {
|
||||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||||
|
|
||||||
let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let voters = make_ids(peers);
|
let voters = make_ids(peers);
|
||||||
|
|
||||||
let mut net = GrandpaTestNet::new(TestApi::new(voters), 4);
|
let mut net = GrandpaTestNet::new(TestApi::new(voters), 4);
|
||||||
@@ -533,24 +533,24 @@ fn finalize_3_voters_1_full_observer() {
|
|||||||
fn transition_3_voters_twice_1_full_observer() {
|
fn transition_3_voters_twice_1_full_observer() {
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
let peers_a = &[
|
let peers_a = &[
|
||||||
AuthorityKeyring::Alice,
|
Ed25519Keyring::Alice,
|
||||||
AuthorityKeyring::Bob,
|
Ed25519Keyring::Bob,
|
||||||
AuthorityKeyring::Charlie,
|
Ed25519Keyring::Charlie,
|
||||||
];
|
];
|
||||||
|
|
||||||
let peers_b = &[
|
let peers_b = &[
|
||||||
AuthorityKeyring::Dave,
|
Ed25519Keyring::Dave,
|
||||||
AuthorityKeyring::Eve,
|
Ed25519Keyring::Eve,
|
||||||
AuthorityKeyring::Ferdie,
|
Ed25519Keyring::Ferdie,
|
||||||
];
|
];
|
||||||
|
|
||||||
let peers_c = &[
|
let peers_c = &[
|
||||||
AuthorityKeyring::Alice,
|
Ed25519Keyring::Alice,
|
||||||
AuthorityKeyring::Eve,
|
Ed25519Keyring::Eve,
|
||||||
AuthorityKeyring::Two,
|
Ed25519Keyring::Two,
|
||||||
];
|
];
|
||||||
|
|
||||||
let observer = &[AuthorityKeyring::One];
|
let observer = &[Ed25519Keyring::One];
|
||||||
|
|
||||||
let genesis_voters = make_ids(peers_a);
|
let genesis_voters = make_ids(peers_a);
|
||||||
|
|
||||||
@@ -700,7 +700,7 @@ fn transition_3_voters_twice_1_full_observer() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn justification_is_emitted_when_consensus_data_changes() {
|
fn justification_is_emitted_when_consensus_data_changes() {
|
||||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||||
let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 3);
|
let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 3);
|
||||||
|
|
||||||
// import block#1 WITH consensus data change
|
// import block#1 WITH consensus data change
|
||||||
@@ -718,7 +718,7 @@ fn justification_is_emitted_when_consensus_data_changes() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn justification_is_generated_periodically() {
|
fn justification_is_generated_periodically() {
|
||||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||||
let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let voters = make_ids(peers);
|
let voters = make_ids(peers);
|
||||||
|
|
||||||
let mut net = GrandpaTestNet::new(TestApi::new(voters), 3);
|
let mut net = GrandpaTestNet::new(TestApi::new(voters), 3);
|
||||||
@@ -757,8 +757,8 @@ fn consensus_changes_works() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn sync_justifications_on_change_blocks() {
|
fn sync_justifications_on_change_blocks() {
|
||||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob];
|
let peers_b = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob];
|
||||||
let voters = make_ids(peers_b);
|
let voters = make_ids(peers_b);
|
||||||
|
|
||||||
// 4 peers, 3 of them are authorities and participate in grandpa
|
// 4 peers, 3 of them are authorities and participate in grandpa
|
||||||
@@ -813,13 +813,13 @@ fn finalizes_multiple_pending_changes_in_order() {
|
|||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||||
|
|
||||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let peers_b = &[AuthorityKeyring::Dave, AuthorityKeyring::Eve, AuthorityKeyring::Ferdie];
|
let peers_b = &[Ed25519Keyring::Dave, Ed25519Keyring::Eve, Ed25519Keyring::Ferdie];
|
||||||
let peers_c = &[AuthorityKeyring::Dave, AuthorityKeyring::Alice, AuthorityKeyring::Bob];
|
let peers_c = &[Ed25519Keyring::Dave, Ed25519Keyring::Alice, Ed25519Keyring::Bob];
|
||||||
|
|
||||||
let all_peers = &[
|
let all_peers = &[
|
||||||
AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie,
|
Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie,
|
||||||
AuthorityKeyring::Dave, AuthorityKeyring::Eve, AuthorityKeyring::Ferdie,
|
Ed25519Keyring::Dave, Ed25519Keyring::Eve, Ed25519Keyring::Ferdie,
|
||||||
];
|
];
|
||||||
let genesis_voters = make_ids(peers_a);
|
let genesis_voters = make_ids(peers_a);
|
||||||
|
|
||||||
@@ -872,7 +872,7 @@ fn finalizes_multiple_pending_changes_in_order() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn doesnt_vote_on_the_tip_of_the_chain() {
|
fn doesnt_vote_on_the_tip_of_the_chain() {
|
||||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let voters = make_ids(peers_a);
|
let voters = make_ids(peers_a);
|
||||||
let api = TestApi::new(voters);
|
let api = TestApi::new(voters);
|
||||||
let mut net = GrandpaTestNet::new(api, 3);
|
let mut net = GrandpaTestNet::new(api, 3);
|
||||||
@@ -898,8 +898,14 @@ fn force_change_to_new_set() {
|
|||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||||
// two of these guys are offline.
|
// two of these guys are offline.
|
||||||
let genesis_authorities = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie, AuthorityKeyring::One, AuthorityKeyring::Two];
|
let genesis_authorities = &[
|
||||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
Ed25519Keyring::Alice,
|
||||||
|
Ed25519Keyring::Bob,
|
||||||
|
Ed25519Keyring::Charlie,
|
||||||
|
Ed25519Keyring::One,
|
||||||
|
Ed25519Keyring::Two,
|
||||||
|
];
|
||||||
|
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let api = TestApi::new(make_ids(genesis_authorities));
|
let api = TestApi::new(make_ids(genesis_authorities));
|
||||||
|
|
||||||
let voters = make_ids(peers_a);
|
let voters = make_ids(peers_a);
|
||||||
@@ -950,8 +956,8 @@ fn force_change_to_new_set() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn allows_reimporting_change_blocks() {
|
fn allows_reimporting_change_blocks() {
|
||||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob];
|
let peers_b = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob];
|
||||||
let voters = make_ids(peers_a);
|
let voters = make_ids(peers_a);
|
||||||
let api = TestApi::new(voters);
|
let api = TestApi::new(voters);
|
||||||
let mut net = GrandpaTestNet::new(api.clone(), 3);
|
let mut net = GrandpaTestNet::new(api.clone(), 3);
|
||||||
@@ -999,8 +1005,8 @@ fn allows_reimporting_change_blocks() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bad_justification() {
|
fn test_bad_justification() {
|
||||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob];
|
let peers_b = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob];
|
||||||
let voters = make_ids(peers_a);
|
let voters = make_ids(peers_a);
|
||||||
let api = TestApi::new(voters);
|
let api = TestApi::new(voters);
|
||||||
let mut net = GrandpaTestNet::new(api.clone(), 3);
|
let mut net = GrandpaTestNet::new(api.clone(), 3);
|
||||||
@@ -1058,7 +1064,7 @@ fn voter_persists_its_votes() {
|
|||||||
|
|
||||||
// we have two authorities but we'll only be running the voter for alice
|
// we have two authorities but we'll only be running the voter for alice
|
||||||
// we are going to be listening for the prevotes it casts
|
// we are going to be listening for the prevotes it casts
|
||||||
let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob];
|
let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob];
|
||||||
let voters = make_ids(peers);
|
let voters = make_ids(peers);
|
||||||
|
|
||||||
// alice has a chain with 20 blocks
|
// alice has a chain with 20 blocks
|
||||||
@@ -1264,7 +1270,7 @@ fn voter_persists_its_votes() {
|
|||||||
fn finalize_3_voters_1_light_observer() {
|
fn finalize_3_voters_1_light_observer() {
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||||
let authorities = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let authorities = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let voters = make_ids(authorities);
|
let voters = make_ids(authorities);
|
||||||
|
|
||||||
let mut net = GrandpaTestNet::new(TestApi::new(voters), 4);
|
let mut net = GrandpaTestNet::new(TestApi::new(voters), 4);
|
||||||
@@ -1308,7 +1314,7 @@ fn finality_proof_is_fetched_by_light_client_when_consensus_data_changes() {
|
|||||||
let _ = ::env_logger::try_init();
|
let _ = ::env_logger::try_init();
|
||||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||||
|
|
||||||
let peers = &[AuthorityKeyring::Alice];
|
let peers = &[Ed25519Keyring::Alice];
|
||||||
let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 1);
|
let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 1);
|
||||||
net.add_light_peer(&GrandpaTestNet::default_config());
|
net.add_light_peer(&GrandpaTestNet::default_config());
|
||||||
|
|
||||||
@@ -1341,20 +1347,20 @@ fn empty_finality_proof_is_returned_to_light_client_when_authority_set_is_differ
|
|||||||
// two of these guys are offline.
|
// two of these guys are offline.
|
||||||
let genesis_authorities = if FORCE_CHANGE {
|
let genesis_authorities = if FORCE_CHANGE {
|
||||||
vec![
|
vec![
|
||||||
AuthorityKeyring::Alice,
|
Ed25519Keyring::Alice,
|
||||||
AuthorityKeyring::Bob,
|
Ed25519Keyring::Bob,
|
||||||
AuthorityKeyring::Charlie,
|
Ed25519Keyring::Charlie,
|
||||||
AuthorityKeyring::One,
|
Ed25519Keyring::One,
|
||||||
AuthorityKeyring::Two,
|
Ed25519Keyring::Two,
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
vec![
|
vec![
|
||||||
AuthorityKeyring::Alice,
|
Ed25519Keyring::Alice,
|
||||||
AuthorityKeyring::Bob,
|
Ed25519Keyring::Bob,
|
||||||
AuthorityKeyring::Charlie,
|
Ed25519Keyring::Charlie,
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||||
let api = TestApi::new(make_ids(&genesis_authorities));
|
let api = TestApi::new(make_ids(&genesis_authorities));
|
||||||
|
|
||||||
let voters = make_ids(peers_a);
|
let voters = make_ids(peers_a);
|
||||||
@@ -1401,7 +1407,7 @@ fn voter_catches_up_to_latest_round_when_behind() {
|
|||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||||
|
|
||||||
let peers = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob];
|
let peers = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob];
|
||||||
let voters = make_ids(peers);
|
let voters = make_ids(peers);
|
||||||
|
|
||||||
let mut net = GrandpaTestNet::new(TestApi::new(voters), 3);
|
let mut net = GrandpaTestNet::new(TestApi::new(voters), 3);
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ pub mod sr25519;
|
|||||||
pub mod ed25519;
|
pub mod ed25519;
|
||||||
|
|
||||||
/// Convenience export: Sr25519's Keyring is exposed as `AccountKeyring`,
|
/// Convenience export: Sr25519's Keyring is exposed as `AccountKeyring`,
|
||||||
/// since it tends to be used for accounts.
|
/// since it tends to be used for accounts (although it may also be used
|
||||||
|
/// by authorities).
|
||||||
pub use sr25519::Keyring as AccountKeyring;
|
pub use sr25519::Keyring as AccountKeyring;
|
||||||
|
|
||||||
/// Convenience export: Ed25519's Keyring is exposed as `AuthorityKeyring`,
|
pub use ed25519::Keyring as Ed25519Keyring;
|
||||||
/// since it tends to be used for authorities (session keys &c.).
|
pub use sr25519::Keyring as Sr25519Keyring;
|
||||||
pub use ed25519::Keyring as AuthorityKeyring;
|
|
||||||
|
|
||||||
pub mod test {
|
pub mod test {
|
||||||
/// The keyring for use with accounts when using the test runtime.
|
/// The keyring for use with accounts when using the test runtime.
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use substrate_primitives::{sr25519::{Pair, Public, Signature}, Pair as PairT, Pu
|
|||||||
pub use substrate_primitives::sr25519;
|
pub use substrate_primitives::sr25519;
|
||||||
|
|
||||||
/// Set of test accounts.
|
/// Set of test accounts.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum_macros::Display, strum_macros::EnumIter)]
|
||||||
pub enum Keyring {
|
pub enum Keyring {
|
||||||
Alice,
|
Alice,
|
||||||
Bob,
|
Bob,
|
||||||
@@ -79,6 +79,11 @@ impl Keyring {
|
|||||||
Pair::from_string(&format!("//{}", <&'static str>::from(self)), None)
|
Pair::from_string(&format!("//{}", <&'static str>::from(self)), None)
|
||||||
.expect("static values are known good; qed")
|
.expect("static values are known good; qed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over all test accounts.
|
||||||
|
pub fn iter() -> impl Iterator<Item=Keyring> {
|
||||||
|
<Self as strum::IntoEnumIterator>::iter()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Keyring> for &'static str {
|
impl From<Keyring> for &'static str {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ use keystore::Store as Keystore;
|
|||||||
use network::{NetworkState, NetworkStateInfo};
|
use network::{NetworkState, NetworkStateInfo};
|
||||||
use log::{log, info, warn, debug, error, Level};
|
use log::{log, info, warn, debug, error, Level};
|
||||||
use parity_codec::{Encode, Decode};
|
use parity_codec::{Encode, Decode};
|
||||||
use primitives::{Pair, ed25519, crypto};
|
use primitives::{Pair, ed25519, sr25519, crypto};
|
||||||
use runtime_primitives::generic::BlockId;
|
use runtime_primitives::generic::BlockId;
|
||||||
use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion, Zero};
|
use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion, Zero};
|
||||||
use substrate_executor::NativeExecutor;
|
use substrate_executor::NativeExecutor;
|
||||||
@@ -192,6 +192,7 @@ impl<Components: components::Components> Service<Components> {
|
|||||||
if let Some(keystore) = keystore.as_mut() {
|
if let Some(keystore) = keystore.as_mut() {
|
||||||
for seed in &config.keys {
|
for seed in &config.keys {
|
||||||
keystore.generate_from_seed::<ed25519::Pair>(seed)?;
|
keystore.generate_from_seed::<ed25519::Pair>(seed)?;
|
||||||
|
keystore.generate_from_seed::<sr25519::Pair>(seed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
public_key = match keystore.contents::<ed25519::Public>()?.get(0) {
|
public_key = match keystore.contents::<ed25519::Public>()?.get(0) {
|
||||||
|
|||||||
@@ -358,7 +358,8 @@ pub fn sync<F, B, E>(spec: FactoryChainSpec<F>, mut block_factory: B, mut extrin
|
|||||||
E: FnMut(&SyncService<F::FullService>) -> FactoryExtrinsic<F>,
|
E: FnMut(&SyncService<F::FullService>) -> FactoryExtrinsic<F>,
|
||||||
{
|
{
|
||||||
const NUM_FULL_NODES: usize = 10;
|
const NUM_FULL_NODES: usize = 10;
|
||||||
const NUM_LIGHT_NODES: usize = 10;
|
// FIXME: BABE light client support is currently not working.
|
||||||
|
const NUM_LIGHT_NODES: usize = 0;
|
||||||
const NUM_BLOCKS: usize = 512;
|
const NUM_BLOCKS: usize = 512;
|
||||||
let temp = TempDir::new("substrate-sync-test").expect("Error creating test dir");
|
let temp = TempDir::new("substrate-sync-test").expect("Error creating test dir");
|
||||||
let mut network = TestNet::<F>::new(
|
let mut network = TestNet::<F>::new(
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ pub use client_db::{Backend, self};
|
|||||||
pub use client_ext::ClientExt;
|
pub use client_ext::ClientExt;
|
||||||
pub use consensus;
|
pub use consensus;
|
||||||
pub use executor::{NativeExecutor, self};
|
pub use executor::{NativeExecutor, self};
|
||||||
pub use keyring::{sr25519::Keyring as AuthorityKeyring, AccountKeyring};
|
pub use keyring::{
|
||||||
|
AccountKeyring,
|
||||||
|
ed25519::Keyring as Ed25519Keyring,
|
||||||
|
sr25519::Keyring as Sr25519Keyring,
|
||||||
|
};
|
||||||
pub use primitives::Blake2Hasher;
|
pub use primitives::Blake2Hasher;
|
||||||
pub use runtime_primitives::{StorageOverlay, ChildrenStorageOverlay};
|
pub use runtime_primitives::{StorageOverlay, ChildrenStorageOverlay};
|
||||||
pub use state_machine::ExecutionStrategy;
|
pub use state_machine::ExecutionStrategy;
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ keyring = { package = "substrate-keyring", path = "../keyring", optional = true
|
|||||||
substrate-client = { path = "../client", default-features = false }
|
substrate-client = { path = "../client", default-features = false }
|
||||||
primitives = { package = "substrate-primitives", path = "../primitives", default-features = false }
|
primitives = { package = "substrate-primitives", path = "../primitives", default-features = false }
|
||||||
inherents = { package = "substrate-inherents", path = "../inherents", default-features = false }
|
inherents = { package = "substrate-inherents", path = "../inherents", default-features = false }
|
||||||
consensus_aura = { package = "substrate-consensus-aura-primitives", path = "../consensus/aura/primitives", default-features = false }
|
aura-primitives = { package = "substrate-consensus-aura-primitives", path = "../consensus/aura/primitives", default-features = false }
|
||||||
consensus_babe = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives", default-features = false }
|
babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives", default-features = false }
|
||||||
rstd = { package = "sr-std", path = "../sr-std", default-features = false }
|
rstd = { package = "sr-std", path = "../sr-std", default-features = false }
|
||||||
runtime_io = { package = "sr-io", path = "../sr-io", default-features = false }
|
runtime_io = { package = "sr-io", path = "../sr-io", default-features = false }
|
||||||
runtime_primitives = { package = "sr-primitives", path = "../sr-primitives", default-features = false }
|
runtime_primitives = { package = "sr-primitives", path = "../sr-primitives", default-features = false }
|
||||||
@@ -54,8 +54,8 @@ std = [
|
|||||||
"inherents/std",
|
"inherents/std",
|
||||||
"runtime_primitives/std",
|
"runtime_primitives/std",
|
||||||
"runtime_version/std",
|
"runtime_version/std",
|
||||||
"consensus_aura/std",
|
"aura-primitives/std",
|
||||||
"consensus_babe/std",
|
"babe-primitives/std",
|
||||||
"primitives/std",
|
"primitives/std",
|
||||||
"substrate-trie/std",
|
"substrate-trie/std",
|
||||||
"trie-db/std",
|
"trie-db/std",
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ pub mod prelude {
|
|||||||
Executor, LightExecutor, LocalExecutor, NativeExecutor,
|
Executor, LightExecutor, LocalExecutor, NativeExecutor,
|
||||||
};
|
};
|
||||||
// Keyring
|
// Keyring
|
||||||
pub use super::{AccountKeyring, AuthorityKeyring};
|
pub use super::{AccountKeyring, Sr25519Keyring};
|
||||||
}
|
}
|
||||||
|
|
||||||
mod local_executor {
|
mod local_executor {
|
||||||
@@ -172,9 +172,9 @@ impl<B> TestClientBuilderExt<B> for TestClientBuilder<
|
|||||||
|
|
||||||
fn genesis_config(support_changes_trie: bool) -> GenesisConfig {
|
fn genesis_config(support_changes_trie: bool) -> GenesisConfig {
|
||||||
GenesisConfig::new(support_changes_trie, vec![
|
GenesisConfig::new(support_changes_trie, vec![
|
||||||
AuthorityKeyring::Alice.into(),
|
Sr25519Keyring::Alice.into(),
|
||||||
AuthorityKeyring::Bob.into(),
|
Sr25519Keyring::Bob.into(),
|
||||||
AuthorityKeyring::Charlie.into(),
|
Sr25519Keyring::Charlie.into(),
|
||||||
], vec![
|
], vec![
|
||||||
AccountKeyring::Alice.into(),
|
AccountKeyring::Alice.into(),
|
||||||
AccountKeyring::Bob.into(),
|
AccountKeyring::Bob.into(),
|
||||||
|
|||||||
@@ -50,11 +50,10 @@ use runtime_version::NativeVersion;
|
|||||||
use runtime_support::{impl_outer_origin, parameter_types};
|
use runtime_support::{impl_outer_origin, parameter_types};
|
||||||
use inherents::{CheckInherentsResult, InherentData};
|
use inherents::{CheckInherentsResult, InherentData};
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
pub use consensus_babe::AuthorityId;
|
|
||||||
// Ensure Babe and Aura use the same crypto to simplify things a bit.
|
// Ensure Babe and Aura use the same crypto to simplify things a bit.
|
||||||
|
pub use babe_primitives::AuthorityId;
|
||||||
pub type AuraId = AuthorityId;
|
pub type AuraId = AuthorityId;
|
||||||
// Ensure Babe and Aura use the same crypto to simplify things a bit.
|
|
||||||
pub type BabeId = AuthorityId;
|
|
||||||
|
|
||||||
// Inlucde the WASM binary
|
// Inlucde the WASM binary
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@@ -356,6 +355,14 @@ impl srml_timestamp::Trait for Runtime {
|
|||||||
type MinimumPeriod = MinimumPeriod;
|
type MinimumPeriod = MinimumPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
pub const EpochDuration: u64 = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl srml_babe::Trait for Runtime {
|
||||||
|
type EpochDuration = EpochDuration;
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds one to the given input and returns the final result.
|
/// Adds one to the given input and returns the final result.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn benchmark_add_one(i: u64) -> u64 {
|
fn benchmark_add_one(i: u64) -> u64 {
|
||||||
@@ -514,29 +521,30 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl consensus_aura::AuraApi<Block, AuraId> for Runtime {
|
impl aura_primitives::AuraApi<Block, AuraId> for Runtime {
|
||||||
fn slot_duration() -> u64 { 1 }
|
fn slot_duration() -> u64 { 1 }
|
||||||
fn authorities() -> Vec<AuraId> { system::authorities() }
|
fn authorities() -> Vec<AuraId> { system::authorities() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl consensus_babe::BabeApi<Block> for Runtime {
|
impl babe_primitives::BabeApi<Block> for Runtime {
|
||||||
fn startup_data() -> consensus_babe::BabeConfiguration {
|
fn startup_data() -> babe_primitives::BabeConfiguration {
|
||||||
consensus_babe::BabeConfiguration {
|
babe_primitives::BabeConfiguration {
|
||||||
median_required_blocks: 0,
|
median_required_blocks: 0,
|
||||||
slot_duration: 3,
|
slot_duration: 3,
|
||||||
expected_block_time: 1,
|
c: (3, 10),
|
||||||
threshold: core::u64::MAX,
|
|
||||||
slots_per_epoch: 6,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn epoch() -> consensus_babe::Epoch {
|
|
||||||
|
fn epoch() -> babe_primitives::Epoch {
|
||||||
let authorities = system::authorities();
|
let authorities = system::authorities();
|
||||||
let authorities: Vec<_> = authorities.into_iter().map(|x|(x, 1)).collect();
|
let authorities: Vec<_> = authorities.into_iter().map(|x|(x, 1)).collect();
|
||||||
consensus_babe::Epoch {
|
|
||||||
|
babe_primitives::Epoch {
|
||||||
|
start_slot: <srml_babe::Module<Runtime>>::epoch_start_slot(),
|
||||||
authorities,
|
authorities,
|
||||||
randomness: <srml_babe::Module<Runtime>>::randomness(),
|
randomness: <srml_babe::Module<Runtime>>::randomness(),
|
||||||
epoch_index: 1,
|
epoch_index: <srml_babe::Module<Runtime>>::epoch_index(),
|
||||||
duration: 6,
|
duration: EpochDuration::get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -669,30 +677,30 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl consensus_aura::AuraApi<Block, AuraId> for Runtime {
|
impl aura_primitives::AuraApi<Block, AuraId> for Runtime {
|
||||||
fn slot_duration() -> u64 { 1 }
|
fn slot_duration() -> u64 { 1 }
|
||||||
fn authorities() -> Vec<AuraId> { system::authorities() }
|
fn authorities() -> Vec<AuraId> { system::authorities() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl consensus_babe::BabeApi<Block> for Runtime {
|
impl babe_primitives::BabeApi<Block> for Runtime {
|
||||||
fn startup_data() -> consensus_babe::BabeConfiguration {
|
fn startup_data() -> babe_primitives::BabeConfiguration {
|
||||||
consensus_babe::BabeConfiguration {
|
babe_primitives::BabeConfiguration {
|
||||||
median_required_blocks: 0,
|
median_required_blocks: 0,
|
||||||
slot_duration: 1,
|
slot_duration: 1,
|
||||||
expected_block_time: 1,
|
c: (3, 10),
|
||||||
threshold: core::u64::MAX,
|
|
||||||
slots_per_epoch: 6,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn epoch() -> consensus_babe::Epoch {
|
fn epoch() -> babe_primitives::Epoch {
|
||||||
let authorities = system::authorities();
|
let authorities = system::authorities();
|
||||||
let authorities: Vec<_> = authorities.into_iter().map(|x|(x, 1)).collect();
|
let authorities: Vec<_> = authorities.into_iter().map(|x|(x, 1)).collect();
|
||||||
consensus_babe::Epoch {
|
|
||||||
|
babe_primitives::Epoch {
|
||||||
|
start_slot: <srml_babe::Module<Runtime>>::epoch_start_slot(),
|
||||||
authorities,
|
authorities,
|
||||||
randomness: <srml_babe::Module<Runtime>>::randomness(),
|
randomness: <srml_babe::Module<Runtime>>::randomness(),
|
||||||
epoch_index: 1,
|
epoch_index: <srml_babe::Module<Runtime>>::epoch_index(),
|
||||||
duration: 6,
|
duration: EpochDuration::get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -313,16 +313,16 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use runtime_io::{with_externalities, TestExternalities};
|
use runtime_io::{with_externalities, TestExternalities};
|
||||||
use substrate_test_runtime_client::{AuthorityKeyring, AccountKeyring};
|
use substrate_test_runtime_client::{AccountKeyring, Sr25519Keyring};
|
||||||
use crate::{Header, Transfer, WASM_BINARY};
|
use crate::{Header, Transfer, WASM_BINARY};
|
||||||
use primitives::{Blake2Hasher, map};
|
use primitives::{Blake2Hasher, map};
|
||||||
use substrate_executor::WasmExecutor;
|
use substrate_executor::WasmExecutor;
|
||||||
|
|
||||||
fn new_test_ext() -> TestExternalities<Blake2Hasher> {
|
fn new_test_ext() -> TestExternalities<Blake2Hasher> {
|
||||||
let authorities = vec![
|
let authorities = vec![
|
||||||
AuthorityKeyring::Alice.to_raw_public(),
|
Sr25519Keyring::Alice.to_raw_public(),
|
||||||
AuthorityKeyring::Bob.to_raw_public(),
|
Sr25519Keyring::Bob.to_raw_public(),
|
||||||
AuthorityKeyring::Charlie.to_raw_public()
|
Sr25519Keyring::Charlie.to_raw_public()
|
||||||
];
|
];
|
||||||
TestExternalities::new(map![
|
TestExternalities::new(map![
|
||||||
twox_128(b"latest").to_vec() => vec![69u8; 32],
|
twox_128(b"latest").to_vec() => vec![69u8; 32],
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ impl<H, N, V> ForkTree<H, N, V> where
|
|||||||
let node = root.find_node_where(hash, number, is_descendent_of, predicate)?;
|
let node = root.find_node_where(hash, number, is_descendent_of, predicate)?;
|
||||||
|
|
||||||
// found the node, early exit
|
// found the node, early exit
|
||||||
if node.is_some() {
|
if let Some(node) = node {
|
||||||
return Ok(node);
|
return Ok(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -498,7 +498,7 @@ mod node_implementation {
|
|||||||
number: &N,
|
number: &N,
|
||||||
is_descendent_of: &F,
|
is_descendent_of: &F,
|
||||||
predicate: &P,
|
predicate: &P,
|
||||||
) -> Result<Option<&Node<H, N, V>>, Error<E>>
|
) -> Result<Option<Option<&Node<H, N, V>>>, Error<E>>
|
||||||
where E: std::error::Error,
|
where E: std::error::Error,
|
||||||
F: Fn(&H, &H) -> Result<bool, E>,
|
F: Fn(&H, &H) -> Result<bool, E>,
|
||||||
P: Fn(&V) -> bool,
|
P: Fn(&V) -> bool,
|
||||||
@@ -519,10 +519,18 @@ mod node_implementation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// node not found in any of the descendents, if the node we're
|
// node not found in any of the descendents, if the node we're
|
||||||
// searching for is a descendent of this node and it passes the
|
// searching for is a descendent of this node then we will stop the
|
||||||
// predicate, then it is this one.
|
// search here, since there aren't any more children and we found
|
||||||
if predicate(&self.data) && is_descendent_of(&self.hash, hash)? {
|
// the correct node so we don't want to backtrack.
|
||||||
Ok(Some(self))
|
if is_descendent_of(&self.hash, hash)? {
|
||||||
|
// if the predicate passes we return the node
|
||||||
|
if predicate(&self.data) {
|
||||||
|
Ok(Some(Some(self)))
|
||||||
|
|
||||||
|
// otherwise we stop the search returning `None`
|
||||||
|
} else {
|
||||||
|
Ok(Some(None))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
@@ -1033,4 +1041,38 @@ mod test {
|
|||||||
vec!["C", "D", "E"],
|
vec!["C", "D", "E"],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn find_node_doesnt_backtrack_after_finding_highest_descending_node() {
|
||||||
|
let mut tree = ForkTree::new();
|
||||||
|
|
||||||
|
//
|
||||||
|
// A - B
|
||||||
|
// \
|
||||||
|
// — C
|
||||||
|
//
|
||||||
|
let is_descendent_of = |base: &&str, block: &&str| -> Result<bool, TestError> {
|
||||||
|
match (*base, *block) {
|
||||||
|
("A", b) => Ok(b == "B" || b == "C" || b == "D"),
|
||||||
|
("B", b) | ("C", b) => Ok(b == "D"),
|
||||||
|
("0", _) => Ok(true),
|
||||||
|
_ => Ok(false),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tree.import("A", 1, 1, &is_descendent_of).unwrap();
|
||||||
|
tree.import("B", 2, 4, &is_descendent_of).unwrap();
|
||||||
|
tree.import("C", 2, 4, &is_descendent_of).unwrap();
|
||||||
|
|
||||||
|
// when searching the tree we reach both node `B` and `C`, but the
|
||||||
|
// predicate doesn't pass. still, we should not backtrack to node `A`.
|
||||||
|
let node = tree.find_node_where(
|
||||||
|
&"D",
|
||||||
|
&3,
|
||||||
|
&is_descendent_of,
|
||||||
|
&|data| *data < 3,
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(node, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ substrate-basic-authorship = { path = "../../core/basic-authorship" }
|
|||||||
substrate-service = { path = "../../core/service" }
|
substrate-service = { path = "../../core/service" }
|
||||||
transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" }
|
transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" }
|
||||||
network = { package = "substrate-network", path = "../../core/network" }
|
network = { package = "substrate-network", path = "../../core/network" }
|
||||||
aura = { package = "substrate-consensus-aura", path = "../../core/consensus/aura" }
|
babe = { package = "substrate-consensus-babe", path = "../../core/consensus/babe" }
|
||||||
aura_primitives = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives" }
|
babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives" }
|
||||||
grandpa = { package = "substrate-finality-grandpa", path = "../../core/finality-grandpa" }
|
grandpa = { package = "substrate-finality-grandpa", path = "../../core/finality-grandpa" }
|
||||||
grandpa_primitives = { package = "substrate-finality-grandpa-primitives", path = "../../core/finality-grandpa/primitives" }
|
grandpa_primitives = { package = "substrate-finality-grandpa-primitives", path = "../../core/finality-grandpa/primitives" }
|
||||||
sr-primitives = { path = "../../core/sr-primitives" }
|
sr-primitives = { path = "../../core/sr-primitives" }
|
||||||
@@ -44,6 +44,7 @@ system = { package = "srml-system", path = "../../srml/system" }
|
|||||||
balances = { package = "srml-balances", path = "../../srml/balances" }
|
balances = { package = "srml-balances", path = "../../srml/balances" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
babe = { package = "substrate-consensus-babe", path = "../../core/consensus/babe", features = ["test-helpers"] }
|
||||||
consensus-common = { package = "substrate-consensus-common", path = "../../core/consensus/common" }
|
consensus-common = { package = "substrate-consensus-common", path = "../../core/consensus/common" }
|
||||||
service-test = { package = "substrate-service-test", path = "../../core/service/test" }
|
service-test = { package = "substrate-service-test", path = "../../core/service/test" }
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,14 @@
|
|||||||
|
|
||||||
//! Substrate chain configurations.
|
//! Substrate chain configurations.
|
||||||
|
|
||||||
|
use babe_primitives::AuthorityId as BabeId;
|
||||||
use primitives::{ed25519, sr25519, Pair, crypto::UncheckedInto};
|
use primitives::{ed25519, sr25519, Pair, crypto::UncheckedInto};
|
||||||
use node_primitives::{AccountId, AuraId, Balance};
|
use node_primitives::{AccountId, Balance};
|
||||||
use node_runtime::{
|
use node_runtime::{
|
||||||
GrandpaConfig, BalancesConfig, ContractsConfig, ElectionsConfig, DemocracyConfig,
|
BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig,
|
||||||
CouncilConfig, AuraConfig, ImOnlineConfig, IndicesConfig, SessionConfig, StakingConfig,
|
ElectionsConfig, GrandpaConfig, ImOnlineConfig, IndicesConfig, Perbill,
|
||||||
SudoConfig, TechnicalCommitteeConfig, SystemConfig, WASM_BINARY, Perbill, SessionKeys,
|
SessionConfig, SessionKeys, StakerStatus, StakingConfig, SudoConfig, SystemConfig,
|
||||||
StakerStatus, DAYS, DOLLARS, MILLICENTS,
|
TechnicalCommitteeConfig, DAYS, DOLLARS, MILLICENTS, WASM_BINARY,
|
||||||
};
|
};
|
||||||
pub use node_runtime::GenesisConfig;
|
pub use node_runtime::GenesisConfig;
|
||||||
use substrate_service;
|
use substrate_service;
|
||||||
@@ -40,8 +41,11 @@ pub fn flaming_fir_config() -> Result<ChainSpec, String> {
|
|||||||
ChainSpec::from_embedded(include_bytes!("../res/flaming-fir.json"))
|
ChainSpec::from_embedded(include_bytes!("../res/flaming-fir.json"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn session_keys(key: ed25519::Public) -> SessionKeys {
|
fn session_keys(ed_key: ed25519::Public, sr_key: sr25519::Public) -> SessionKeys {
|
||||||
SessionKeys { ed25519: key }
|
SessionKeys {
|
||||||
|
ed25519: ed_key,
|
||||||
|
sr25519: sr_key,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn staging_testnet_config_genesis() -> GenesisConfig {
|
fn staging_testnet_config_genesis() -> GenesisConfig {
|
||||||
@@ -51,7 +55,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
|||||||
// and
|
// and
|
||||||
// for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 inspect "$secret"//fir//$j//$i; done; done
|
// for i in 1 2 3 4 ; do for j in session; do subkey --ed25519 inspect "$secret"//fir//$j//$i; done; done
|
||||||
|
|
||||||
let initial_authorities: Vec<(AccountId, AccountId, AuraId, GrandpaId)> = vec![(
|
let initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId)> = vec![(
|
||||||
// 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy
|
// 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy
|
||||||
hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].unchecked_into(),
|
hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].unchecked_into(),
|
||||||
// 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq
|
// 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq
|
||||||
@@ -116,7 +120,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
|||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
}),
|
}),
|
||||||
session: Some(SessionConfig {
|
session: Some(SessionConfig {
|
||||||
keys: initial_authorities.iter().map(|x| (x.0.clone(), session_keys(x.2.clone()))).collect::<Vec<_>>(),
|
keys: initial_authorities.iter().map(|x| {
|
||||||
|
(x.0.clone(), session_keys(x.3.clone(), x.2.clone()))
|
||||||
|
}).collect::<Vec<_>>(),
|
||||||
}),
|
}),
|
||||||
staking: Some(StakingConfig {
|
staking: Some(StakingConfig {
|
||||||
current_era: 0,
|
current_era: 0,
|
||||||
@@ -124,7 +130,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
|||||||
validator_count: 7,
|
validator_count: 7,
|
||||||
offline_slash_grace: 4,
|
offline_slash_grace: 4,
|
||||||
minimum_validator_count: 4,
|
minimum_validator_count: 4,
|
||||||
stakers: initial_authorities.iter().map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)).collect(),
|
stakers: initial_authorities.iter().map(|x| {
|
||||||
|
(x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)
|
||||||
|
}).collect(),
|
||||||
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
|
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
|
||||||
}),
|
}),
|
||||||
democracy: Some(DemocracyConfig::default()),
|
democracy: Some(DemocracyConfig::default()),
|
||||||
@@ -149,8 +157,8 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
|||||||
sudo: Some(SudoConfig {
|
sudo: Some(SudoConfig {
|
||||||
key: endowed_accounts[0].clone(),
|
key: endowed_accounts[0].clone(),
|
||||||
}),
|
}),
|
||||||
aura: Some(AuraConfig {
|
babe: Some(BabeConfig {
|
||||||
authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(),
|
authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(),
|
||||||
}),
|
}),
|
||||||
im_online: Some(ImOnlineConfig {
|
im_online: Some(ImOnlineConfig {
|
||||||
gossip_at: 0,
|
gossip_at: 0,
|
||||||
@@ -184,9 +192,9 @@ pub fn get_account_id_from_seed(seed: &str) -> AccountId {
|
|||||||
.public()
|
.public()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to generate AuraId from seed
|
/// Helper function to generate BabeId from seed
|
||||||
pub fn get_aura_id_from_seed(seed: &str) -> AuraId {
|
pub fn get_babe_id_from_seed(seed: &str) -> BabeId {
|
||||||
ed25519::Pair::from_string(&format!("//{}", seed), None)
|
sr25519::Pair::from_string(&format!("//{}", seed), None)
|
||||||
.expect("static values are valid; qed")
|
.expect("static values are valid; qed")
|
||||||
.public()
|
.public()
|
||||||
}
|
}
|
||||||
@@ -199,18 +207,18 @@ pub fn get_grandpa_id_from_seed(seed: &str) -> GrandpaId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to generate stash, controller and session key from seed
|
/// Helper function to generate stash, controller and session key from seed
|
||||||
pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, AuraId, GrandpaId) {
|
pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, BabeId, GrandpaId) {
|
||||||
(
|
(
|
||||||
get_account_id_from_seed(&format!("{}//stash", seed)),
|
get_account_id_from_seed(&format!("{}//stash", seed)),
|
||||||
get_account_id_from_seed(seed),
|
get_account_id_from_seed(seed),
|
||||||
get_aura_id_from_seed(seed),
|
get_babe_id_from_seed(seed),
|
||||||
get_grandpa_id_from_seed(seed)
|
get_grandpa_id_from_seed(seed)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to create GenesisConfig for testing
|
/// Helper function to create GenesisConfig for testing
|
||||||
pub fn testnet_genesis(
|
pub fn testnet_genesis(
|
||||||
initial_authorities: Vec<(AccountId, AccountId, AuraId, GrandpaId)>,
|
initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId)>,
|
||||||
root_key: AccountId,
|
root_key: AccountId,
|
||||||
endowed_accounts: Option<Vec<AccountId>>,
|
endowed_accounts: Option<Vec<AccountId>>,
|
||||||
enable_println: bool,
|
enable_println: bool,
|
||||||
@@ -250,7 +258,9 @@ pub fn testnet_genesis(
|
|||||||
vesting: vec![],
|
vesting: vec![],
|
||||||
}),
|
}),
|
||||||
session: Some(SessionConfig {
|
session: Some(SessionConfig {
|
||||||
keys: initial_authorities.iter().map(|x| (x.0.clone(), session_keys(x.2.clone()))).collect::<Vec<_>>(),
|
keys: initial_authorities.iter().map(|x| {
|
||||||
|
(x.0.clone(), session_keys(x.3.clone(), x.2.clone()))
|
||||||
|
}).collect::<Vec<_>>(),
|
||||||
}),
|
}),
|
||||||
staking: Some(StakingConfig {
|
staking: Some(StakingConfig {
|
||||||
current_era: 0,
|
current_era: 0,
|
||||||
@@ -258,7 +268,9 @@ pub fn testnet_genesis(
|
|||||||
validator_count: 2,
|
validator_count: 2,
|
||||||
offline_slash: Perbill::zero(),
|
offline_slash: Perbill::zero(),
|
||||||
offline_slash_grace: 0,
|
offline_slash_grace: 0,
|
||||||
stakers: initial_authorities.iter().map(|x| (x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)).collect(),
|
stakers: initial_authorities.iter().map(|x| {
|
||||||
|
(x.0.clone(), x.1.clone(), STASH, StakerStatus::Validator)
|
||||||
|
}).collect(),
|
||||||
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
|
invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
|
||||||
}),
|
}),
|
||||||
democracy: Some(DemocracyConfig::default()),
|
democracy: Some(DemocracyConfig::default()),
|
||||||
@@ -288,8 +300,8 @@ pub fn testnet_genesis(
|
|||||||
sudo: Some(SudoConfig {
|
sudo: Some(SudoConfig {
|
||||||
key: root_key,
|
key: root_key,
|
||||||
}),
|
}),
|
||||||
aura: Some(AuraConfig {
|
babe: Some(BabeConfig {
|
||||||
authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(),
|
authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(),
|
||||||
}),
|
}),
|
||||||
im_online: Some(ImOnlineConfig{
|
im_online: Some(ImOnlineConfig{
|
||||||
gossip_at: 0,
|
gossip_at: 0,
|
||||||
|
|||||||
@@ -21,14 +21,15 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use aura::{import_queue, start_aura, AuraImportQueue, SlotDuration};
|
use babe::{import_queue, start_babe, BabeImportQueue, Config};
|
||||||
|
use babe_primitives::AuthorityPair as BabePair;
|
||||||
use client::{self, LongestChain};
|
use client::{self, LongestChain};
|
||||||
use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
|
use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
|
||||||
use node_executor;
|
use node_executor;
|
||||||
use primitives::Pair;
|
use primitives::Pair;
|
||||||
use grandpa_primitives::AuthorityPair as GrandpaPair;
|
use grandpa_primitives::AuthorityPair as GrandpaPair;
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use node_primitives::{AuraPair, Block};
|
use node_primitives::Block;
|
||||||
use node_runtime::{GenesisConfig, RuntimeApi};
|
use node_runtime::{GenesisConfig, RuntimeApi};
|
||||||
use substrate_service::{
|
use substrate_service::{
|
||||||
FactoryFullConfiguration, LightComponents, FullComponents, FullBackend,
|
FactoryFullConfiguration, LightComponents, FullComponents, FullBackend,
|
||||||
@@ -47,19 +48,40 @@ construct_simple_protocol! {
|
|||||||
pub struct NodeProtocol where Block = Block { }
|
pub struct NodeProtocol where Block = Block { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BabeBlockImportForService<F> = babe::BabeBlockImport<
|
||||||
|
FullBackend<F>,
|
||||||
|
FullExecutor<F>,
|
||||||
|
<F as crate::ServiceFactory>::Block,
|
||||||
|
grandpa::BlockImportForService<F>,
|
||||||
|
<F as crate::ServiceFactory>::RuntimeApi,
|
||||||
|
client::Client<
|
||||||
|
FullBackend<F>,
|
||||||
|
FullExecutor<F>,
|
||||||
|
<F as crate::ServiceFactory>::Block,
|
||||||
|
<F as crate::ServiceFactory>::RuntimeApi
|
||||||
|
>,
|
||||||
|
>;
|
||||||
|
|
||||||
/// Node specific configuration
|
/// Node specific configuration
|
||||||
pub struct NodeConfig<F: substrate_service::ServiceFactory> {
|
pub struct NodeConfig<F: substrate_service::ServiceFactory> {
|
||||||
/// grandpa connection to import block
|
/// GRANDPA and BABE connection to import block.
|
||||||
// FIXME #1134 rather than putting this on the config, let's have an actual intermediate setup state
|
// FIXME #1134 rather than putting this on the config, let's have an actual intermediate setup state
|
||||||
pub grandpa_import_setup: Option<(grandpa::BlockImportForService<F>, grandpa::LinkHalfForService<F>)>,
|
pub import_setup: Option<(
|
||||||
|
BabeBlockImportForService<F>,
|
||||||
|
grandpa::LinkHalfForService<F>,
|
||||||
|
babe::BabeLink,
|
||||||
|
)>,
|
||||||
|
/// Tasks that were created by previous setup steps and should be spawned.
|
||||||
|
pub tasks_to_spawn: Option<Vec<Box<dyn Future<Item = (), Error = ()> + Send>>>,
|
||||||
inherent_data_providers: InherentDataProviders,
|
inherent_data_providers: InherentDataProviders,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Default for NodeConfig<F> where F: substrate_service::ServiceFactory {
|
impl<F> Default for NodeConfig<F> where F: substrate_service::ServiceFactory {
|
||||||
fn default() -> NodeConfig<F> {
|
fn default() -> NodeConfig<F> {
|
||||||
NodeConfig {
|
NodeConfig {
|
||||||
grandpa_import_setup: None,
|
import_setup: None,
|
||||||
inherent_data_providers: InherentDataProviders::new(),
|
inherent_data_providers: InherentDataProviders::new(),
|
||||||
|
tasks_to_spawn: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,7 +89,7 @@ impl<F> Default for NodeConfig<F> where F: substrate_service::ServiceFactory {
|
|||||||
construct_service_factory! {
|
construct_service_factory! {
|
||||||
struct Factory {
|
struct Factory {
|
||||||
Block = Block,
|
Block = Block,
|
||||||
ConsensusPair = AuraPair,
|
ConsensusPair = BabePair,
|
||||||
FinalityPair = GrandpaPair,
|
FinalityPair = GrandpaPair,
|
||||||
RuntimeApi = RuntimeApi,
|
RuntimeApi = RuntimeApi,
|
||||||
NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) },
|
NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) },
|
||||||
@@ -83,11 +105,22 @@ construct_service_factory! {
|
|||||||
FullComponents::<Factory>::new(config) },
|
FullComponents::<Factory>::new(config) },
|
||||||
AuthoritySetup = {
|
AuthoritySetup = {
|
||||||
|mut service: Self::FullService| {
|
|mut service: Self::FullService| {
|
||||||
let (block_import, link_half) = service.config.custom.grandpa_import_setup.take()
|
let (block_import, link_half, babe_link) = service.config.custom.import_setup.take()
|
||||||
.expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
|
.expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
|
||||||
|
|
||||||
if let Some(aura_key) = service.authority_key() {
|
// spawn any futures that were created in the previous setup steps
|
||||||
info!("Using aura key {}", aura_key.public());
|
if let Some(tasks) = service.config.custom.tasks_to_spawn.take() {
|
||||||
|
for task in tasks {
|
||||||
|
service.spawn_task(
|
||||||
|
task.select(service.on_exit())
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|_| ())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(babe_key) = service.authority_key() {
|
||||||
|
info!("Using BABE key {}", babe_key.public());
|
||||||
|
|
||||||
let proposer = Arc::new(substrate_basic_authorship::ProposerFactory {
|
let proposer = Arc::new(substrate_basic_authorship::ProposerFactory {
|
||||||
client: service.client(),
|
client: service.client(),
|
||||||
@@ -98,18 +131,21 @@ construct_service_factory! {
|
|||||||
let select_chain = service.select_chain()
|
let select_chain = service.select_chain()
|
||||||
.ok_or(ServiceError::SelectChainRequired)?;
|
.ok_or(ServiceError::SelectChainRequired)?;
|
||||||
|
|
||||||
let aura = start_aura(
|
let babe_config = babe::BabeParams {
|
||||||
SlotDuration::get_or_compute(&*client)?,
|
config: Config::get_or_compute(&*client)?,
|
||||||
Arc::new(aura_key),
|
local_key: Arc::new(babe_key),
|
||||||
client,
|
client,
|
||||||
select_chain,
|
select_chain,
|
||||||
block_import,
|
block_import,
|
||||||
proposer,
|
env: proposer,
|
||||||
service.network(),
|
sync_oracle: service.network(),
|
||||||
service.config.custom.inherent_data_providers.clone(),
|
inherent_data_providers: service.config.custom.inherent_data_providers.clone(),
|
||||||
service.config.force_authoring,
|
force_authoring: service.config.force_authoring,
|
||||||
)?;
|
time_source: babe_link,
|
||||||
let select = aura.select(service.on_exit()).then(|_| Ok(()));
|
};
|
||||||
|
|
||||||
|
let babe = start_babe(babe_config)?;
|
||||||
|
let select = babe.select(service.on_exit()).then(|_| Ok(()));
|
||||||
service.spawn_task(Box::new(select));
|
service.spawn_task(Box::new(select));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,27 +194,30 @@ construct_service_factory! {
|
|||||||
},
|
},
|
||||||
LightService = LightComponents<Self>
|
LightService = LightComponents<Self>
|
||||||
{ |config| <LightComponents<Factory>>::new(config) },
|
{ |config| <LightComponents<Factory>>::new(config) },
|
||||||
FullImportQueue = AuraImportQueue<Self::Block>
|
FullImportQueue = BabeImportQueue<Self::Block>
|
||||||
{ |config: &mut FactoryFullConfiguration<Self> , client: Arc<FullClient<Self>>, select_chain: Self::SelectChain| {
|
{ |config: &mut FactoryFullConfiguration<Self> , client: Arc<FullClient<Self>>, select_chain: Self::SelectChain| {
|
||||||
let slot_duration = SlotDuration::get_or_compute(&*client)?;
|
|
||||||
let (block_import, link_half) =
|
let (block_import, link_half) =
|
||||||
grandpa::block_import::<_, _, _, RuntimeApi, FullClient<Self>, _>(
|
grandpa::block_import::<_, _, _, RuntimeApi, FullClient<Self>, _>(
|
||||||
client.clone(), client.clone(), select_chain
|
client.clone(), client.clone(), select_chain
|
||||||
)?;
|
)?;
|
||||||
let justification_import = block_import.clone();
|
let justification_import = block_import.clone();
|
||||||
|
|
||||||
config.custom.grandpa_import_setup = Some((block_import.clone(), link_half));
|
let (import_queue, babe_link, babe_block_import, pruning_task) = import_queue(
|
||||||
|
Config::get_or_compute(&*client)?,
|
||||||
import_queue::<_, _, AuraPair>(
|
block_import,
|
||||||
slot_duration,
|
|
||||||
Box::new(block_import),
|
|
||||||
Some(Box::new(justification_import)),
|
Some(Box::new(justification_import)),
|
||||||
None,
|
None,
|
||||||
|
client.clone(),
|
||||||
client,
|
client,
|
||||||
config.custom.inherent_data_providers.clone(),
|
config.custom.inherent_data_providers.clone(),
|
||||||
).map_err(Into::into)
|
)?;
|
||||||
|
|
||||||
|
config.custom.import_setup = Some((babe_block_import.clone(), link_half, babe_link));
|
||||||
|
config.custom.tasks_to_spawn = Some(vec![Box::new(pruning_task)]);
|
||||||
|
|
||||||
|
Ok(import_queue)
|
||||||
}},
|
}},
|
||||||
LightImportQueue = AuraImportQueue<Self::Block>
|
LightImportQueue = BabeImportQueue<Self::Block>
|
||||||
{ |config: &FactoryFullConfiguration<Self>, client: Arc<LightClient<Self>>| {
|
{ |config: &FactoryFullConfiguration<Self>, client: Arc<LightClient<Self>>| {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let fetch_checker = client.backend().blockchain().fetcher()
|
let fetch_checker = client.backend().blockchain().fetcher()
|
||||||
@@ -188,17 +227,22 @@ construct_service_factory! {
|
|||||||
let block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, LightClient<Self>>(
|
let block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, LightClient<Self>>(
|
||||||
client.clone(), Arc::new(fetch_checker), client.clone()
|
client.clone(), Arc::new(fetch_checker), client.clone()
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let finality_proof_import = block_import.clone();
|
let finality_proof_import = block_import.clone();
|
||||||
let finality_proof_request_builder = finality_proof_import.create_finality_proof_request_builder();
|
let finality_proof_request_builder = finality_proof_import.create_finality_proof_request_builder();
|
||||||
|
|
||||||
import_queue::<_, _, AuraPair>(
|
// FIXME: pruning task isn't started since light client doesn't do `AuthoritySetup`.
|
||||||
SlotDuration::get_or_compute(&*client)?,
|
let (import_queue, ..) = import_queue(
|
||||||
Box::new(block_import),
|
Config::get_or_compute(&*client)?,
|
||||||
|
block_import,
|
||||||
None,
|
None,
|
||||||
Some(Box::new(finality_proof_import)),
|
Some(Box::new(finality_proof_import)),
|
||||||
|
client.clone(),
|
||||||
client,
|
client,
|
||||||
config.custom.inherent_data_providers.clone(),
|
config.custom.inherent_data_providers.clone(),
|
||||||
).map(|q| (q, finality_proof_request_builder)).map_err(Into::into)
|
)?;
|
||||||
|
|
||||||
|
Ok((import_queue, finality_proof_request_builder))
|
||||||
}},
|
}},
|
||||||
SelectChain = LongestChain<FullBackend<Self>, Self::Block>
|
SelectChain = LongestChain<FullBackend<Self>, Self::Block>
|
||||||
{ |config: &FactoryFullConfiguration<Self>, client: Arc<FullClient<Self>>| {
|
{ |config: &FactoryFullConfiguration<Self>, client: Arc<FullClient<Self>>| {
|
||||||
@@ -216,25 +260,27 @@ construct_service_factory! {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use aura::CompatibleDigestItem;
|
use babe::CompatibleDigestItem;
|
||||||
use consensus_common::{Environment, Proposer, BlockImportParams, BlockOrigin, ForkChoiceStrategy};
|
use consensus_common::{Environment, Proposer, BlockImportParams, BlockOrigin, ForkChoiceStrategy};
|
||||||
use node_primitives::DigestItem;
|
use node_primitives::DigestItem;
|
||||||
use node_runtime::{BalancesCall, Call, CENTS, SECS_PER_BLOCK, UncheckedExtrinsic};
|
use node_runtime::{BalancesCall, Call, CENTS, SECS_PER_BLOCK, UncheckedExtrinsic};
|
||||||
use parity_codec::{Encode, Decode};
|
use parity_codec::{Encode, Decode};
|
||||||
use primitives::{
|
use primitives::{
|
||||||
crypto::Pair as CryptoPair, ed25519::Pair, blake2_256,
|
crypto::Pair as CryptoPair, blake2_256,
|
||||||
sr25519::Public as AddressPublic, H256,
|
sr25519::Public as AddressPublic, H256,
|
||||||
};
|
};
|
||||||
use sr_primitives::{generic::{BlockId, Era, Digest}, traits::Block, OpaqueExtrinsic};
|
use sr_primitives::{generic::{BlockId, Era, Digest}, traits::Block, OpaqueExtrinsic};
|
||||||
use timestamp;
|
use timestamp;
|
||||||
use finality_tracker;
|
use finality_tracker;
|
||||||
use keyring::{ed25519::Keyring as AuthorityKeyring, sr25519::Keyring as AccountKeyring};
|
use keyring::{AccountKeyring, Sr25519Keyring};
|
||||||
use substrate_service::ServiceFactory;
|
use substrate_service::ServiceFactory;
|
||||||
use service_test::SyncService;
|
use service_test::SyncService;
|
||||||
use crate::service::Factory;
|
use crate::service::Factory;
|
||||||
|
|
||||||
#[cfg(feature = "rhd")]
|
#[cfg(feature = "rhd")]
|
||||||
fn test_sync() {
|
fn test_sync() {
|
||||||
|
use primitives::ed25519::Pair;
|
||||||
|
|
||||||
use {service_test, Factory};
|
use {service_test, Factory};
|
||||||
use client::{BlockImportParams, BlockOrigin};
|
use client::{BlockImportParams, BlockOrigin};
|
||||||
|
|
||||||
@@ -294,7 +340,7 @@ mod tests {
|
|||||||
fn test_sync() {
|
fn test_sync() {
|
||||||
let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
|
let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority();
|
||||||
|
|
||||||
let alice = Arc::new(AuthorityKeyring::Alice.pair());
|
let alice = Arc::new(Sr25519Keyring::Alice.pair());
|
||||||
let mut slot_num = 1u64;
|
let mut slot_num = 1u64;
|
||||||
let block_factory = |service: &SyncService<<Factory as ServiceFactory>::FullService>| {
|
let block_factory = |service: &SyncService<<Factory as ServiceFactory>::FullService>| {
|
||||||
let service = service.get();
|
let service = service.get();
|
||||||
@@ -305,7 +351,6 @@ mod tests {
|
|||||||
.create_inherent_data()
|
.create_inherent_data()
|
||||||
.expect("Creates inherent data.");
|
.expect("Creates inherent data.");
|
||||||
inherent_data.replace_data(finality_tracker::INHERENT_IDENTIFIER, &1u64);
|
inherent_data.replace_data(finality_tracker::INHERENT_IDENTIFIER, &1u64);
|
||||||
inherent_data.replace_data(timestamp::INHERENT_IDENTIFIER, &(slot_num * SECS_PER_BLOCK));
|
|
||||||
|
|
||||||
let parent_id = BlockId::number(service.client().info().chain.best_number);
|
let parent_id = BlockId::number(service.client().info().chain.best_number);
|
||||||
let parent_header = service.client().header(&parent_id).unwrap().unwrap();
|
let parent_header = service.client().header(&parent_id).unwrap().unwrap();
|
||||||
@@ -315,7 +360,26 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let mut digest = Digest::<H256>::default();
|
let mut digest = Digest::<H256>::default();
|
||||||
digest.push(<DigestItem as CompatibleDigestItem<Pair>>::aura_pre_digest(slot_num));
|
|
||||||
|
// even though there's only one authority some slots might be empty,
|
||||||
|
// so we must keep trying the next slots until we can claim one.
|
||||||
|
let babe_pre_digest = loop {
|
||||||
|
inherent_data.replace_data(timestamp::INHERENT_IDENTIFIER, &(slot_num * SECS_PER_BLOCK));
|
||||||
|
if let Some(babe_pre_digest) = babe::test_helpers::claim_slot(
|
||||||
|
&*service.client(),
|
||||||
|
&parent_id,
|
||||||
|
slot_num,
|
||||||
|
&alice,
|
||||||
|
(3, 10),
|
||||||
|
) {
|
||||||
|
break babe_pre_digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot_num += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
digest.push(<DigestItem as CompatibleDigestItem>::babe_pre_digest(babe_pre_digest));
|
||||||
|
|
||||||
let proposer = proposer_factory.init(&parent_header).unwrap();
|
let proposer = proposer_factory.init(&parent_header).unwrap();
|
||||||
let new_block = proposer.propose(
|
let new_block = proposer.propose(
|
||||||
inherent_data,
|
inherent_data,
|
||||||
@@ -329,7 +393,7 @@ mod tests {
|
|||||||
// add it to a digest item.
|
// add it to a digest item.
|
||||||
let to_sign = pre_hash.encode();
|
let to_sign = pre_hash.encode();
|
||||||
let signature = alice.sign(&to_sign[..]);
|
let signature = alice.sign(&to_sign[..]);
|
||||||
let item = <DigestItem as CompatibleDigestItem<Pair>>::aura_seal(
|
let item = <DigestItem as CompatibleDigestItem>::babe_seal(
|
||||||
signature,
|
signature,
|
||||||
);
|
);
|
||||||
slot_num += 1;
|
slot_num += 1;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ mod tests {
|
|||||||
use super::Executor;
|
use super::Executor;
|
||||||
use substrate_executor::{WasmExecutor, NativeExecutionDispatch};
|
use substrate_executor::{WasmExecutor, NativeExecutionDispatch};
|
||||||
use parity_codec::{Encode, Decode, Joiner};
|
use parity_codec::{Encode, Decode, Joiner};
|
||||||
use keyring::{AuthorityKeyring, AccountKeyring};
|
use keyring::{AccountKeyring, Ed25519Keyring, Sr25519Keyring};
|
||||||
use runtime_support::{Hashable, StorageValue, StorageMap, traits::{Currency, Get}};
|
use runtime_support::{Hashable, StorageValue, StorageMap, traits::{Currency, Get}};
|
||||||
use state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities};
|
use state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities};
|
||||||
use primitives::{
|
use primitives::{
|
||||||
@@ -314,15 +314,19 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_session_keys(ring: &AuthorityKeyring) -> SessionKeys {
|
fn to_session_keys(
|
||||||
|
ed25519_keyring: &Ed25519Keyring,
|
||||||
|
sr25519_keyring: &Sr25519Keyring,
|
||||||
|
) -> SessionKeys {
|
||||||
SessionKeys {
|
SessionKeys {
|
||||||
ed25519: ring.to_owned().into(),
|
ed25519: ed25519_keyring.to_owned().into(),
|
||||||
|
sr25519: sr25519_keyring.to_owned().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities<Blake2Hasher> {
|
fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities<Blake2Hasher> {
|
||||||
let mut ext = TestExternalities::new_with_code_with_children(code, GenesisConfig {
|
let mut ext = TestExternalities::new_with_code_with_children(code, GenesisConfig {
|
||||||
aura: Some(Default::default()),
|
babe: Some(Default::default()),
|
||||||
system: Some(SystemConfig {
|
system: Some(SystemConfig {
|
||||||
changes_trie_config: if support_changes_trie { Some(ChangesTrieConfiguration {
|
changes_trie_config: if support_changes_trie { Some(ChangesTrieConfiguration {
|
||||||
digest_interval: 2,
|
digest_interval: 2,
|
||||||
@@ -346,9 +350,18 @@ mod tests {
|
|||||||
}),
|
}),
|
||||||
session: Some(SessionConfig {
|
session: Some(SessionConfig {
|
||||||
keys: vec![
|
keys: vec![
|
||||||
(alice(), to_session_keys(&AuthorityKeyring::Alice)),
|
(alice(), to_session_keys(
|
||||||
(bob(), to_session_keys(&AuthorityKeyring::Bob)),
|
&Ed25519Keyring::Alice,
|
||||||
(charlie(), to_session_keys(&AuthorityKeyring::Charlie)),
|
&Sr25519Keyring::Alice,
|
||||||
|
)),
|
||||||
|
(bob(), to_session_keys(
|
||||||
|
&Ed25519Keyring::Bob,
|
||||||
|
&Sr25519Keyring::Bob,
|
||||||
|
)),
|
||||||
|
(charlie(), to_session_keys(
|
||||||
|
&Ed25519Keyring::Charlie,
|
||||||
|
&Sr25519Keyring::Charlie,
|
||||||
|
)),
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
staking: Some(StakingConfig {
|
staking: Some(StakingConfig {
|
||||||
|
|||||||
@@ -44,16 +44,6 @@ pub type Balance = u128;
|
|||||||
/// Type used for expressing timestamp.
|
/// Type used for expressing timestamp.
|
||||||
pub type Moment = u64;
|
pub type Moment = u64;
|
||||||
|
|
||||||
/// The aura crypto scheme defined via the keypair type.
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub type AuraPair = primitives::ed25519::Pair;
|
|
||||||
|
|
||||||
/// Identity of an Aura authority.
|
|
||||||
pub type AuraId = primitives::ed25519::Public;
|
|
||||||
|
|
||||||
/// Signature for an Aura authority.
|
|
||||||
pub type AuraSignature = primitives::ed25519::Signature;
|
|
||||||
|
|
||||||
/// Index of a transaction in the chain.
|
/// Index of a transaction in the chain.
|
||||||
pub type Index = u64;
|
pub type Index = u64;
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitiv
|
|||||||
offchain-primitives = { package = "substrate-offchain-primitives", path = "../../core/offchain/primitives", default-features = false }
|
offchain-primitives = { package = "substrate-offchain-primitives", path = "../../core/offchain/primitives", default-features = false }
|
||||||
version = { package = "sr-version", path = "../../core/sr-version", default-features = false }
|
version = { package = "sr-version", path = "../../core/sr-version", default-features = false }
|
||||||
support = { package = "srml-support", path = "../../srml/support", default-features = false }
|
support = { package = "srml-support", path = "../../srml/support", default-features = false }
|
||||||
aura = { package = "srml-aura", path = "../../srml/aura", default-features = false }
|
|
||||||
authorship = { package = "srml-authorship", path = "../../srml/authorship", default-features = false }
|
authorship = { package = "srml-authorship", path = "../../srml/authorship", default-features = false }
|
||||||
|
babe = { package = "srml-babe", path = "../../srml/babe", default-features = false }
|
||||||
|
babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives", default-features = false }
|
||||||
balances = { package = "srml-balances", path = "../../srml/balances", default-features = false }
|
balances = { package = "srml-balances", path = "../../srml/balances", default-features = false }
|
||||||
contracts = { package = "srml-contracts", path = "../../srml/contracts", default-features = false }
|
contracts = { package = "srml-contracts", path = "../../srml/contracts", default-features = false }
|
||||||
collective = { package = "srml-collective", path = "../../srml/collective", default-features = false }
|
collective = { package = "srml-collective", path = "../../srml/collective", default-features = false }
|
||||||
@@ -35,7 +36,6 @@ treasury = { package = "srml-treasury", path = "../../srml/treasury", default-fe
|
|||||||
sudo = { package = "srml-sudo", path = "../../srml/sudo", default-features = false }
|
sudo = { package = "srml-sudo", path = "../../srml/sudo", default-features = false }
|
||||||
im-online = { package = "srml-im-online", path = "../../srml/im-online", default-features = false }
|
im-online = { package = "srml-im-online", path = "../../srml/im-online", default-features = false }
|
||||||
node-primitives = { path = "../primitives", default-features = false }
|
node-primitives = { path = "../primitives", default-features = false }
|
||||||
consensus_aura = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives", default-features = false }
|
|
||||||
rustc-hex = { version = "2.0", optional = true }
|
rustc-hex = { version = "2.0", optional = true }
|
||||||
serde = { version = "1.0", optional = true }
|
serde = { version = "1.0", optional = true }
|
||||||
substrate-keyring = { path = "../../core/keyring", optional = true }
|
substrate-keyring = { path = "../../core/keyring", optional = true }
|
||||||
@@ -54,8 +54,9 @@ std = [
|
|||||||
"rstd/std",
|
"rstd/std",
|
||||||
"runtime_primitives/std",
|
"runtime_primitives/std",
|
||||||
"support/std",
|
"support/std",
|
||||||
"aura/std",
|
|
||||||
"authorship/std",
|
"authorship/std",
|
||||||
|
"babe/std",
|
||||||
|
"babe-primitives/std",
|
||||||
"balances/std",
|
"balances/std",
|
||||||
"contracts/std",
|
"contracts/std",
|
||||||
"collective/std",
|
"collective/std",
|
||||||
@@ -76,7 +77,6 @@ std = [
|
|||||||
"serde",
|
"serde",
|
||||||
"safe-mix/std",
|
"safe-mix/std",
|
||||||
"client/std",
|
"client/std",
|
||||||
"consensus_aura/std",
|
|
||||||
"rustc-hex",
|
"rustc-hex",
|
||||||
"substrate-keyring",
|
"substrate-keyring",
|
||||||
"offchain-primitives/std",
|
"offchain-primitives/std",
|
||||||
|
|||||||
@@ -26,9 +26,10 @@ use support::{
|
|||||||
};
|
};
|
||||||
use substrate_primitives::u32_trait::{_1, _2, _3, _4};
|
use substrate_primitives::u32_trait::{_1, _2, _3, _4};
|
||||||
use node_primitives::{
|
use node_primitives::{
|
||||||
AccountId, AccountIndex, AuraId, Balance, BlockNumber, Hash, Index,
|
AccountId, AccountIndex, Balance, BlockNumber, Hash, Index,
|
||||||
Moment, Signature,
|
Moment, Signature,
|
||||||
};
|
};
|
||||||
|
use babe::{AuthorityId as BabeId};
|
||||||
use grandpa::fg_primitives::{self, ScheduledChange};
|
use grandpa::fg_primitives::{self, ScheduledChange};
|
||||||
use client::{
|
use client::{
|
||||||
block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult},
|
block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult},
|
||||||
@@ -137,9 +138,12 @@ impl system::Trait for Runtime {
|
|||||||
type MaximumBlockLength = MaximumBlockLength;
|
type MaximumBlockLength = MaximumBlockLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl aura::Trait for Runtime {
|
parameter_types! {
|
||||||
type HandleReport = aura::StakingSlasher<Runtime>;
|
pub const EpochDuration: u64 = 10 * MINUTES;
|
||||||
type AuthorityId = AuraId;
|
}
|
||||||
|
|
||||||
|
impl babe::Trait for Runtime {
|
||||||
|
type EpochDuration = EpochDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl indices::Trait for Runtime {
|
impl indices::Trait for Runtime {
|
||||||
@@ -177,7 +181,7 @@ parameter_types! {
|
|||||||
}
|
}
|
||||||
impl timestamp::Trait for Runtime {
|
impl timestamp::Trait for Runtime {
|
||||||
type Moment = Moment;
|
type Moment = Moment;
|
||||||
type OnTimestampSet = Aura;
|
type OnTimestampSet = Babe;
|
||||||
type MinimumPeriod = MinimumPeriod;
|
type MinimumPeriod = MinimumPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,17 +197,14 @@ impl authorship::Trait for Runtime {
|
|||||||
type EventHandler = ();
|
type EventHandler = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
parameter_types! {
|
type SessionHandlers = (Grandpa, Babe, ImOnline);
|
||||||
pub const Period: BlockNumber = 10 * MINUTES;
|
|
||||||
pub const Offset: BlockNumber = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
type SessionHandlers = (Grandpa, Aura, ImOnline);
|
|
||||||
|
|
||||||
impl_opaque_keys! {
|
impl_opaque_keys! {
|
||||||
pub struct SessionKeys {
|
pub struct SessionKeys {
|
||||||
#[id(key_types::ED25519)]
|
#[id(key_types::ED25519)]
|
||||||
pub ed25519: GrandpaId,
|
pub ed25519: GrandpaId,
|
||||||
|
#[id(key_types::SR25519)]
|
||||||
|
pub sr25519: BabeId,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +217,7 @@ impl_opaque_keys! {
|
|||||||
impl session::Trait for Runtime {
|
impl session::Trait for Runtime {
|
||||||
type OnSessionEnding = Staking;
|
type OnSessionEnding = Staking;
|
||||||
type SessionHandler = SessionHandlers;
|
type SessionHandler = SessionHandlers;
|
||||||
type ShouldEndSession = session::PeriodicSessions<Period, Offset>;
|
type ShouldEndSession = Babe;
|
||||||
type Event = Event;
|
type Event = Event;
|
||||||
type Keys = SessionKeys;
|
type Keys = SessionKeys;
|
||||||
type ValidatorId = AccountId;
|
type ValidatorId = AccountId;
|
||||||
@@ -378,12 +379,12 @@ impl sudo::Trait for Runtime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl im_online::Trait for Runtime {
|
impl im_online::Trait for Runtime {
|
||||||
type AuthorityId = AuraId;
|
type AuthorityId = BabeId;
|
||||||
type Call = Call;
|
type Call = Call;
|
||||||
type Event = Event;
|
type Event = Event;
|
||||||
type SessionsPerEra = SessionsPerEra;
|
type SessionsPerEra = SessionsPerEra;
|
||||||
type UncheckedExtrinsic = UncheckedExtrinsic;
|
type UncheckedExtrinsic = UncheckedExtrinsic;
|
||||||
type IsValidAuthorityId = Aura;
|
type IsValidAuthorityId = Babe;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl grandpa::Trait for Runtime {
|
impl grandpa::Trait for Runtime {
|
||||||
@@ -408,7 +409,7 @@ construct_runtime!(
|
|||||||
UncheckedExtrinsic = UncheckedExtrinsic
|
UncheckedExtrinsic = UncheckedExtrinsic
|
||||||
{
|
{
|
||||||
System: system::{Module, Call, Storage, Config, Event},
|
System: system::{Module, Call, Storage, Config, Event},
|
||||||
Aura: aura::{Module, Call, Storage, Config<T>, Inherent(Timestamp)},
|
Babe: babe::{Module, Call, Storage, Config, Inherent(Timestamp)},
|
||||||
Timestamp: timestamp::{Module, Call, Storage, Inherent},
|
Timestamp: timestamp::{Module, Call, Storage, Inherent},
|
||||||
Authorship: authorship::{Module, Call, Storage},
|
Authorship: authorship::{Module, Call, Storage},
|
||||||
Indices: indices,
|
Indices: indices,
|
||||||
@@ -525,12 +526,23 @@ impl_runtime_apis! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl consensus_aura::AuraApi<Block, AuraId> for Runtime {
|
impl babe_primitives::BabeApi<Block> for Runtime {
|
||||||
fn slot_duration() -> u64 {
|
fn startup_data() -> babe_primitives::BabeConfiguration {
|
||||||
Aura::slot_duration()
|
babe_primitives::BabeConfiguration {
|
||||||
|
median_required_blocks: 1000,
|
||||||
|
slot_duration: Babe::slot_duration(),
|
||||||
|
c: (3, 10),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn authorities() -> Vec<AuraId> {
|
|
||||||
Aura::authorities()
|
fn epoch() -> babe_primitives::Epoch {
|
||||||
|
babe_primitives::Epoch {
|
||||||
|
start_slot: Babe::epoch_start_slot(),
|
||||||
|
authorities: Babe::authorities(),
|
||||||
|
epoch_index: Babe::epoch_index(),
|
||||||
|
randomness: Babe::randomness(),
|
||||||
|
duration: EpochDuration::get(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,12 @@
|
|||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![forbid(unused_must_use, unsafe_code, unused_variables, dead_code)]
|
#![forbid(unused_must_use, unsafe_code, unused_variables, dead_code)]
|
||||||
|
|
||||||
pub use timestamp;
|
pub use timestamp;
|
||||||
|
|
||||||
use rstd::{result, prelude::*};
|
use rstd::{result, prelude::*};
|
||||||
use srml_support::{decl_storage, decl_module, StorageValue, traits::FindAuthor, traits::Get};
|
use srml_support::{decl_storage, decl_module, StorageValue, traits::FindAuthor, traits::Get};
|
||||||
use timestamp::{OnTimestampSet, Trait};
|
use timestamp::{OnTimestampSet};
|
||||||
use primitives::{generic::DigestItem, ConsensusEngineId};
|
use primitives::{generic::DigestItem, ConsensusEngineId};
|
||||||
use primitives::traits::{IsMember, SaturatedConversion, Saturating, RandomnessBeacon, Convert};
|
use primitives::traits::{IsMember, SaturatedConversion, Saturating, RandomnessBeacon, Convert};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@@ -31,7 +32,7 @@ use parity_codec::{Encode, Decode};
|
|||||||
use inherents::{RuntimeString, InherentIdentifier, InherentData, ProvideInherent, MakeFatalError};
|
use inherents::{RuntimeString, InherentIdentifier, InherentData, ProvideInherent, MakeFatalError};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use inherents::{InherentDataProviders, ProvideInherentData};
|
use inherents::{InherentDataProviders, ProvideInherentData};
|
||||||
use babe_primitives::{BABE_ENGINE_ID, ConsensusLog, Weight, Epoch, RawBabePreDigest};
|
use babe_primitives::{BABE_ENGINE_ID, ConsensusLog, BabeWeight, Epoch, RawBabePreDigest};
|
||||||
pub use babe_primitives::{AuthorityId, VRF_OUTPUT_LENGTH, PUBLIC_KEY_LENGTH};
|
pub use babe_primitives::{AuthorityId, VRF_OUTPUT_LENGTH, PUBLIC_KEY_LENGTH};
|
||||||
|
|
||||||
/// The BABE inherent identifier.
|
/// The BABE inherent identifier.
|
||||||
@@ -106,18 +107,28 @@ impl ProvideInherentData for InherentDataProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Trait: timestamp::Trait {
|
||||||
|
type EpochDuration: Get<u64>;
|
||||||
|
}
|
||||||
|
|
||||||
/// The length of the BABE randomness
|
/// The length of the BABE randomness
|
||||||
pub const RANDOMNESS_LENGTH: usize = 32;
|
pub const RANDOMNESS_LENGTH: usize = 32;
|
||||||
|
|
||||||
decl_storage! {
|
decl_storage! {
|
||||||
trait Store for Module<T: Trait> as Babe {
|
trait Store for Module<T: Trait> as Babe {
|
||||||
NextRandomness: [u8; RANDOMNESS_LENGTH];
|
/// Current epoch index.
|
||||||
|
pub EpochIndex get(epoch_index): u64;
|
||||||
|
|
||||||
/// Randomness under construction
|
/// Current epoch authorities.
|
||||||
UnderConstruction: [u8; VRF_OUTPUT_LENGTH];
|
pub Authorities get(authorities) config(): Vec<(AuthorityId, BabeWeight)>;
|
||||||
|
|
||||||
/// Current epoch
|
/// Slot at which the current epoch started. It is possible that no
|
||||||
pub Authorities get(authorities) config(): Vec<(AuthorityId, Weight)>;
|
/// block was authored at the given slot and the epoch change was
|
||||||
|
/// signalled later than this.
|
||||||
|
pub EpochStartSlot get(epoch_start_slot): u64;
|
||||||
|
|
||||||
|
/// Current slot number.
|
||||||
|
pub CurrentSlot get(current_slot): u64;
|
||||||
|
|
||||||
/// The epoch randomness for the *current* epoch.
|
/// The epoch randomness for the *current* epoch.
|
||||||
///
|
///
|
||||||
@@ -129,10 +140,16 @@ decl_storage! {
|
|||||||
/// (like everything else on-chain) it is public. For example, it can be
|
/// (like everything else on-chain) it is public. For example, it can be
|
||||||
/// used where a number is needed that cannot have been chosen by an
|
/// used where a number is needed that cannot have been chosen by an
|
||||||
/// adversary, for purposes such as public-coin zero-knowledge proofs.
|
/// adversary, for purposes such as public-coin zero-knowledge proofs.
|
||||||
pub Randomness get(randomness): [u8; RANDOMNESS_LENGTH];
|
// NOTE: the following fields don't use the constants to define the
|
||||||
|
// array size because the metadata API currently doesn't resolve the
|
||||||
|
// variable to its underlying value.
|
||||||
|
pub Randomness get(randomness): [u8; 32 /* RANDOMNESS_LENGTH */];
|
||||||
|
|
||||||
/// Current epoch index
|
/// Next epoch randomness.
|
||||||
EpochIndex: u64;
|
NextRandomness: [u8; 32 /* RANDOMNESS_LENGTH */];
|
||||||
|
|
||||||
|
/// Randomness under construction.
|
||||||
|
UnderConstruction: [u8; 32 /* VRF_OUTPUT_LENGTH */];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +158,7 @@ decl_module! {
|
|||||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||||
/// Initialization
|
/// Initialization
|
||||||
fn on_initialize() {
|
fn on_initialize() {
|
||||||
for i in Self::get_inherent_digests()
|
for digest in Self::get_inherent_digests()
|
||||||
.logs
|
.logs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|s| s.as_pre_runtime())
|
.filter_map(|s| s.as_pre_runtime())
|
||||||
@@ -149,9 +166,15 @@ decl_module! {
|
|||||||
RawBabePreDigest::decode(&mut data)
|
RawBabePreDigest::decode(&mut data)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}) {
|
})
|
||||||
|
{
|
||||||
|
if EpochStartSlot::get() == 0 {
|
||||||
|
EpochStartSlot::put(digest.slot_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentSlot::put(digest.slot_number);
|
||||||
|
Self::deposit_vrf_output(&digest.vrf_output);
|
||||||
|
|
||||||
Self::deposit_vrf_output(&i.vrf_output);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,7 +203,7 @@ impl<T: Trait> FindAuthor<u64> for Module<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: timestamp::Trait> IsMember<AuthorityId> for Module<T> {
|
impl<T: Trait> IsMember<AuthorityId> for Module<T> {
|
||||||
fn is_member(authority_id: &AuthorityId) -> bool {
|
fn is_member(authority_id: &AuthorityId) -> bool {
|
||||||
<Module<T>>::authorities()
|
<Module<T>>::authorities()
|
||||||
.iter()
|
.iter()
|
||||||
@@ -188,6 +211,13 @@ impl<T: timestamp::Trait> IsMember<AuthorityId> for Module<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Trait> session::ShouldEndSession<T::BlockNumber> for Module<T> {
|
||||||
|
fn should_end_session(_: T::BlockNumber) -> bool {
|
||||||
|
let diff = CurrentSlot::get().saturating_sub(EpochStartSlot::get());
|
||||||
|
diff >= T::EpochDuration::get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Trait> Module<T> {
|
impl<T: Trait> Module<T> {
|
||||||
/// Determine the BABE slot duration based on the Timestamp module configuration.
|
/// Determine the BABE slot duration based on the Timestamp module configuration.
|
||||||
pub fn slot_duration() -> T::Moment {
|
pub fn slot_duration() -> T::Moment {
|
||||||
@@ -205,23 +235,17 @@ impl<T: Trait> Module<T> {
|
|||||||
<system::Module<T>>::digest()
|
<system::Module<T>>::digest()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_epoch(new: Epoch) {
|
|
||||||
Authorities::put(&new.authorities);
|
|
||||||
Randomness::put(&new.randomness);
|
|
||||||
Self::deposit_consensus(ConsensusLog::NextEpochData(new))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deposit_vrf_output(vrf_output: &[u8; VRF_OUTPUT_LENGTH]) {
|
fn deposit_vrf_output(vrf_output: &[u8; VRF_OUTPUT_LENGTH]) {
|
||||||
UnderConstruction::mutate(|z| z.iter_mut().zip(vrf_output).for_each(|(x, y)| *x^=y))
|
UnderConstruction::mutate(|z| z.iter_mut().zip(vrf_output).for_each(|(x, y)| *x^=y))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call this function exactly once when an epoch changes, to update the
|
/// Call this function exactly once when an epoch changes, to update the
|
||||||
/// randomness. Returns the new randomness.
|
/// randomness. Returns the new randomness.
|
||||||
fn randomness_change_epoch(epoch_index: u64) -> [u8; RANDOMNESS_LENGTH] {
|
fn randomness_change_epoch(next_epoch_index: u64) -> [u8; RANDOMNESS_LENGTH] {
|
||||||
let this_randomness = NextRandomness::get();
|
let this_randomness = NextRandomness::get();
|
||||||
let next_randomness = compute_randomness(
|
let next_randomness = compute_randomness(
|
||||||
this_randomness,
|
this_randomness,
|
||||||
epoch_index,
|
next_epoch_index,
|
||||||
UnderConstruction::get(),
|
UnderConstruction::get(),
|
||||||
);
|
);
|
||||||
UnderConstruction::put(&[0; RANDOMNESS_LENGTH]);
|
UnderConstruction::put(&[0; RANDOMNESS_LENGTH]);
|
||||||
@@ -235,13 +259,9 @@ impl<T: Trait> OnTimestampSet<T::Moment> for Module<T> {
|
|||||||
fn on_timestamp_set(_moment: T::Moment) { }
|
fn on_timestamp_set(_moment: T::Moment) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Duration {
|
impl<T: Trait + staking::Trait> session::OneSessionHandler<T::AccountId> for Module<T> {
|
||||||
fn babe_epoch_duration() -> u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Trait + staking::Trait + Duration> session::OneSessionHandler<T::AccountId> for Module<T> {
|
|
||||||
type Key = AuthorityId;
|
type Key = AuthorityId;
|
||||||
fn on_new_session<'a, I: 'a>(_changed: bool, _validators: I, queued_validators: I)
|
fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I)
|
||||||
where I: Iterator<Item=(&'a T::AccountId, AuthorityId)>
|
where I: Iterator<Item=(&'a T::AccountId, AuthorityId)>
|
||||||
{
|
{
|
||||||
use staking::BalanceOf;
|
use staking::BalanceOf;
|
||||||
@@ -249,25 +269,63 @@ impl<T: Trait + staking::Trait + Duration> session::OneSessionHandler<T::Account
|
|||||||
<T::CurrencyToVote as Convert<BalanceOf<T>, u64>>::convert(b)
|
<T::CurrencyToVote as Convert<BalanceOf<T>, u64>>::convert(b)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Update epoch index
|
||||||
let epoch_index = EpochIndex::get()
|
let epoch_index = EpochIndex::get()
|
||||||
.checked_add(1)
|
.checked_add(1)
|
||||||
.expect("epoch indices will never reach 2^64 before the death of the universe; qed");
|
.expect("epoch indices will never reach 2^64 before the death of the universe; qed");
|
||||||
|
|
||||||
EpochIndex::put(epoch_index);
|
EpochIndex::put(epoch_index);
|
||||||
|
|
||||||
// *Next* epoch's authorities.
|
// Update authorities.
|
||||||
let authorities = queued_validators.map(|(account, k)| {
|
let authorities = validators.map(|(account, k)| {
|
||||||
(k, to_votes(staking::Module::<T>::stakers(account).total))
|
(k, to_votes(staking::Module::<T>::stakers(account).total))
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
// What was the next epoch is now the current epoch
|
Authorities::put(authorities);
|
||||||
let randomness = Self::randomness_change_epoch(epoch_index);
|
|
||||||
Self::change_epoch(Epoch {
|
// Update epoch start slot.
|
||||||
randomness,
|
let now = CurrentSlot::get();
|
||||||
authorities,
|
EpochStartSlot::mutate(|previous| {
|
||||||
epoch_index,
|
loop {
|
||||||
duration: T::babe_epoch_duration(),
|
// on the first epoch we must account for skipping at least one
|
||||||
})
|
// whole epoch, in case the first block is authored with a slot
|
||||||
|
// number far in the past.
|
||||||
|
if now.saturating_sub(*previous) < T::EpochDuration::get() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*previous = previous.saturating_add(T::EpochDuration::get());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update epoch randomness.
|
||||||
|
let next_epoch_index = epoch_index
|
||||||
|
.checked_add(1)
|
||||||
|
.expect("epoch indices will never reach 2^64 before the death of the universe; qed");
|
||||||
|
|
||||||
|
// Returns randomness for the current epoch and computes the *next*
|
||||||
|
// epoch randomness.
|
||||||
|
let randomness = Self::randomness_change_epoch(next_epoch_index);
|
||||||
|
Randomness::put(randomness);
|
||||||
|
|
||||||
|
// After we update the current epoch, we signal the *next* epoch change
|
||||||
|
// so that nodes can track changes.
|
||||||
|
let next_authorities = queued_validators.map(|(account, k)| {
|
||||||
|
(k, to_votes(staking::Module::<T>::stakers(account).total))
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let next_epoch_start_slot = EpochStartSlot::get().saturating_add(T::EpochDuration::get());
|
||||||
|
let next_randomness = NextRandomness::get();
|
||||||
|
|
||||||
|
let next = Epoch {
|
||||||
|
epoch_index: next_epoch_index,
|
||||||
|
start_slot: next_epoch_start_slot,
|
||||||
|
duration: T::EpochDuration::get(),
|
||||||
|
authorities: next_authorities,
|
||||||
|
randomness: next_randomness,
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::deposit_consensus(ConsensusLog::NextEpochData(next))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_disabled(i: usize) {
|
fn on_disabled(i: usize) {
|
||||||
@@ -304,6 +362,7 @@ impl<T: Trait> ProvideInherent for Module<T> {
|
|||||||
|
|
||||||
let timestamp_based_slot = (timestamp / Self::slot_duration()).saturated_into::<u64>();
|
let timestamp_based_slot = (timestamp / Self::slot_duration()).saturated_into::<u64>();
|
||||||
let seal_slot = data.babe_inherent_data()?;
|
let seal_slot = data.babe_inherent_data()?;
|
||||||
|
|
||||||
if timestamp_based_slot == seal_slot {
|
if timestamp_based_slot == seal_slot {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -451,11 +451,12 @@ pub struct Exposure<AccountId, Balance: HasCompact> {
|
|||||||
pub others: Vec<IndividualExposure<AccountId, Balance>>,
|
pub others: Vec<IndividualExposure<AccountId, Balance>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
|
pub type BalanceOf<T> =
|
||||||
|
<<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
|
||||||
type PositiveImbalanceOf<T> =
|
type PositiveImbalanceOf<T> =
|
||||||
<<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::PositiveImbalance;
|
<<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::PositiveImbalance;
|
||||||
type NegativeImbalanceOf<T> =
|
type NegativeImbalanceOf<T> =
|
||||||
<<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
|
<<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
|
||||||
type MomentOf<T>= <<T as Trait>::Time as Time>::Moment;
|
type MomentOf<T>= <<T as Trait>::Time as Time>::Moment;
|
||||||
|
|
||||||
type RawAssignment<T> = (<T as system::Trait>::AccountId, ExtendedBalance);
|
type RawAssignment<T> = (<T as system::Trait>::AccountId, ExtendedBalance);
|
||||||
|
|||||||
Reference in New Issue
Block a user