看一下区块的结构:(substate/primitives/src/block.rs)
/// Simple generic extrinsic type.
//核心就是一个BYTE数组
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct Extrinsic(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
//定义块结构并设置相关属性
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct Block<Transaction: PartialEq + Eq + Clone> {
/// The block header.
pub header: Header,
/// All relay-chain transactions.
pub transactions: Vec<Transaction>,
}
//对Block的编码解码
impl<T: PartialEq + Eq + Clone> Slicable for Block<T> where Vec<T>: Slicable {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Block {
header: Slicable::decode(input)?,
transactions: Slicable::decode(input)?,
})
}
fn encode(&self) -> Vec<u8> {
let mut v: Vec<u8> = Vec::new();
v.extend(self.header.encode());
v.extend(self.transactions.encode());
v
}
}
///正式定义Block.
pub type Block = generic::Block<Extrinsic>;
从数据结构上来看,Block包含Header和Transaction的一个数组向量。和其它的链没有太大的区别。重点看一下头:
/// A substrate chain block header.
// TODO: split out into light-client-specific fields and runtime-specific fields.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Header {
/// Block parent's hash.
pub parent_hash: HeaderHash,//父哈希,成链的前提
/// Block number.
pub number: Number,//块号
/// State root after this transition.
pub state_root: Hash,//状态哈希的根
/// The root of the trie that represents this block's transactions, indexed by a 32-byte integer.
pub extrinsics_root: Hash,//trie的根哈希,类似于以太坊的三大哈希树
// TODO...
// /// The root of the trie that represents the receipts from this block's transactions
// pub receipts_root: Hash,//收据哈希根
/// The digest of activity on the block.
pub digest: Digest,//摘要
}
中继链的区块其实和其它的链的块结构原理基本都是类似的,没有什么特别的地方,可能不同的就是要有一个外部默克尔树的提交的HASH,但也可以透明的理解成相关的数据哈希。
波卡链的区块产生分为以下几步:
1、由收集者产生区块
在波卡链中,对上面的块进行了进一步的抽象:
/// Abstraction over a substrate block.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Block<Number, Hash, DigestItem, AccountId, Index, Call, Signature> where
Number: Member,
Hash: Member,
DigestItem: Member,
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member
{
/// The block header.
pub header: Header<Number, Hash, DigestItem>,
/// The accompanying extrinsics.
pub extrinsics: Vec<UncheckedExtrinsic<AccountId, Index, Call, Signature>>,
}
impl<Number, Hash, DigestItem, AccountId, Index, Call, Signature> Slicable
for Block<Number, Hash, DigestItem, AccountId, Index, Call, Signature>
where
Number: Member,
Hash: Member,
DigestItem: Member,
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member,
Header<Number, Hash, DigestItem>: Slicable,
UncheckedExtrinsic<AccountId, Index, Call, Signature>: Slicable,
{
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Block {
header: Slicable::decode(input)?,
extrinsics: Slicable::decode(input)?,
})
}
fn encode(&self) -> Vec<u8> {
let mut v: Vec<u8> = Vec::new();
v.extend(self.header.encode());
v.extend(self.extrinsics.encode());
v
}
}
impl<Number, Hash, DigestItem, AccountId, Index, Call, Signature> traits::Block
for Block<Number, Hash, DigestItem, AccountId, Index, Call, Signature>
where
Number: Member + Slicable,
Hash: Member + Slicable,
DigestItem: Member + Slicable,
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member
{
type Extrinsic = UncheckedExtrinsic<AccountId, Index, Call, Signature>;
type Header = Header<Number, Hash, DigestItem>;
fn header(&self) -> &Self::Header {
&self.header
}
fn extrinsics(&self) -> &[Self::Extrinsic] {
&self.extrinsics[..]
}
fn deconstruct(self) -> (Self::Header, Vec<Self::Extrinsic>) {
(self.header, self.extrinsics)
}
}
//此处为交易池代码:
/// Useful functions for working with Polkadot blocks.
pub struct PolkadotBlock {
block: Block,
location: Option<(&'static str, usize)>,
}
impl PolkadotBlock {
/// Create a new block, checking high-level well-formedness.
pub fn from(unchecked: Block) -> ::std::result::Result<Self, Block> {
if unchecked.extrinsics.len() < 2 {
return Err(unchecked);
}
if unchecked.extrinsics[0].is_signed() {
return Err(unchecked);
}
if unchecked.extrinsics[1].is_signed() {
return Err(unchecked);
}
match unchecked.extrinsics[0].extrinsic.function {
Call::Timestamp(TimestampCall::set(_)) => {},
_ => return Err(unchecked),
}
match unchecked.extrinsics[1].extrinsic.function {
Call::Parachains(ParachainsCall::set_heads(_)) => {},
_ => return Err(unchecked),
}
// any further checks...
Ok(PolkadotBlock { block: unchecked, location: None })
}
/// Create a new block, skipping any high-level well-formedness checks. WARNING: This could
/// result in internal functions panicking if the block is, in fact, not well-formed.
pub fn force_from(known_good: Block, file: &'static str, line: usize) -> Self {
PolkadotBlock { block: known_good, location: Some((file, line)) }
}
/// Retrieve the timestamp of a Polkadot block.
pub fn timestamp(&self) -> Timestamp {
if let Call::Timestamp(TimestampCall::set(t)) = self.block.extrinsics[0].extrinsic.function {
t
} else {
if let Some((file, line)) = self.location {
panic!("Invalid block used in `PolkadotBlock::force_from` at {}:{}", file, line);
} else {
panic!("Invalid block made it through the PolkadotBlock verification!?");
}
}
}
/// Retrieve the parachain candidates proposed for this block.
pub fn parachain_heads(&self) -> &[CandidateReceipt] {
if let Call::Parachains(ParachainsCall::set_heads(ref t)) = self.block.extrinsics[1].extrinsic.function {
&t[..]
} else {
if let Some((file, line)) = self.location {
panic!("Invalid block used in `PolkadotBlock::force_from` at {}:{}", file, line);
} else {
panic!("Invalid block made it through the PolkadotBlock verification!?");
}
}
}
}
#[macro_export]
macro_rules! assert_polkadot_block {
($known_good:expr) => ( PolkadotBlock::force_from(known_good, file!(), line!()) )
}
impl ::std::ops::Deref for PolkadotBlock {
type Target = Block;
fn deref(&self) -> &Block {
&self.block
}
}
impl From<PolkadotBlock> for Block {
fn from(pd: PolkadotBlock) -> Self {
pd.block
}
}
/// Iterator over pending transactions.
pub type PendingIterator<'a, C> =
transaction_pool::PendingIterator<'a, VerifiedTransaction, Ready<'a, C>, Scoring, NoopListener>;
error_chain! {
errors {
/// Attempted to queue an inherent transaction.
IsInherent(xt: UncheckedExtrinsic) {
description("Inherent transactions cannot be queued."),
display("Inehrent transactions cannot be queued."),
}
/// Attempted to queue a transaction with bad signature.
BadSignature(xt: UncheckedExtrinsic) {
description("Transaction had bad signature."),
display("Transaction had bad signature."),
}
/// Attempted to queue a transaction that is already in the pool.
AlreadyImported(hash: Hash) {
description("Transaction is already in the pool."),
display("Transaction {:?} is already in the pool.", hash),
}
/// Import error.
Import(err: Box<::std::error::Error + Send>) {
description("Error importing transaction"),
display("Error importing transaction: {}", err.description()),
}
}
}
共识主要在consensus/src中,在substrate/primitives/bft.rs中是基本的BFT共识算法。
1、共识的发起
/// The Polkadot proposer logic.
pub struct Proposer<C: PolkadotApi, R, P> {
client: Arc<C>,
collators: P,
delay: Shared<Timeout>,
dynamic_inclusion: DynamicInclusion,
handle: Handle,
local_duty: LocalDuty,
local_key: Arc<ed25519::Pair>,
parent_hash: HeaderHash,
parent_id: C::CheckedBlockId,
parent_number: BlockNumber,
random_seed: Hash,
router: R,
table: Arc<SharedTable>,
transaction_pool: Arc<Mutex<TransactionPool>>,
}
//启动共识
fn start_bft<F, C>(
header: &Header,
handle: reactor::Handle,
client: &bft::Authorities,
network: Arc<net::ConsensusService>,
bft_service: &BftService<F, C>,
) where
F: bft::ProposerFactory + 'static,
C: bft::BlockImport + bft::Authorities + 'static,
<F as bft::ProposerFactory>::Error: ::std::fmt::Debug,
<F::Proposer as bft::Proposer>::Error: ::std::fmt::Display + Into<error::Error>,
{
let parent_hash = header.blake2_256().into();
if bft_service.live_agreement().map_or(false, |h| h == parent_hash) {
return;
}
let authorities = match client.authorities(&BlockId::Hash(parent_hash)) {
Ok(authorities) => authorities,
Err(e) => {
debug!("Error reading authorities: {:?}", e);
return;
}
};
let input = Messages {
network_stream: network.bft_messages(parent_hash),
local_id: bft_service.local_id(),
authorities,
};
let output = BftSink { network: network, parent_hash: parent_hash, _e: Default::default() };
match bft_service.build_upon(&header, input.map_err(Into::into), output) {
Ok(Some(bft)) => handle.spawn(bft),
Ok(None) => {},
Err(e) => debug!(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, C>(
client: Arc<C>,
api: Arc<A>,
network: Arc<net::ConsensusService>,
transaction_pool: Arc<Mutex<TransactionPool>>,
parachain_empty_duration: Duration,
key: ed25519::Pair,
) -> Service
where
A: LocalPolkadotApi + Send + Sync + 'static,
C: BlockchainEvents + ChainHead + bft::BlockImport + bft::Authorities + Send + Sync + 'static,
{
let (signal, exit) = ::exit_future::signal();
let thread = thread::spawn(move || {
let mut core = reactor::Core::new().expect("tokio::Core could not be created");
let key = Arc::new(key);
let factory = ProposerFactory {
client: api.clone(),
transaction_pool: transaction_pool.clone(),
network: Network(network.clone()),
collators: NoCollators,
parachain_empty_duration,
handle: core.handle(),
};
let bft_service = Arc::new(BftService::new(client.clone(), key, factory));
//网络消息通知
let notifications = {
let handle = core.handle();
let network = network.clone();
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(¬ification.header, handle.clone(), &*client, network.clone(), &*bft_service);
}
Ok(())
})
};
//时间控制
let interval = reactor::Interval::new_at(
Instant::now() + Duration::from_millis(TIMER_DELAY_MS),
Duration::from_millis(TIMER_INTERVAL_MS),
&core.handle(),
).expect("it is always possible to create an interval with valid params");
let mut prev_best = match client.best_block_header() {
Ok(header) => header.blake2_256(),
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();
let n = network.clone();
let handle = core.handle();
interval.map_err(|e| debug!("Timer error: {:?}", e)).for_each(move |_| {
if let Ok(best_block) = c.best_block_header() {
let hash = best_block.blake2_256();
if hash == prev_best {
debug!("Starting consensus round after a timeout");
start_bft(&best_block, handle.clone(), &*c, n.clone(), &*s);
}
prev_best = hash;
}
Ok(())
})
};
//生产相关线程并监听事件
core.handle().spawn(notifications);
core.handle().spawn(timed);
if let Err(e) = core.run(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");
}
}
}
//处理收集的区块和路由信息
// Collators implementation which never collates anything.
// TODO: do a real implementation.
#[derive(Clone, Copy)]
struct NoCollators;
impl ::collation::Collators for NoCollators {
type Error = ();
type Collation = future::Empty<::collation::Collation, ()>;
fn collate(&self, _parachain: ParaId, _relay_parent: Hash) -> Self::Collation {
future::empty()
}
fn note_bad_collator(&self, _collator: AccountId) { }
}
type FetchCandidateAdapter = future::Map<net::FetchFuture, fn(Vec<u8>) -> BlockData>;
#[derive(Clone)]
struct Router {
network: Arc<net::ConsensusService>,
}
impl Router {
fn fetch_candidate_adapter(data: Vec<u8>) -> BlockData {
BlockData(data)
}
}
impl TableRouter for Router {
type Error = Canceled;
type FetchCandidate = FetchCandidateAdapter;
type FetchExtrinsic = future::FutureResult<Extrinsic, Self::Error>;
fn local_candidate_data(&self, hash: Hash, block_data: BlockData, _extrinsic: Extrinsic) {
let data = block_data.0;
self.network.set_local_candidate(Some((hash, data)))
}
fn fetch_block_data(&self, candidate: &CandidateReceipt) -> Self::FetchCandidate {
let hash = candidate.hash();
self.network.fetch_candidate(&hash).map(Self::fetch_candidate_adapter)
}
fn fetch_extrinsic_data(&self, _candidate: &CandidateReceipt) -> Self::FetchExtrinsic {
future::ok(Extrinsic)
}
}
在一个循环里不断的收集:
impl<C: Collators, P: PolkadotApi> Future for CollationFetch<C, P> {
type Item = (Collation, Extrinsic);
type Error = C::Error;
fn poll(&mut self) -> Poll<(Collation, Extrinsic), C::Error> {
let parachain = match self.parachain.as_ref() {
Some(p) => p.clone(),
None => return Ok(Async::NotReady),
};
loop {
let x = {
let (r, c) = (self.relay_parent_hash, &self.collators);
let poll = self.live_fetch
.get_or_insert_with(move || c.collate(parachain, r).into_future())
.poll();
if let Err(_) = poll { self.parachain = None }
try_ready!(poll)
};
match validate_collation(&*self.client, &self.relay_parent, &x) {
Ok(()) => {
self.parachain = None;
// TODO: generate extrinsic while verifying.
return Ok(Async::Ready((x, Extrinsic)));
}
Err(e) => {
debug!("Failed to validate parachain due to API error: {}", e);
// just continue if we got a bad collation or failed to validate
self.live_fetch = None;
self.collators.note_bad_collator(x.receipt.collator)
}
}
}
}
处理提议,并达成共识:
/// Import a single statement. Provide a handle to a table router
/// for dispatching any other requests which come up.
pub fn import_statement<R: TableRouter, C: FnMut(Collation) -> bool>(
&self,
router: &R,
statement: table::SignedStatement,
received_from: StatementSource,
check_candidate: C,
) -> StatementProducer<<R::FetchCandidate as IntoFuture>::Future, <R::FetchExtrinsic as IntoFuture>::Future, C> {
self.inner.lock().import_statement(&*self.context, router, statement, received_from, check_candidate)
}
/// Sign and import a local statement.
pub fn sign_and_import<R: TableRouter>(
&self,
router: &R,
statement: table::Statement,
) {
let proposed_digest = match statement {
GenericStatement::Candidate(ref c) => Some(c.hash()),
_ => None,
};
let signed_statement = self.context.sign_statement(statement);
let mut inner = self.inner.lock();
if proposed_digest.is_some() {
inner.proposed_digest = proposed_digest;
}
let producer = inner.import_statement(
&*self.context,
router,
signed_statement,
StatementSource::Local,
|_| true,
);
assert!(producer.work.is_none(), "local statement import never leads to additional work; qed");
}
/// Import many statements at once.
///
/// Provide an iterator yielding pairs of (statement, statement_source).
pub fn import_statements<R, I, C, U>(&self, router: &R, iterable: I) -> U
where
R: TableRouter,
I: IntoIterator<Item=(table::SignedStatement, StatementSource, C)>,
C: FnMut(Collation) -> bool,
U: ::std::iter::FromIterator<StatementProducer<
<R::FetchCandidate as IntoFuture>::Future,
<R::FetchExtrinsic as IntoFuture>::Future,
C,
>>,
{
let mut inner = self.inner.lock();
iterable.into_iter().map(move |(statement, statement_source, check_candidate)| {
inner.import_statement(&*self.context, router, statement, statement_source, check_candidate)
}).collect()
}
/// Execute a closure using a specific candidate.
///
/// Deadlocks if called recursively.
pub fn with_candidate<F, U>(&self, digest: &Hash, f: F) -> U
where F: FnOnce(Option<&CandidateReceipt>) -> U
{
let inner = self.inner.lock();
f(inner.table.get_candidate(digest))
}
/// Execute a closure using the current proposed set.
///
/// Deadlocks if called recursively.
pub fn with_proposal<F, U>(&self, f: F) -> U
where F: FnOnce(Vec<&CandidateReceipt>) -> U
{
let inner = self.inner.lock();
f(inner.table.proposed_candidates(&*self.context))
}
/// Get the number of parachains which have available candidates.
pub fn includable_count(&self) -> usize {
self.inner.lock().table.includable_count()
}
/// Get all witnessed misbehavior.
pub fn get_misbehavior(&self) -> HashMap<AuthorityId, table::Misbehavior> {
self.inner.lock().table.get_misbehavior().clone()
}
/// Fill a statement batch.
pub fn fill_batch<B: table::StatementBatch>(&self, batch: &mut B) {
self.inner.lock().table.fill_batch(batch);
}
/// Track includability of a given set of candidate hashes.
pub fn track_includability<I>(&self, iterable: I) -> Includable
where I: IntoIterator<Item=Hash>
{
let mut inner = self.inner.lock();
let (tx, rx) = includable::track(iterable.into_iter().map(|x| {
let includable = inner.table.candidate_includable(&x, &*self.context);
(x, includable)
}));
if !tx.is_complete() {
inner.trackers.push(tx);
}
rx
}
}
最终的BFT处理:
/// Actions which can be taken during the BFT process.
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum Action {
/// Proposal of a block candidate.
Propose(u32, Block),
/// Proposal header of a block candidate. Accompanies any proposal,
/// but is used for misbehavior reporting since blocks themselves are big.
ProposeHeader(u32, HeaderHash),
/// Preparation to commit for a candidate.
Prepare(u32, HeaderHash),
/// Vote to commit to a candidate.
Commit(u32, HeaderHash),
/// Vote to advance round after inactive primary.
AdvanceRound(u32),
}
impl Slicable for Action {
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
match *self {
Action::Propose(ref round, ref block) => {
v.push(ActionKind::Propose as u8);
round.using_encoded(|s| v.extend(s));
block.using_encoded(|s| v.extend(s));
}
Action::ProposeHeader(ref round, ref hash) => {
v.push(ActionKind::ProposeHeader as u8);
round.using_encoded(|s| v.extend(s));
hash.using_encoded(|s| v.extend(s));
}
Action::Prepare(ref round, ref hash) => {
v.push(ActionKind::Prepare as u8);
round.using_encoded(|s| v.extend(s));
hash.using_encoded(|s| v.extend(s));
}
Action::Commit(ref round, ref hash) => {
v.push(ActionKind::Commit as u8);
round.using_encoded(|s| v.extend(s));
hash.using_encoded(|s| v.extend(s));
}
Action::AdvanceRound(ref round) => {
v.push(ActionKind::AdvanceRound as u8);
round.using_encoded(|s| v.extend(s));
}
}
v
}
fn decode<I: Input>(value: &mut I) -> Option<Self> {
match i8::decode(value) {
Some(x) if x == ActionKind::Propose as i8 => {
let (round, block) = try_opt!(Slicable::decode(value));
Some(Action::Propose(round, block))
}
Some(x) if x == ActionKind::ProposeHeader as i8 => {
let (round, hash) = try_opt!(Slicable::decode(value));
Some(Action::ProposeHeader(round, hash))
}
Some(x) if x == ActionKind::Prepare as i8 => {
let (round, hash) = try_opt!(Slicable::decode(value));
Some(Action::Prepare(round, hash))
}
Some(x) if x == ActionKind::Commit as i8 => {
let (round, hash) = try_opt!(Slicable::decode(value));
Some(Action::Commit(round, hash))
}
Some(x) if x == ActionKind::AdvanceRound as i8 => {
Slicable::decode(value).map(Action::AdvanceRound)
}
_ => None,
}
}
}
/// Messages exchanged between participants in the BFT consensus.
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct Message {
/// The parent header hash this action is relative to.
pub parent: HeaderHash,
/// The action being broadcasted.
pub action: Action,
}
impl Slicable for Message {
fn encode(&self) -> Vec<u8> {
let mut v = self.parent.encode();
self.action.using_encoded(|s| v.extend(s));
v
}
fn decode<I: Input>(value: &mut I) -> Option<Self> {
Some(Message {
parent: try_opt!(Slicable::decode(value)),
action: try_opt!(Slicable::decode(value)),
})
}
}
/// Justification of a block.
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub struct Justification {
/// The round consensus was reached in.
pub round_number: u32,
/// The hash of the header justified.
pub hash: HeaderHash,
/// The signatures and signers of the hash.
pub signatures: Vec<(::AuthorityId, ::Signature)>
}
impl Slicable for Justification {
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
self.round_number.using_encoded(|s| v.extend(s));
self.hash.using_encoded(|s| v.extend(s));
self.signatures.using_encoded(|s| v.extend(s));
v
}
fn decode<I: Input>(value: &mut I) -> Option<Self> {
Some(Justification {
round_number: try_opt!(Slicable::decode(value)),
hash: try_opt!(Slicable::decode(value)),
signatures: try_opt!(Slicable::decode(value)),
})
}
}
// single-byte code to represent misbehavior kind.
#[repr(i8)]
enum MisbehaviorCode {
/// BFT: double prepare.
BftDoublePrepare = 0x11,
/// BFT: double commit.
BftDoubleCommit = 0x12,
}
impl MisbehaviorCode {
fn from_i8(x: i8) -> Option<Self> {
match x {
0x11 => Some(MisbehaviorCode::BftDoublePrepare),
0x12 => Some(MisbehaviorCode::BftDoubleCommit),
_ => None,
}
}
}
/// Misbehavior kinds.
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub enum MisbehaviorKind {
/// BFT: double prepare.
BftDoublePrepare(u32, (HeaderHash, Signature), (HeaderHash, Signature)),
/// BFT: double commit.
BftDoubleCommit(u32, (HeaderHash, Signature), (HeaderHash, Signature)),
}
/// A report of misbehavior by an authority.
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub struct MisbehaviorReport {
/// The parent hash of the block where the misbehavior occurred.
pub parent_hash: HeaderHash,
/// The parent number of the block where the misbehavior occurred.
pub parent_number: ::block::Number,
/// The authority who misbehavior.
pub target: AuthorityId,
/// The misbehavior kind.
pub misbehavior: MisbehaviorKind,
}
impl Slicable for MisbehaviorReport {
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
self.parent_hash.using_encoded(|s| v.extend(s));
self.parent_number.using_encoded(|s| v.extend(s));
self.target.using_encoded(|s| v.extend(s));
match self.misbehavior {
MisbehaviorKind::BftDoublePrepare(ref round, (ref h_a, ref s_a), (ref h_b, ref s_b)) => {
(MisbehaviorCode::BftDoublePrepare as i8).using_encoded(|s| v.extend(s));
round.using_encoded(|s| v.extend(s));
h_a.using_encoded(|s| v.extend(s));
s_a.using_encoded(|s| v.extend(s));
h_b.using_encoded(|s| v.extend(s));
s_b.using_encoded(|s| v.extend(s));
}
MisbehaviorKind::BftDoubleCommit(ref round, (ref h_a, ref s_a), (ref h_b, ref s_b)) => {
(MisbehaviorCode::BftDoubleCommit as i8).using_encoded(|s| v.extend(s));
round.using_encoded(|s| v.extend(s));
h_a.using_encoded(|s| v.extend(s));
s_a.using_encoded(|s| v.extend(s));
h_b.using_encoded(|s| v.extend(s));
s_b.using_encoded(|s| v.extend(s));
}
}
v
}
fn decode<I: Input>(input: &mut I) -> Option<Self> {
let parent_hash = HeaderHash::decode(input)?;
let parent_number = ::block::Number::decode(input)?;
let target = AuthorityId::decode(input)?;
let misbehavior = match i8::decode(input).and_then(MisbehaviorCode::from_i8)? {
MisbehaviorCode::BftDoublePrepare => {
MisbehaviorKind::BftDoublePrepare(
u32::decode(input)?,
(HeaderHash::decode(input)?, Signature::decode(input)?),
(HeaderHash::decode(input)?, Signature::decode(input)?),
)
}
MisbehaviorCode::BftDoubleCommit => {
MisbehaviorKind::BftDoubleCommit(
u32::decode(input)?,
(HeaderHash::decode(input)?, Signature::decode(input)?),
(HeaderHash::decode(input)?, Signature::decode(input)?),
)
}
};
Some(MisbehaviorReport {
parent_hash,
parent_number,
target,
misbehavior,
})
}
}
波卡链的共识没有特别之处,它的难点还在于Router的控制和对链的进入、出口的管理。通过注册机制可以较好的控制这些,但是缺点就在于,会开成中心机制(因为不可能向链数量扩展,否则就是一条链了,必然是代表节点,最终形成类似于EOS的超级节点)。