Commit cc7a4d62 authored by Tomasz Drwięga's avatar Tomasz Drwięga Committed by Sergey Pepyakin
Browse files

Derivable Encode & Decode (#509)

* Derive macro for simple structs.

* Derive Encode/Decode wherever we can.

* Derive for enums.

* Support discriminant.

* Get rid of some repetition.

* Support custom indices.

* Derive codec for enums wherever possible.

* Fix no_std

* WASM rebuilt

* Avoid excessive import.

* Fix compilation.

* Address review grumbles.
parent 5b4de48a
......@@ -12,6 +12,7 @@ polkadot-consensus = { path = "../consensus" }
polkadot-primitives = { path = "../primitives" }
substrate-bft = { path = "../../substrate/bft" }
substrate-codec = { path = "../../substrate/codec" }
substrate-codec-derive = { path = "../../substrate/codec/derive" }
substrate-network = { path = "../../substrate/network" }
substrate-primitives = { path = "../../substrate/primitives" }
ed25519 = { path = "../../substrate/ed25519" }
......
......@@ -18,7 +18,6 @@
use polkadot_primitives::{AccountId, Hash};
use polkadot_primitives::parachain::{Id as ParaId, Collation};
use codec;
use futures::sync::oneshot;
......@@ -28,7 +27,7 @@ use std::time::{Duration, Instant};
const COLLATION_LIFETIME: Duration = Duration::from_secs(60 * 5);
/// The role of the collator. Whether they're the primary or backup for this parachain.
#[derive(PartialEq, Debug, Clone, Copy)]
#[derive(PartialEq, Debug, Clone, Copy, Encode, Decode)]
pub enum Role {
/// Primary collators should send collations whenever it's time.
Primary = 0,
......@@ -36,22 +35,6 @@ pub enum Role {
Backup = 1,
}
impl codec::Encode for Role {
fn encode_to<T: codec::Output>(&self, dest: &mut T) {
dest.push_byte(*self as u8);
}
}
impl codec::Decode for Role {
fn decode<I: codec::Input>(input: &mut I) -> Option<Self> {
match input.read_byte()? {
x if x == Role::Primary as u8 => Some(Role::Primary),
x if x == Role::Backup as u8 => Some(Role::Backup),
_ => None,
}
}
}
/// A maintenance action for the collator set.
#[derive(PartialEq, Debug)]
#[allow(dead_code)]
......
......@@ -38,13 +38,15 @@ extern crate rhododendron;
#[macro_use]
extern crate log;
#[macro_use]
extern crate substrate_codec_derive;
mod collator_pool;
mod local_collations;
mod router;
pub mod consensus;
use codec::{Decode, Encode, Input, Output};
use codec::{Decode, Encode};
use futures::sync::oneshot;
use parking_lot::Mutex;
use polkadot_consensus::{Statement, SignedStatement, GenericStatement};
......@@ -74,36 +76,11 @@ type FullStatus = GenericFullStatus<Block>;
pub type NetworkService = ::substrate_network::Service<Block, PolkadotProtocol>;
/// Status of a Polkadot node.
#[derive(Debug, PartialEq, Eq, Clone)]
#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
pub struct Status {
collating_for: Option<(AccountId, ParaId)>,
}
impl Encode for Status {
fn encode_to<T: codec::Output>(&self, dest: &mut T) {
match self.collating_for {
Some(ref details) => {
dest.push_byte(1);
dest.push(details);
}
None => {
dest.push_byte(0);
}
}
}
}
impl Decode for Status {
fn decode<I: codec::Input>(input: &mut I) -> Option<Self> {
let collating_for = match input.read_byte()? {
0 => None,
1 => Some(Decode::decode(input)?),
_ => return None,
};
Some(Status { collating_for })
}
}
struct BlockDataRequest {
attempted_peers: HashSet<SessionKey>,
consensus_parent: Hash,
......@@ -207,7 +184,7 @@ impl CurrentConsensus {
}
/// Polkadot-specific messages.
#[derive(Debug)]
#[derive(Debug, Encode, Decode)]
pub enum Message {
/// signed statement and localized parent hash.
Statement(Hash, SignedStatement),
......@@ -224,59 +201,6 @@ pub enum Message {
Collation(Hash, Collation),
}
impl Encode for Message {
fn encode_to<T: Output>(&self, dest: &mut T) {
match *self {
Message::Statement(ref h, ref s) => {
dest.push_byte(0);
dest.push(h);
dest.push(s);
}
Message::SessionKey(ref k) => {
dest.push_byte(1);
dest.push(k);
}
Message::RequestBlockData(ref id, ref r, ref d) => {
dest.push_byte(2);
dest.push(id);
dest.push(r);
dest.push(d);
}
Message::BlockData(ref id, ref d) => {
dest.push_byte(3);
dest.push(id);
dest.push(d);
}
Message::CollatorRole(ref r) => {
dest.push_byte(4);
dest.push(r);
}
Message::Collation(ref h, ref c) => {
dest.push_byte(5);
dest.push(h);
dest.push(c);
}
}
}
}
impl Decode for Message {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
match input.read_byte()? {
0 => Some(Message::Statement(Decode::decode(input)?, Decode::decode(input)?)),
1 => Some(Message::SessionKey(Decode::decode(input)?)),
2 => {
let x: (_, _, _) = Decode::decode(input)?;
Some(Message::RequestBlockData(x.0, x.1, x.2))
}
3 => Some(Message::BlockData(Decode::decode(input)?, Decode::decode(input)?)),
4 => Some(Message::CollatorRole(Decode::decode(input)?)),
5 => Some(Message::Collation(Decode::decode(input)?, Decode::decode(input)?)),
_ => None,
}
}
}
fn send_polkadot_message(ctx: &mut Context<Block>, to: NodeIndex, message: Message) {
trace!(target: "p_net", "Sending polkadot message to {}: {:?}", to, message);
let encoded = message.encode();
......
......@@ -6,6 +6,7 @@ description = "Types and utilities for creating and working with parachains"
[dependencies]
substrate-codec = { path = "../../substrate/codec", default-features = false }
substrate-codec-derive = { path = "../../substrate/codec/derive", default-features = false }
wasmi = { version = "0.4", optional = true }
error-chain = { version = "0.12", optional = true }
......
......@@ -46,6 +46,9 @@
/// Re-export of substrate-codec.
pub extern crate substrate_codec as codec;
#[macro_use]
extern crate substrate_codec_derive;
#[cfg(not(feature = "std"))]
extern crate alloc;
......@@ -61,14 +64,14 @@ extern crate error_chain;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use codec::{Encode, Decode, Input, Output};
use codec::{Encode, Decode};
#[cfg(feature = "std")]
pub mod wasm;
/// Validation parameters for evaluating the parachain validity function.
// TODO: consolidated ingress and balance downloads
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct ValidationParams {
/// The collation body.
......@@ -77,45 +80,15 @@ pub struct ValidationParams {
pub parent_head: Vec<u8>,
}
impl Encode for ValidationParams {
fn encode_to<T: Output>(&self, dest: &mut T) {
dest.push(&self.block_data);
dest.push(&self.parent_head);
}
}
impl Decode for ValidationParams {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(ValidationParams {
block_data: Decode::decode(input)?,
parent_head: Decode::decode(input)?,
})
}
}
/// The result of parachain validation.
// TODO: egress and balance uploads
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct ValidationResult {
/// New head data that should be included in the relay chain state.
pub head_data: Vec<u8>
}
impl Encode for ValidationResult {
fn encode_to<T: Output>(&self, dest: &mut T) {
dest.push(&self.head_data);
}
}
impl Decode for ValidationResult {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(ValidationResult {
head_data: Decode::decode(input)?,
})
}
}
/// Load the validation params from memory when implementing a Rust parachain.
///
/// Offset and length must have been provided by the validation
......
......@@ -16,66 +16,35 @@
//! Basic parachain that adds a number as part of its state.
#[macro_use]
extern crate substrate_codec_derive;
extern crate substrate_codec as codec;
extern crate polkadot_parachain as parachain;
extern crate tiny_keccak;
use parachain::ValidationParams;
use parachain::codec::{Decode, Encode, Input, Output};
use codec::{Decode, Encode};
// Head data for this parachain.
#[derive(Default, Clone)]
/// Head data for this parachain.
#[derive(Default, Clone, Encode, Decode)]
struct HeadData {
// Block number
/// Block number
number: u64,
// parent block keccak256
/// parent block keccak256
parent_hash: [u8; 32],
// hash of post-execution state.
/// hash of post-execution state.
post_state: [u8; 32],
}
impl Encode for HeadData {
fn encode_to<T: Output>(&self, dest: &mut T) {
dest.push(&self.number);
dest.push(&self.parent_hash);
dest.push(&self.post_state);
}
}
impl Decode for HeadData {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(HeadData {
number: Decode::decode(input)?,
parent_hash: Decode::decode(input)?,
post_state: Decode::decode(input)?,
})
}
}
// Block data for this parachain.
#[derive(Default, Clone)]
/// Block data for this parachain.
#[derive(Default, Clone, Encode, Decode)]
struct BlockData {
// State to begin from.
/// State to begin from.
state: u64,
// Amount to add (overflowing)
/// Amount to add (overflowing)
add: u64,
}
impl Encode for BlockData {
fn encode_to<T: Output>(&self, dest: &mut T) {
dest.push(&self.state);
dest.push(&self.add);
}
}
impl Decode for BlockData {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(BlockData {
state: Decode::decode(input)?,
add: Decode::decode(input)?,
})
}
}
const TEST_CODE: &[u8] = include_bytes!("res/adder.wasm");
fn hash_state(state: u64) -> [u8; 32] {
......
......@@ -7,6 +7,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
serde = { version = "1.0", default_features = false }
serde_derive = { version = "1.0", optional = true }
substrate-codec = { path = "../../substrate/codec", default_features = false }
substrate-codec-derive = { path = "../../substrate/codec/derive", default_features = false }
substrate-primitives = { path = "../../substrate/primitives", default_features = false }
substrate-runtime-std = { path = "../../substrate/runtime-std", default_features = false }
substrate-runtime-primitives = { path = "../../substrate/runtime/primitives", default_features = false }
......
......@@ -21,13 +21,16 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]
extern crate substrate_runtime_std as rstd;
extern crate substrate_codec as codec;
extern crate substrate_primitives as primitives;
extern crate substrate_runtime_primitives as runtime_primitives;
extern crate substrate_runtime_std as rstd;
#[cfg(test)]
extern crate substrate_serializer;
extern crate substrate_codec as codec;
#[macro_use]
extern crate substrate_codec_derive;
#[cfg(feature = "std")]
#[macro_use]
......@@ -42,7 +45,6 @@ use primitives::bytes;
use rstd::prelude::*;
use runtime_primitives::traits::BlakeTwo256;
use runtime_primitives::generic;
use codec::{Encode, Decode, Input, Output};
pub mod parachain;
......@@ -105,18 +107,6 @@ pub type Balance = u128;
pub type BlockId = generic::BlockId<Block>;
/// A log entry in the block.
#[derive(PartialEq, Eq, Clone, Default)]
#[derive(PartialEq, Eq, Clone, Default, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct Log(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
impl Decode for Log {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Vec::<u8>::decode(input).map(Log)
}
}
impl Encode for Log {
fn encode_to<T: Output>(&self, dest: &mut T) {
self.0.encode_to(dest)
}
}
......@@ -16,7 +16,6 @@
//! Polkadot parachain types.
use codec::{Encode, Decode, Input, Output};
use rstd::prelude::*;
use rstd::cmp::Ordering;
use super::Hash;
......@@ -28,7 +27,7 @@ use primitives::bytes;
pub type CandidateSignature = ::runtime_primitives::Ed25519Signature;
/// Unique identifier of a parachain.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct Id(u32);
......@@ -47,20 +46,8 @@ impl Id {
}
}
impl Decode for Id {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
u32::decode(input).map(Id)
}
}
impl Encode for Id {
fn using_encoded<R, F: FnOnce(&[u8]) -> 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)]
#[derive(Copy, Clone, PartialEq, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum Chain {
/// The relay chain.
......@@ -69,31 +56,8 @@ pub enum Chain {
Parachain(Id),
}
impl Decode for Chain {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
let disc = input.read_byte()?;
match disc {
0 => Some(Chain::Relay),
1 => Some(Chain::Parachain(Decode::decode(input)?)),
_ => None,
}
}
}
impl Encode for Chain {
fn encode_to<T: Output>(&self, dest: &mut T) {
match *self {
Chain::Relay => { dest.push_byte(0); }
Chain::Parachain(id) => {
dest.push_byte(1u8);
dest.push(&id);
}
}
}
}
/// The duty roster specifying what jobs each validator must do.
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Encode, Decode)]
#[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.
......@@ -103,22 +67,6 @@ pub struct DutyRoster {
pub guarantor_duty: Vec<Chain>,
}
impl Decode for DutyRoster {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(DutyRoster {
validator_duty: Decode::decode(input)?,
guarantor_duty: Decode::decode(input)?,
})
}
}
impl Encode for DutyRoster {
fn encode_to<T: Output>(&self, dest: &mut T) {
dest.push(&self.validator_duty);
dest.push(&self.guarantor_duty);
}
}
/// Extrinsic data for a parachain.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
......@@ -127,7 +75,7 @@ impl Encode for DutyRoster {
pub struct Extrinsic;
/// Candidate receipt type.
#[derive(PartialEq, Eq, Clone)]
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
......@@ -150,34 +98,6 @@ pub struct CandidateReceipt {
pub block_data_hash: Hash,
}
impl Encode for CandidateReceipt {
fn encode_to<T: Output>(&self, dest: &mut T) {
dest.push(&self.parachain_index);
dest.push(&self.collator);
dest.push(&self.signature);
dest.push(&self.head_data.0);
dest.push(&self.balance_uploads);
dest.push(&self.egress_queue_roots);
dest.push(&self.fees);
dest.push(&self.block_data_hash);
}
}
impl Decode for CandidateReceipt {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(CandidateReceipt {
parachain_index: Decode::decode(input)?,
collator: Decode::decode(input)?,
signature: Decode::decode(input)?,
head_data: Decode::decode(input).map(HeadData)?,
balance_uploads: Decode::decode(input)?,
egress_queue_roots: Decode::decode(input)?,
fees: Decode::decode(input)?,
block_data_hash: Decode::decode(input)?,
})
}
}
impl CandidateReceipt {
/// Get the blake2_256 hash
#[cfg(feature = "std")]
......@@ -213,7 +133,7 @@ impl Ord for CandidateReceipt {
}
/// A full collation.
#[derive(PartialEq, Eq, Clone)]
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
......@@ -224,22 +144,6 @@ pub struct Collation {
pub receipt: CandidateReceipt,
}
impl Decode for Collation {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Collation {
block_data: Decode::decode(input)?,
receipt: Decode::decode(input)?,
})
}
}
impl Encode for Collation {
fn encode_to<T: Output>(&self, dest: &mut T) {
dest.push(&self.block_data);
dest.push(&self.receipt);
}
}
/// Parachain ingress queue message.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
......@@ -256,7 +160,7 @@ 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)]
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct BlockData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
......@@ -268,26 +172,13 @@ impl BlockData {
BlakeTwo256::hash(&self.0[..])
}
}
impl Decode for BlockData {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(BlockData(Decode::decode(input)?))
}
}
impl Encode for BlockData {
fn encode_to<T: Output>(&self, dest: &mut T) {
dest.push(&self.0);
}
}
/// Parachain header raw bytes wrapper type.
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, 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)]
#[derive(PartialEq, Eq, Clone, PartialOrd, Ord, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct HeadData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
......@@ -297,22 +188,10 @@ pub struct HeadData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8
pub struct ValidationCode(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
/// Activitiy bit field
#[derive(PartialEq, Eq, Clone, Default)]
#[derive(PartialEq, Eq, Clone, Default, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct Activity(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
impl Decode for Activity {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Vec::<u8>::decode(input).map(Activity)
}
}
impl Encode for Activity {
fn encode_to<T: Output>(&self, dest: &mut T) {
self.0.encode_to(dest)
}
}