// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see .
//! Parachain data types.
#[cfg(feature = "std")]
use primitives::bytes;
use primitives;
use codec::{Input, Slicable};
use rstd::cmp::{PartialOrd, Ord, Ordering};
use rstd::vec::Vec;
use ::Hash;
/// Unique identifier of a parachain.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct Id(u32);
impl From for u32 {
fn from(x: Id) -> Self { x.0 }
}
impl From for Id {
fn from(x: u32) -> Self { Id(x) }
}
impl Slicable for Id {
fn decode(input: &mut I) -> Option {
u32::decode(input).map(Id)
}
fn using_encoded R>(&self, f: F) -> R {
self.0.using_encoded(f)
}
}
/// Identifier for a chain, either one of a number of parachains or the relay chain.
#[derive(Copy, Clone, PartialEq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum Chain {
/// The relay chain.
Relay,
/// A parachain of the given index.
Parachain(Id),
}
impl Slicable for Chain {
fn decode(input: &mut I) -> Option {
let disc = input.read_byte()?;
match disc {
0 => Some(Chain::Relay),
1 => Some(Chain::Parachain(Slicable::decode(input)?)),
_ => None,
}
}
fn encode(&self) -> Vec {
let mut v = Vec::new();
match *self {
Chain::Relay => { v.push(0); }
Chain::Parachain(id) => {
v.push(1u8);
id.using_encoded(|s| v.extend(s));
}
}
v
}
fn using_encoded R>(&self, f: F) -> R {
f(&self.encode().as_slice())
}
}
/// The duty roster specifying what jobs each validator must do.
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "std", derive(Default, Debug))]
pub struct DutyRoster {
/// Lookup from validator index to chain on which that validator has a duty to validate.
pub validator_duty: Vec,
/// Lookup from validator index to chain on which that validator has a duty to guarantee
/// availability.
pub guarantor_duty: Vec,
}
impl Slicable for DutyRoster {
fn decode(input: &mut I) -> Option {
Some(DutyRoster {
validator_duty: Slicable::decode(input)?,
guarantor_duty: Slicable::decode(input)?,
})
}
fn encode(&self) -> Vec {
let mut v = Vec::new();
v.extend(self.validator_duty.encode());
v.extend(self.guarantor_duty.encode());
v
}
fn using_encoded R>(&self, f: F) -> R {
f(&self.encode().as_slice())
}
}
/// Extrinsic data for a parachain.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Extrinsic;
/// Candidate parachain block.
///
/// https://github.com/w3f/polkadot-spec/blob/master/spec.md#candidate-para-chain-block
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Candidate {
/// The ID of the parachain this is a proposal for.
pub parachain_index: Id,
/// Collator's signature
pub collator_signature: ::Signature,
/// Unprocessed ingress queue.
///
/// Ordered by parachain ID and block number.
pub unprocessed_ingress: ConsolidatedIngress,
/// Block data
pub block: BlockData,
}
/// Candidate receipt type.
#[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 CandidateReceipt {
/// The ID of the parachain this is a candidate for.
pub parachain_index: Id,
/// The collator's relay-chain account ID
pub collator: ::AccountId,
/// The head-data
pub head_data: HeadData,
/// Balance uploads to the relay chain.
pub balance_uploads: Vec<(::AccountId, u64)>,
/// Egress queue roots.
pub egress_queue_roots: Vec<(Id, primitives::H256)>,
/// Fees paid from the chain to the relay chain validators
pub fees: u64,
}
impl Slicable for CandidateReceipt {
fn encode(&self) -> Vec {
let mut v = Vec::new();
self.parachain_index.using_encoded(|s| v.extend(s));
self.collator.using_encoded(|s| v.extend(s));
self.head_data.0.using_encoded(|s| v.extend(s));
self.balance_uploads.using_encoded(|s| v.extend(s));
self.egress_queue_roots.using_encoded(|s| v.extend(s));
self.fees.using_encoded(|s| v.extend(s));
v
}
fn decode(input: &mut I) -> Option {
Some(CandidateReceipt {
parachain_index: Slicable::decode(input)?,
collator: Slicable::decode(input)?,
head_data: Slicable::decode(input).map(HeadData)?,
balance_uploads: Slicable::decode(input)?,
egress_queue_roots: Slicable::decode(input)?,
fees: Slicable::decode(input)?,
})
}
}
impl CandidateReceipt {
/// Get the blake2_256 hash
#[cfg(feature = "std")]
pub fn hash(&self) -> Hash {
let encoded = self.encode();
primitives::hashing::blake2_256(&encoded).into()
}
}
impl PartialOrd for CandidateReceipt {
fn partial_cmp(&self, other: &Self) -> Option {
Some(self.cmp(other))
}
}
impl Ord for CandidateReceipt {
fn cmp(&self, other: &Self) -> Ordering {
// TODO: compare signatures or something more sane
self.parachain_index.cmp(&other.parachain_index)
.then_with(|| self.head_data.cmp(&other.head_data))
}
}
/// Parachain ingress queue message.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct Message(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec);
/// Consolidated ingress queue data.
///
/// This is just an ordered vector of other parachains' egress queues,
/// obtained according to the routing rules.
#[derive(Default, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct ConsolidatedIngress(pub Vec<(Id, Vec)>);
/// Parachain block data.
///
/// contains everything required to validate para-block, may contain block and witness data
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct BlockData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec);
/// Parachain header raw bytes wrapper type.
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct Header(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec);
/// Parachain head data included in the chain.
#[derive(PartialEq, Eq, Clone, PartialOrd, Ord)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct HeadData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec);
/// Parachain validation code.
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct ValidationCode(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec);
/// Activitiy bit field
#[derive(PartialEq, Eq, Clone, Default)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct Activity(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec);
impl Slicable for Activity {
fn decode(input: &mut I) -> Option {
Vec::::decode(input).map(Activity)
}
fn using_encoded R>(&self, f: F) -> R {
self.0.using_encoded(f)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
#[repr(u8)]
enum StatementKind {
Candidate = 1,
Valid = 2,
Invalid = 3,
Available = 4,
}
/// Statements which can be made about parachain candidates.
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum Statement {
/// Proposal of a parachain candidate.
Candidate(CandidateReceipt),
/// State that a parachain candidate is valid.
Valid(Hash),
/// Vote to commit to a candidate.
Invalid(Hash),
/// Vote to advance round after inactive primary.
Available(Hash),
}
impl Slicable for Statement {
fn encode(&self) -> Vec {
let mut v = Vec::new();
match *self {
Statement::Candidate(ref candidate) => {
v.push(StatementKind::Candidate as u8);
candidate.using_encoded(|s| v.extend(s));
}
Statement::Valid(ref hash) => {
v.push(StatementKind::Valid as u8);
hash.using_encoded(|s| v.extend(s));
}
Statement::Invalid(ref hash) => {
v.push(StatementKind::Invalid as u8);
hash.using_encoded(|s| v.extend(s));
}
Statement::Available(ref hash) => {
v.push(StatementKind::Available as u8);
hash.using_encoded(|s| v.extend(s));
}
}
v
}
fn decode(value: &mut I) -> Option {
match value.read_byte() {
Some(x) if x == StatementKind::Candidate as u8 => {
Slicable::decode(value).map(Statement::Candidate)
}
Some(x) if x == StatementKind::Valid as u8 => {
Slicable::decode(value).map(Statement::Valid)
}
Some(x) if x == StatementKind::Invalid as u8 => {
Slicable::decode(value).map(Statement::Invalid)
}
Some(x) if x == StatementKind::Available as u8 => {
Slicable::decode(value).map(Statement::Available)
}
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use substrate_serializer as ser;
#[test]
fn test_candidate() {
assert_eq!(ser::to_string_pretty(&Candidate {
parachain_index: 5.into(),
collator_signature: primitives::hash::H512::from(10).into(),
unprocessed_ingress: ConsolidatedIngress(vec![
(Id(1), vec![Message(vec![2])]),
(Id(2), vec![Message(vec![2]), Message(vec![3])]),
]),
block: BlockData(vec![1, 2, 3]),
}), r#"{
"parachainIndex": 5,
"collatorSignature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a",
"unprocessedIngress": [
[
1,
[
"0x02"
]
],
[
2,
[
"0x02",
"0x03"
]
]
],
"block": "0x010203"
}"#);
}
}