Skip to content

Latest commit

 

History

History
913 lines (815 loc) · 26.1 KB

波卡链源码分析之五区块及共识.md

File metadata and controls

913 lines (815 loc) · 26.1 KB

波卡链源码分析之五区块及共识

一、区块和区块头数据结构


看一下区块的结构:(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(&notification.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的超级节点)。