mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-06 04:28:01 +00:00
Generalize the Consensus Infrastructure (#883)
* Split out Consensus * Supply ImportQueue through network-service - simplify ImportQueue.import_blocks - remove Deadlock on import_block - Adding Verifier-Trait - Implement import_queue provisioning in service; allow cli to import * Allow to actually customize import queue * Consensus Gossip: Cache Message hash per Topic
This commit is contained in:
committed by
GitHub
parent
a24e61cb29
commit
ac4bcf879f
@@ -18,8 +18,7 @@
|
||||
|
||||
use error;
|
||||
use primitives::AuthorityId;
|
||||
use runtime_primitives::bft::Justification;
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use runtime_primitives::{generic::BlockId, Justification};
|
||||
use runtime_primitives::traits::{Block as BlockT, NumberFor};
|
||||
use state_machine::backend::Backend as StateBackend;
|
||||
use state_machine::ChangesTrieStorage as StateChangesTrieStorage;
|
||||
@@ -64,7 +63,7 @@ where
|
||||
&mut self,
|
||||
header: Block::Header,
|
||||
body: Option<Vec<Block::Extrinsic>>,
|
||||
justification: Option<Justification<Block::Hash>>,
|
||||
justification: Option<Justification>,
|
||||
state: NewBlockState,
|
||||
) -> error::Result<()>;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
use primitives::AuthorityId;
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor};
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use runtime_primitives::bft::Justification;
|
||||
use runtime_primitives::Justification;
|
||||
|
||||
use error::{ErrorKind, Result};
|
||||
|
||||
@@ -47,10 +47,9 @@ pub trait Backend<Block: BlockT>: HeaderBackend<Block> {
|
||||
/// Get block body. Returns `None` if block is not found.
|
||||
fn body(&self, id: BlockId<Block>) -> Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
|
||||
/// Get block justification. Returns `None` if justification does not exist.
|
||||
fn justification(&self, id: BlockId<Block>) -> Result<Option<Justification<Block::Hash>>>;
|
||||
fn justification(&self, id: BlockId<Block>) -> Result<Option<Justification>>;
|
||||
/// Get last finalized block hash.
|
||||
fn last_finalized(&self) -> Result<Block::Hash>;
|
||||
|
||||
/// Returns data cache reference, if it is enabled on this backend.
|
||||
fn cache(&self) -> Option<&Cache<Block>>;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ use futures::sync::mpsc;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use primitives::AuthorityId;
|
||||
use runtime_primitives::{
|
||||
bft::Justification,
|
||||
Justification,
|
||||
generic::{BlockId, SignedBlock, Block as RuntimeBlock},
|
||||
transaction_validity::{TransactionValidity, TransactionTag},
|
||||
};
|
||||
@@ -44,7 +44,7 @@ use blockchain::{self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend
|
||||
use call_executor::{CallExecutor, LocalCallExecutor};
|
||||
use executor::{RuntimeVersion, RuntimeInfo};
|
||||
use notifications::{StorageNotifications, StorageEventStream};
|
||||
use {cht, error, in_mem, block_builder, bft, genesis};
|
||||
use {cht, error, in_mem, block_builder, genesis};
|
||||
|
||||
/// Type that implements `futures::Stream` of block import events.
|
||||
pub type ImportNotifications<Block> = mpsc::UnboundedReceiver<BlockImportNotification<Block>>;
|
||||
@@ -151,6 +151,53 @@ pub enum BlockOrigin {
|
||||
File,
|
||||
}
|
||||
|
||||
/// Data required to import a Block
|
||||
pub struct ImportBlock<Block: BlockT> {
|
||||
/// Origin of the Block
|
||||
pub origin: BlockOrigin,
|
||||
/// Header
|
||||
pub header: Block::Header,
|
||||
/// Justification provided for this block from the outside
|
||||
pub external_justification: Justification,
|
||||
/// Internal Justification for the block
|
||||
pub internal_justification: Vec<u8>, // Block::Digest::DigestItem?
|
||||
/// Block's body
|
||||
pub body: Option<Vec<Block::Extrinsic>>,
|
||||
/// Is this block finalized already?
|
||||
/// `true` implies instant finality.
|
||||
pub finalized: bool,
|
||||
/// Auxiliary consensus data produced by the block.
|
||||
/// Contains a list of key-value pairs. If values are `None`, the keys
|
||||
/// will be deleted.
|
||||
pub auxiliary: Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> ImportBlock<Block> {
|
||||
/// Deconstruct the justified header into parts.
|
||||
pub fn into_inner(self)
|
||||
-> (
|
||||
BlockOrigin,
|
||||
<Block as BlockT>::Header,
|
||||
Justification,
|
||||
Justification,
|
||||
Option<Vec<<Block as BlockT>::Extrinsic>>,
|
||||
bool,
|
||||
Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
||||
) {
|
||||
(
|
||||
self.origin,
|
||||
self.header,
|
||||
self.external_justification,
|
||||
self.internal_justification,
|
||||
self.body,
|
||||
self.finalized,
|
||||
self.auxiliary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Summary of an imported block
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BlockImportNotification<Block: BlockT> {
|
||||
@@ -175,21 +222,6 @@ pub struct FinalityNotification<Block: BlockT> {
|
||||
pub header: Block::Header,
|
||||
}
|
||||
|
||||
/// A header paired with a justification which has already been checked.
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct JustifiedHeader<Block: BlockT> {
|
||||
header: <Block as BlockT>::Header,
|
||||
justification: ::bft::Justification<Block::Hash>,
|
||||
authorities: Vec<AuthorityId>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> JustifiedHeader<Block> {
|
||||
/// Deconstruct the justified header into parts.
|
||||
pub fn into_inner(self) -> (<Block as BlockT>::Header, ::bft::Justification<Block::Hash>, Vec<AuthorityId>) {
|
||||
(self.header, self.justification, self.authorities)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an instance of in-memory client.
|
||||
pub fn new_in_mem<E, Block, S>(
|
||||
executor: E,
|
||||
@@ -486,37 +518,24 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
)
|
||||
}
|
||||
|
||||
/// Check a header's justification.
|
||||
pub fn check_justification(
|
||||
&self,
|
||||
header: <Block as BlockT>::Header,
|
||||
justification: ::bft::UncheckedJustification<Block::Hash>,
|
||||
) -> error::Result<JustifiedHeader<Block>> {
|
||||
let parent_hash = header.parent_hash().clone();
|
||||
let authorities = self.authorities_at(&BlockId::Hash(parent_hash))?;
|
||||
let just = ::bft::check_justification::<Block>(&authorities[..], parent_hash, justification)
|
||||
.map_err(|_|
|
||||
error::ErrorKind::BadJustification(
|
||||
format!("{}", header.hash())
|
||||
)
|
||||
)?;
|
||||
Ok(JustifiedHeader {
|
||||
header,
|
||||
justification: just,
|
||||
authorities,
|
||||
})
|
||||
}
|
||||
|
||||
/// Queue a block for import.
|
||||
/// Import a checked and validated block
|
||||
pub fn import_block(
|
||||
&self,
|
||||
origin: BlockOrigin,
|
||||
header: JustifiedHeader<Block>,
|
||||
body: Option<Vec<<Block as BlockT>::Extrinsic>>,
|
||||
finalized: bool,
|
||||
import_block: ImportBlock<Block>,
|
||||
new_authorities: Option<Vec<AuthorityId>>,
|
||||
) -> error::Result<ImportResult> {
|
||||
let (header, justification, authorities) = header.into_inner();
|
||||
|
||||
let (
|
||||
origin,
|
||||
header,
|
||||
_,
|
||||
justification,
|
||||
body,
|
||||
finalized,
|
||||
_aux, // TODO: write this to DB also
|
||||
) = import_block.into_inner();
|
||||
let parent_hash = header.parent_hash().clone();
|
||||
|
||||
match self.backend.blockchain().status(BlockId::Hash(parent_hash))? {
|
||||
blockchain::BlockStatus::InChain => {},
|
||||
blockchain::BlockStatus::Unknown => return Ok(ImportResult::UnknownParent),
|
||||
@@ -532,8 +551,8 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
header,
|
||||
justification,
|
||||
body,
|
||||
authorities,
|
||||
finalized
|
||||
new_authorities,
|
||||
finalized,
|
||||
);
|
||||
|
||||
*self.importing_block.write() = None;
|
||||
@@ -574,9 +593,9 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
origin: BlockOrigin,
|
||||
hash: Block::Hash,
|
||||
header: Block::Header,
|
||||
justification: bft::Justification<Block::Hash>,
|
||||
justification: Justification,
|
||||
body: Option<Vec<Block::Extrinsic>>,
|
||||
authorities: Vec<AuthorityId>,
|
||||
authorities: Option<Vec<AuthorityId>>,
|
||||
finalized: bool,
|
||||
) -> error::Result<ImportResult> {
|
||||
let parent_hash = header.parent_hash().clone();
|
||||
@@ -650,16 +669,17 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
};
|
||||
|
||||
trace!("Imported {}, (#{}), best={}, origin={:?}", hash, header.number(), is_new_best, origin);
|
||||
let unchecked: bft::UncheckedJustification<_> = justification.uncheck().into();
|
||||
|
||||
transaction.set_block_data(
|
||||
header.clone(),
|
||||
body,
|
||||
Some(unchecked.into()),
|
||||
Some(justification),
|
||||
leaf_state,
|
||||
)?;
|
||||
|
||||
transaction.update_authorities(authorities);
|
||||
if let Some(authorities) = authorities {
|
||||
transaction.update_authorities(authorities);
|
||||
}
|
||||
if let Some(storage_update) = storage_update {
|
||||
transaction.update_storage(storage_update)?;
|
||||
}
|
||||
@@ -843,12 +863,14 @@ impl<B, E, Block> Client<B, E, Block> where
|
||||
}
|
||||
|
||||
/// Get block justification set by id.
|
||||
pub fn justification(&self, id: &BlockId<Block>) -> error::Result<Option<Justification<Block::Hash>>> {
|
||||
pub fn justification(&self, id: &BlockId<Block>) -> error::Result<Option<Justification>> {
|
||||
self.backend.blockchain().justification(*id)
|
||||
}
|
||||
|
||||
/// Get full block by id.
|
||||
pub fn block(&self, id: &BlockId<Block>) -> error::Result<Option<SignedBlock<Block::Header, Block::Extrinsic, Block::Hash>>> {
|
||||
pub fn block(&self, id: &BlockId<Block>)
|
||||
-> error::Result<Option<SignedBlock<Block::Header, Block::Extrinsic>>>
|
||||
{
|
||||
Ok(match (self.header(id)?, self.body(id)?, self.justification(id)?) {
|
||||
(Some(header), Some(extrinsics), Some(justification)) =>
|
||||
Some(SignedBlock { block: RuntimeBlock { header, extrinsics }, justification }),
|
||||
@@ -985,57 +1007,6 @@ impl<B, E, Block> BlockNumberToHash for Client<B, E, Block> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> bft::BlockImport<Block> for Client<B, E, Block>
|
||||
where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT,
|
||||
{
|
||||
fn import_block(
|
||||
&self,
|
||||
block: Block,
|
||||
justification: ::bft::Justification<Block::Hash>,
|
||||
authorities: &[AuthorityId],
|
||||
) -> bool {
|
||||
let (header, extrinsics) = block.deconstruct();
|
||||
let justified_header = JustifiedHeader {
|
||||
header: header,
|
||||
justification,
|
||||
authorities: authorities.to_vec(),
|
||||
};
|
||||
|
||||
// TODO [rob]: non-instant finality.
|
||||
self.import_block(
|
||||
BlockOrigin::ConsensusBroadcast,
|
||||
justified_header,
|
||||
Some(extrinsics),
|
||||
true
|
||||
).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> bft::Authorities<Block> for Client<B, E, Block>
|
||||
where
|
||||
B: backend::Backend<Block, Blake2Hasher>,
|
||||
E: CallExecutor<Block, Blake2Hasher>,
|
||||
Block: BlockT,
|
||||
{
|
||||
fn authorities(&self, at: &BlockId<Block>) -> Result<Vec<AuthorityId>, bft::Error> {
|
||||
let on_chain_version: Result<_, bft::Error> = self.runtime_version_at(at)
|
||||
.map_err(|e| { trace!("Error getting runtime version {:?}", e); bft::ErrorKind::RuntimeVersionMissing.into() });
|
||||
let on_chain_version = on_chain_version?;
|
||||
let native_version: Result<_, bft::Error> = self.executor.native_runtime_version()
|
||||
.ok_or_else(|| bft::ErrorKind::NativeRuntimeMissing.into());
|
||||
let native_version = native_version?;
|
||||
if !native_version.can_author_with(&on_chain_version) {
|
||||
return Err(bft::ErrorKind::IncompatibleAuthoringRuntime(on_chain_version, native_version.runtime_version.clone()).into())
|
||||
}
|
||||
self.authorities_at(at).map_err(|_| {
|
||||
let descriptor = format!("{:?}", at);
|
||||
bft::ErrorKind::StateUnavailable(descriptor).into()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E, Block> BlockchainEvents<Block> for Client<B, E, Block>
|
||||
where
|
||||
@@ -1095,7 +1066,7 @@ impl<B, E, Block> api::Core<Block, AuthorityId> for Client<B, E, Block> where
|
||||
}
|
||||
|
||||
fn authorities(&self, at: &BlockId<Block>) -> Result<Vec<AuthorityId>, Self::Error> {
|
||||
bft::Authorities::authorities(self, at).map_err(Into::into)
|
||||
self.authorities_at(at)
|
||||
}
|
||||
|
||||
fn execute_block(&self, at: &BlockId<Block>, block: &Block) -> Result<(), Self::Error> {
|
||||
|
||||
@@ -19,13 +19,8 @@
|
||||
use std;
|
||||
use state_machine;
|
||||
use runtime_primitives::ApplyError;
|
||||
use bft;
|
||||
|
||||
error_chain! {
|
||||
links {
|
||||
BFT(bft::error::Error, bft::error::ErrorKind) #[doc="BFT error"];
|
||||
}
|
||||
|
||||
errors {
|
||||
/// Backend error.
|
||||
Backend(s: String) {
|
||||
|
||||
@@ -26,7 +26,7 @@ use primitives::AuthorityId;
|
||||
use runtime_primitives::generic::BlockId;
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero,
|
||||
NumberFor, As, Digest, DigestItem};
|
||||
use runtime_primitives::bft::Justification;
|
||||
use runtime_primitives::Justification;
|
||||
use blockchain::{self, BlockStatus, HeaderBackend};
|
||||
use state_machine::backend::{Backend as StateBackend, InMemory};
|
||||
use state_machine::InMemoryChangesTrieStorage;
|
||||
@@ -42,12 +42,12 @@ struct PendingBlock<B: BlockT> {
|
||||
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
enum StoredBlock<B: BlockT> {
|
||||
Header(B::Header, Option<Justification<B::Hash>>),
|
||||
Full(B, Option<Justification<B::Hash>>),
|
||||
Header(B::Header, Option<Justification>),
|
||||
Full(B, Option<Justification>),
|
||||
}
|
||||
|
||||
impl<B: BlockT> StoredBlock<B> {
|
||||
fn new(header: B::Header, body: Option<Vec<B::Extrinsic>>, just: Option<Justification<B::Hash>>) -> Self {
|
||||
fn new(header: B::Header, body: Option<Vec<B::Extrinsic>>, just: Option<Justification>) -> Self {
|
||||
match body {
|
||||
Some(body) => StoredBlock::Full(B::new(header, body), just),
|
||||
None => StoredBlock::Header(header, just),
|
||||
@@ -61,7 +61,7 @@ impl<B: BlockT> StoredBlock<B> {
|
||||
}
|
||||
}
|
||||
|
||||
fn justification(&self) -> Option<&Justification<B::Hash>> {
|
||||
fn justification(&self) -> Option<&Justification> {
|
||||
match *self {
|
||||
StoredBlock::Header(_, ref j) | StoredBlock::Full(_, ref j) => j.as_ref()
|
||||
}
|
||||
@@ -74,7 +74,7 @@ impl<B: BlockT> StoredBlock<B> {
|
||||
}
|
||||
}
|
||||
|
||||
fn into_inner(self) -> (B::Header, Option<Vec<B::Extrinsic>>, Option<Justification<B::Hash>>) {
|
||||
fn into_inner(self) -> (B::Header, Option<Vec<B::Extrinsic>>, Option<Justification>) {
|
||||
match self {
|
||||
StoredBlock::Header(header, just) => (header, None, just),
|
||||
StoredBlock::Full(block, just) => {
|
||||
@@ -159,7 +159,7 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
&self,
|
||||
hash: Block::Hash,
|
||||
header: <Block as BlockT>::Header,
|
||||
justification: Option<Justification<Block::Hash>>,
|
||||
justification: Option<Justification>,
|
||||
body: Option<Vec<<Block as BlockT>::Extrinsic>>,
|
||||
new_state: NewBlockState,
|
||||
) -> ::error::Result<()> {
|
||||
@@ -292,7 +292,7 @@ impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> {
|
||||
}))
|
||||
}
|
||||
|
||||
fn justification(&self, id: BlockId<Block>) -> error::Result<Option<Justification<Block::Hash>>> {
|
||||
fn justification(&self, id: BlockId<Block>) -> error::Result<Option<Justification>> {
|
||||
Ok(self.id(id).and_then(|hash| self.storage.read().blocks.get(&hash).and_then(|b|
|
||||
b.justification().map(|x| x.clone()))
|
||||
))
|
||||
@@ -375,7 +375,7 @@ where
|
||||
&mut self,
|
||||
header: <Block as BlockT>::Header,
|
||||
body: Option<Vec<<Block as BlockT>::Extrinsic>>,
|
||||
justification: Option<Justification<Block::Hash>>,
|
||||
justification: Option<Justification>,
|
||||
state: NewBlockState,
|
||||
) -> error::Result<()> {
|
||||
assert!(self.pending_block.is_none(), "Only one block per operation is allowed");
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#![warn(missing_docs)]
|
||||
#![recursion_limit="128"]
|
||||
|
||||
extern crate substrate_bft as bft;
|
||||
extern crate substrate_trie as trie;
|
||||
extern crate parity_codec as codec;
|
||||
extern crate substrate_primitives as primitives;
|
||||
@@ -63,7 +62,7 @@ pub use client::{
|
||||
new_with_backend,
|
||||
new_in_mem,
|
||||
BlockBody, BlockStatus, BlockOrigin, ImportNotifications, FinalityNotifications, BlockchainEvents,
|
||||
Client, ClientInfo, ChainHead, ImportResult, JustifiedHeader,
|
||||
Client, ClientInfo, ChainHead, ImportResult, ImportBlock,
|
||||
};
|
||||
pub use notifications::{StorageEventStream, StorageChangeSet};
|
||||
pub use state_machine::ExecutionStrategy;
|
||||
|
||||
@@ -22,9 +22,9 @@ use futures::{Future, IntoFuture};
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use primitives::AuthorityId;
|
||||
use runtime_primitives::{bft::Justification, generic::BlockId};
|
||||
use runtime_primitives::traits::{Block as BlockT, NumberFor};
|
||||
use runtime_primitives::{generic::BlockId, Justification};
|
||||
use state_machine::{Backend as StateBackend, InMemoryChangesTrieStorage, TrieBackend};
|
||||
use runtime_primitives::traits::{Block as BlockT, NumberFor};
|
||||
|
||||
use backend::{Backend as ClientBackend, BlockImportOperation, RemoteBackend, NewBlockState};
|
||||
use blockchain::HeaderBackend as BlockchainHeaderBackend;
|
||||
@@ -167,7 +167,7 @@ where
|
||||
&mut self,
|
||||
header: Block::Header,
|
||||
_body: Option<Vec<Block::Extrinsic>>,
|
||||
_justification: Option<Justification<Block::Hash>>,
|
||||
_justification: Option<Justification>,
|
||||
state: NewBlockState,
|
||||
) -> ClientResult<()> {
|
||||
self.leaf_state = state;
|
||||
|
||||
@@ -22,8 +22,8 @@ use futures::{Future, IntoFuture};
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use primitives::AuthorityId;
|
||||
use runtime_primitives::{bft::Justification, generic::BlockId};
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero};
|
||||
use runtime_primitives::{Justification, generic::BlockId};
|
||||
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT,NumberFor, Zero};
|
||||
|
||||
use backend::NewBlockState;
|
||||
use blockchain::{Backend as BlockchainBackend, BlockStatus, Cache as BlockchainCache,
|
||||
@@ -139,7 +139,7 @@ impl<S, F, Block> BlockchainBackend<Block> for Blockchain<S, F> where Block: Blo
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn justification(&self, _id: BlockId<Block>) -> ClientResult<Option<Justification<Block::Hash>>> {
|
||||
fn justification(&self, _id: BlockId<Block>) -> ClientResult<Option<Justification>> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user