BABE signing and verification (#2270)

* Add basic BABE consensus type

* Update core/consensus/babe/slots/Cargo.toml

Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>

* Fix parameterization and run `rustfmt`

* Respond to review comments

* Update various Cargo.lock files

* Revert "Update various Cargo.lock files"

This reverts commit af53d7624752a744320e9cbb25749fdd8e6f46d2.

* `BabeSealSignature` → `BabeSeal`

* Move slot code to its own crate

This was highly non-trivial, due to cyclic dependencies.

* Remove redundancy between AuRa and BABE

Some of the code duplication was removed using a macro.

* Fix build error

* Avoid non-`#[doc(hidden)]` re-exports

Also, bump some library versions in `Cargo.toml`.

* Remove dead code in AuRa

* Remove impl_slot macro

It was more trouble than it was worth.

Also, delete useless dependencies on Serde.

* AuRa and BABE need different DB keys

* Bring back `aura::Network`, but deprecate it.

* Improve docs and add `slot_duration` inherent method

* Add docs to `substrate_consensus_aura::SlotDuration`

* Add missing documentation and #![forbid(missing_docs, unsafe_code)]

* Add a #![forbid(missing_docs)]

* Remove dependency of `test-runtime` on `slots`

* Update core/consensus/babe/src/lib.rs

Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>

* Remove wrongly added file

* Fix copyright notice

Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>

* Bump `impl_version` and `spec_version`

* Add more code to BABE

Most of it is copied from AuRa code, but at least the initial core is
there.

* Stuck on horrible compiler error message

* add missing files

* Spaces → tabs

* Simplify code

* Fix compilation

This involved fixing dependencies and adding a `Mutex`.

* More work on BABE

* Fix deprecation version

* Fix deprecation version; remove spurious carets

* Fix Cargo.toml

* Implement VRF signing logic

* The import queue code compiles, though it probably doesn’t work.

* Add VRF verification

* Update Cargo.lock

* Update dependencies

* Move test network to sr25519 authority keys

* Fix accidental build bustage

* Trying to get the tests to work

* Add logging messages and remove dead code

There seems to be a problem with the test network.  Since AuRa and BABE
are both affected, this is most likely due to the switch from ed25519 to
sr25519.

* Trying to get the tests to work

* Add logging messages and remove dead code

There seems to be a problem with the test network.  Since AuRa and BABE
are both affected, this is most likely due to the switch from ed25519 to
sr25519.

* Working testsuite at last!

The problem was with serialization and deserialization.  Normally,
those functions are generated automatically, but those for `BabeSeal`
had to be written manually.  The hand-written versions were not
correct, however, as shown by the decoder not being able to decode the
output of the encoder.

* Enable BabeSeal::Encode asserts in --release tests

* Bump runtime and dependency versions

* Fix wasm compilation

The wasm build was broken because of a typo in
`core/test-runtime/src/lib.rs`, and missing gates on the `std` feature
in `core/consensus/{aura,babe}/primitives/Cargo.toml`.  Additionally,
improve the quotation in the build scripts.

* Merge Cargo.lock

* Change expected JSON string

The test was also broken on `master`, so I suspect that the test was
incorrect.

* Responded to review

* Remove hard-coded threshold from production code

A hard-coded threshold is now only used in tests.

* Fix swapped doc comments

* Fix unused import warnings

* fix ci error

* fix typo

* Fix spacing in docs

* Minor changes suggested by @joepetrowski

on https://github.com/paritytech/substrate/pull/2372

* Remove unnecessary getters

* fix compile error

* Fix silly unused-variable error

* Improve documentation formatting

Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>

* Add issue links

* Revert excess verbosity and #![forbid(warnings)]

* Apply suggestions from code review

Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>

* Reformat some comments

* Threshold should depend on number of validators

Also, respond to code review

* Fix silly compilation errors

* Reduce logging verbosity

* Fix missing import
This commit is contained in:
DemiMarie-parity
2019-05-02 11:16:54 -04:00
committed by GitHub
parent d3f59a0712
commit fb19684358
40 changed files with 1570 additions and 263 deletions
+28 -19
View File
@@ -2892,23 +2892,6 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "schnorrkel"
version = "0.1.1"
source = "git+https://github.com/paritytech/schnorrkel#1762df02ac48ba5c3fa8c162e19a393247079f88"
dependencies = [
"clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"curve25519-dalek 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"merlin 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sha3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "schnorrkel"
version = "0.1.1"
@@ -3271,6 +3254,29 @@ dependencies = [
"substrate-primitives 1.0.0",
]
[[package]]
name = "srml-babe"
version = "0.1.0"
dependencies = [
"hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 1.0.0",
"sr-primitives 1.0.0",
"sr-std 1.0.0",
"srml-consensus 1.0.0",
"srml-session 1.0.0",
"srml-staking 1.0.0",
"srml-support 1.0.0",
"srml-system 1.0.0",
"srml-timestamp 1.0.0",
"substrate-consensus-babe-primitives 1.0.0",
"substrate-inherents 1.0.0",
"substrate-primitives 1.0.0",
]
[[package]]
name = "srml-balances"
version = "1.0.0"
@@ -3936,13 +3942,16 @@ dependencies = [
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"merlin 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec-derive 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"schnorrkel 0.1.1 (git+https://github.com/paritytech/schnorrkel)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 1.0.0",
"sr-primitives 1.0.0",
"sr-version 1.0.0",
"srml-babe 0.1.0",
"srml-consensus 1.0.0",
"srml-support 1.0.0",
"substrate-client 1.0.0",
@@ -4450,6 +4459,7 @@ dependencies = [
"substrate-client 1.0.0",
"substrate-consensus-aura-primitives 1.0.0",
"substrate-consensus-authorities 1.0.0",
"substrate-consensus-babe-primitives 1.0.0",
"substrate-executor 1.0.0",
"substrate-inherents 1.0.0",
"substrate-keyring 1.0.0",
@@ -5671,7 +5681,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
"checksum schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339"
"checksum schnorrkel 0.1.1 (git+https://github.com/paritytech/schnorrkel)" = "<none>"
"checksum schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5eff518f9bed3d803a0d002af0ab96339b0ebbedde3bec98a684986134b7a39"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaccd3a23619349e0878d9a241f34b1982343cdf67367058cd7d078d326b63e"
@@ -12,5 +12,6 @@ runtime_primitives = { package = "sr-primitives", path = "../../../sr-primitives
[features]
default = ["std"]
std = [
"runtime_primitives/std",
"substrate-client/std",
]
+9 -36
View File
@@ -62,10 +62,10 @@ use srml_aura::{
};
use substrate_telemetry::{telemetry, CONSENSUS_TRACE, CONSENSUS_DEBUG, CONSENSUS_WARN, CONSENSUS_INFO};
use slots::{CheckedHeader, SlotWorker, SlotInfo, SlotCompatible};
use slots::{CheckedHeader, SlotWorker, SlotInfo, SlotCompatible, slot_now};
pub use aura_primitives::*;
pub use consensus_common::SyncOracle;
pub use consensus_common::{SyncOracle, ExtraVerification};
type AuthorityId<P> = <P as Pair>::Public;
type Signature<P> = <P as Pair>::Signature;
@@ -120,20 +120,6 @@ fn slot_author<P: Pair>(slot_num: u64, authorities: &[AuthorityId<P>]) -> Option
Some(current_author)
}
fn duration_now() -> Option<Duration> {
use std::time::SystemTime;
let now = SystemTime::now();
now.duration_since(SystemTime::UNIX_EPOCH).map_err(|e| {
warn!("Current time {:?} is before unix epoch. Something is wrong: {:?}", now, e);
}).ok()
}
/// Get the slot for now.
fn slot_now(slot_duration: u64) -> Option<u64> {
duration_now().map(|s| s.as_secs() / slot_duration)
}
fn inherent_to_common_error(err: RuntimeString) -> consensus_common::Error {
consensus_common::ErrorKind::InherentData(err.into()).into()
}
@@ -467,7 +453,6 @@ impl<B: Block, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, S
/// This digest item will always return `Some` when used with `as_aura_seal`.
//
// FIXME #1018 needs misbehavior types
#[forbid(deprecated)]
fn check_header<B: Block, P: Pair>(
slot_now: u64,
mut header: B::Header,
@@ -517,19 +502,6 @@ fn check_header<B: Block, P: Pair>(
}
}
/// Extra verification for Aura blocks.
pub trait ExtraVerification<B: Block>: Send + Sync {
/// Future that resolves when the block is verified or fails with error if not.
type Verified: IntoFuture<Item=(),Error=String>;
/// Do additional verification for this block.
fn verify(
&self,
header: &B::Header,
body: Option<&[B::Extrinsic]>,
) -> Self::Verified;
}
/// A verifier for Aura blocks.
pub struct AuraVerifier<C, E, P> {
client: Arc<C>,
@@ -785,7 +757,8 @@ pub fn import_queue<B, C, E, P>(
/// Start an import queue for the Aura consensus algorithm with backwards compatibility.
#[deprecated(
note = "should not be used unless backwards compatibility with an older chain is needed."
since = "1.0.1",
note = "should not be used unless backwards compatibility with an older chain is needed.",
)]
pub fn import_queue_accept_old_seals<B, C, E, P>(
slot_duration: SlotDuration,
@@ -828,8 +801,8 @@ mod tests {
use network::config::ProtocolConfig;
use parking_lot::Mutex;
use tokio::runtime::current_thread;
use keyring::ed25519::Keyring;
use primitives::ed25519;
use keyring::sr25519::Keyring;
use primitives::sr25519;
use client::BlockchainEvents;
use test_client;
@@ -844,7 +817,7 @@ mod tests {
type Proposer = DummyProposer;
type Error = Error;
fn init(&self, parent_header: &<TestBlock as BlockT>::Header, _authorities: &[AuthorityId<ed25519::Pair>])
fn init(&self, parent_header: &<TestBlock as BlockT>::Header, _authorities: &[AuthorityId<sr25519::Pair>])
-> Result<DummyProposer, Error>
{
Ok(DummyProposer(parent_header.number + 1, self.0.clone()))
@@ -870,7 +843,7 @@ mod tests {
impl TestNetFactory for AuraTestNet {
type Specialization = DummySpecialization;
type Verifier = AuraVerifier<PeersClient, NothingExtra, ed25519::Pair>;
type Verifier = AuraVerifier<PeersClient, NothingExtra, sr25519::Pair>;
type PeerData = ();
/// Create new test network with peers and given config.
@@ -957,7 +930,7 @@ mod tests {
&inherent_data_providers, slot_duration.get()
).expect("Registers aura inherent data provider");
let aura = start_aura::<_, _, _, _, ed25519::Pair, _, _, _>(
let aura = start_aura::<_, _, _, _, sr25519::Pair, _, _, _>(
slot_duration,
Arc::new(key.clone().into()),
client.clone(),
+4 -4
View File
@@ -16,6 +16,7 @@ runtime_io = { package = "sr-io", path = "../../sr-io" }
inherents = { package = "substrate-inherents", path = "../../inherents" }
srml-consensus = { path = "../../../srml/consensus" }
substrate-telemetry = { path = "../../telemetry" }
srml-babe = { path = "../../../srml/babe" }
client = { package = "substrate-client", path = "../../client" }
consensus_common = { package = "substrate-consensus-common", path = "../common" }
authorities = { package = "substrate-consensus-authorities", path = "../authorities" }
@@ -26,10 +27,9 @@ tokio = "0.1.18"
parking_lot = "0.7.1"
error-chain = "0.12.0"
log = "0.4.6"
[dependencies.schnorrkel]
git = "https://github.com/paritytech/schnorrkel"
branch = "master"
schnorrkel = "0.1.1"
rand = "0.6.5"
merlin = "1.0.3"
[dev-dependencies]
keyring = { package = "substrate-keyring", path = "../../keyring" }
@@ -9,11 +9,13 @@ edition = "2018"
substrate-client = { path = "../../../client", default-features = false }
runtime_primitives = { package = "sr-primitives", path = "../../../sr-primitives", default-features = false }
slots = { package = "substrate-consensus-slots", path = "../../slots", optional = true }
parity-codec = "^3.4.0"
parity-codec = { version = "3.5.1", default-features = false }
[features]
default = ["std"]
std = [
"runtime_primitives/std",
"substrate-client/std",
"parity-codec/std",
"slots",
]
@@ -29,31 +29,28 @@ pub const BABE_ENGINE_ID: ConsensusEngineId = [b'b', b'a', b'b', b'e'];
/// Configuration data used by the BABE consensus engine.
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Encode, Decode)]
pub struct BabeConfiguration {
slot_duration: u64,
expected_block_time: u64,
}
impl BabeConfiguration {
/// Return 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 fn expected_block_time(&self) -> u64 {
self.expected_block_time
}
/// Return the slot duration in milliseconds for BABE. Currently, only
/// The slot duration in milliseconds for BABE. Currently, only
/// the value provided by this type at genesis will be used.
///
/// Dynamic slot duration may be supported in the future.
pub fn slot_duration(&self) -> u64 {
self.slot_duration
}
pub slot_duration: 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,
}
#[cfg(feature = "std")]
impl slots::SlotData for BabeConfiguration {
/// Return the slot duration in milliseconds for BABE. Currently, only
/// Return the slot duration in milliseconds for BABE. Currently, only
/// the value provided by this type at genesis will be used.
///
/// Dynamic slot duration may be supported in the future.
@@ -67,7 +64,7 @@ impl slots::SlotData for BabeConfiguration {
decl_runtime_apis! {
/// API necessary for block authorship with BABE.
pub trait BabeApi {
/// Return the configuration for BABE. Currently,
/// Return the configuration for BABE. Currently,
/// only the value provided by this type at genesis will be used.
///
/// Dynamic configuration may be supported in the future.
File diff suppressed because it is too large Load Diff
@@ -17,12 +17,13 @@
//! Import Queue primitive: something which can verify and import blocks.
//!
//! This serves as an intermediate and abstracted step between synchronization
//! and import. Each mode of consensus will have its own requirements for block verification.
//! Some algorithms can verify in parallel, while others only sequentially.
//! and import. Each mode of consensus will have its own requirements for block
//! verification. Some algorithms can verify in parallel, while others only
//! sequentially.
//!
//! The `ImportQueue` trait allows such verification strategies to be instantiated.
//! The `BasicQueue` and `BasicVerifier` traits allow serial queues to be
//! instantiated simply.
//! The `ImportQueue` trait allows such verification strategies to be
//! instantiated. The `BasicQueue` and `BasicVerifier` traits allow serial
//! queues to be instantiated simply.
use crate::block_import::{
BlockImport, BlockOrigin, ImportBlock, ImportedAux, ImportResult, JustificationImport,
@@ -106,8 +107,8 @@ impl<B: BlockT> Clone for Box<ImportQueue<B>> {
}
}
/// Interface to a basic block import queue that is importing blocks sequentially in a separate thread,
/// with pluggable verification.
/// Interface to a basic block import queue that is importing blocks
/// sequentially in a separate thread, with pluggable verification.
#[derive(Clone)]
pub struct BasicQueue<B: BlockT> {
sender: Sender<BlockImportMsg<B>>,
@@ -120,20 +121,24 @@ impl<B: BlockT> ImportQueueClone<B> for BasicQueue<B> {
}
/// "BasicQueue" is a wrapper around a channel sender to the "BlockImporter".
/// "BasicQueue" itself does not keep any state or do any importing work, and can therefore be send to other threads.
/// "BasicQueue" itself does not keep any state or do any importing work, and
/// can therefore be send to other threads.
///
/// "BasicQueue" implements "ImportQueue" by sending messages to the "BlockImporter", which runs in it's own thread.
/// "BasicQueue" implements "ImportQueue" by sending messages to the
/// "BlockImporter", which runs in it's own thread.
///
/// The "BlockImporter" is responsible for handling incoming requests from the "BasicQueue",
/// some of these requests are handled by the "BlockImporter" itself, such as "is_importing" or "status",
/// and justifications are also imported by the "BlockImporter".
/// The "BlockImporter" is responsible for handling incoming requests from the
/// "BasicQueue". Some of these requests are handled by the "BlockImporter"
/// itself, such as "is_importing", "status", and justifications.
///
/// The "import block" work will be offloaded to a single "BlockImportWorker", running in another thread.
/// Offloading the work is done via a channel,
/// ensuring blocks in this implementation are imported sequentially and in order(as received by the "BlockImporter")
/// The "import block" work will be offloaded to a single "BlockImportWorker",
/// running in another thread. Offloading the work is done via a channel,
/// ensuring blocks in this implementation are imported sequentially and in
/// order (as received by the "BlockImporter").
///
/// As long as the "BasicQueue" is not dropped, the "BlockImporter" will keep running.
/// The "BlockImporter" owns a sender to the "BlockImportWorker", ensuring that the worker is kept alive until that sender is dropped.
/// As long as the "BasicQueue" is not dropped, the "BlockImporter" will keep
/// running. The "BlockImporter" owns a sender to the "BlockImportWorker",
/// ensuring that the worker is kept alive until that sender is dropped.
impl<B: BlockT> BasicQueue<B> {
/// Instantiate a new basic queue, with given verifier.
pub fn new<V: 'static + Verifier<B>>(
@@ -152,8 +157,8 @@ impl<B: BlockT> BasicQueue<B> {
/// Send synchronization request to the block import channel.
///
/// The caller should wait for Link::synchronized() call to ensure that it has synchronized
/// with ImportQueue.
/// The caller should wait for Link::synchronized() call to ensure that it
/// has synchronized with ImportQueue.
#[cfg(any(test, feature = "test-helpers"))]
pub fn synchronize(&self) {
self
@@ -238,6 +243,7 @@ impl<B: BlockT> BlockImporter<B> {
worker_sender: Sender<BlockImportWorkerMsg<B>>,
justification_import: Option<SharedJustificationImport<B>>,
) -> Sender<BlockImportMsg<B>> {
trace!(target: "block_import", "Creating new Block Importer!");
let (sender, port) = channel::bounded(4);
let _ = thread::Builder::new()
.name("ImportQueue".into())
@@ -258,6 +264,7 @@ impl<B: BlockT> BlockImporter<B> {
}
fn run(&mut self) -> bool {
trace!(target: "import_queue", "Running import queue");
let msg = select! {
recv(self.port) -> msg => {
match msg {
@@ -297,6 +304,7 @@ impl<B: BlockT> BlockImporter<B> {
BlockImportMsg::Stop => return false,
#[cfg(any(test, feature = "test-helpers"))]
BlockImportMsg::Synchronize => {
trace!(target: "sync", "Received synchronization message");
self.worker_sender
.send(BlockImportWorkerMsg::Synchronize)
.expect("1. This is holding a sender to the worker, 2. the worker should not quit while a sender is still held; qed");
@@ -318,6 +326,7 @@ impl<B: BlockT> BlockImporter<B> {
BlockImportWorkerMsg::Imported(results) => (results),
#[cfg(any(test, feature = "test-helpers"))]
BlockImportWorkerMsg::Synchronize => {
trace!(target: "sync", "Synchronizing link");
link.synchronized();
return true;
},
@@ -434,6 +443,7 @@ impl<B: BlockT, V: 'static + Verifier<B>> BlockImportWorker<B, V> {
},
#[cfg(any(test, feature = "test-helpers"))]
BlockImportWorkerMsg::Synchronize => {
trace!(target: "sync", "Sending sync message");
let _ = worker.result_sender.send(BlockImportWorkerMsg::Synchronize);
},
_ => unreachable!("Import Worker does not receive the Imported message; qed"),
@@ -118,6 +118,20 @@ impl<T: SyncOracle> SyncOracle for Arc<T> {
}
}
/// Extra verification for blocks.
pub trait ExtraVerification<B: Block>: Send + Sync {
/// Future that resolves when the block is verified, or fails with error if
/// not.
type Verified: IntoFuture<Item=(),Error=String>;
/// Do additional verification for this block.
fn verify(
&self,
header: &B::Header,
body: Option<&[B::Extrinsic]>,
) -> Self::Verified;
}
/// A list of all well known keys in the cache.
pub mod well_known_cache_keys {
/// The type representing cache keys.
+70 -53
View File
@@ -24,45 +24,44 @@
mod slots;
pub use slots::{Slots, SlotInfo};
pub use slots::{slot_now, SlotInfo, Slots};
use client::ChainHead;
use codec::{Decode, Encode};
use consensus_common::SyncOracle;
use futures::prelude::*;
use futures::{
future::{self, Either},
Future, IntoFuture,
};
use inherents::{InherentData, InherentDataProviders};
use log::{debug, error, info, warn};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{ApiRef, Block, ProvideRuntimeApi};
use std::fmt::Debug;
use std::ops::Deref;
use std::sync::{mpsc, Arc};
use std::thread;
use std::fmt::Debug;
use futures::prelude::*;
use futures::{Future, IntoFuture, future::{self, Either}};
use log::{warn, debug, info};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{ProvideRuntimeApi, Block, ApiRef};
use consensus_common::SyncOracle;
use inherents::{InherentData, InherentDataProviders};
use client::ChainHead;
use codec::{Encode, Decode};
/// A worker that should be invoked at every new slot.
pub trait SlotWorker<B: Block> {
/// The type of the future that will be returned when a new slot is
/// triggered.
type OnSlot: IntoFuture<Item=(), Error=consensus_common::Error>;
type OnSlot: IntoFuture<Item = (), Error = consensus_common::Error>;
/// Called when the proposer starts.
fn on_start(
&self,
slot_duration: u64
) -> Result<(), consensus_common::Error>;
fn on_start(&self, slot_duration: u64) -> Result<(), consensus_common::Error>;
/// Called when a new slot is triggered.
fn on_slot(
&self,
chain_head: B::Header,
slot_info: SlotInfo,
) -> Self::OnSlot;
fn on_slot(&self, chain_head: B::Header, slot_info: SlotInfo) -> Self::OnSlot;
}
/// Slot compatible inherent data.
pub trait SlotCompatible {
/// Extract timestamp and slot from inherent data.
fn extract_timestamp_and_slot(inherent: &InherentData) -> Result<(u64, u64), consensus_common::Error>;
fn extract_timestamp_and_slot(
inherent: &InherentData,
) -> Result<(u64, u64), consensus_common::Error>;
}
/// Convert an inherent error to common error.
@@ -79,13 +78,14 @@ pub fn start_slot_worker_thread<B, C, W, SO, SC, T, OnExit>(
sync_oracle: SO,
on_exit: OnExit,
inherent_data_providers: InherentDataProviders,
) -> Result<(), consensus_common::Error> where
) -> Result<(), consensus_common::Error>
where
B: Block + 'static,
C: ChainHead<B> + Send + Sync + 'static,
W: SlotWorker<B> + Send + Sync + 'static,
SO: SyncOracle + Send + Clone + 'static,
SC: SlotCompatible + 'static,
OnExit: Future<Item=(), Error=()> + Send + 'static,
OnExit: Future<Item = (), Error = ()> + Send + 'static,
T: SlotData + Send + Clone + 'static,
{
use tokio::runtime::current_thread::Runtime;
@@ -96,7 +96,7 @@ pub fn start_slot_worker_thread<B, C, W, SO, SC, T, OnExit>(
let mut runtime = match Runtime::new() {
Ok(r) => r,
Err(e) => {
warn!("Unable to start authorship: {:?}", e);
warn!(target: "slots", "Unable to start authorship: {:?}", e);
return;
}
};
@@ -114,7 +114,7 @@ pub fn start_slot_worker_thread<B, C, W, SO, SC, T, OnExit>(
.send(Ok(()))
.expect("Receive is not dropped before receiving a result; qed");
slot_worker_future
},
}
Err(e) => {
result_sender
.send(Err(e))
@@ -126,7 +126,9 @@ pub fn start_slot_worker_thread<B, C, W, SO, SC, T, OnExit>(
let _ = runtime.block_on(slot_worker_future);
});
result_recv.recv().expect("Slots start thread result sender dropped")
result_recv
.recv()
.expect("Slots start thread result sender dropped")
}
/// Start a new slot worker.
@@ -137,13 +139,14 @@ pub fn start_slot_worker<B, C, W, T, SO, SC, OnExit>(
sync_oracle: SO,
on_exit: OnExit,
inherent_data_providers: InherentDataProviders,
) -> Result<impl Future<Item=(), Error=()>, consensus_common::Error> where
) -> Result<impl Future<Item = (), Error = ()>, consensus_common::Error>
where
B: Block,
C: ChainHead<B>,
W: SlotWorker<B>,
SO: SyncOracle + Send + Clone,
SC: SlotCompatible,
OnExit: Future<Item=(), Error=()>,
OnExit: Future<Item = (), Error = ()>,
T: SlotData + Clone,
{
worker.on_start(slot_duration.slot_duration())?;
@@ -174,15 +177,14 @@ pub fn start_slot_worker<B, C, W, T, SO, SC, OnExit>(
Ok(x) => x,
Err(e) => {
warn!(target: "slots", "Unable to author block in slot {}. \
no best block header: {:?}", slot_num, e);
return Either::B(future::ok(()))
no best block header: {:?}", slot_num, e);
return Either::B(future::ok(()));
}
};
Either::A(
worker.on_slot(chain_head, slot_info).into_future()
.map_err(|e| debug!(target: "slots", "Encountered consensus error: {:?}", e))
)
Either::A(worker.on_slot(chain_head, slot_info).into_future().map_err(
|e| warn!(target: "slots", "Encountered consensus error: {:?}", e),
))
})
};
@@ -230,7 +232,9 @@ pub trait SlotData {
}
impl SlotData for u64 {
fn slot_duration(&self) -> u64 { *self }
fn slot_duration(&self) -> u64 {
*self
}
const SLOT_KEY: &'static [u8] = b"aura_slot_duration";
}
@@ -238,7 +242,25 @@ impl SlotData for u64 {
/// A slot duration. Create with `get_or_compute`.
// The internal member should stay private here.
#[derive(Clone, Copy, Debug, Encode, Decode, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct SlotDuration<T: Clone>(T);
pub struct SlotDuration<T>(T);
impl<T> Deref for SlotDuration<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T: SlotData + Clone> SlotData for SlotDuration<T> {
/// Get the slot duration in milliseconds.
fn slot_duration(&self) -> u64
where T: SlotData,
{
self.0.slot_duration()
}
const SLOT_KEY: &'static [u8] = T::SLOT_KEY;
}
impl<T: Clone> SlotDuration<T> {
/// Either fetch the slot duration from disk or compute it from the
@@ -255,23 +277,25 @@ impl<T: Clone> SlotDuration<T> {
match client.get_aux(T::SLOT_KEY)? {
Some(v) => <T as codec::Decode>::decode(&mut &v[..])
.map(SlotDuration)
.ok_or_else(|| ::client::error::Error::Backend(
format!("slot duration kept in invalid format"),
).into()),
.ok_or_else(|| {
::client::error::Error::Backend({
error!(target: "slots", "slot duration kept in invalid format");
format!("slot duration kept in invalid format")
})
.into()
}),
None => {
use runtime_primitives::traits::Zero;
let genesis_slot_duration = cb(
client.runtime_api(),
&BlockId::number(Zero::zero()))?;
let genesis_slot_duration =
cb(client.runtime_api(), &BlockId::number(Zero::zero()))?;
info!(
"Loaded block-time = {:?} seconds from genesis on first-launch",
genesis_slot_duration
);
genesis_slot_duration.using_encoded(|s| {
client.insert_aux(&[(T::SLOT_KEY, &s[..])], &[])
})?;
genesis_slot_duration
.using_encoded(|s| client.insert_aux(&[(T::SLOT_KEY, &s[..])], &[]))?;
Ok(SlotDuration(genesis_slot_duration))
}
@@ -282,11 +306,4 @@ impl<T: Clone> SlotDuration<T> {
pub fn get(&self) -> T {
self.0.clone()
}
/// Get the slot duration in milliseconds
pub fn slot_duration(&self) -> u64
where T: SlotData
{
self.0.slot_duration()
}
}
+34 -23
View File
@@ -18,24 +18,34 @@
//!
//! This is used instead of `tokio_timer::Interval` because it was unreliable.
use std::time::{Instant, Duration};
use std::marker::PhantomData;
use tokio::timer::Delay;
use super::SlotCompatible;
use consensus_common::{Error, ErrorKind};
use futures::prelude::*;
use futures::try_ready;
use inherents::{InherentData, InherentDataProviders};
use log::warn;
use inherents::{InherentDataProviders, InherentData};
use consensus_common::{Error, ErrorKind};
use crate::SlotCompatible;
use std::marker::PhantomData;
use std::time::{Duration, Instant};
use tokio::timer::Delay;
/// Returns current duration since unix epoch.
pub fn duration_now() -> Option<Duration> {
use std::time::SystemTime;
let now = SystemTime::now();
now.duration_since(SystemTime::UNIX_EPOCH).map_err(|e| {
warn!("Current time {:?} is before unix epoch. Something is wrong: {:?}", now, e);
}).ok()
now.duration_since(SystemTime::UNIX_EPOCH)
.map_err(|e| {
warn!(
"Current time {:?} is before unix epoch. Something is wrong: {:?}",
now, e
);
})
.ok()
}
/// Get the slot for now.
pub fn slot_now(slot_duration: u64) -> Option<u64> {
duration_now().map(|s| s.as_secs() / slot_duration)
}
/// Returns the duration until the next slot, based on current duration since
@@ -113,34 +123,35 @@ impl<SC: SlotCompatible> Stream for Slots<SC> {
};
if let Some(ref mut inner_delay) = self.inner_delay {
try_ready!(inner_delay.poll().map_err(|e| Error::from(ErrorKind::FaultyTimer(e))));
try_ready!(inner_delay
.poll()
.map_err(|e| Error::from(ErrorKind::FaultyTimer(e))));
}
// timeout has fired.
let inherent_data = self.inherent_data_providers.create_inherent_data()
let inherent_data = self
.inherent_data_providers
.create_inherent_data()
.map_err(crate::inherent_to_common_error)?;
let (timestamp, slot_num) = SC::extract_timestamp_and_slot(&inherent_data)?;
// reschedule delay for next slot.
let ends_at = Instant::now() + time_until_next(Duration::from_secs(timestamp), slot_duration);
let ends_at =
Instant::now() + time_until_next(Duration::from_secs(timestamp), slot_duration);
self.inner_delay = Some(Delay::new(ends_at));
// never yield the same slot twice.
if slot_num > self.last_slot {
self.last_slot = slot_num;
Ok(
Async::Ready(
Some(SlotInfo {
number: slot_num,
duration: self.slot_duration,
timestamp,
ends_at,
inherent_data,
})
)
)
Ok(Async::Ready(Some(SlotInfo {
number: slot_num,
duration: self.slot_duration,
timestamp,
ends_at,
inherent_data,
})))
} else {
// re-poll until we get a new slot.
self.poll()
@@ -33,10 +33,10 @@ use fg_primitives::GrandpaApi;
use runtime_primitives::Justification;
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{
Block as BlockT, DigestFor, DigestItemFor, DigestItem,
Block as BlockT, DigestFor,
Header as HeaderT, NumberFor, ProvideRuntimeApi,
};
use substrate_primitives::{H256, ed25519, Blake2Hasher};
use substrate_primitives::{H256, Blake2Hasher};
use crate::{Error, CommandOrError, NewAuthoritySet, VoterCommand};
use crate::authorities::{AuthoritySet, SharedAuthoritySet, DelayKind, PendingChange};
@@ -44,8 +44,6 @@ use crate::consensus_changes::SharedConsensusChanges;
use crate::environment::{finalize_block, is_descendent_of};
use crate::justification::GrandpaJustification;
use ed25519::Public as AuthorityId;
/// A block-import handler for GRANDPA.
///
/// This scans each imported block for signals of changing authority set.
@@ -69,7 +67,6 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> JustificationImport<Block>
B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
DigestFor<Block>: Encode,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
RA: Send + Sync,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi<Block>,
@@ -163,7 +160,6 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> GrandpaBlockImport<B, E, Block, RA
B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
DigestFor<Block>: Encode,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
RA: Send + Sync,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi<Block>,
@@ -381,7 +377,6 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> BlockImport<Block>
B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
DigestFor<Block>: Encode,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
RA: Send + Sync,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi<Block>,
+2 -5
View File
@@ -51,7 +51,7 @@
//! number (this is num(signal) + N). When finalizing a block, we either apply
//! or prune any signaled changes based on whether the signaling block is
//! included in the newly-finalized chain.
#![forbid(warnings)]
use futures::prelude::*;
use log::{debug, info, warn};
use futures::sync::mpsc;
@@ -62,7 +62,7 @@ use client::{
use client::blockchain::HeaderBackend;
use parity_codec::Encode;
use runtime_primitives::traits::{
NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi, DigestItemFor, DigestItem,
NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi,
};
use fg_primitives::GrandpaApi;
use inherents::InherentDataProviders;
@@ -362,7 +362,6 @@ fn global_communication<Block: BlockT<Hash=H256>, B, E, N, RA>(
N: Network<Block>,
RA: Send + Sync,
NumberFor<Block>: BlockNumberOps,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
{
let is_voter = local_key
@@ -463,7 +462,6 @@ pub fn run_grandpa_voter<B, E, Block: BlockT<Hash=H256>, N, RA, X>(
N::In: Send + 'static,
NumberFor<Block>: BlockNumberOps,
DigestFor<Block>: Encode,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
RA: Send + Sync + 'static,
X: Future<Item=(),Error=()> + Clone + Send + 'static,
{
@@ -716,7 +714,6 @@ pub fn run_grandpa<B, E, Block: BlockT<Hash=H256>, N, RA, X>(
N::In: Send + 'static,
NumberFor<Block>: BlockNumberOps,
DigestFor<Block>: Encode,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
RA: Send + Sync + 'static,
X: Future<Item=(),Error=()> + Clone + Send + 'static,
{
@@ -25,9 +25,8 @@ use grandpa::{
use log::{debug, info, warn};
use client::{CallExecutor, Client, backend::Backend};
use ed25519::Public as AuthorityId;
use runtime_primitives::traits::{NumberFor, Block as BlockT, DigestItemFor, DigestItem};
use substrate_primitives::{ed25519, H256, Blake2Hasher};
use runtime_primitives::traits::{NumberFor, Block as BlockT};
use substrate_primitives::{ed25519::Public as AuthorityId, H256, Blake2Hasher};
use crate::{
AuthoritySignature, global_communication, CommandOrError, Config, environment,
@@ -155,7 +154,6 @@ pub fn run_grandpa_observer<B, E, Block: BlockT<Hash=H256>, N, RA>(
N: Network<Block> + Send + Sync + 'static,
N::In: Send + 'static,
NumberFor<Block>: BlockNumberOps,
DigestItemFor<Block>: DigestItem<AuthorityId=AuthorityId>,
RA: Send + Sync + 'static,
{
let LinkHalf {
+6 -6
View File
@@ -23,7 +23,7 @@ use network::config::{ProtocolConfig, Roles};
use network::consensus_gossip as network_gossip;
use parking_lot::Mutex;
use tokio::runtime::current_thread;
use keyring::AuthorityKeyring;
use keyring::ed25519::{Keyring as AuthorityKeyring};
use client::{
BlockchainEvents, error::Result,
blockchain::Backend as BlockchainBackend,
@@ -36,7 +36,7 @@ use std::collections::{HashMap, HashSet};
use std::result;
use runtime_primitives::traits::{ApiRef, ProvideRuntimeApi, Header as HeaderT};
use runtime_primitives::generic::BlockId;
use substrate_primitives::{NativeOrEncoded, ExecutionContext};
use substrate_primitives::{NativeOrEncoded, ExecutionContext, ed25519::Public as AuthorityId};
use authorities::AuthoritySet;
use communication::GRANDPA_ENGINE_ID;
@@ -290,7 +290,7 @@ impl Core<Block> for RuntimeApi {
_: ExecutionContext,
_: Option<()>,
_: Vec<u8>,
) -> Result<NativeOrEncoded<Vec<AuthorityId>>> {
) -> Result<NativeOrEncoded<Vec<substrate_primitives::sr25519::Public>>> {
unimplemented!("Not required for testing!")
}
}
@@ -323,7 +323,7 @@ impl GrandpaApi<Block> for RuntimeApi {
_: ExecutionContext,
_: Option<()>,
_: Vec<u8>,
) -> Result<NativeOrEncoded<Vec<(AuthorityId, u64)>>> {
) -> Result<NativeOrEncoded<Vec<(substrate_primitives::ed25519::Public, u64)>>> {
if at == &BlockId::Number(0) {
Ok(self.inner.genesis_authorities.clone()).map(NativeOrEncoded::Native)
} else {
@@ -370,7 +370,7 @@ impl GrandpaApi<Block> for RuntimeApi {
const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500);
const TEST_ROUTING_INTERVAL: Duration = Duration::from_millis(50);
fn make_ids(keys: &[AuthorityKeyring]) -> Vec<(AuthorityId, u64)> {
fn make_ids(keys: &[AuthorityKeyring]) -> Vec<(substrate_primitives::ed25519::Public, u64)> {
keys.iter()
.map(|key| AuthorityId(key.to_raw_public()))
.map(|id| (id, 1))
@@ -734,7 +734,7 @@ fn justification_is_emitted_when_consensus_data_changes() {
let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 3);
// import block#1 WITH consensus data change
let new_authorities = vec![AuthorityId::from_raw([42; 32])];
let new_authorities = vec![substrate_primitives::sr25519::Public::from_raw([42; 32])];
net.peer(0).push_authorities_change_block(new_authorities);
net.sync();
let net = Arc::new(Mutex::new(net));
+3 -1
View File
@@ -114,7 +114,9 @@ impl InherentData {
match self.data.get(identifier) {
Some(inherent) =>
I::decode(&mut &inherent[..])
.ok_or_else(|| "Could not decode requested inherent type!".into())
.ok_or_else(|| {
"Could not decode requested inherent type!".into()
})
.map(Some),
None => Ok(None)
}
+1 -1
View File
@@ -40,4 +40,4 @@ consensus = { package = "substrate-consensus-common", path = "../../core/consens
[features]
default = []
test-helpers = ["keyring", "test_client"]
test-helpers = ["keyring", "test_client", "consensus/test-helpers"]
+10 -1
View File
@@ -435,7 +435,10 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
return false;
},
#[cfg(any(test, feature = "test-helpers"))]
ProtocolMsg::Synchronize => self.network_chan.send(NetworkMsg::Synchronized),
ProtocolMsg::Synchronize => {
trace!(target: "sync", "handle_client_msg: received Synchronize msg");
self.network_chan.send(NetworkMsg::Synchronized)
}
}
true
}
@@ -755,6 +758,11 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
"Peer is on different chain (our genesis: {} theirs: {})",
self.genesis_hash, status.genesis_hash
);
trace!(
target: "protocol",
"Peer is on different chain (our genesis: {} theirs: {})",
self.genesis_hash, status.genesis_hash
);
self.network_chan.send(NetworkMsg::ReportPeer(
who,
Severity::Bad(reason),
@@ -763,6 +771,7 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
}
if status.version < MIN_VERSION && CURRENT_VERSION < status.min_supported_version {
let reason = format!("Peer using unsupported protocol version {}", status.version);
trace!(target: "protocol", "Peer {:?} using unsupported protocol version {}", who, status.version);
self.network_chan.send(NetworkMsg::ReportPeer(
who,
Severity::Bad(reason),
+1 -1
View File
@@ -589,7 +589,7 @@ fn run_thread<B: BlockT + 'static>(
}
}
}
Ok(Async::NotReady)
})
}
+2 -1
View File
@@ -848,8 +848,9 @@ impl<B: BlockT> ChainSync<B> {
/// Handle new block announcement.
pub(crate) fn on_block_announce(&mut self, protocol: &mut Context<B>, who: PeerId, hash: B::Hash, header: &B::Header) {
let number = *header.number();
debug!(target: "sync", "Received block announcement with number {:?}", number);
if number <= As::sa(0) {
trace!(target: "sync", "Ignored invalid block announcement from {}: {}", who, hash);
warn!(target: "sync", "Ignored invalid block announcement from {}: {}", who, hash);
return;
}
let parent_status = block_status(&*protocol.client(), &self.queue_blocks, header.parent_hash().clone()).ok()
+28 -5
View File
@@ -40,7 +40,7 @@ use futures::sync::{mpsc, oneshot};
use crate::message::Message;
use network_libp2p::PeerId;
use parking_lot::{Mutex, RwLock};
use primitives::{H256, ed25519::Public as AuthorityId};
use primitives::{H256, sr25519::Public as AuthorityId};
use crate::protocol::{ConnectedPeer, Context, FromNetworkMsg, Protocol, ProtocolMsg};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{AuthorityIdFor, Block as BlockT, Digest, DigestItem, Header, NumberFor};
@@ -48,6 +48,7 @@ use runtime_primitives::{Justification, ConsensusEngineId};
use crate::service::{network_channel, NetworkChan, NetworkLink, NetworkMsg, NetworkPort, TransactionPool};
use crate::specialization::NetworkSpecialization;
use test_client::{self, AccountKeyring};
use log::debug;
pub use test_client::runtime::{Block, Extrinsic, Hash, Transfer};
pub use test_client::TestClient;
@@ -117,17 +118,20 @@ pub type PeersClient = client::Client<test_client::Backend, test_client::Executo
/// A Link that can wait for a block to have been imported.
pub struct TestLink<S: NetworkSpecialization<Block>> {
link: NetworkLink<Block, S>,
#[cfg(any(test, feature = "test-helpers"))]
network_to_protocol_sender: Sender<FromNetworkMsg<Block>>,
}
impl<S: NetworkSpecialization<Block>> TestLink<S> {
fn new(
protocol_sender: Sender<ProtocolMsg<Block, S>>,
network_to_protocol_sender: Sender<FromNetworkMsg<Block>>,
_network_to_protocol_sender: Sender<FromNetworkMsg<Block>>,
network_sender: NetworkChan<Block>
) -> TestLink<S> {
TestLink {
network_to_protocol_sender,
#[cfg(any(test, feature = "test-helpers"))]
network_to_protocol_sender: _network_to_protocol_sender,
link: NetworkLink {
protocol_sender,
network_sender,
@@ -165,8 +169,14 @@ impl<S: NetworkSpecialization<Block>> Link<Block> for TestLink<S> {
self.link.restart();
}
/// Send synchronization request to the block import channel.
///
/// The caller should wait for the `Link::synchronized` call to ensure that it has synchronized
/// with `ImportQueue`.
#[cfg(any(test, feature = "test-helpers"))]
fn synchronized(&self) {
let _ = self.network_to_protocol_sender.send(FromNetworkMsg::Synchronize);
trace!(target: "test_network", "Synchronizing");
drop(self.network_to_protocol_sender.send(FromNetworkMsg::Synchronize))
}
}
@@ -225,12 +235,14 @@ impl<S: NetworkSpecialization<Block>> ProtocolChannel<S> {
/// Wait until synchronization response is generated by the protocol.
pub fn wait_sync(&self) -> Result<(), RecvError> {
trace!(target: "test_network", "Waiting for sync");
loop {
match self.protocol_to_network_receiver.receiver().recv() {
Ok(NetworkMsg::Synchronized) => return Ok(()),
Err(error) => return Err(error),
Ok(msg) => self.buffered_messages.lock().push_back(msg),
}
trace!(target: "test_network", "Retrying sync");
}
}
@@ -370,8 +382,11 @@ impl<D, S: NetworkSpecialization<Block>> Peer<D, S> {
}
/// Synchronize with import queue.
#[cfg(any(test, feature = "test-helpers"))]
fn import_queue_sync(&self) {
trace!(target: "test_network", "syncing this queue");
self.import_queue.synchronize();
trace!(target: "test_network", "wating for sync to finish");
let _ = self.net_proto_channel.wait_sync();
}
@@ -491,6 +506,7 @@ impl<D, S: NetworkSpecialization<Block>> Peer<D, S> {
let block = edit_block(builder);
let hash = block.header.hash();
trace!(
target: "test_network",
"Generating {}, (#{}, parent={})",
hash,
block.header.number,
@@ -610,10 +626,12 @@ pub trait TestNetFactory: Sized {
/// Create new test network with this many peers.
fn new(n: usize) -> Self {
trace!(target: "test_network", "Creating test network");
let config = Self::default_config();
let mut net = Self::from_config(&config);
for _ in 0..n {
for i in 0..n {
trace!(target: "test_network", "Adding peer {}", i);
net.add_peer(&config);
}
net
@@ -681,6 +699,7 @@ pub trait TestNetFactory: Sized {
}
loop {
debug!(target: "test_network", "loop iteration");
// we only deliver Status messages during start
let need_continue = self.route_single(true, None, &|msg| match *msg {
NetworkMsg::Outgoing(_, crate::message::generic::Message::Status(_)) => true,
@@ -706,6 +725,7 @@ pub trait TestNetFactory: Sized {
let mut to_disconnect = HashSet::new();
let peers = self.peers();
for peer in peers {
debug!(target: "test_network", "checking peer");
if let Some(message) = peer.pending_message(message_filter) {
match message {
NetworkMsg::Outgoing(recipient_id, packet) => {
@@ -744,10 +764,13 @@ pub trait TestNetFactory: Sized {
}
}
}
debug!(target: "test_network", "syncing queues");
// make sure that the protocol(s) has processed all messages that have been queued
self.peers().iter().for_each(|peer| peer.import_queue_sync());
debug!(target: "test_network", "queues synced");
had_messages
}
+1 -1
View File
@@ -288,7 +288,7 @@ impl<T: AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
///
/// For now it just specifies how to create a key from a phrase and derivation path.
#[cfg(feature = "std")]
pub trait Pair: Sized {
pub trait Pair: Sized + 'static {
/// TThe type which is used to encode a public key.
type Public;
+14 -9
View File
@@ -18,16 +18,21 @@ use error_chain::*;
use client;
use crate::rpc;
use crate::errors;
pub use internal_errors::*;
error_chain! {
foreign_links {
Client(client::error::Error) #[doc = "Client error"];
}
errors {
/// Not implemented yet
Unimplemented {
description("not yet implemented"),
display("Method Not Implemented"),
#[allow(deprecated)]
mod internal_errors {
use super::*;
error_chain! {
foreign_links {
Client(client::error::Error) #[doc = "Client error"];
}
errors {
/// Not implemented yet
Unimplemented {
description("not yet implemented"),
display("Method Not Implemented"),
}
}
}
}
+2 -1
View File
@@ -221,7 +221,7 @@ fn should_return_runtime_version() {
assert_eq!(
::serde_json::to_string(&api.runtime_version(None.into()).unwrap()).unwrap(),
r#"{"specName":"test","implName":"parity-test","authoringVersion":1,"specVersion":1,"implVersion":1,"apis":[["0xdf6acb689907609b",2],["0x37e397fc7c91f5e4",1],["0xd2bc9897eed08f15",1],["0x40fe3ad401f8959a",3],["0xc6e9a76309f39b09",1],["0xdd718d5cc53262d4",1],["0xf78b278be53f454c",1],["0x7801759919ee83e5",1]]}"#
r#"{"specName":"test","implName":"parity-test","authoringVersion":1,"specVersion":1,"implVersion":1,"apis":[["0xdf6acb689907609b",2],["0x37e397fc7c91f5e4",1],["0xd2bc9897eed08f15",1],["0x40fe3ad401f8959a",3],["0xc6e9a76309f39b09",1],["0xdd718d5cc53262d4",1],["0xcbca25e39f142387",1],["0xf78b278be53f454c",1],["0x7801759919ee83e5",1]]}"#
);
}
@@ -246,3 +246,4 @@ fn should_notify_on_runtime_version_initially() {
// no more notifications on this channel
assert_eq!(core.block_on(next.into_future()).unwrap().0, None);
}
+1 -1
View File
@@ -11,7 +11,7 @@ rustc_version = "0.2"
[dependencies]
rstd = { package = "sr-std", path = "../sr-std", default-features = false }
primitives = { package = "substrate-primitives", path = "../primitives", default-features = false }
codec = { package="parity-codec", version = "3.3", default-features = false }
codec = { package = "parity-codec", version = "3.5.1", default-features = false }
hash-db = { version = "0.12", default-features = false }
libsecp256k1 = { version = "0.2.1", optional = true }
tiny-keccak = { version = "1.4.2", optional = true }
+1 -1
View File
@@ -23,7 +23,7 @@ use crate::traits::{self, Checkable, Applyable, BlakeTwo256, Convert};
use crate::generic::DigestItem as GenDigestItem;
pub use substrate_primitives::H256;
use substrate_primitives::U256;
use substrate_primitives::ed25519::{Public as AuthorityId, Signature as AuthoritySignature};
use substrate_primitives::sr25519::{Public as AuthorityId, Signature as AuthoritySignature};
/// Authority Id
#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug)]
+1 -1
View File
@@ -6,7 +6,7 @@ build = "build.rs"
edition = "2018"
[build-dependencies]
rustc_version = "0.2"
rustc_version = "0.2.3"
[features]
default = ["std"]
+1 -1
View File
@@ -29,7 +29,7 @@ pub use client::{ExecutionStrategies, blockchain, backend, self};
pub use executor::{NativeExecutor, self};
pub use runtime;
pub use consensus;
pub use keyring::{AuthorityKeyring, AccountKeyring};
pub use keyring::{sr25519::Keyring as AuthorityKeyring, AccountKeyring};
use std::{sync::Arc, collections::HashMap};
use futures::future::FutureResult;
+2
View File
@@ -13,6 +13,7 @@ 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 }
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 }
@@ -49,6 +50,7 @@ std = [
"runtime_primitives/std",
"runtime_version/std",
"consensus_aura/std",
"consensus_babe/std",
"primitives/std",
"substrate-trie/std",
"trie-db/std",
@@ -22,7 +22,7 @@ use super::AccountId;
use parity_codec::{Encode, KeyedVec, Joiner};
use primitives::{ChangesTrieConfiguration, map, storage::well_known_keys};
use runtime_primitives::traits::Block;
use primitives::ed25519::Public as AuthorityId;
use primitives::sr25519::Public as AuthorityId;
/// Configuration of a general Substrate test genesis block.
pub struct GenesisConfig {
+24 -4
View File
@@ -43,7 +43,7 @@ use runtime_primitives::{
};
use runtime_version::RuntimeVersion;
pub use primitives::hash::H256;
use primitives::{ed25519, sr25519, OpaqueMetadata};
use primitives::{sr25519, OpaqueMetadata};
#[cfg(any(feature = "std", test))]
use runtime_version::NativeVersion;
use inherents::{CheckInherentsResult, InherentData};
@@ -142,7 +142,7 @@ impl Extrinsic {
}
/// The signature type used by authorities.
pub type AuthoritySignature = ed25519::Signature;
pub type AuthoritySignature = sr25519::Signature;
/// The identity type used by authorities.
pub type AuthorityId = <AuthoritySignature as Verify>::Signer;
/// The signature type used by accounts/transactions.
@@ -448,6 +448,16 @@ cfg_if! {
fn slot_duration() -> u64 { 1 }
}
impl consensus_babe::BabeApi<Block> for Runtime {
fn startup_data() -> consensus_babe::BabeConfiguration {
consensus_babe::BabeConfiguration {
slot_duration: 1,
expected_block_time: 1,
threshold: std::u64::MAX,
}
}
}
impl offchain_primitives::OffchainWorkerApi<Block> for Runtime {
fn offchain_worker(block: u64) {
let ex = Extrinsic::IncludeData(block.encode());
@@ -457,7 +467,7 @@ cfg_if! {
impl consensus_authorities::AuthoritiesApi<Block> for Runtime {
fn authorities() -> Vec<AuthorityIdFor<Block>> {
crate::system::authorities()
system::authorities()
}
}
}
@@ -580,6 +590,16 @@ cfg_if! {
fn slot_duration() -> u64 { 1 }
}
impl consensus_babe::BabeApi<Block> for Runtime {
fn startup_data() -> consensus_babe::BabeConfiguration {
consensus_babe::BabeConfiguration {
slot_duration: 1,
expected_block_time: 1,
threshold: core::u64::MAX,
}
}
}
impl offchain_primitives::OffchainWorkerApi<Block> for Runtime {
fn offchain_worker(block: u64) {
let ex = Extrinsic::IncludeData(block.encode());
@@ -589,7 +609,7 @@ cfg_if! {
impl consensus_authorities::AuthoritiesApi<Block> for Runtime {
fn authorities() -> Vec<AuthorityIdFor<Block>> {
crate::system::authorities()
system::authorities()
}
}
}
+1 -1
View File
@@ -27,7 +27,7 @@ use runtime_primitives::{ApplyError, ApplyOutcome, ApplyResult, transaction_vali
use parity_codec::{KeyedVec, Encode};
use super::{AccountId, BlockNumber, Extrinsic, Transfer, H256 as Hash, Block, Header, Digest};
use primitives::{Blake2Hasher, storage::well_known_keys};
use primitives::ed25519::Public as AuthorityId;
use primitives::sr25519::Public as AuthorityId;
const NONCE_OF: &[u8] = b"nonce:";
const BALANCE_OF: &[u8] = b"balance:";
+28
View File
@@ -2433,6 +2433,16 @@ dependencies = [
"substrate-primitives 1.0.0",
]
[[package]]
name = "substrate-consensus-babe-primitives"
version = "1.0.0"
dependencies = [
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-primitives 1.0.0",
"substrate-client 1.0.0",
"substrate-consensus-slots 1.1.0",
]
[[package]]
name = "substrate-consensus-common"
version = "1.0.0"
@@ -2450,6 +2460,23 @@ dependencies = [
"tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "substrate-consensus-slots"
version = "1.1.0"
dependencies = [
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-primitives 1.0.0",
"substrate-client 1.0.0",
"substrate-consensus-common 1.0.0",
"substrate-inherents 1.0.0",
"substrate-primitives 1.0.0",
"tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "substrate-executor"
version = "1.0.0"
@@ -2596,6 +2623,7 @@ dependencies = [
"substrate-client 1.0.0",
"substrate-consensus-aura-primitives 1.0.0",
"substrate-consensus-authorities 1.0.0",
"substrate-consensus-babe-primitives 1.0.0",
"substrate-inherents 1.0.0",
"substrate-keyring 1.0.0",
"substrate-offchain-primitives 0.1.0",
+1 -1
View File
@@ -9,5 +9,5 @@ fi
CARGO_INCREMENTAL=0 RUSTFLAGS="-C link-arg=--export-table" $CARGO_CMD build --target=wasm32-unknown-unknown --release
for i in substrate_test_runtime
do
wasm-gc target/wasm32-unknown-unknown/release/$i.wasm target/wasm32-unknown-unknown/release/$i.compact.wasm
wasm-gc "target/wasm32-unknown-unknown/release/$i.wasm" "target/wasm32-unknown-unknown/release/$i.compact.wasm"
done
@@ -14,7 +14,7 @@ substrate-primitives = { path = "../../primitives" }
sr-primitives = { path = "../../sr-primitives" }
[dev-dependencies]
assert_matches = "1.1"
env_logger = "0.6"
parity-codec = "3.3"
assert_matches = "1.3.0"
env_logger = "0.6.1"
parity-codec = "3.5.1"
test_runtime = { package = "substrate-test-runtime", path = "../../test-runtime" }
+2 -2
View File
@@ -58,8 +58,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("node"),
impl_name: create_runtime_str!("substrate-node"),
authoring_version: 10,
spec_version: 67,
impl_version: 68,
spec_version: 69,
impl_version: 70,
apis: RUNTIME_API_VERSIONS,
};
+2 -2
View File
@@ -5,14 +5,14 @@
set -e
PROJECT_ROOT=`git rev-parse --show-toplevel`
source `dirname "$0"`/common.sh
source "`dirname \"$0\"`/common.sh"
export CARGO_INCREMENTAL=0
# Save current directory.
pushd .
cd $ROOT
cd -- "$ROOT"
for SRC in "${SRCS[@]}"
do
+41
View File
@@ -0,0 +1,41 @@
[package]
name = "srml-babe"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
hex-literal = "0.1.4"
parity-codec = { version = "3.5.1", default-features = false, features = ["derive"] }
serde = { version = "1.0.90", optional = true }
inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false }
rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false }
primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false }
srml-support = { path = "../support", default-features = false }
system = { package = "srml-system", path = "../system", default-features = false }
timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false }
staking = { package = "srml-staking", path = "../staking", default-features = false }
session = { package = "srml-session", path = "../session", default-features = false }
babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives", default-features = false }
[dev-dependencies]
lazy_static = "1.3.0"
parking_lot = "0.7.1"
substrate-primitives = { path = "../../core/primitives" }
runtime_io = { package = "sr-io", path = "../../core/sr-io" }
consensus = { package = "srml-consensus", path = "../consensus" }
[features]
default = ["std"]
std = [
"serde",
"parity-codec/std",
"rstd/std",
"srml-support/std",
"primitives/std",
"system/std",
"timestamp/std",
"staking/std",
"inherents/std",
"babe-primitives/std",
]
+155
View File
@@ -0,0 +1,155 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Consensus extension module for BABE consensus.
#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code, warnings)]
pub use timestamp;
use rstd::{result, prelude::*};
use srml_support::{decl_storage, decl_module};
use primitives::traits::As;
use timestamp::{OnTimestampSet, Trait};
#[cfg(feature = "std")]
use timestamp::TimestampInherentData;
use parity_codec::Decode;
use inherents::{RuntimeString, InherentIdentifier, InherentData, ProvideInherent, MakeFatalError};
#[cfg(feature = "std")]
use inherents::{InherentDataProviders, ProvideInherentData};
/// The BABE inherent identifier.
pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"babeslot";
/// The type of the BABE inherent.
pub type InherentType = u64;
/// Auxiliary trait to extract BABE inherent data.
pub trait BabeInherentData {
/// Get BABE inherent data.
fn babe_inherent_data(&self) -> result::Result<InherentType, RuntimeString>;
/// Replace BABE inherent data.
fn babe_replace_inherent_data(&mut self, new: InherentType);
}
impl BabeInherentData for InherentData {
fn babe_inherent_data(&self) -> result::Result<InherentType, RuntimeString> {
self.get_data(&INHERENT_IDENTIFIER)
.and_then(|r| r.ok_or_else(|| "BABE inherent data not found".into()))
}
fn babe_replace_inherent_data(&mut self, new: InherentType) {
self.replace_data(INHERENT_IDENTIFIER, &new);
}
}
/// Provides the slot duration inherent data for BABE.
#[cfg(feature = "std")]
pub struct InherentDataProvider {
slot_duration: u64,
}
#[cfg(feature = "std")]
impl InherentDataProvider {
pub fn new(slot_duration: u64) -> Self {
Self {
slot_duration
}
}
}
#[cfg(feature = "std")]
impl ProvideInherentData for InherentDataProvider {
fn on_register(
&self,
providers: &InherentDataProviders,
) -> result::Result<(), RuntimeString> {
if !providers.has_provider(&timestamp::INHERENT_IDENTIFIER) {
// Add the timestamp inherent data provider, as we require it.
providers.register_provider(timestamp::InherentDataProvider)
} else {
Ok(())
}
}
fn inherent_identifier(&self) -> &'static inherents::InherentIdentifier {
&INHERENT_IDENTIFIER
}
fn provide_inherent_data(
&self,
inherent_data: &mut InherentData,
) -> result::Result<(), RuntimeString> {
let timestamp = inherent_data.timestamp_inherent_data()?;
let slot_num = timestamp / self.slot_duration;
inherent_data.put_data(INHERENT_IDENTIFIER, &slot_num)
}
fn error_to_string(&self, error: &[u8]) -> Option<String> {
RuntimeString::decode(&mut &error[..]).map(Into::into)
}
}
decl_storage! {
trait Store for Module<T: Trait> as Babe {
// The last timestamp.
LastTimestamp get(last): T::Moment;
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin { }
}
impl<T: Trait> Module<T> {
/// Determine the BABE slot duration based on the Timestamp module configuration.
pub fn slot_duration() -> u64 {
// we double the minimum block-period so each author can always propose within
// the majority of their slot.
<timestamp::Module<T>>::minimum_period().as_().saturating_mul(2)
}
}
impl<T: Trait> OnTimestampSet<T::Moment> for Module<T> {
fn on_timestamp_set(_moment: T::Moment) { }
}
impl<T: Trait> ProvideInherent for Module<T> {
type Call = timestamp::Call<T>;
type Error = MakeFatalError<RuntimeString>;
const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
fn create_inherent(_: &InherentData) -> Option<Self::Call> {
None
}
fn check_inherent(call: &Self::Call, data: &InherentData) -> result::Result<(), Self::Error> {
let timestamp = match call {
timestamp::Call::set(ref timestamp) => timestamp.clone(),
_ => return Ok(()),
};
let timestamp_based_slot = timestamp.as_() / Self::slot_duration();
let seal_slot = data.babe_inherent_data()?;
if timestamp_based_slot == seal_slot {
Ok(())
} else {
Err(RuntimeString::from("timestamp set in block doesnt match slot in seal").into())
}
}
}
+1 -1
View File
@@ -142,7 +142,7 @@ use inherents::{
};
#[cfg(any(feature = "std", test))]
use substrate_primitives::ed25519::Public as AuthorityId;
use substrate_primitives::sr25519::Public as AuthorityId;
mod mock;
mod tests;