Newer
Older
// 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 <http://www.gnu.org/licenses/>.
//! Parachain data types.
#[cfg(feature = "std")]
use primitives::bytes;
use primitives;
use rstd::cmp::{PartialOrd, Ord, Ordering};
use ::Hash;
/// Unique identifier of a parachain.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
asynchronous rob
committed
pub struct Id(u32);
asynchronous rob
committed
impl From<Id> for u32 {
asynchronous rob
committed
impl From<u32> for Id {
fn from(x: u32) -> Self { Id(x) }
impl Id {
/// Convert this Id into its inner representation.
pub fn into_inner(self) -> u32 {
self.0
}
}
asynchronous rob
committed
impl Slicable for Id {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
u32::decode(input).map(Id)
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
self.0.using_encoded(f)
asynchronous rob
committed
/// 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<I: Input>(input: &mut I) -> Option<Self> {
asynchronous rob
committed
match disc {
0 => Some(Chain::Relay),
1 => Some(Chain::Parachain(Slicable::decode(input)?)),
asynchronous rob
committed
_ => None,
}
}
fn encode(&self) -> Vec<u8> {
asynchronous rob
committed
let mut v = Vec::new();
match *self {
asynchronous rob
committed
Chain::Parachain(id) => {
id.using_encoded(|s| v.extend(s));
asynchronous rob
committed
}
}
v
}
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
f(&self.encode().as_slice())
asynchronous rob
committed
}
}
/// 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<Chain>,
/// Lookup from validator index to chain on which that validator has a duty to guarantee
/// availability.
pub guarantor_duty: Vec<Chain>,
}
impl Slicable for DutyRoster {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(DutyRoster {
validator_duty: Slicable::decode(input)?,
guarantor_duty: Slicable::decode(input)?,
asynchronous rob
committed
})
}
fn encode(&self) -> Vec<u8> {
asynchronous rob
committed
let mut v = Vec::new();
v.extend(self.validator_duty.encode());
v.extend(self.guarantor_duty.encode());
asynchronous rob
committed
v
}
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
f(&self.encode().as_slice())
asynchronous rob
committed
}
}
/// 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<u8> {
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<I: Input>(input: &mut I) -> Option<Self> {
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)?,
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
})
}
}
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<Ordering> {
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<u8>);
/// 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<Message>)>);
/// 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<u8>);
/// 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<u8>);
/// 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<u8>);
/// 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<u8>);
/// 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<u8>);
asynchronous rob
committed
impl Slicable for Activity {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Vec::<u8>::decode(input).map(Activity)
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
self.0.using_encoded(f)
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
#[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<u8> {
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<I: Input>(value: &mut I) -> Option<Self> {
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(),
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
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"
}"#);
}
}