mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Consensus Engines Implementation: Aura (#911)
* Generalize BlockImport - move ImportBlock, BlockOrigin, ImportResult into shared sr-primitives - let Consensus provide and traits again - update consensus traits to latest development - implement traits on client::Client, test_client::TestClient - update RHD to use the new import_block API * Move ImportBlock into consensus-common * Send import notification in aura tests * Integrating aura into service * Make Signatures more generic * Aura Block Production with the given key * run aura on the thread pool * start at exact step start in aura * Add needed wasm blob, in leiu of better solutions. * Make API ids consistent with traits and bring upstream for sharing. * Add decrease_free_balance to Balances module * Encode `Metadata` once instead of two times * Bitops include xor * Upgrade key module. * Default pages to somewhat bigger. * Introduce upgrade key into node * Add `Created` event
This commit is contained in:
committed by
GitHub
parent
c0f7021427
commit
50adea6220
@@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2018 Parity Technologies (UK) Ltd.
|
||||
// Copyright 2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
@@ -14,81 +14,44 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Error types in the BFT service.
|
||||
use runtime_version::RuntimeVersion;
|
||||
//! Error types in the rhododendron Consensus service.
|
||||
use consensus::error::{Error as CommonError, ErrorKind as CommonErrorKind};
|
||||
use primitives::AuthorityId;
|
||||
use client;
|
||||
|
||||
error_chain! {
|
||||
links {
|
||||
Client(client::error::Error, client::error::ErrorKind);
|
||||
Common(CommonError, CommonErrorKind);
|
||||
}
|
||||
errors {
|
||||
/// Missing state at block with given descriptor.
|
||||
StateUnavailable(b: String) {
|
||||
description("State missing at given block."),
|
||||
display("State unavailable at block {}", b),
|
||||
NotValidator(id: AuthorityId) {
|
||||
description("Local account ID not a validator at this block."),
|
||||
display("Local account ID ({:?}) not a validator at this block.", id),
|
||||
}
|
||||
|
||||
/// I/O terminated unexpectedly
|
||||
IoTerminated {
|
||||
description("I/O terminated unexpectedly."),
|
||||
display("I/O terminated unexpectedly."),
|
||||
PrematureDestruction {
|
||||
description("Proposer destroyed before finishing proposing or evaluating"),
|
||||
display("Proposer destroyed before finishing proposing or evaluating"),
|
||||
}
|
||||
|
||||
/// Unable to schedule wakeup.
|
||||
FaultyTimer(e: ::tokio::timer::Error) {
|
||||
description("Timer error"),
|
||||
display("Timer error: {}", e),
|
||||
Timer(e: ::tokio::timer::Error) {
|
||||
description("Failed to register or resolve async timer."),
|
||||
display("Timer failed: {}", e),
|
||||
}
|
||||
|
||||
/// Unable to propose a block.
|
||||
CannotPropose {
|
||||
description("Unable to create block proposal."),
|
||||
display("Unable to create block proposal."),
|
||||
}
|
||||
|
||||
/// Error checking signature
|
||||
InvalidSignature(s: ::primitives::ed25519::Signature, a: ::primitives::AuthorityId) {
|
||||
description("Message signature is invalid"),
|
||||
display("Message signature {:?} by {:?} is invalid.", s, a),
|
||||
}
|
||||
|
||||
/// Account is not an authority.
|
||||
InvalidAuthority(a: ::primitives::AuthorityId) {
|
||||
description("Message sender is not a valid authority"),
|
||||
display("Message sender {:?} is not a valid authority.", a),
|
||||
}
|
||||
|
||||
/// Authoring interface does not match the runtime.
|
||||
IncompatibleAuthoringRuntime(native: RuntimeVersion, on_chain: RuntimeVersion) {
|
||||
description("Authoring for current runtime is not supported"),
|
||||
display("Authoring for current runtime is not supported. Native ({}) cannot author for on-chain ({}).", native, on_chain),
|
||||
}
|
||||
|
||||
/// Authoring interface does not match the runtime.
|
||||
RuntimeVersionMissing {
|
||||
description("Current runtime has no version"),
|
||||
display("Authoring for current runtime is not supported since it has no version."),
|
||||
}
|
||||
|
||||
/// Authoring interface does not match the runtime.
|
||||
NativeRuntimeMissing {
|
||||
description("This build has no native runtime"),
|
||||
display("Authoring in current build is not supported since it has no runtime."),
|
||||
}
|
||||
|
||||
/// Justification requirements not met.
|
||||
InvalidJustification {
|
||||
description("Invalid justification"),
|
||||
display("Invalid justification."),
|
||||
}
|
||||
|
||||
/// Some other error.
|
||||
Other(e: Box<::std::error::Error + Send>) {
|
||||
description("Other error")
|
||||
display("Other error: {}", e.description())
|
||||
Executor(e: ::futures::future::ExecuteErrorKind) {
|
||||
description("Unable to dispatch agreement future"),
|
||||
display("Unable to dispatch agreement future: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<::rhododendron::InputStreamConcluded> for Error {
|
||||
fn from(_: ::rhododendron::InputStreamConcluded) -> Error {
|
||||
ErrorKind::IoTerminated.into()
|
||||
fn from(_: ::rhododendron::InputStreamConcluded) -> Self {
|
||||
CommonErrorKind::IoTerminated.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CommonErrorKind> for Error {
|
||||
fn from(e: CommonErrorKind) -> Self {
|
||||
CommonError::from(e).into()
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,181 @@
|
||||
// Copyright 2018 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 service.
|
||||
|
||||
/// Consensus service. A long running service that manages BFT agreement
|
||||
/// the network.
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::sync::Arc;
|
||||
|
||||
use client::{BlockchainEvents, ChainHead, BlockBody};
|
||||
use futures::prelude::*;
|
||||
use transaction_pool::txpool::{Pool as TransactionPool, ChainApi as PoolChainApi};
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, BlockNumberToHash};
|
||||
|
||||
use tokio::executor::current_thread::TaskExecutor as LocalThreadHandle;
|
||||
use tokio::runtime::TaskExecutor as ThreadPoolHandle;
|
||||
use tokio::runtime::current_thread::Runtime as LocalRuntime;
|
||||
use tokio::timer::Interval;
|
||||
|
||||
use parking_lot::RwLock;
|
||||
use consensus::offline_tracker::OfflineTracker;
|
||||
|
||||
use super::{Network, ProposerFactory, AuthoringApi};
|
||||
use {consensus, primitives, ed25519, error, BftService, LocalProposer};
|
||||
|
||||
const TIMER_DELAY_MS: u64 = 5000;
|
||||
const TIMER_INTERVAL_MS: u64 = 500;
|
||||
|
||||
// spin up an instance of BFT agreement on the current thread's executor.
|
||||
// panics if there is no current thread executor.
|
||||
fn start_bft<F, C, Block>(
|
||||
header: <Block as BlockT>::Header,
|
||||
bft_service: Arc<BftService<Block, F, C>>,
|
||||
) where
|
||||
F: consensus::Environment<Block> + 'static,
|
||||
C: consensus::BlockImport<Block> + consensus::Authorities<Block> + 'static,
|
||||
F::Error: ::std::fmt::Debug,
|
||||
<F::Proposer as consensus::Proposer<Block>>::Error: ::std::fmt::Display + Into<error::Error>,
|
||||
<F as consensus::Environment<Block>>::Proposer : LocalProposer<Block>,
|
||||
<F as consensus::Environment<Block>>::Error: ::std::fmt::Display,
|
||||
Block: BlockT,
|
||||
{
|
||||
let mut handle = LocalThreadHandle::current();
|
||||
match bft_service.build_upon(&header) {
|
||||
Ok(Some(bft_work)) => if let Err(e) = handle.spawn_local(Box::new(bft_work)) {
|
||||
warn!(target: "bft", "Couldn't initialize BFT agreement: {:?}", e);
|
||||
}
|
||||
Ok(None) => trace!(target: "bft", "Could not start agreement on top of {}", header.hash()),
|
||||
Err(e) => warn!(target: "bft", "BFT agreement error: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Consensus service. Starts working when created.
|
||||
pub struct Service {
|
||||
thread: Option<thread::JoinHandle<()>>,
|
||||
exit_signal: Option<::exit_future::Signal>,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
/// Create and start a new instance.
|
||||
pub fn new<A, P, C, N>(
|
||||
client: Arc<C>,
|
||||
api: Arc<A>,
|
||||
network: N,
|
||||
transaction_pool: Arc<TransactionPool<P>>,
|
||||
thread_pool: ThreadPoolHandle,
|
||||
key: ed25519::Pair,
|
||||
block_delay: u64,
|
||||
) -> Service
|
||||
where
|
||||
error::Error: From<<A as AuthoringApi>::Error>,
|
||||
A: AuthoringApi + BlockNumberToHash + 'static,
|
||||
P: PoolChainApi<Block = <A as AuthoringApi>::Block> + 'static,
|
||||
C: BlockchainEvents<<A as AuthoringApi>::Block>
|
||||
+ ChainHead<<A as AuthoringApi>::Block>
|
||||
+ BlockBody<<A as AuthoringApi>::Block>,
|
||||
C: consensus::BlockImport<<A as AuthoringApi>::Block>
|
||||
+ consensus::Authorities<<A as AuthoringApi>::Block> + Send + Sync + 'static,
|
||||
primitives::H256: From<<<A as AuthoringApi>::Block as BlockT>::Hash>,
|
||||
<<A as AuthoringApi>::Block as BlockT>::Hash: PartialEq<primitives::H256> + PartialEq,
|
||||
N: Network<Block = <A as AuthoringApi>::Block> + Send + 'static,
|
||||
{
|
||||
|
||||
let (signal, exit) = ::exit_future::signal();
|
||||
let thread = thread::spawn(move || {
|
||||
let mut runtime = LocalRuntime::new().expect("Could not create local runtime");
|
||||
let key = Arc::new(key);
|
||||
|
||||
let factory = ProposerFactory {
|
||||
client: api.clone(),
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
network,
|
||||
handle: thread_pool.clone(),
|
||||
offline: Arc::new(RwLock::new(OfflineTracker::new())),
|
||||
force_delay: block_delay,
|
||||
};
|
||||
let bft_service = Arc::new(BftService::new(client.clone(), key, factory));
|
||||
|
||||
let notifications = {
|
||||
let client = client.clone();
|
||||
let bft_service = bft_service.clone();
|
||||
|
||||
client.import_notification_stream().for_each(move |notification| {
|
||||
if notification.is_new_best {
|
||||
start_bft(notification.header, bft_service.clone());
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
};
|
||||
|
||||
let interval = Interval::new(
|
||||
Instant::now() + Duration::from_millis(TIMER_DELAY_MS),
|
||||
Duration::from_millis(TIMER_INTERVAL_MS),
|
||||
);
|
||||
|
||||
let mut prev_best = match client.best_block_header() {
|
||||
Ok(header) => header.hash(),
|
||||
Err(e) => {
|
||||
warn!("Cant's start consensus service. Error reading best block header: {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let timed = {
|
||||
let c = client.clone();
|
||||
let s = bft_service.clone();
|
||||
|
||||
interval.map_err(|e| debug!(target: "bft", "Timer error: {:?}", e)).for_each(move |_| {
|
||||
if let Ok(best_block) = c.best_block_header() {
|
||||
let hash = best_block.hash();
|
||||
|
||||
if hash == prev_best {
|
||||
debug!(target: "bft", "Starting consensus round after a timeout");
|
||||
start_bft(best_block, s.clone());
|
||||
}
|
||||
prev_best = hash;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
};
|
||||
|
||||
runtime.spawn(notifications);
|
||||
runtime.spawn(timed);
|
||||
|
||||
if let Err(e) = runtime.block_on(exit) {
|
||||
debug!("BFT event loop error {:?}", e);
|
||||
}
|
||||
});
|
||||
Service {
|
||||
thread: Some(thread),
|
||||
exit_signal: Some(signal),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Service {
|
||||
fn drop(&mut self) {
|
||||
if let Some(signal) = self.exit_signal.take() {
|
||||
signal.fire();
|
||||
}
|
||||
|
||||
if let Some(thread) = self.thread.take() {
|
||||
thread.join().expect("The service thread has panicked");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user