mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 09:31:12 +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-cli 2.0.0",
|
||||
"substrate-client 2.0.0",
|
||||
"substrate-consensus-aura 2.0.0",
|
||||
"substrate-consensus-aura-primitives 2.0.0",
|
||||
"substrate-consensus-babe 2.0.0",
|
||||
"substrate-consensus-babe-primitives 2.0.0",
|
||||
"substrate-consensus-common 2.0.0",
|
||||
"substrate-finality-grandpa 2.0.0",
|
||||
"substrate-finality-grandpa-primitives 2.0.0",
|
||||
@@ -2360,8 +2360,8 @@ dependencies = [
|
||||
"sr-primitives 2.0.0",
|
||||
"sr-std 2.0.0",
|
||||
"sr-version 2.0.0",
|
||||
"srml-aura 2.0.0",
|
||||
"srml-authorship 0.1.0",
|
||||
"srml-babe 2.0.0",
|
||||
"srml-balances 2.0.0",
|
||||
"srml-collective 2.0.0",
|
||||
"srml-contracts 2.0.0",
|
||||
@@ -2380,7 +2380,7 @@ dependencies = [
|
||||
"srml-timestamp 2.0.0",
|
||||
"srml-treasury 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-offchain-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)",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "num-integer"
|
||||
version = "0.1.41"
|
||||
@@ -2469,6 +2478,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "num-traits"
|
||||
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)",
|
||||
"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)",
|
||||
"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)",
|
||||
"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)",
|
||||
@@ -6153,7 +6176,9 @@ dependencies = [
|
||||
"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 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-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_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"
|
||||
|
||||
@@ -431,15 +431,15 @@ struct KeyringTestAccountCliValues {
|
||||
help: String,
|
||||
conflicts_with: Vec<String>,
|
||||
name: String,
|
||||
variant: keyring::AuthorityKeyring,
|
||||
variant: keyring::Sr25519Keyring,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
/// The Cli values for all test accounts.
|
||||
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 conflicts_with = keyring::AuthorityKeyring::iter()
|
||||
let conflicts_with = keyring::Sr25519Keyring::iter()
|
||||
.filter(|b| a != *b)
|
||||
.map(|b| b.to_string().to_lowercase())
|
||||
.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.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Keyring {
|
||||
pub account: Option<keyring::AuthorityKeyring>,
|
||||
pub account: Option<keyring::Sr25519Keyring>,
|
||||
}
|
||||
|
||||
impl StructOpt for Keyring {
|
||||
|
||||
@@ -47,7 +47,7 @@ mod tests {
|
||||
use test_client::{
|
||||
runtime::genesismap::{GenesisConfig, additional_storage_with_genesis},
|
||||
runtime::{Hash, Transfer, Block, BlockNumber, Header, Digest},
|
||||
AccountKeyring, AuthorityKeyring
|
||||
AccountKeyring, Sr25519Keyring,
|
||||
};
|
||||
use runtime_primitives::traits::BlakeTwo256;
|
||||
use primitives::Blake2Hasher;
|
||||
@@ -147,7 +147,7 @@ mod tests {
|
||||
#[test]
|
||||
fn construct_genesis_should_work_with_native() {
|
||||
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()],
|
||||
1000
|
||||
).genesis_map();
|
||||
@@ -176,7 +176,7 @@ mod tests {
|
||||
#[test]
|
||||
fn construct_genesis_should_work_with_wasm() {
|
||||
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()],
|
||||
1000
|
||||
).genesis_map();
|
||||
@@ -205,7 +205,7 @@ mod tests {
|
||||
#[test]
|
||||
fn construct_genesis_with_bad_transaction_should_panic() {
|
||||
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()],
|
||||
68
|
||||
).genesis_map();
|
||||
|
||||
@@ -7,8 +7,11 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
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" }
|
||||
num-bigint = "0.2"
|
||||
num-rational = "0.2"
|
||||
num-traits = "0.2"
|
||||
runtime_support = { package = "srml-support", path = "../../../srml/support" }
|
||||
runtime_version = { package = "sr-version", path = "../../sr-version" }
|
||||
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" }
|
||||
tokio = "0.1.18"
|
||||
env_logger = "0.6.1"
|
||||
|
||||
[features]
|
||||
test-helpers = []
|
||||
|
||||
@@ -24,16 +24,21 @@ mod digest;
|
||||
use parity_codec::{Encode, Decode};
|
||||
use rstd::vec::Vec;
|
||||
use runtime_primitives::ConsensusEngineId;
|
||||
use substrate_primitives::sr25519::Public;
|
||||
use substrate_primitives::sr25519;
|
||||
use substrate_client::decl_runtime_apis;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use digest::{BabePreDigest, CompatibleDigestItem};
|
||||
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
|
||||
/// 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.
|
||||
pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE";
|
||||
@@ -54,20 +59,24 @@ pub type AuthorityIndex = u64;
|
||||
pub type SlotNumber = u64;
|
||||
|
||||
/// 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
|
||||
#[derive(Decode, Encode, Default, PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(any(feature = "std", test), derive(Debug))]
|
||||
pub struct Epoch {
|
||||
/// The authorities and their weights
|
||||
pub authorities: Vec<(AuthorityId, Weight)>,
|
||||
/// The epoch index
|
||||
pub epoch_index: u64,
|
||||
/// Randomness for this epoch
|
||||
pub randomness: [u8; VRF_OUTPUT_LENGTH],
|
||||
/// The starting slot of the epoch,
|
||||
pub start_slot: u64,
|
||||
/// The duration of this epoch
|
||||
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.
|
||||
@@ -93,23 +102,10 @@ pub struct BabeConfiguration {
|
||||
/// Dynamic slot duration may be supported in the future.
|
||||
pub slot_duration: u64,
|
||||
|
||||
/// The number of slots per BABE epoch. Currently, only
|
||||
/// the value provided by this type at genesis will be used.
|
||||
///
|
||||
/// Dynamic slot duration may be supported in the future.
|
||||
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,
|
||||
/// A constant value that is used in the threshold calculation formula.
|
||||
/// Expressed as a fraction where the first member of the tuple is the
|
||||
/// numerator and the second is the denominator.
|
||||
pub c: (u64, u64),
|
||||
|
||||
/// 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
|
||||
|
||||
@@ -27,7 +27,7 @@ use consensus_common::import_queue::{
|
||||
BoxJustificationImport, BoxFinalityProofImport,
|
||||
};
|
||||
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::{
|
||||
Block as BlockT, Header, DigestItemFor, NumberFor, ProvideRuntimeApi,
|
||||
SimpleBitOps, Zero,
|
||||
@@ -114,9 +114,9 @@ impl Config {
|
||||
self.0.slot_duration
|
||||
}
|
||||
|
||||
/// Retrieve the threshold for BABE
|
||||
pub fn threshold(&self) -> u64 {
|
||||
self.0.threshold
|
||||
/// Retrieve the threshold calculation constant `c`.
|
||||
pub fn c(&self) -> (u64, u64) {
|
||||
self.0.c
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ pub fn start_babe<B, C, SC, E, I, SO, Error, H>(BabeParams {
|
||||
local_key,
|
||||
sync_oracle: sync_oracle.clone(),
|
||||
force_authoring,
|
||||
threshold: config.threshold(),
|
||||
c: config.c(),
|
||||
};
|
||||
register_babe_inherent_data_provider(&inherent_data_providers, config.0.slot_duration())?;
|
||||
Ok(slots::start_slot_worker(
|
||||
@@ -224,7 +224,7 @@ struct BabeWorker<C, E, I, SO> {
|
||||
local_key: Arc<sr25519::Pair>,
|
||||
sync_oracle: SO,
|
||||
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
|
||||
@@ -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() {
|
||||
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(()));
|
||||
}
|
||||
|
||||
let proposal_work = if let Some(((inout, vrf_proof, _batchable_proof), authority_index)) = claim_slot(
|
||||
&randomness,
|
||||
let proposal_work = if let Some(claim) = claim_slot(
|
||||
slot_info.number,
|
||||
epoch_index,
|
||||
epoch,
|
||||
&pair,
|
||||
self.threshold,
|
||||
self.c,
|
||||
) {
|
||||
let ((inout, vrf_proof, _batchable_proof), authority_index) = claim;
|
||||
|
||||
debug!(
|
||||
target: "babe", "Starting authorship at slot {}; timestamp = {}",
|
||||
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) {
|
||||
Ok(p) => p,
|
||||
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";
|
||||
"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_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> {
|
||||
origin: BlockOrigin::Own,
|
||||
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,
|
||||
);
|
||||
|
||||
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 {:?}: {:?}",
|
||||
parent_hash, e);
|
||||
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>
|
||||
where DigestItemFor<B>: CompatibleDigestItem,
|
||||
{
|
||||
let mut pre_digest: Option<_> = None;
|
||||
for log in header.digest().logs() {
|
||||
if let Some(pre_digest) = log.as_babe_pre_digest() {
|
||||
return Ok(pre_digest);
|
||||
trace!(target: "babe", "Checking log {:?}, looking for pre runtime digest", log);
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
Err(babe_err!("No BABE pre-runtime digest found"))
|
||||
pre_digest.ok_or_else(|| babe_err!("No BABE pre-runtime digest found"))
|
||||
}
|
||||
|
||||
/// 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,
|
||||
{
|
||||
let mut epoch_digest: Option<_> = None;
|
||||
for log in header.digest().logs() {
|
||||
if let Some(epoch_digest) = log.as_babe_epoch() {
|
||||
return Some(epoch_digest);
|
||||
trace!(target: "babe", "Checking log {:?}, looking for epoch change digest.", log);
|
||||
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
|
||||
@@ -459,10 +466,10 @@ fn check_header<B: BlockT + Sized, C: AuxStore>(
|
||||
slot_now: u64,
|
||||
mut header: B::Header,
|
||||
hash: B::Hash,
|
||||
authorities: &[AuthorityId],
|
||||
authorities: &[(AuthorityId, BabeWeight)],
|
||||
randomness: [u8; 32],
|
||||
epoch_index: u64,
|
||||
threshold: u64,
|
||||
c: (u64, u64),
|
||||
) -> Result<CheckedHeader<B::Header, (DigestItemFor<B>, DigestItemFor<B>)>, String>
|
||||
where DigestItemFor<B>: CompatibleDigestItem,
|
||||
{
|
||||
@@ -486,7 +493,7 @@ fn check_header<B: BlockT + Sized, C: AuxStore>(
|
||||
} else if authority_index > authorities.len() as u64 {
|
||||
Err(babe_err!("Slot author not found"))
|
||||
} 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()) {
|
||||
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) {
|
||||
return Err(babe_err!("VRF verification of block by author {:?} failed: \
|
||||
threshold {} exceeded", author, threshold));
|
||||
@@ -562,7 +570,9 @@ impl<C> BabeVerifier<C> {
|
||||
if !inherent_res.ok() {
|
||||
inherent_res
|
||||
.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 {
|
||||
Ok(())
|
||||
}
|
||||
@@ -581,7 +591,9 @@ fn median_algorithm(
|
||||
let mut new_list: Vec<_> = time_source.1.iter().map(|&(t, sl)| {
|
||||
let offset: u128 = u128::from(slot_duration)
|
||||
.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");
|
||||
|
||||
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))
|
||||
.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.
|
||||
// FIXME #1019 in the future, alter this queue to allow deferring of headers
|
||||
let checked_header = check_header::<B, C>(
|
||||
@@ -649,10 +659,10 @@ impl<B: BlockT, C> Verifier<B> for BabeVerifier<C> where
|
||||
slot_now + 1,
|
||||
header,
|
||||
hash,
|
||||
&authorities[..],
|
||||
&authorities,
|
||||
randomness,
|
||||
epoch_index,
|
||||
self.config.threshold(),
|
||||
self.config.c(),
|
||||
)?;
|
||||
|
||||
match checked_header {
|
||||
@@ -683,12 +693,6 @@ impl<B: BlockT, C> Verifier<B> for BabeVerifier<C> where
|
||||
"babe.checked_and_importing";
|
||||
"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 {
|
||||
origin,
|
||||
header: pre_header,
|
||||
@@ -709,8 +713,7 @@ impl<B: BlockT, C> Verifier<B> for BabeVerifier<C> where
|
||||
&mut *self.time_source.0.lock(),
|
||||
);
|
||||
|
||||
// FIXME #1019 extract authorities
|
||||
Ok((import_block, maybe_keys))
|
||||
Ok((import_block, Default::default()))
|
||||
}
|
||||
CheckedHeader::Deferred(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
|
||||
.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[..])))
|
||||
.or_else(|| {
|
||||
if client.runtime_api().has_api::<dyn BabeApi<B>>(at).unwrap_or(false) {
|
||||
@@ -786,8 +789,33 @@ fn make_transcript(
|
||||
transcript
|
||||
}
|
||||
|
||||
fn check(inout: &VRFInOut, threshold: u64) -> bool {
|
||||
u64::from_le_bytes(inout.make_bytes::<[u8; 8]>(BABE_VRF_PREFIX)) < threshold
|
||||
fn check(inout: &VRFInOut, threshold: u128) -> bool {
|
||||
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.
|
||||
@@ -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,
|
||||
/// so it returns `Some(_)`. Otherwise, it returns `None`.
|
||||
fn claim_slot(
|
||||
randomness: &[u8],
|
||||
slot_number: u64,
|
||||
epoch: u64,
|
||||
Epoch { ref authorities, .. }: Epoch,
|
||||
Epoch { ref authorities, ref randomness, epoch_index, .. }: Epoch,
|
||||
key: &sr25519::Pair,
|
||||
threshold: u64,
|
||||
c: (u64, u64),
|
||||
) -> Option<((VRFInOut, VRFProof, VRFProofBatchable), usize)> {
|
||||
let public = &key.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.
|
||||
//
|
||||
// We already checked that authorities contains `key.public()`, so it can't
|
||||
// be empty. Therefore, this division is safe.
|
||||
let threshold = threshold / authorities.len() as u64;
|
||||
// be empty. Therefore, this division in `calculate_threshold` is safe.
|
||||
let threshold = calculate_threshold(c, authorities, authority_index);
|
||||
|
||||
get_keypair(key)
|
||||
.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
|
||||
let genesis_id = BlockId::Number(Zero::zero());
|
||||
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[..]));
|
||||
if genesis_epoch.is_some() {
|
||||
return Ok(());
|
||||
@@ -845,18 +871,17 @@ fn initialize_authorities_cache<B, C>(client: &C) -> Result<(), ConsensusError>
|
||||
)));
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
/// Tree of all epoch changes across all *seen* forks. Data stored in tree is the
|
||||
/// hash and block number of the block signaling the epoch change, the new epoch
|
||||
/// index and the minimum *slot number* when the next epoch should start (i.e.
|
||||
/// slot number begin + duration).
|
||||
/// Tree of all epoch changes across all *seen* forks. Data stored in tree is
|
||||
/// the hash and block number of the block signaling the epoch change, and the
|
||||
/// epoch that was signalled at that block.
|
||||
type EpochChanges<Block> = ForkTree<
|
||||
<Block as BlockT>::Hash,
|
||||
NumberFor<Block>,
|
||||
(u64, SlotNumber),
|
||||
Epoch,
|
||||
>;
|
||||
|
||||
/// A shared epoch changes tree.
|
||||
@@ -893,50 +918,56 @@ impl<Block: BlockT> From<EpochChanges<Block>> for SharedEpochChanges<Block> {
|
||||
/// it is missing.
|
||||
///
|
||||
/// 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,
|
||||
client: Arc<Client<B, E, Block, RA>>,
|
||||
api: Arc<PRA>,
|
||||
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 {
|
||||
BabeBlockImport {
|
||||
inner: self.inner.clone(),
|
||||
client: self.client.clone(),
|
||||
api: self.api.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(
|
||||
client: Arc<Client<B, E, Block, RA>>,
|
||||
api: Arc<PRA>,
|
||||
epoch_changes: SharedEpochChanges<Block>,
|
||||
block_import: I,
|
||||
) -> Self {
|
||||
BabeBlockImport {
|
||||
client,
|
||||
api,
|
||||
inner: block_import,
|
||||
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>,
|
||||
I: BlockImport<Block> + Send + Sync,
|
||||
I::Error: Into<ConsensusError>,
|
||||
B: Backend<Block, Blake2Hasher> + 'static,
|
||||
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
|
||||
RA: Send + Sync,
|
||||
PRA: ProvideRuntimeApi + ProvideCache<Block>,
|
||||
PRA::Api: BabeApi<Block>,
|
||||
{
|
||||
type Error = ConsensusError;
|
||||
|
||||
fn import_block(
|
||||
&mut self,
|
||||
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> {
|
||||
let hash = block.post_header().hash();
|
||||
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
|
||||
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,
|
||||
&number,
|
||||
&is_descendent_of,
|
||||
&|(_, expected_epoch_change_slot)| {
|
||||
*expected_epoch_change_slot <= slot_number
|
||||
}
|
||||
&|epoch| epoch.start_slot <= slot_number,
|
||||
).map_err(|e| ConsensusError::from(ConsensusError::ClientImport(e.to_string())))?;
|
||||
|
||||
let check_roots = || -> Result<bool, ConsensusError> {
|
||||
// this can only happen when the chain starts, since there's no epoch change at genesis.
|
||||
// afterwards every time we expect an epoch change it means we will import another one.
|
||||
// this can only happen when the chain starts, since there's no
|
||||
// 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() {
|
||||
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 {
|
||||
return Ok(false);
|
||||
@@ -989,14 +1021,18 @@ impl<B, E, Block, I, RA> BlockImport<Block> for BabeBlockImport<B, E, Block, I,
|
||||
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) => {},
|
||||
(false, false) => {},
|
||||
(true, false) => {
|
||||
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) => {
|
||||
@@ -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
|
||||
let mut old_epoch_changes = None;
|
||||
|
||||
if let Some(entry) = new_cache.get(&well_known_cache_keys::AUTHORITIES) {
|
||||
if let Some(epoch) = Epoch::decode(&mut &entry[..]) {
|
||||
if let Some(last_epoch_change) = epoch_change {
|
||||
let last_epoch_index = last_epoch_change.data.0;
|
||||
if epoch.epoch_index.checked_sub(last_epoch_index) != Some(1) {
|
||||
return Err(ConsensusError::ClientImport(format!(
|
||||
"Invalid BABE epoch change: expected next epoch to be {:?}, got {:?}",
|
||||
last_epoch_index.saturating_add(1),
|
||||
epoch.epoch_index,
|
||||
)));
|
||||
}
|
||||
if let Some(next_epoch) = next_epoch_digest {
|
||||
if let Some(enacted_epoch) = enacted_epoch {
|
||||
let enacted_epoch = &enacted_epoch.data;
|
||||
if next_epoch.epoch_index.checked_sub(enacted_epoch.epoch_index) != Some(1) {
|
||||
return Err(ConsensusError::ClientImport(format!(
|
||||
"Invalid BABE epoch change: expected next epoch to be {:?}, got {:?}",
|
||||
enacted_epoch.epoch_index.saturating_add(1),
|
||||
next_epoch.epoch_index,
|
||||
)));
|
||||
}
|
||||
|
||||
old_epoch_changes = Some(epoch_changes.clone());
|
||||
|
||||
// track the epoch change in the fork tree
|
||||
epoch_changes.import(
|
||||
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())
|
||||
// update the current epoch in the client cache
|
||||
new_cache.insert(
|
||||
well_known_cache_keys::EPOCH,
|
||||
enacted_epoch.encode(),
|
||||
);
|
||||
|
||||
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);
|
||||
@@ -1085,7 +1136,7 @@ pub fn import_queue<B, E, Block: BlockT<Hash=H256>, I, RA, PRA>(
|
||||
) -> ClientResult<(
|
||||
BabeImportQueue<Block>,
|
||||
BabeLink,
|
||||
BabeBlockImport<B, E, Block, I, RA>,
|
||||
BabeBlockImport<B, E, Block, I, RA, PRA>,
|
||||
impl Future<Item = (), Error = ()>,
|
||||
)> where
|
||||
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)?;
|
||||
|
||||
let verifier = BabeVerifier {
|
||||
api,
|
||||
api: api.clone(),
|
||||
inherent_data_providers,
|
||||
time_source: Default::default(),
|
||||
config,
|
||||
@@ -1111,6 +1162,7 @@ pub fn import_queue<B, E, Block: BlockT<Hash=H256>, I, RA, PRA>(
|
||||
|
||||
let block_import = BabeBlockImport::new(
|
||||
client.clone(),
|
||||
api,
|
||||
epoch_changes.clone(),
|
||||
block_import,
|
||||
);
|
||||
@@ -1123,7 +1175,9 @@ pub fn import_queue<B, E, Block: BlockT<Hash=H256>, I, RA, PRA>(
|
||||
¬ification.hash,
|
||||
*notification.header.number(),
|
||||
&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(())
|
||||
});
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
/// 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 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())
|
||||
}
|
||||
}
|
||||
@@ -232,7 +237,10 @@ fn run_one_test() {
|
||||
// wait for all finalized on each.
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -306,17 +314,17 @@ fn sig_is_not_pre_digest() {
|
||||
#[test]
|
||||
fn can_author_block() {
|
||||
let _ = env_logger::try_init();
|
||||
let randomness = &[];
|
||||
let (pair, _) = sr25519::Pair::generate();
|
||||
let mut i = 0;
|
||||
let epoch = Epoch {
|
||||
authorities: vec![(pair.public(), 0)],
|
||||
start_slot: 0,
|
||||
authorities: vec![(pair.public(), 1)],
|
||||
randomness: [0; 32],
|
||||
epoch_index: 1,
|
||||
duration: 100,
|
||||
};
|
||||
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,
|
||||
Some(s) => {
|
||||
debug!(target: "babe", "Authored block {:?}", s);
|
||||
|
||||
@@ -123,4 +123,7 @@ pub mod well_known_cache_keys {
|
||||
|
||||
/// A list of authorities.
|
||||
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 primitives::H256;
|
||||
use keyring::AuthorityKeyring;
|
||||
use keyring::Ed25519Keyring;
|
||||
|
||||
type TestBlock = GenericTestBlock<()>;
|
||||
|
||||
@@ -1436,7 +1436,7 @@ mod tests {
|
||||
start_round: 0,
|
||||
})),
|
||||
round_timeout_multiplier: 10,
|
||||
key: Arc::new(AuthorityKeyring::One.into()),
|
||||
key: Arc::new(Ed25519Keyring::One.into()),
|
||||
factory: DummyFactory
|
||||
}
|
||||
}
|
||||
@@ -1462,10 +1462,10 @@ mod tests {
|
||||
fn future_gets_preempted() {
|
||||
let client = FakeClient {
|
||||
authorities: vec![
|
||||
AuthorityKeyring::One.into(),
|
||||
AuthorityKeyring::Two.into(),
|
||||
AuthorityKeyring::Alice.into(),
|
||||
AuthorityKeyring::Eve.into(),
|
||||
Ed25519Keyring::One.into(),
|
||||
Ed25519Keyring::Two.into(),
|
||||
Ed25519Keyring::Alice.into(),
|
||||
Ed25519Keyring::Eve.into(),
|
||||
],
|
||||
imported_heights: Mutex::new(HashSet::new()),
|
||||
};
|
||||
@@ -1509,17 +1509,17 @@ mod tests {
|
||||
let hash = [0xff; 32].into();
|
||||
|
||||
let authorities = vec![
|
||||
AuthorityKeyring::One.into(),
|
||||
AuthorityKeyring::Two.into(),
|
||||
AuthorityKeyring::Alice.into(),
|
||||
AuthorityKeyring::Eve.into(),
|
||||
Ed25519Keyring::One.into(),
|
||||
Ed25519Keyring::Two.into(),
|
||||
Ed25519Keyring::Alice.into(),
|
||||
Ed25519Keyring::Eve.into(),
|
||||
];
|
||||
|
||||
let authorities_keys = vec![
|
||||
AuthorityKeyring::One.into(),
|
||||
AuthorityKeyring::Two.into(),
|
||||
AuthorityKeyring::Alice.into(),
|
||||
AuthorityKeyring::Eve.into(),
|
||||
Ed25519Keyring::One.into(),
|
||||
Ed25519Keyring::Two.into(),
|
||||
Ed25519Keyring::Alice.into(),
|
||||
Ed25519Keyring::Eve.into(),
|
||||
];
|
||||
|
||||
let unchecked = UncheckedJustification(rhododendron::UncheckedJustification {
|
||||
@@ -1570,8 +1570,8 @@ mod tests {
|
||||
let parent_hash = Default::default();
|
||||
|
||||
let authorities = vec![
|
||||
AuthorityKeyring::Alice.into(),
|
||||
AuthorityKeyring::Eve.into(),
|
||||
Ed25519Keyring::Alice.into(),
|
||||
Ed25519Keyring::Eve.into(),
|
||||
];
|
||||
|
||||
let block = TestBlock {
|
||||
@@ -1579,7 +1579,11 @@ mod tests {
|
||||
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 {
|
||||
assert!(check_proposal(&authorities, &parent_hash, &proposal).is_ok());
|
||||
let mut invalid_round = proposal.clone();
|
||||
@@ -1593,7 +1597,11 @@ mod tests {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
assert!(check_proposal(&authorities, &parent_hash, &proposal).is_err());
|
||||
} else {
|
||||
@@ -1607,8 +1615,8 @@ mod tests {
|
||||
let hash: H256 = [0xff; 32].into();
|
||||
|
||||
let authorities = vec![
|
||||
AuthorityKeyring::Alice.into(),
|
||||
AuthorityKeyring::Eve.into(),
|
||||
Ed25519Keyring::Alice.into(),
|
||||
Ed25519Keyring::Eve.into(),
|
||||
];
|
||||
|
||||
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() {
|
||||
let client = FakeClient {
|
||||
authorities: vec![
|
||||
AuthorityKeyring::One.into(),
|
||||
AuthorityKeyring::Two.into(),
|
||||
AuthorityKeyring::Alice.into(),
|
||||
AuthorityKeyring::Eve.into(),
|
||||
Ed25519Keyring::One.into(),
|
||||
Ed25519Keyring::Two.into(),
|
||||
Ed25519Keyring::Alice.into(),
|
||||
Ed25519Keyring::Eve.into(),
|
||||
],
|
||||
imported_heights: Mutex::new(HashSet::new()),
|
||||
};
|
||||
@@ -1659,10 +1667,10 @@ mod tests {
|
||||
fn bft_can_build_though_skipped() {
|
||||
let client = FakeClient {
|
||||
authorities: vec![
|
||||
AuthorityKeyring::One.into(),
|
||||
AuthorityKeyring::Two.into(),
|
||||
AuthorityKeyring::Alice.into(),
|
||||
AuthorityKeyring::Eve.into(),
|
||||
Ed25519Keyring::One.into(),
|
||||
Ed25519Keyring::Two.into(),
|
||||
Ed25519Keyring::Alice.into(),
|
||||
Ed25519Keyring::Eve.into(),
|
||||
],
|
||||
imported_heights: Mutex::new(HashSet::new()),
|
||||
};
|
||||
|
||||
@@ -74,7 +74,7 @@ pub fn evaluate_misbehavior<B: Codec, H: Codec + Copy>(
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use keyring::AuthorityKeyring;
|
||||
use keyring::Ed25519Keyring;
|
||||
use rhododendron;
|
||||
|
||||
use runtime_primitives::testing::{H256, Block as RawBlock};
|
||||
@@ -109,7 +109,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn evaluates_double_prepare() {
|
||||
let key = AuthorityKeyring::One.pair();
|
||||
let key = Ed25519Keyring::One.pair();
|
||||
let parent_hash = [0xff; 32].into();
|
||||
let hash_1 = [0; 32].into();
|
||||
let hash_2 = [1; 32].into();
|
||||
@@ -138,7 +138,7 @@ mod tests {
|
||||
|
||||
// misbehavior has wrong target.
|
||||
assert!(!evaluate_misbehavior::<Block, H256>(
|
||||
&AuthorityKeyring::Two.into(),
|
||||
&Ed25519Keyring::Two.into(),
|
||||
parent_hash,
|
||||
&MisbehaviorKind::BftDoublePrepare(
|
||||
1,
|
||||
@@ -150,7 +150,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn evaluates_double_commit() {
|
||||
let key = AuthorityKeyring::One.pair();
|
||||
let key = Ed25519Keyring::One.pair();
|
||||
let parent_hash = [0xff; 32].into();
|
||||
let hash_1 = [0; 32].into();
|
||||
let hash_2 = [1; 32].into();
|
||||
@@ -179,7 +179,7 @@ mod tests {
|
||||
|
||||
// misbehavior has wrong target.
|
||||
assert!(!evaluate_misbehavior::<Block, H256>(
|
||||
&AuthorityKeyring::Two.into(),
|
||||
&Ed25519Keyring::Two.into(),
|
||||
parent_hash,
|
||||
&MisbehaviorKind::BftDoubleCommit(
|
||||
1,
|
||||
|
||||
@@ -23,7 +23,7 @@ use network::test::{Block, Hash};
|
||||
use network_gossip::Validator;
|
||||
use tokio::runtime::current_thread;
|
||||
use std::sync::Arc;
|
||||
use keyring::AuthorityKeyring;
|
||||
use keyring::Ed25519Keyring;
|
||||
use parity_codec::Encode;
|
||||
|
||||
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()
|
||||
.map(|key| AuthorityId(key.to_raw_public()))
|
||||
.map(|id| (id, 1))
|
||||
@@ -220,7 +220,7 @@ impl network_gossip::ValidatorContext<Block> for NoopContext {
|
||||
|
||||
#[test]
|
||||
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 voter_set = Arc::new(public.iter().cloned().collect::<VoterSet<AuthorityId>>());
|
||||
|
||||
@@ -335,7 +335,7 @@ fn good_commit_leads_to_relay() {
|
||||
|
||||
#[test]
|
||||
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 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`
|
||||
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 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`
|
||||
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 mut imported_aux = match import_result {
|
||||
|
||||
@@ -23,7 +23,7 @@ use network::config::{ProtocolConfig, Roles, BoxFinalityProofRequestBuilder};
|
||||
use parking_lot::Mutex;
|
||||
use futures03::{StreamExt as _, TryStreamExt as _};
|
||||
use tokio::runtime::current_thread;
|
||||
use keyring::ed25519::{Keyring as AuthorityKeyring};
|
||||
use keyring::Ed25519Keyring;
|
||||
use client::{
|
||||
error::Result,
|
||||
runtime_api::{Core, RuntimeVersion, ApiExt},
|
||||
@@ -342,7 +342,7 @@ impl AuthoritySetForFinalityChecker<Block> for TestApi {
|
||||
|
||||
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()
|
||||
.map(|key| AuthorityId::from_raw(key.to_raw_public()))
|
||||
.map(|id| (id, 1))
|
||||
@@ -355,7 +355,7 @@ fn run_to_completion_with<F>(
|
||||
runtime: &mut current_thread::Runtime,
|
||||
blocks: u64,
|
||||
net: Arc<Mutex<GrandpaTestNet>>,
|
||||
peers: &[AuthorityKeyring],
|
||||
peers: &[Ed25519Keyring],
|
||||
with: F,
|
||||
) -> u64 where
|
||||
F: FnOnce(current_thread::Handle) -> Option<Box<dyn Future<Item=(), Error=()>>>
|
||||
@@ -437,7 +437,7 @@ fn run_to_completion(
|
||||
runtime: &mut current_thread::Runtime,
|
||||
blocks: u64,
|
||||
net: Arc<Mutex<GrandpaTestNet>>,
|
||||
peers: &[AuthorityKeyring]
|
||||
peers: &[Ed25519Keyring]
|
||||
) -> u64 {
|
||||
run_to_completion_with(runtime, blocks, net, peers, |_| None)
|
||||
}
|
||||
@@ -446,7 +446,7 @@ fn run_to_completion(
|
||||
fn finalize_3_voters_no_observers() {
|
||||
let _ = env_logger::try_init();
|
||||
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 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() {
|
||||
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 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() {
|
||||
let _ = env_logger::try_init();
|
||||
let peers_a = &[
|
||||
AuthorityKeyring::Alice,
|
||||
AuthorityKeyring::Bob,
|
||||
AuthorityKeyring::Charlie,
|
||||
Ed25519Keyring::Alice,
|
||||
Ed25519Keyring::Bob,
|
||||
Ed25519Keyring::Charlie,
|
||||
];
|
||||
|
||||
let peers_b = &[
|
||||
AuthorityKeyring::Dave,
|
||||
AuthorityKeyring::Eve,
|
||||
AuthorityKeyring::Ferdie,
|
||||
Ed25519Keyring::Dave,
|
||||
Ed25519Keyring::Eve,
|
||||
Ed25519Keyring::Ferdie,
|
||||
];
|
||||
|
||||
let peers_c = &[
|
||||
AuthorityKeyring::Alice,
|
||||
AuthorityKeyring::Eve,
|
||||
AuthorityKeyring::Two,
|
||||
Ed25519Keyring::Alice,
|
||||
Ed25519Keyring::Eve,
|
||||
Ed25519Keyring::Two,
|
||||
];
|
||||
|
||||
let observer = &[AuthorityKeyring::One];
|
||||
let observer = &[Ed25519Keyring::One];
|
||||
|
||||
let genesis_voters = make_ids(peers_a);
|
||||
|
||||
@@ -700,7 +700,7 @@ fn transition_3_voters_twice_1_full_observer() {
|
||||
#[test]
|
||||
fn justification_is_emitted_when_consensus_data_changes() {
|
||||
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);
|
||||
|
||||
// import block#1 WITH consensus data change
|
||||
@@ -718,7 +718,7 @@ fn justification_is_emitted_when_consensus_data_changes() {
|
||||
#[test]
|
||||
fn justification_is_generated_periodically() {
|
||||
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 mut net = GrandpaTestNet::new(TestApi::new(voters), 3);
|
||||
@@ -757,8 +757,8 @@ fn consensus_changes_works() {
|
||||
#[test]
|
||||
fn sync_justifications_on_change_blocks() {
|
||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
||||
let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob];
|
||||
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||
let peers_b = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob];
|
||||
let voters = make_ids(peers_b);
|
||||
|
||||
// 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 mut runtime = current_thread::Runtime::new().unwrap();
|
||||
|
||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
||||
let peers_b = &[AuthorityKeyring::Dave, AuthorityKeyring::Eve, AuthorityKeyring::Ferdie];
|
||||
let peers_c = &[AuthorityKeyring::Dave, AuthorityKeyring::Alice, AuthorityKeyring::Bob];
|
||||
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||
let peers_b = &[Ed25519Keyring::Dave, Ed25519Keyring::Eve, Ed25519Keyring::Ferdie];
|
||||
let peers_c = &[Ed25519Keyring::Dave, Ed25519Keyring::Alice, Ed25519Keyring::Bob];
|
||||
|
||||
let all_peers = &[
|
||||
AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie,
|
||||
AuthorityKeyring::Dave, AuthorityKeyring::Eve, AuthorityKeyring::Ferdie,
|
||||
Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie,
|
||||
Ed25519Keyring::Dave, Ed25519Keyring::Eve, Ed25519Keyring::Ferdie,
|
||||
];
|
||||
let genesis_voters = make_ids(peers_a);
|
||||
|
||||
@@ -872,7 +872,7 @@ fn finalizes_multiple_pending_changes_in_order() {
|
||||
#[test]
|
||||
fn doesnt_vote_on_the_tip_of_the_chain() {
|
||||
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 api = TestApi::new(voters);
|
||||
let mut net = GrandpaTestNet::new(api, 3);
|
||||
@@ -898,8 +898,14 @@ fn force_change_to_new_set() {
|
||||
let _ = env_logger::try_init();
|
||||
let mut runtime = current_thread::Runtime::new().unwrap();
|
||||
// two of these guys are offline.
|
||||
let genesis_authorities = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie, AuthorityKeyring::One, AuthorityKeyring::Two];
|
||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
||||
let genesis_authorities = &[
|
||||
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 voters = make_ids(peers_a);
|
||||
@@ -950,8 +956,8 @@ fn force_change_to_new_set() {
|
||||
|
||||
#[test]
|
||||
fn allows_reimporting_change_blocks() {
|
||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
||||
let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob];
|
||||
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||
let peers_b = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob];
|
||||
let voters = make_ids(peers_a);
|
||||
let api = TestApi::new(voters);
|
||||
let mut net = GrandpaTestNet::new(api.clone(), 3);
|
||||
@@ -999,8 +1005,8 @@ fn allows_reimporting_change_blocks() {
|
||||
|
||||
#[test]
|
||||
fn test_bad_justification() {
|
||||
let peers_a = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob, AuthorityKeyring::Charlie];
|
||||
let peers_b = &[AuthorityKeyring::Alice, AuthorityKeyring::Bob];
|
||||
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
|
||||
let peers_b = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob];
|
||||
let voters = make_ids(peers_a);
|
||||
let api = TestApi::new(voters);
|
||||
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 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);
|
||||
|
||||
// alice has a chain with 20 blocks
|
||||
@@ -1264,7 +1270,7 @@ fn voter_persists_its_votes() {
|
||||
fn finalize_3_voters_1_light_observer() {
|
||||
let _ = env_logger::try_init();
|
||||
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 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 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);
|
||||
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.
|
||||
let genesis_authorities = if FORCE_CHANGE {
|
||||
vec![
|
||||
AuthorityKeyring::Alice,
|
||||
AuthorityKeyring::Bob,
|
||||
AuthorityKeyring::Charlie,
|
||||
AuthorityKeyring::One,
|
||||
AuthorityKeyring::Two,
|
||||
Ed25519Keyring::Alice,
|
||||
Ed25519Keyring::Bob,
|
||||
Ed25519Keyring::Charlie,
|
||||
Ed25519Keyring::One,
|
||||
Ed25519Keyring::Two,
|
||||
]
|
||||
} else {
|
||||
vec![
|
||||
AuthorityKeyring::Alice,
|
||||
AuthorityKeyring::Bob,
|
||||
AuthorityKeyring::Charlie,
|
||||
Ed25519Keyring::Alice,
|
||||
Ed25519Keyring::Bob,
|
||||
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 voters = make_ids(peers_a);
|
||||
@@ -1401,7 +1407,7 @@ fn voter_catches_up_to_latest_round_when_behind() {
|
||||
let _ = env_logger::try_init();
|
||||
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 mut net = GrandpaTestNet::new(TestApi::new(voters), 3);
|
||||
|
||||
@@ -23,12 +23,12 @@ pub mod sr25519;
|
||||
pub mod ed25519;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Convenience export: Ed25519's Keyring is exposed as `AuthorityKeyring`,
|
||||
/// since it tends to be used for authorities (session keys &c.).
|
||||
pub use ed25519::Keyring as AuthorityKeyring;
|
||||
pub use ed25519::Keyring as Ed25519Keyring;
|
||||
pub use sr25519::Keyring as Sr25519Keyring;
|
||||
|
||||
pub mod test {
|
||||
/// 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;
|
||||
|
||||
/// 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 {
|
||||
Alice,
|
||||
Bob,
|
||||
@@ -79,6 +79,11 @@ impl Keyring {
|
||||
Pair::from_string(&format!("//{}", <&'static str>::from(self)), None)
|
||||
.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 {
|
||||
|
||||
@@ -41,7 +41,7 @@ use keystore::Store as Keystore;
|
||||
use network::{NetworkState, NetworkStateInfo};
|
||||
use log::{log, info, warn, debug, error, Level};
|
||||
use parity_codec::{Encode, Decode};
|
||||
use primitives::{Pair, ed25519, crypto};
|
||||
use primitives::{Pair, ed25519, sr25519, crypto};
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use runtime_primitives::traits::{Header, NumberFor, SaturatedConversion, Zero};
|
||||
use substrate_executor::NativeExecutor;
|
||||
@@ -192,6 +192,7 @@ impl<Components: components::Components> Service<Components> {
|
||||
if let Some(keystore) = keystore.as_mut() {
|
||||
for seed in &config.keys {
|
||||
keystore.generate_from_seed::<ed25519::Pair>(seed)?;
|
||||
keystore.generate_from_seed::<sr25519::Pair>(seed)?;
|
||||
}
|
||||
|
||||
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>,
|
||||
{
|
||||
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;
|
||||
let temp = TempDir::new("substrate-sync-test").expect("Error creating test dir");
|
||||
let mut network = TestNet::<F>::new(
|
||||
|
||||
@@ -25,7 +25,11 @@ pub use client_db::{Backend, self};
|
||||
pub use client_ext::ClientExt;
|
||||
pub use consensus;
|
||||
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 runtime_primitives::{StorageOverlay, ChildrenStorageOverlay};
|
||||
pub use state_machine::ExecutionStrategy;
|
||||
|
||||
@@ -13,8 +13,8 @@ keyring = { package = "substrate-keyring", path = "../keyring", optional = true
|
||||
substrate-client = { path = "../client", default-features = false }
|
||||
primitives = { package = "substrate-primitives", path = "../primitives", 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 }
|
||||
consensus_babe = { package = "substrate-consensus-babe-primitives", path = "../consensus/babe/primitives", default-features = false }
|
||||
aura-primitives = { package = "substrate-consensus-aura-primitives", path = "../consensus/aura/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 }
|
||||
runtime_io = { package = "sr-io", path = "../sr-io", default-features = false }
|
||||
runtime_primitives = { package = "sr-primitives", path = "../sr-primitives", default-features = false }
|
||||
@@ -54,8 +54,8 @@ std = [
|
||||
"inherents/std",
|
||||
"runtime_primitives/std",
|
||||
"runtime_version/std",
|
||||
"consensus_aura/std",
|
||||
"consensus_babe/std",
|
||||
"aura-primitives/std",
|
||||
"babe-primitives/std",
|
||||
"primitives/std",
|
||||
"substrate-trie/std",
|
||||
"trie-db/std",
|
||||
|
||||
@@ -39,7 +39,7 @@ pub mod prelude {
|
||||
Executor, LightExecutor, LocalExecutor, NativeExecutor,
|
||||
};
|
||||
// Keyring
|
||||
pub use super::{AccountKeyring, AuthorityKeyring};
|
||||
pub use super::{AccountKeyring, Sr25519Keyring};
|
||||
}
|
||||
|
||||
mod local_executor {
|
||||
@@ -172,9 +172,9 @@ impl<B> TestClientBuilderExt<B> for TestClientBuilder<
|
||||
|
||||
fn genesis_config(support_changes_trie: bool) -> GenesisConfig {
|
||||
GenesisConfig::new(support_changes_trie, vec![
|
||||
AuthorityKeyring::Alice.into(),
|
||||
AuthorityKeyring::Bob.into(),
|
||||
AuthorityKeyring::Charlie.into(),
|
||||
Sr25519Keyring::Alice.into(),
|
||||
Sr25519Keyring::Bob.into(),
|
||||
Sr25519Keyring::Charlie.into(),
|
||||
], vec![
|
||||
AccountKeyring::Alice.into(),
|
||||
AccountKeyring::Bob.into(),
|
||||
|
||||
@@ -50,11 +50,10 @@ use runtime_version::NativeVersion;
|
||||
use runtime_support::{impl_outer_origin, parameter_types};
|
||||
use inherents::{CheckInherentsResult, InherentData};
|
||||
use cfg_if::cfg_if;
|
||||
pub use consensus_babe::AuthorityId;
|
||||
|
||||
// Ensure Babe and Aura use the same crypto to simplify things a bit.
|
||||
pub use babe_primitives::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
|
||||
#[cfg(feature = "std")]
|
||||
@@ -356,6 +355,14 @@ impl srml_timestamp::Trait for Runtime {
|
||||
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.
|
||||
#[inline(never)]
|
||||
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 authorities() -> Vec<AuraId> { system::authorities() }
|
||||
}
|
||||
|
||||
impl consensus_babe::BabeApi<Block> for Runtime {
|
||||
fn startup_data() -> consensus_babe::BabeConfiguration {
|
||||
consensus_babe::BabeConfiguration {
|
||||
impl babe_primitives::BabeApi<Block> for Runtime {
|
||||
fn startup_data() -> babe_primitives::BabeConfiguration {
|
||||
babe_primitives::BabeConfiguration {
|
||||
median_required_blocks: 0,
|
||||
slot_duration: 3,
|
||||
expected_block_time: 1,
|
||||
threshold: core::u64::MAX,
|
||||
slots_per_epoch: 6,
|
||||
c: (3, 10),
|
||||
}
|
||||
}
|
||||
fn epoch() -> consensus_babe::Epoch {
|
||||
|
||||
fn epoch() -> babe_primitives::Epoch {
|
||||
let authorities = system::authorities();
|
||||
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,
|
||||
randomness: <srml_babe::Module<Runtime>>::randomness(),
|
||||
epoch_index: 1,
|
||||
duration: 6,
|
||||
epoch_index: <srml_babe::Module<Runtime>>::epoch_index(),
|
||||
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 authorities() -> Vec<AuraId> { system::authorities() }
|
||||
}
|
||||
|
||||
impl consensus_babe::BabeApi<Block> for Runtime {
|
||||
fn startup_data() -> consensus_babe::BabeConfiguration {
|
||||
consensus_babe::BabeConfiguration {
|
||||
impl babe_primitives::BabeApi<Block> for Runtime {
|
||||
fn startup_data() -> babe_primitives::BabeConfiguration {
|
||||
babe_primitives::BabeConfiguration {
|
||||
median_required_blocks: 0,
|
||||
slot_duration: 1,
|
||||
expected_block_time: 1,
|
||||
threshold: core::u64::MAX,
|
||||
slots_per_epoch: 6,
|
||||
c: (3, 10),
|
||||
}
|
||||
}
|
||||
|
||||
fn epoch() -> consensus_babe::Epoch {
|
||||
fn epoch() -> babe_primitives::Epoch {
|
||||
let authorities = system::authorities();
|
||||
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,
|
||||
randomness: <srml_babe::Module<Runtime>>::randomness(),
|
||||
epoch_index: 1,
|
||||
duration: 6,
|
||||
epoch_index: <srml_babe::Module<Runtime>>::epoch_index(),
|
||||
duration: EpochDuration::get(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,16 +313,16 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
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 primitives::{Blake2Hasher, map};
|
||||
use substrate_executor::WasmExecutor;
|
||||
|
||||
fn new_test_ext() -> TestExternalities<Blake2Hasher> {
|
||||
let authorities = vec![
|
||||
AuthorityKeyring::Alice.to_raw_public(),
|
||||
AuthorityKeyring::Bob.to_raw_public(),
|
||||
AuthorityKeyring::Charlie.to_raw_public()
|
||||
Sr25519Keyring::Alice.to_raw_public(),
|
||||
Sr25519Keyring::Bob.to_raw_public(),
|
||||
Sr25519Keyring::Charlie.to_raw_public()
|
||||
];
|
||||
TestExternalities::new(map![
|
||||
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)?;
|
||||
|
||||
// found the node, early exit
|
||||
if node.is_some() {
|
||||
if let Some(node) = node {
|
||||
return Ok(node);
|
||||
}
|
||||
}
|
||||
@@ -498,7 +498,7 @@ mod node_implementation {
|
||||
number: &N,
|
||||
is_descendent_of: &F,
|
||||
predicate: &P,
|
||||
) -> Result<Option<&Node<H, N, V>>, Error<E>>
|
||||
) -> Result<Option<Option<&Node<H, N, V>>>, Error<E>>
|
||||
where E: std::error::Error,
|
||||
F: Fn(&H, &H) -> Result<bool, E>,
|
||||
P: Fn(&V) -> bool,
|
||||
@@ -519,10 +519,18 @@ mod node_implementation {
|
||||
}
|
||||
|
||||
// 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
|
||||
// predicate, then it is this one.
|
||||
if predicate(&self.data) && is_descendent_of(&self.hash, hash)? {
|
||||
Ok(Some(self))
|
||||
// searching for is a descendent of this node then we will stop the
|
||||
// search here, since there aren't any more children and we found
|
||||
// the correct node so we don't want to backtrack.
|
||||
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 {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -1033,4 +1041,38 @@ mod test {
|
||||
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" }
|
||||
transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" }
|
||||
network = { package = "substrate-network", path = "../../core/network" }
|
||||
aura = { package = "substrate-consensus-aura", path = "../../core/consensus/aura" }
|
||||
aura_primitives = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives" }
|
||||
babe = { package = "substrate-consensus-babe", path = "../../core/consensus/babe" }
|
||||
babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives" }
|
||||
grandpa = { package = "substrate-finality-grandpa", path = "../../core/finality-grandpa" }
|
||||
grandpa_primitives = { package = "substrate-finality-grandpa-primitives", path = "../../core/finality-grandpa/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" }
|
||||
|
||||
[dev-dependencies]
|
||||
babe = { package = "substrate-consensus-babe", path = "../../core/consensus/babe", features = ["test-helpers"] }
|
||||
consensus-common = { package = "substrate-consensus-common", path = "../../core/consensus/common" }
|
||||
service-test = { package = "substrate-service-test", path = "../../core/service/test" }
|
||||
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
|
||||
//! Substrate chain configurations.
|
||||
|
||||
use babe_primitives::AuthorityId as BabeId;
|
||||
use primitives::{ed25519, sr25519, Pair, crypto::UncheckedInto};
|
||||
use node_primitives::{AccountId, AuraId, Balance};
|
||||
use node_primitives::{AccountId, Balance};
|
||||
use node_runtime::{
|
||||
GrandpaConfig, BalancesConfig, ContractsConfig, ElectionsConfig, DemocracyConfig,
|
||||
CouncilConfig, AuraConfig, ImOnlineConfig, IndicesConfig, SessionConfig, StakingConfig,
|
||||
SudoConfig, TechnicalCommitteeConfig, SystemConfig, WASM_BINARY, Perbill, SessionKeys,
|
||||
StakerStatus, DAYS, DOLLARS, MILLICENTS,
|
||||
BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig,
|
||||
ElectionsConfig, GrandpaConfig, ImOnlineConfig, IndicesConfig, Perbill,
|
||||
SessionConfig, SessionKeys, StakerStatus, StakingConfig, SudoConfig, SystemConfig,
|
||||
TechnicalCommitteeConfig, DAYS, DOLLARS, MILLICENTS, WASM_BINARY,
|
||||
};
|
||||
pub use node_runtime::GenesisConfig;
|
||||
use substrate_service;
|
||||
@@ -40,8 +41,11 @@ pub fn flaming_fir_config() -> Result<ChainSpec, String> {
|
||||
ChainSpec::from_embedded(include_bytes!("../res/flaming-fir.json"))
|
||||
}
|
||||
|
||||
fn session_keys(key: ed25519::Public) -> SessionKeys {
|
||||
SessionKeys { ed25519: key }
|
||||
fn session_keys(ed_key: ed25519::Public, sr_key: sr25519::Public) -> SessionKeys {
|
||||
SessionKeys {
|
||||
ed25519: ed_key,
|
||||
sr25519: sr_key,
|
||||
}
|
||||
}
|
||||
|
||||
fn staging_testnet_config_genesis() -> GenesisConfig {
|
||||
@@ -51,7 +55,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
||||
// and
|
||||
// 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
|
||||
hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].unchecked_into(),
|
||||
// 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq
|
||||
@@ -116,7 +120,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
||||
.collect::<Vec<_>>(),
|
||||
}),
|
||||
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 {
|
||||
current_era: 0,
|
||||
@@ -124,7 +130,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
||||
validator_count: 7,
|
||||
offline_slash_grace: 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(),
|
||||
}),
|
||||
democracy: Some(DemocracyConfig::default()),
|
||||
@@ -149,8 +157,8 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
||||
sudo: Some(SudoConfig {
|
||||
key: endowed_accounts[0].clone(),
|
||||
}),
|
||||
aura: Some(AuraConfig {
|
||||
authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(),
|
||||
babe: Some(BabeConfig {
|
||||
authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(),
|
||||
}),
|
||||
im_online: Some(ImOnlineConfig {
|
||||
gossip_at: 0,
|
||||
@@ -184,9 +192,9 @@ pub fn get_account_id_from_seed(seed: &str) -> AccountId {
|
||||
.public()
|
||||
}
|
||||
|
||||
/// Helper function to generate AuraId from seed
|
||||
pub fn get_aura_id_from_seed(seed: &str) -> AuraId {
|
||||
ed25519::Pair::from_string(&format!("//{}", seed), None)
|
||||
/// Helper function to generate BabeId from seed
|
||||
pub fn get_babe_id_from_seed(seed: &str) -> BabeId {
|
||||
sr25519::Pair::from_string(&format!("//{}", seed), None)
|
||||
.expect("static values are valid; qed")
|
||||
.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
|
||||
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(seed),
|
||||
get_aura_id_from_seed(seed),
|
||||
get_babe_id_from_seed(seed),
|
||||
get_grandpa_id_from_seed(seed)
|
||||
)
|
||||
}
|
||||
|
||||
/// Helper function to create GenesisConfig for testing
|
||||
pub fn testnet_genesis(
|
||||
initial_authorities: Vec<(AccountId, AccountId, AuraId, GrandpaId)>,
|
||||
initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId)>,
|
||||
root_key: AccountId,
|
||||
endowed_accounts: Option<Vec<AccountId>>,
|
||||
enable_println: bool,
|
||||
@@ -250,7 +258,9 @@ pub fn testnet_genesis(
|
||||
vesting: vec![],
|
||||
}),
|
||||
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 {
|
||||
current_era: 0,
|
||||
@@ -258,7 +268,9 @@ pub fn testnet_genesis(
|
||||
validator_count: 2,
|
||||
offline_slash: Perbill::zero(),
|
||||
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(),
|
||||
}),
|
||||
democracy: Some(DemocracyConfig::default()),
|
||||
@@ -288,8 +300,8 @@ pub fn testnet_genesis(
|
||||
sudo: Some(SudoConfig {
|
||||
key: root_key,
|
||||
}),
|
||||
aura: Some(AuraConfig {
|
||||
authorities: initial_authorities.iter().map(|x| x.2.clone()).collect(),
|
||||
babe: Some(BabeConfig {
|
||||
authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(),
|
||||
}),
|
||||
im_online: Some(ImOnlineConfig{
|
||||
gossip_at: 0,
|
||||
|
||||
@@ -21,14 +21,15 @@
|
||||
use std::sync::Arc;
|
||||
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 grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
|
||||
use node_executor;
|
||||
use primitives::Pair;
|
||||
use grandpa_primitives::AuthorityPair as GrandpaPair;
|
||||
use futures::prelude::*;
|
||||
use node_primitives::{AuraPair, Block};
|
||||
use node_primitives::Block;
|
||||
use node_runtime::{GenesisConfig, RuntimeApi};
|
||||
use substrate_service::{
|
||||
FactoryFullConfiguration, LightComponents, FullComponents, FullBackend,
|
||||
@@ -47,19 +48,40 @@ construct_simple_protocol! {
|
||||
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
|
||||
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
|
||||
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,
|
||||
}
|
||||
|
||||
impl<F> Default for NodeConfig<F> where F: substrate_service::ServiceFactory {
|
||||
fn default() -> NodeConfig<F> {
|
||||
NodeConfig {
|
||||
grandpa_import_setup: None,
|
||||
import_setup: None,
|
||||
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! {
|
||||
struct Factory {
|
||||
Block = Block,
|
||||
ConsensusPair = AuraPair,
|
||||
ConsensusPair = BabePair,
|
||||
FinalityPair = GrandpaPair,
|
||||
RuntimeApi = RuntimeApi,
|
||||
NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) },
|
||||
@@ -83,11 +105,22 @@ construct_service_factory! {
|
||||
FullComponents::<Factory>::new(config) },
|
||||
AuthoritySetup = {
|
||||
|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");
|
||||
|
||||
if let Some(aura_key) = service.authority_key() {
|
||||
info!("Using aura key {}", aura_key.public());
|
||||
// spawn any futures that were created in the previous setup steps
|
||||
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 {
|
||||
client: service.client(),
|
||||
@@ -98,18 +131,21 @@ construct_service_factory! {
|
||||
let select_chain = service.select_chain()
|
||||
.ok_or(ServiceError::SelectChainRequired)?;
|
||||
|
||||
let aura = start_aura(
|
||||
SlotDuration::get_or_compute(&*client)?,
|
||||
Arc::new(aura_key),
|
||||
let babe_config = babe::BabeParams {
|
||||
config: Config::get_or_compute(&*client)?,
|
||||
local_key: Arc::new(babe_key),
|
||||
client,
|
||||
select_chain,
|
||||
block_import,
|
||||
proposer,
|
||||
service.network(),
|
||||
service.config.custom.inherent_data_providers.clone(),
|
||||
service.config.force_authoring,
|
||||
)?;
|
||||
let select = aura.select(service.on_exit()).then(|_| Ok(()));
|
||||
env: proposer,
|
||||
sync_oracle: service.network(),
|
||||
inherent_data_providers: service.config.custom.inherent_data_providers.clone(),
|
||||
force_authoring: service.config.force_authoring,
|
||||
time_source: babe_link,
|
||||
};
|
||||
|
||||
let babe = start_babe(babe_config)?;
|
||||
let select = babe.select(service.on_exit()).then(|_| Ok(()));
|
||||
service.spawn_task(Box::new(select));
|
||||
}
|
||||
|
||||
@@ -158,27 +194,30 @@ construct_service_factory! {
|
||||
},
|
||||
LightService = LightComponents<Self>
|
||||
{ |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| {
|
||||
let slot_duration = SlotDuration::get_or_compute(&*client)?;
|
||||
let (block_import, link_half) =
|
||||
grandpa::block_import::<_, _, _, RuntimeApi, FullClient<Self>, _>(
|
||||
client.clone(), client.clone(), select_chain
|
||||
)?;
|
||||
let justification_import = block_import.clone();
|
||||
|
||||
config.custom.grandpa_import_setup = Some((block_import.clone(), link_half));
|
||||
|
||||
import_queue::<_, _, AuraPair>(
|
||||
slot_duration,
|
||||
Box::new(block_import),
|
||||
let (import_queue, babe_link, babe_block_import, pruning_task) = import_queue(
|
||||
Config::get_or_compute(&*client)?,
|
||||
block_import,
|
||||
Some(Box::new(justification_import)),
|
||||
None,
|
||||
client.clone(),
|
||||
client,
|
||||
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>>| {
|
||||
#[allow(deprecated)]
|
||||
let fetch_checker = client.backend().blockchain().fetcher()
|
||||
@@ -188,17 +227,22 @@ construct_service_factory! {
|
||||
let block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, LightClient<Self>>(
|
||||
client.clone(), Arc::new(fetch_checker), client.clone()
|
||||
)?;
|
||||
|
||||
let finality_proof_import = block_import.clone();
|
||||
let finality_proof_request_builder = finality_proof_import.create_finality_proof_request_builder();
|
||||
|
||||
import_queue::<_, _, AuraPair>(
|
||||
SlotDuration::get_or_compute(&*client)?,
|
||||
Box::new(block_import),
|
||||
// FIXME: pruning task isn't started since light client doesn't do `AuthoritySetup`.
|
||||
let (import_queue, ..) = import_queue(
|
||||
Config::get_or_compute(&*client)?,
|
||||
block_import,
|
||||
None,
|
||||
Some(Box::new(finality_proof_import)),
|
||||
client.clone(),
|
||||
client,
|
||||
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>
|
||||
{ |config: &FactoryFullConfiguration<Self>, client: Arc<FullClient<Self>>| {
|
||||
@@ -216,25 +260,27 @@ construct_service_factory! {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
use aura::CompatibleDigestItem;
|
||||
use babe::CompatibleDigestItem;
|
||||
use consensus_common::{Environment, Proposer, BlockImportParams, BlockOrigin, ForkChoiceStrategy};
|
||||
use node_primitives::DigestItem;
|
||||
use node_runtime::{BalancesCall, Call, CENTS, SECS_PER_BLOCK, UncheckedExtrinsic};
|
||||
use parity_codec::{Encode, Decode};
|
||||
use primitives::{
|
||||
crypto::Pair as CryptoPair, ed25519::Pair, blake2_256,
|
||||
crypto::Pair as CryptoPair, blake2_256,
|
||||
sr25519::Public as AddressPublic, H256,
|
||||
};
|
||||
use sr_primitives::{generic::{BlockId, Era, Digest}, traits::Block, OpaqueExtrinsic};
|
||||
use timestamp;
|
||||
use finality_tracker;
|
||||
use keyring::{ed25519::Keyring as AuthorityKeyring, sr25519::Keyring as AccountKeyring};
|
||||
use keyring::{AccountKeyring, Sr25519Keyring};
|
||||
use substrate_service::ServiceFactory;
|
||||
use service_test::SyncService;
|
||||
use crate::service::Factory;
|
||||
|
||||
#[cfg(feature = "rhd")]
|
||||
fn test_sync() {
|
||||
use primitives::ed25519::Pair;
|
||||
|
||||
use {service_test, Factory};
|
||||
use client::{BlockImportParams, BlockOrigin};
|
||||
|
||||
@@ -294,7 +340,7 @@ mod tests {
|
||||
fn test_sync() {
|
||||
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 block_factory = |service: &SyncService<<Factory as ServiceFactory>::FullService>| {
|
||||
let service = service.get();
|
||||
@@ -305,7 +351,6 @@ mod tests {
|
||||
.create_inherent_data()
|
||||
.expect("Creates inherent data.");
|
||||
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_header = service.client().header(&parent_id).unwrap().unwrap();
|
||||
@@ -315,7 +360,26 @@ mod tests {
|
||||
});
|
||||
|
||||
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 new_block = proposer.propose(
|
||||
inherent_data,
|
||||
@@ -329,7 +393,7 @@ mod tests {
|
||||
// add it to a digest item.
|
||||
let to_sign = pre_hash.encode();
|
||||
let signature = alice.sign(&to_sign[..]);
|
||||
let item = <DigestItem as CompatibleDigestItem<Pair>>::aura_seal(
|
||||
let item = <DigestItem as CompatibleDigestItem>::babe_seal(
|
||||
signature,
|
||||
);
|
||||
slot_num += 1;
|
||||
|
||||
@@ -39,7 +39,7 @@ mod tests {
|
||||
use super::Executor;
|
||||
use substrate_executor::{WasmExecutor, NativeExecutionDispatch};
|
||||
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 state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities};
|
||||
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 {
|
||||
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> {
|
||||
let mut ext = TestExternalities::new_with_code_with_children(code, GenesisConfig {
|
||||
aura: Some(Default::default()),
|
||||
babe: Some(Default::default()),
|
||||
system: Some(SystemConfig {
|
||||
changes_trie_config: if support_changes_trie { Some(ChangesTrieConfiguration {
|
||||
digest_interval: 2,
|
||||
@@ -346,9 +350,18 @@ mod tests {
|
||||
}),
|
||||
session: Some(SessionConfig {
|
||||
keys: vec![
|
||||
(alice(), to_session_keys(&AuthorityKeyring::Alice)),
|
||||
(bob(), to_session_keys(&AuthorityKeyring::Bob)),
|
||||
(charlie(), to_session_keys(&AuthorityKeyring::Charlie)),
|
||||
(alice(), to_session_keys(
|
||||
&Ed25519Keyring::Alice,
|
||||
&Sr25519Keyring::Alice,
|
||||
)),
|
||||
(bob(), to_session_keys(
|
||||
&Ed25519Keyring::Bob,
|
||||
&Sr25519Keyring::Bob,
|
||||
)),
|
||||
(charlie(), to_session_keys(
|
||||
&Ed25519Keyring::Charlie,
|
||||
&Sr25519Keyring::Charlie,
|
||||
)),
|
||||
]
|
||||
}),
|
||||
staking: Some(StakingConfig {
|
||||
|
||||
@@ -44,16 +44,6 @@ pub type Balance = u128;
|
||||
/// Type used for expressing timestamp.
|
||||
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.
|
||||
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 }
|
||||
version = { package = "sr-version", path = "../../core/sr-version", 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 }
|
||||
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 }
|
||||
contracts = { package = "srml-contracts", path = "../../srml/contracts", 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 }
|
||||
im-online = { package = "srml-im-online", path = "../../srml/im-online", 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 }
|
||||
serde = { version = "1.0", optional = true }
|
||||
substrate-keyring = { path = "../../core/keyring", optional = true }
|
||||
@@ -54,8 +54,9 @@ std = [
|
||||
"rstd/std",
|
||||
"runtime_primitives/std",
|
||||
"support/std",
|
||||
"aura/std",
|
||||
"authorship/std",
|
||||
"babe/std",
|
||||
"babe-primitives/std",
|
||||
"balances/std",
|
||||
"contracts/std",
|
||||
"collective/std",
|
||||
@@ -76,7 +77,6 @@ std = [
|
||||
"serde",
|
||||
"safe-mix/std",
|
||||
"client/std",
|
||||
"consensus_aura/std",
|
||||
"rustc-hex",
|
||||
"substrate-keyring",
|
||||
"offchain-primitives/std",
|
||||
|
||||
@@ -26,9 +26,10 @@ use support::{
|
||||
};
|
||||
use substrate_primitives::u32_trait::{_1, _2, _3, _4};
|
||||
use node_primitives::{
|
||||
AccountId, AccountIndex, AuraId, Balance, BlockNumber, Hash, Index,
|
||||
AccountId, AccountIndex, Balance, BlockNumber, Hash, Index,
|
||||
Moment, Signature,
|
||||
};
|
||||
use babe::{AuthorityId as BabeId};
|
||||
use grandpa::fg_primitives::{self, ScheduledChange};
|
||||
use client::{
|
||||
block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult},
|
||||
@@ -137,9 +138,12 @@ impl system::Trait for Runtime {
|
||||
type MaximumBlockLength = MaximumBlockLength;
|
||||
}
|
||||
|
||||
impl aura::Trait for Runtime {
|
||||
type HandleReport = aura::StakingSlasher<Runtime>;
|
||||
type AuthorityId = AuraId;
|
||||
parameter_types! {
|
||||
pub const EpochDuration: u64 = 10 * MINUTES;
|
||||
}
|
||||
|
||||
impl babe::Trait for Runtime {
|
||||
type EpochDuration = EpochDuration;
|
||||
}
|
||||
|
||||
impl indices::Trait for Runtime {
|
||||
@@ -177,7 +181,7 @@ parameter_types! {
|
||||
}
|
||||
impl timestamp::Trait for Runtime {
|
||||
type Moment = Moment;
|
||||
type OnTimestampSet = Aura;
|
||||
type OnTimestampSet = Babe;
|
||||
type MinimumPeriod = MinimumPeriod;
|
||||
}
|
||||
|
||||
@@ -193,17 +197,14 @@ impl authorship::Trait for Runtime {
|
||||
type EventHandler = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const Period: BlockNumber = 10 * MINUTES;
|
||||
pub const Offset: BlockNumber = 0;
|
||||
}
|
||||
|
||||
type SessionHandlers = (Grandpa, Aura, ImOnline);
|
||||
type SessionHandlers = (Grandpa, Babe, ImOnline);
|
||||
|
||||
impl_opaque_keys! {
|
||||
pub struct SessionKeys {
|
||||
#[id(key_types::ED25519)]
|
||||
pub ed25519: GrandpaId,
|
||||
#[id(key_types::SR25519)]
|
||||
pub sr25519: BabeId,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +217,7 @@ impl_opaque_keys! {
|
||||
impl session::Trait for Runtime {
|
||||
type OnSessionEnding = Staking;
|
||||
type SessionHandler = SessionHandlers;
|
||||
type ShouldEndSession = session::PeriodicSessions<Period, Offset>;
|
||||
type ShouldEndSession = Babe;
|
||||
type Event = Event;
|
||||
type Keys = SessionKeys;
|
||||
type ValidatorId = AccountId;
|
||||
@@ -378,12 +379,12 @@ impl sudo::Trait for Runtime {
|
||||
}
|
||||
|
||||
impl im_online::Trait for Runtime {
|
||||
type AuthorityId = AuraId;
|
||||
type AuthorityId = BabeId;
|
||||
type Call = Call;
|
||||
type Event = Event;
|
||||
type SessionsPerEra = SessionsPerEra;
|
||||
type UncheckedExtrinsic = UncheckedExtrinsic;
|
||||
type IsValidAuthorityId = Aura;
|
||||
type IsValidAuthorityId = Babe;
|
||||
}
|
||||
|
||||
impl grandpa::Trait for Runtime {
|
||||
@@ -408,7 +409,7 @@ construct_runtime!(
|
||||
UncheckedExtrinsic = UncheckedExtrinsic
|
||||
{
|
||||
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},
|
||||
Authorship: authorship::{Module, Call, Storage},
|
||||
Indices: indices,
|
||||
@@ -525,12 +526,23 @@ impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl consensus_aura::AuraApi<Block, AuraId> for Runtime {
|
||||
fn slot_duration() -> u64 {
|
||||
Aura::slot_duration()
|
||||
impl babe_primitives::BabeApi<Block> for Runtime {
|
||||
fn startup_data() -> babe_primitives::BabeConfiguration {
|
||||
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)]
|
||||
#![forbid(unused_must_use, unsafe_code, unused_variables, dead_code)]
|
||||
|
||||
pub use timestamp;
|
||||
|
||||
use rstd::{result, prelude::*};
|
||||
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::traits::{IsMember, SaturatedConversion, Saturating, RandomnessBeacon, Convert};
|
||||
#[cfg(feature = "std")]
|
||||
@@ -31,7 +32,7 @@ use parity_codec::{Encode, Decode};
|
||||
use inherents::{RuntimeString, InherentIdentifier, InherentData, ProvideInherent, MakeFatalError};
|
||||
#[cfg(feature = "std")]
|
||||
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};
|
||||
|
||||
/// 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
|
||||
pub const RANDOMNESS_LENGTH: usize = 32;
|
||||
|
||||
decl_storage! {
|
||||
trait Store for Module<T: Trait> as Babe {
|
||||
NextRandomness: [u8; RANDOMNESS_LENGTH];
|
||||
/// Current epoch index.
|
||||
pub EpochIndex get(epoch_index): u64;
|
||||
|
||||
/// Randomness under construction
|
||||
UnderConstruction: [u8; VRF_OUTPUT_LENGTH];
|
||||
/// Current epoch authorities.
|
||||
pub Authorities get(authorities) config(): Vec<(AuthorityId, BabeWeight)>;
|
||||
|
||||
/// Current epoch
|
||||
pub Authorities get(authorities) config(): Vec<(AuthorityId, Weight)>;
|
||||
/// Slot at which the current epoch started. It is possible that no
|
||||
/// 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.
|
||||
///
|
||||
@@ -129,10 +140,16 @@ decl_storage! {
|
||||
/// (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
|
||||
/// 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
|
||||
EpochIndex: u64;
|
||||
/// Next epoch randomness.
|
||||
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 {
|
||||
/// Initialization
|
||||
fn on_initialize() {
|
||||
for i in Self::get_inherent_digests()
|
||||
for digest in Self::get_inherent_digests()
|
||||
.logs
|
||||
.iter()
|
||||
.filter_map(|s| s.as_pre_runtime())
|
||||
@@ -149,9 +166,15 @@ decl_module! {
|
||||
RawBabePreDigest::decode(&mut data)
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
<Module<T>>::authorities()
|
||||
.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> {
|
||||
/// Determine the BABE slot duration based on the Timestamp module configuration.
|
||||
pub fn slot_duration() -> T::Moment {
|
||||
@@ -205,23 +235,17 @@ impl<T: Trait> Module<T> {
|
||||
<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]) {
|
||||
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
|
||||
/// 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 next_randomness = compute_randomness(
|
||||
this_randomness,
|
||||
epoch_index,
|
||||
next_epoch_index,
|
||||
UnderConstruction::get(),
|
||||
);
|
||||
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) { }
|
||||
}
|
||||
|
||||
pub trait Duration {
|
||||
fn babe_epoch_duration() -> u64;
|
||||
}
|
||||
|
||||
impl<T: Trait + staking::Trait + Duration> session::OneSessionHandler<T::AccountId> for Module<T> {
|
||||
impl<T: Trait + staking::Trait> session::OneSessionHandler<T::AccountId> for Module<T> {
|
||||
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)>
|
||||
{
|
||||
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)
|
||||
};
|
||||
|
||||
// Update epoch index
|
||||
let epoch_index = EpochIndex::get()
|
||||
.checked_add(1)
|
||||
.expect("epoch indices will never reach 2^64 before the death of the universe; qed");
|
||||
|
||||
EpochIndex::put(epoch_index);
|
||||
|
||||
// *Next* epoch's authorities.
|
||||
let authorities = queued_validators.map(|(account, k)| {
|
||||
// Update authorities.
|
||||
let authorities = validators.map(|(account, k)| {
|
||||
(k, to_votes(staking::Module::<T>::stakers(account).total))
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
// What was the next epoch is now the current epoch
|
||||
let randomness = Self::randomness_change_epoch(epoch_index);
|
||||
Self::change_epoch(Epoch {
|
||||
randomness,
|
||||
authorities,
|
||||
epoch_index,
|
||||
duration: T::babe_epoch_duration(),
|
||||
})
|
||||
Authorities::put(authorities);
|
||||
|
||||
// Update epoch start slot.
|
||||
let now = CurrentSlot::get();
|
||||
EpochStartSlot::mutate(|previous| {
|
||||
loop {
|
||||
// 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) {
|
||||
@@ -304,6 +362,7 @@ impl<T: Trait> ProvideInherent for Module<T> {
|
||||
|
||||
let timestamp_based_slot = (timestamp / Self::slot_duration()).saturated_into::<u64>();
|
||||
let seal_slot = data.babe_inherent_data()?;
|
||||
|
||||
if timestamp_based_slot == seal_slot {
|
||||
Ok(())
|
||||
} else {
|
||||
|
||||
@@ -451,11 +451,12 @@ pub struct Exposure<AccountId, Balance: HasCompact> {
|
||||
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> =
|
||||
<<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> =
|
||||
<<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 RawAssignment<T> = (<T as system::Trait>::AccountId, ExtendedBalance);
|
||||
|
||||
Reference in New Issue
Block a user