From 20f3e9f63634d38174ddac66ae96b04e1ca42449 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan <arkady.paronyan@gmail.com> Date: Mon, 16 Jul 2018 15:28:31 +0200 Subject: [PATCH] Use substrate codec for network messages (#333) * Use substrate codec for network messages * Version bump * Removed redundant format --- polkadot/cli/src/lib.rs | 10 ++-- polkadot/network/Cargo.toml | 3 - polkadot/network/src/collator_pool.rs | 23 +++++++- polkadot/network/src/consensus.rs | 3 +- polkadot/network/src/lib.rs | 78 +++++++++++++++++++------ polkadot/network/src/tests.rs | 21 +++---- polkadot/primitives/src/parachain.rs | 28 +++++++++ polkadot/service/src/lib.rs | 4 +- polkadot/statement-table/Cargo.toml | 2 - polkadot/statement-table/src/generic.rs | 21 ++++++- polkadot/statement-table/src/lib.rs | 4 -- 11 files changed, 145 insertions(+), 52 deletions(-) diff --git a/polkadot/cli/src/lib.rs b/polkadot/cli/src/lib.rs index a4b1900d22d..791010b1287 100644 --- a/polkadot/cli/src/lib.rs +++ b/polkadot/cli/src/lib.rs @@ -222,19 +222,19 @@ pub fn run<I, T, W>(args: I, worker: W) -> error::Result<()> where // TODO [rob]: collation node implementation // This isn't a thing. Different parachains will have their own collator executables and // maybe link to libpolkadot to get a light-client. - service::Role::LIGHT + service::Roles::LIGHT } else if matches.is_present("light") { info!("Starting (light)"); config.execution_strategy = service::ExecutionStrategy::NativeWhenPossible; - service::Role::LIGHT + service::Roles::LIGHT } else if matches.is_present("validator") || matches.is_present("dev") { info!("Starting validator"); config.execution_strategy = service::ExecutionStrategy::Both; - service::Role::AUTHORITY + service::Roles::AUTHORITY } else { info!("Starting (heavy)"); config.execution_strategy = service::ExecutionStrategy::NativeWhenPossible; - service::Role::FULL + service::Roles::FULL }; if let Some(s) = matches.value_of("execution") { @@ -303,7 +303,7 @@ pub fn run<I, T, W>(args: I, worker: W) -> error::Result<()> where None }; - match role == service::Role::LIGHT { + match role == service::Roles::LIGHT { true => run_until_exit(&mut runtime, service::new_light(config, executor)?, &matches, sys_conf, worker)?, false => run_until_exit(&mut runtime, service::new_full(config, executor)?, &matches, sys_conf, worker)?, } diff --git a/polkadot/network/Cargo.toml b/polkadot/network/Cargo.toml index 71ab17d2aff..37d36ea205e 100644 --- a/polkadot/network/Cargo.toml +++ b/polkadot/network/Cargo.toml @@ -5,9 +5,6 @@ authors = ["Parity Technologies <admin@parity.io>"] description = "Polkadot-specific networking protocol" [dependencies] -serde = "1.0" -serde_derive = "1.0" -serde_json = "1.0" parking_lot = "0.4" polkadot-api = { path = "../api" } polkadot-consensus = { path = "../consensus" } diff --git a/polkadot/network/src/collator_pool.rs b/polkadot/network/src/collator_pool.rs index 12ddade1de1..7070eece88c 100644 --- a/polkadot/network/src/collator_pool.rs +++ b/polkadot/network/src/collator_pool.rs @@ -18,6 +18,7 @@ use polkadot_primitives::{AccountId, Hash}; use polkadot_primitives::parachain::{Id as ParaId, Collation}; +use codec; use futures::sync::oneshot; @@ -27,12 +28,28 @@ 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, Serialize, Deserialize)] +#[derive(PartialEq, Debug, Clone, Copy)] pub enum Role { /// Primary collators should send collations whenever it's time. - Primary, + Primary = 0, /// Backup collators should not. - Backup, + 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. diff --git a/polkadot/network/src/consensus.rs b/polkadot/network/src/consensus.rs index 5b6570dc9ec..6b1b141ecac 100644 --- a/polkadot/network/src/consensus.rs +++ b/polkadot/network/src/consensus.rs @@ -26,6 +26,7 @@ use polkadot_api::{PolkadotApi, LocalPolkadotApi}; use polkadot_consensus::{Network, SharedTable, Collators}; use polkadot_primitives::{AccountId, Block, Hash, SessionKey}; use polkadot_primitives::parachain::{Id as ParaId, Collation}; +use codec::Decode; use futures::prelude::*; use futures::sync::mpsc; @@ -175,7 +176,7 @@ impl<P: LocalPolkadotApi + Send + Sync + 'static> MessageProcessTask<P> { } } ConsensusMessage::ChainSpecific(msg, _) => { - if let Ok(Message::Statement(parent_hash, statement)) = ::serde_json::from_slice(&msg) { + if let Some(Message::Statement(parent_hash, statement)) = Decode::decode(&mut msg.as_slice()) { if ::polkadot_consensus::check_statement(&statement.statement, &statement.signature, statement.sender, &parent_hash) { self.table_router.import_statement(statement); } diff --git a/polkadot/network/src/lib.rs b/polkadot/network/src/lib.rs index b419c9c88d2..7ccd69ea66b 100644 --- a/polkadot/network/src/lib.rs +++ b/polkadot/network/src/lib.rs @@ -20,11 +20,6 @@ //! parachain block and extrinsic data fetching, communication between collators and validators, //! and more. -extern crate serde; -#[macro_use] -extern crate serde_derive; -extern crate serde_json; - extern crate substrate_bft as bft; extern crate substrate_codec as codec; extern crate substrate_network; @@ -47,7 +42,7 @@ mod collator_pool; mod router; pub mod consensus; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, Input, Output}; use futures::sync::oneshot; use parking_lot::Mutex; use polkadot_consensus::{Statement, SignedStatement, GenericStatement}; @@ -188,7 +183,6 @@ impl CurrentConsensus { } /// Polkadot-specific messages. -#[derive(Serialize, Deserialize)] pub enum Message { /// signed statement and localized parent hash. Statement(Hash, SignedStatement), @@ -205,8 +199,58 @@ 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 h, ref k) => { + dest.push_byte(1); + dest.push(h); + dest.push(k); + } + Message::RequestBlockData(ref id, ref d) => { + dest.push_byte(2); + dest.push(id); + 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)?, Decode::decode(input)?)), + 2 => Some(Message::RequestBlockData(Decode::decode(input)?, Decode::decode(input)?)), + 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: PeerId, message: Message) { - let encoded = ::serde_json::to_vec(&message).expect("serialization of messages infallible; qed"); + let encoded = message.encode(); ctx.send_message(to, generic_message::Message::ChainSpecific(encoded)) } @@ -244,9 +288,7 @@ impl PolkadotProtocol { /// Send a statement to a validator. fn send_statement(&mut self, ctx: &mut Context<Block>, _val: SessionKey, parent_hash: Hash, statement: SignedStatement) { // TODO: something more targeted than gossip. - let raw = ::serde_json::to_vec(&Message::Statement(parent_hash, statement)) - .expect("message serialization infallible; qed"); - + let raw = Message::Statement(parent_hash, statement).encode(); self.consensus_gossip.multicast_chain_specific(ctx, raw, parent_hash); } @@ -427,7 +469,7 @@ impl Specialization<Block> for PolkadotProtocol { ); } - let validator = status.roles.iter().any(|r| *r == message::Role::Authority); + let validator = status.roles.contains(substrate_network::Roles::AUTHORITY); let send_key = validator || local_status.collating_for.is_some(); self.peers.insert(peer_id, PeerInfo { @@ -436,7 +478,7 @@ impl Specialization<Block> for PolkadotProtocol { validator, }); - self.consensus_gossip.new_peer(ctx, peer_id, &status.roles); + self.consensus_gossip.new_peer(ctx, peer_id, status.roles); if let (true, &Some(ref consensus)) = (send_key, &self.live_consensus) { send_polkadot_message( ctx, @@ -497,11 +539,11 @@ impl Specialization<Block> for PolkadotProtocol { self.consensus_gossip.on_bft_message(ctx, peer_id, msg) } generic_message::Message::ChainSpecific(raw) => { - match serde_json::from_slice(&raw) { - Ok(msg) => self.on_polkadot_message(ctx, peer_id, raw, msg), - Err(e) => { - trace!(target: "p_net", "Bad message from {}: {}", peer_id, e); - ctx.disable_peer(peer_id, "Unknown Polkadot-protocol reason"); + match Message::decode(&mut raw.as_slice()) { + Some(msg) => self.on_polkadot_message(ctx, peer_id, raw, msg), + None => { + trace!(target: "p_net", "Bad message from {}", peer_id); + ctx.disable_peer(peer_id, "Invalid polkadot protocol message format"); } } } diff --git a/polkadot/network/src/tests.rs b/polkadot/network/src/tests.rs index deec3b8129d..06d679dcd0e 100644 --- a/polkadot/network/src/tests.rs +++ b/polkadot/network/src/tests.rs @@ -24,7 +24,7 @@ use polkadot_primitives::{Block, Hash, SessionKey}; use polkadot_primitives::parachain::{CandidateReceipt, HeadData, BlockData}; use substrate_primitives::H512; use codec::Encode; -use substrate_network::{PeerId, PeerInfo, ClientHandle, Context, message::Message as SubstrateMessage, message::Role, specialization::Specialization, generic_message::Message as GenericMessage}; +use substrate_network::{PeerId, PeerInfo, ClientHandle, Context, Roles, message::Message as SubstrateMessage, specialization::Specialization, generic_message::Message as GenericMessage}; use std::sync::Arc; use futures::Future; @@ -62,7 +62,7 @@ impl TestContext { fn has_message(&self, to: PeerId, message: Message) -> bool { use substrate_network::generic_message::Message as GenericMessage; - let encoded = ::serde_json::to_vec(&message).unwrap(); + let encoded = message.encode(); self.messages.iter().any(|&(ref peer, ref msg)| match msg { GenericMessage::ChainSpecific(ref data) => peer == &to && data == &encoded, _ => false, @@ -70,7 +70,7 @@ impl TestContext { } } -fn make_status(status: &Status, roles: Vec<Role>) -> FullStatus { +fn make_status(status: &Status, roles: Roles) -> FullStatus { FullStatus { version: 1, roles, @@ -78,9 +78,6 @@ fn make_status(status: &Status, roles: Vec<Role>) -> FullStatus { best_hash: Default::default(), genesis_hash: Default::default(), chain_status: status.encode(), - parachain_id: None, - validator_id: None, - validator_signature: None, } } @@ -97,7 +94,7 @@ fn make_consensus(parent_hash: Hash, local_key: SessionKey) -> (CurrentConsensus } fn on_message(protocol: &mut PolkadotProtocol, ctx: &mut TestContext, from: PeerId, message: Message) { - let encoded = ::serde_json::to_vec(&message).unwrap(); + let encoded = message.encode(); protocol.on_message(ctx, from, GenericMessage::ChainSpecific(encoded)); } @@ -115,7 +112,7 @@ fn sends_session_key() { { let mut ctx = TestContext::default(); - protocol.on_connect(&mut ctx, peer_a, make_status(&validator_status, vec![Role::Authority])); + protocol.on_connect(&mut ctx, peer_a, make_status(&validator_status, Roles::AUTHORITY)); assert!(ctx.messages.is_empty()); } @@ -129,7 +126,7 @@ fn sends_session_key() { { let mut ctx = TestContext::default(); - protocol.on_connect(&mut ctx, peer_b, make_status(&collator_status, vec![])); + protocol.on_connect(&mut ctx, peer_b, make_status(&collator_status, Roles::NONE)); assert!(ctx.has_message(peer_b, Message::SessionKey(parent_hash, local_key))); } } @@ -171,7 +168,7 @@ fn fetches_from_those_with_knowledge() { // connect peer A { let mut ctx = TestContext::default(); - protocol.on_connect(&mut ctx, peer_a, make_status(&status, vec![Role::Authority])); + protocol.on_connect(&mut ctx, peer_a, make_status(&status, Roles::AUTHORITY)); assert!(ctx.has_message(peer_a, Message::SessionKey(parent_hash, local_key))); } @@ -187,7 +184,7 @@ fn fetches_from_those_with_knowledge() { // peer B connects and sends session key. request already assigned to A { let mut ctx = TestContext::default(); - protocol.on_connect(&mut ctx, peer_b, make_status(&status, vec![Role::Authority])); + protocol.on_connect(&mut ctx, peer_b, make_status(&status, Roles::AUTHORITY)); on_message(&mut protocol, &mut ctx, peer_b, Message::SessionKey(parent_hash, b_key)); assert!(!ctx.has_message(peer_b, Message::RequestBlockData(2, candidate_hash))); @@ -220,7 +217,7 @@ fn remove_bad_collator() { { let mut ctx = TestContext::default(); - protocol.on_connect(&mut ctx, peer_id, make_status(&status, vec![])); + protocol.on_connect(&mut ctx, peer_id, make_status(&status, Roles::NONE)); } { diff --git a/polkadot/primitives/src/parachain.rs b/polkadot/primitives/src/parachain.rs index 31ba6463285..ff7580067e1 100644 --- a/polkadot/primitives/src/parachain.rs +++ b/polkadot/primitives/src/parachain.rs @@ -224,6 +224,22 @@ 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))] @@ -253,6 +269,18 @@ impl BlockData { } } +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))] diff --git a/polkadot/service/src/lib.rs b/polkadot/service/src/lib.rs index a9952261a08..ed650ae680b 100644 --- a/polkadot/service/src/lib.rs +++ b/polkadot/service/src/lib.rs @@ -52,7 +52,7 @@ use client::Client; use polkadot_network::{PolkadotProtocol, consensus::ConsensusNetwork}; use tokio::runtime::TaskExecutor; -pub use service::{Configuration, Role, PruningMode, ExtrinsicPoolOptions, +pub use service::{Configuration, Roles, PruningMode, ExtrinsicPoolOptions, ErrorKind, Error, ComponentBlock, LightComponents, FullComponents}; pub use client::ExecutionStrategy; @@ -166,7 +166,7 @@ pub fn new_light(config: Configuration<GenesisConfig>, executor: TaskExecutor) pub fn new_full(config: Configuration<GenesisConfig>, executor: TaskExecutor) -> Result<Service<FullComponents<Factory>>, Error> { - let is_validator = (config.roles & Role::AUTHORITY) == Role::AUTHORITY; + let is_validator = (config.roles & Roles::AUTHORITY) == Roles::AUTHORITY; let service = service::Service::<FullComponents<Factory>>::new(config, executor.clone())?; // Spin consensus service if configured let consensus = if is_validator { diff --git a/polkadot/statement-table/Cargo.toml b/polkadot/statement-table/Cargo.toml index 2e9120a4f09..b81ee1db907 100644 --- a/polkadot/statement-table/Cargo.toml +++ b/polkadot/statement-table/Cargo.toml @@ -7,5 +7,3 @@ authors = ["Parity Technologies <admin@parity.io>"] substrate-codec = { path = "../../substrate/codec" } substrate-primitives = { path = "../../substrate/primitives" } polkadot-primitives = { path = "../primitives" } -serde = "1.0" -serde_derive = "1.0" diff --git a/polkadot/statement-table/src/generic.rs b/polkadot/statement-table/src/generic.rs index 56740288f8e..06f9f942927 100644 --- a/polkadot/statement-table/src/generic.rs +++ b/polkadot/statement-table/src/generic.rs @@ -70,7 +70,7 @@ pub trait Context { } /// Statements circulated among peers. -#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Debug, Clone)] pub enum Statement<C, D> { /// Broadcast by a authority to indicate that this is his candidate for /// inclusion. @@ -141,7 +141,7 @@ impl<C: Decode, D: Decode> Decode for Statement<C, D> { } /// A signed statement. -#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Debug, Clone)] pub struct SignedStatement<C, D, V, S> { /// The statement. pub statement: Statement<C, D>, @@ -151,6 +151,23 @@ pub struct SignedStatement<C, D, V, S> { pub sender: V, } +impl<C: Encode, D: Encode, V: Encode, S: Encode> Encode for SignedStatement<C, D, V, S> { + fn encode_to<T: Output>(&self, dest: &mut T) { + dest.push(&self.statement); + dest.push(&self.signature); + dest.push(&self.sender); + } +} + +impl<C: Decode, D: Decode, V: Decode, S: Decode> Decode for SignedStatement<C, D, V, S> { + fn decode<I: Input>(value: &mut I) -> Option<Self> { + Some(SignedStatement { + statement: Decode::decode(value)?, + signature: Decode::decode(value)?, + sender: Decode::decode(value)?, + }) + } +} /// Misbehavior: voting more than one way on candidate validity. /// /// Since there are three possible ways to vote, a double vote is possible in diff --git a/polkadot/statement-table/src/lib.rs b/polkadot/statement-table/src/lib.rs index 779a7fc2df5..ecbe832b6a5 100644 --- a/polkadot/statement-table/src/lib.rs +++ b/polkadot/statement-table/src/lib.rs @@ -18,10 +18,6 @@ extern crate substrate_codec as codec; extern crate substrate_primitives; extern crate polkadot_primitives as primitives; -extern crate serde; -#[macro_use] -extern crate serde_derive; - pub mod generic; pub use generic::Table; -- GitLab