diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 6a8b5b8946bb9029730d737bc9350d437b32d9b9..7fe0b0e3cfd9c042bc5e6a7b5119486580c20dc1 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -1917,9 +1917,6 @@ dependencies = [ "polkadot-consensus 0.1.0", "polkadot-primitives 0.1.0", "rhododendron 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-bft 0.1.0", "substrate-codec 0.1.0", "substrate-network 0.1.0", @@ -2014,8 +2011,6 @@ name = "polkadot-statement-table" version = "0.1.0" dependencies = [ "polkadot-primitives 0.1.0", - "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-codec 0.1.0", "substrate-primitives 0.1.0", ] @@ -2765,19 +2760,12 @@ dependencies = [ "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", - "substrate-bft 0.1.0", "substrate-client 0.1.0", "substrate-codec 0.1.0", "substrate-keyring 0.1.0", "substrate-network-libp2p 0.1.0", "substrate-primitives 0.1.0", "substrate-runtime-primitives 0.1.0", - "substrate-runtime-support 0.1.0", - "substrate-serializer 0.1.0", "substrate-test-client 0.1.0", ] diff --git a/substrate/polkadot/cli/src/lib.rs b/substrate/polkadot/cli/src/lib.rs index a4b1900d22d31191d151f0c8518fcdf017595e95..791010b12876a5a810718a3f198e8eb4156e5b8c 100644 --- a/substrate/polkadot/cli/src/lib.rs +++ b/substrate/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/substrate/polkadot/network/Cargo.toml b/substrate/polkadot/network/Cargo.toml index 71ab17d2affb93dd1ac357476eca75bac9b199e7..37d36ea205e50d07d30e52d26cbb0c8ffc83fc15 100644 --- a/substrate/polkadot/network/Cargo.toml +++ b/substrate/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/substrate/polkadot/network/src/collator_pool.rs b/substrate/polkadot/network/src/collator_pool.rs index 12ddade1de1e87f2e8562741d4992afc8311b606..7070eece88c20cd74738c0f8d78f728179f47f04 100644 --- a/substrate/polkadot/network/src/collator_pool.rs +++ b/substrate/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/substrate/polkadot/network/src/consensus.rs b/substrate/polkadot/network/src/consensus.rs index 5b6570dc9ec4d7c8d5de767151bb5d94b4ab5576..6b1b141ecacf9411da29546f31adf013a63f4b40 100644 --- a/substrate/polkadot/network/src/consensus.rs +++ b/substrate/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/substrate/polkadot/network/src/lib.rs b/substrate/polkadot/network/src/lib.rs index b419c9c88d27d49e65eb02674935892a9532b24d..7ccd69ea66b0f7a2380cab1d7ffccf906abbbc08 100644 --- a/substrate/polkadot/network/src/lib.rs +++ b/substrate/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/substrate/polkadot/network/src/tests.rs b/substrate/polkadot/network/src/tests.rs index deec3b8129d0af237fc311cff4f1bc00ac29e593..06d679dcd0eb5e688b3348afcf81bb8584330b8b 100644 --- a/substrate/polkadot/network/src/tests.rs +++ b/substrate/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/substrate/polkadot/primitives/src/parachain.rs b/substrate/polkadot/primitives/src/parachain.rs index 31ba646328511dd462cd9773f57f691c7fe0277b..ff7580067e1019ce78939ad5b33625dd01abee13 100644 --- a/substrate/polkadot/primitives/src/parachain.rs +++ b/substrate/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/substrate/polkadot/service/src/lib.rs b/substrate/polkadot/service/src/lib.rs index a9952261a082e931589f0106c4151178462b909d..ed650ae680b17135e05997c8d6b88ce26374ef17 100644 --- a/substrate/polkadot/service/src/lib.rs +++ b/substrate/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/substrate/polkadot/statement-table/Cargo.toml b/substrate/polkadot/statement-table/Cargo.toml index 2e9120a4f0939fbcb52a860db31f51beb9ae2257..b81ee1db907e18789b3d229e05991ebd5aab89fd 100644 --- a/substrate/polkadot/statement-table/Cargo.toml +++ b/substrate/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/substrate/polkadot/statement-table/src/generic.rs b/substrate/polkadot/statement-table/src/generic.rs index 56740288f8e7448680dca83f8a9c444d27579613..06f9f94292799faf7720b8320925499b43fff048 100644 --- a/substrate/polkadot/statement-table/src/generic.rs +++ b/substrate/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/substrate/polkadot/statement-table/src/lib.rs b/substrate/polkadot/statement-table/src/lib.rs index 779a7fc2df5fd4309dfd9ca7e0e527117390b955..ecbe832b6a530568fb588e35c0659326fc79b62b 100644 --- a/substrate/polkadot/statement-table/src/lib.rs +++ b/substrate/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; diff --git a/substrate/substrate/network/Cargo.toml b/substrate/substrate/network/Cargo.toml index 930f5307c3d390608c62f4e3a5c014f96101ca78..0185cf49f2216d9fd8838d05e4ff3ba047b35eca 100644 --- a/substrate/substrate/network/Cargo.toml +++ b/substrate/substrate/network/Cargo.toml @@ -9,23 +9,16 @@ authors = ["Parity Technologies <admin@parity.io>"] [dependencies] log = "0.3" -rand = "0.3" parking_lot = "0.4" error-chain = "0.12" bitflags = "1.0" -serde = "1.0" -serde_derive = "1.0" -serde_json = "1.0" futures = "0.1.17" linked-hash-map = "0.5" ethcore-io = { git = "https://github.com/paritytech/parity.git" } ed25519 = { path = "../../substrate/ed25519" } substrate-primitives = { path = "../../substrate/primitives" } substrate-client = { path = "../../substrate/client" } -substrate-serializer = { path = "../../substrate/serializer" } -substrate-runtime-support = { path = "../../substrate/runtime-support" } substrate-runtime-primitives = { path = "../../substrate/runtime/primitives" } -substrate-bft = { path = "../../substrate/bft" } substrate-codec = { path = "../../substrate/codec" } substrate-network-libp2p = { path = "../../substrate/network-libp2p" } diff --git a/substrate/substrate/network/src/config.rs b/substrate/substrate/network/src/config.rs index 7e21a5ded3b0276a1daecd3951dbdf4e2abb82e5..008b662b872914b2ddc8f9d4f694533b0af5da01 100644 --- a/substrate/substrate/network/src/config.rs +++ b/substrate/substrate/network/src/config.rs @@ -14,19 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.? -pub use service::Role; +pub use service::Roles; /// Protocol configuration #[derive(Clone)] pub struct ProtocolConfig { /// Assigned roles. - pub roles: Role, + pub roles: Roles, } impl Default for ProtocolConfig { fn default() -> ProtocolConfig { ProtocolConfig { - roles: Role::FULL, + roles: Roles::FULL, } } } diff --git a/substrate/substrate/network/src/consensus_gossip.rs b/substrate/substrate/network/src/consensus_gossip.rs index 37925d302a33d08cb494d480eabcb24808f818ce..bff296acdeed3a6677bf474fe80a3e4e37d10aec 100644 --- a/substrate/substrate/network/src/consensus_gossip.rs +++ b/substrate/substrate/network/src/consensus_gossip.rs @@ -25,6 +25,7 @@ use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; use runtime_primitives::generic::BlockId; use message::{self, generic::Message as GenericMessage}; use protocol::Context; +use service::Roles; // TODO: Add additional spam/DoS attack protection. const MESSAGE_LIFETIME: Duration = Duration::from_secs(600); @@ -73,8 +74,8 @@ impl<B: BlockT> ConsensusGossip<B> where B::Header: HeaderT<Number=u64> { } /// Handle new connected peer. - pub fn new_peer(&mut self, protocol: &mut Context<B>, peer_id: PeerId, roles: &[message::Role]) { - if roles.iter().any(|r| *r == message::Role::Validator) { + pub fn new_peer(&mut self, protocol: &mut Context<B>, peer_id: PeerId, roles: Roles) { + if roles.contains(Roles::AUTHORITY) { trace!(target:"gossip", "Registering authority {}", peer_id); // Send out all known messages. // TODO: limit by size diff --git a/substrate/substrate/network/src/lib.rs b/substrate/substrate/network/src/lib.rs index b0e3e7c7e46a0596b2babee193fc7b0084987d40..9319918db15d7c1c31c4ada45b5191f18b026c15 100644 --- a/substrate/substrate/network/src/lib.rs +++ b/substrate/substrate/network/src/lib.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.? +#![warn(unused_extern_crates)] #![warn(missing_docs)] //! Substrate-specific P2P networking: synchronizing blocks, propagating BFT messages. @@ -21,21 +22,14 @@ extern crate ethcore_io as core_io; extern crate linked_hash_map; -extern crate rand; extern crate parking_lot; extern crate substrate_primitives as primitives; -extern crate substrate_serializer as ser; extern crate substrate_client as client; -extern crate substrate_runtime_support as runtime_support; extern crate substrate_runtime_primitives as runtime_primitives; extern crate substrate_network_libp2p as network_libp2p; -extern crate substrate_bft; extern crate substrate_codec as codec; -extern crate serde; -extern crate serde_json; extern crate futures; extern crate ed25519; -#[macro_use] extern crate serde_derive; #[macro_use] extern crate log; #[macro_use] extern crate bitflags; #[macro_use] extern crate error_chain; @@ -67,5 +61,5 @@ pub use sync::{Status as SyncStatus, SyncState}; pub use network_libp2p::{NonReservedPeerMode, NetworkConfiguration, PeerId, ProtocolId, ConnectionFilter, ConnectionDirection}; pub use message::{generic as generic_message, RequestId, BftMessage, LocalizedBftMessage, ConsensusVote, SignedConsensusVote, SignedConsensusMessage, SignedConsensusProposal, Status as StatusMessage}; pub use error::Error; -pub use config::{Role, ProtocolConfig}; +pub use config::{Roles, ProtocolConfig}; pub use on_demand::{OnDemand, OnDemandService, RemoteCallResponse}; diff --git a/substrate/substrate/network/src/message.rs b/substrate/substrate/network/src/message.rs index a0f863c406da45302b87d5fef897059028de2439..341dccaa2a2b6ec2f7eed86d846c4de0643d24f2 100644 --- a/substrate/substrate/network/src/message.rs +++ b/substrate/substrate/network/src/message.rs @@ -17,9 +17,8 @@ //! Network packet message types. These get serialized and put into the lower level protocol payload. use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; -use service::Role as RoleFlags; - -pub use self::generic::{BlockAnnounce, RemoteCallRequest, ConsensusVote, SignedConsensusVote, FromBlock, Body}; +use codec::{Encode, Decode, Input, Output}; +pub use self::generic::{BlockAnnounce, RemoteCallRequest, ConsensusVote, SignedConsensusVote, FromBlock}; /// A unique ID of a request. pub type RequestId = u64; @@ -86,76 +85,34 @@ pub type SignedConsensusMessage<B> = generic::SignedConsensusProposal< /// A set of transactions. pub type Transactions<E> = Vec<E>; -/// Configured node role. -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub enum Role { - /// Full node with no additional responsibilities. - Full, - /// Light client. - Light, - /// Parachain validator. - Authority, - /// Same as `Authority` - Validator, -} - -impl Role { - /// Convert enum to service flags. - pub fn as_flags(roles: &[Role]) -> RoleFlags { - let mut flags = RoleFlags::NONE; - for r in roles { - match *r { - Role::Full => flags = flags | RoleFlags::FULL, - Role::Light => flags = flags | RoleFlags::LIGHT, - Role::Authority | Role::Validator => flags = flags | RoleFlags::AUTHORITY, - } - } - flags - } -} - -impl From<RoleFlags> for Vec<Role> where { - fn from(flags: RoleFlags) -> Vec<Role> { - let mut roles = Vec::new(); - if !(flags & RoleFlags::FULL).is_empty() { - roles.push(Role::Full); - } - if !(flags & RoleFlags::LIGHT).is_empty() { - roles.push(Role::Light); - } - if !(flags & RoleFlags::AUTHORITY).is_empty() { - roles.push(Role::Validator); - } - roles - } -} - /// Bits of block data and associated artefacts to request. -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Copy, Clone)] -pub enum BlockAttribute { - /// Include block header. - Header, - /// Include block body. - Body, - /// Include block receipt. - Receipt, - /// Include block message queue. - MessageQueue, - /// Include a justification for the block. - Justification, +bitflags! { + /// Node roles bitmask. + pub struct BlockAttributes: u8 { + /// Include block header. + const HEADER = 0b00000001; + /// Include block body. + const BODY = 0b00000010; + /// Include block receipt. + const RECEIPT = 0b00000100; + /// Include block message queue. + const MESSAGE_QUEUE = 0b00001000; + /// Include a justification for the block. + const JUSTIFICATION = 0b00010000; + } } -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] /// Block enumeration direction. pub enum Direction { /// Enumerate in ascending order (from child to parent). - Ascending, + Ascending = 0, /// Enumerate in descendfing order (from parent to canonical child). - Descending, + Descending = 1, } /// Remote call response. -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct RemoteCallResponse { /// Id of a request this response was made for. pub id: RequestId, @@ -163,106 +120,75 @@ pub struct RemoteCallResponse { pub proof: Vec<Vec<u8>>, } +impl Encode for RemoteCallResponse { + fn encode_to<T: Output>(&self, dest: &mut T) { + dest.push(&self.id); + dest.push(&self.proof); + } +} + +impl Decode for RemoteCallResponse { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + Some(RemoteCallResponse { + id: Decode::decode(input)?, + proof: Decode::decode(input)?, + }) + } +} + /// Generic types. pub mod generic { use primitives::AuthorityId; - use codec::{Codec, Decode, Encode}; + use codec::{Decode, Encode, Input, Output}; use runtime_primitives::bft::Justification; use ed25519; - use primitives::Signature; - - use super::{Role, BlockAttribute, RemoteCallResponse, RequestId, Transactions, Direction}; - - use primitives::bytes; - - /// Emulates Poc-1 extrinsic primitive. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] - pub struct V1Extrinsic(#[serde(with="bytes")] pub Vec<u8>); - // Alternative block format for poc-1 compatibility. - // TODO: remove this after poc-2 - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] - #[serde(untagged)] - /// Serialized block body type. - pub enum Body<Extrinsic> { - /// Poc-1. Extrinsics as bytes. - V1(Vec<V1Extrinsic>), - /// Poc-2 or later. A structured type. - Extrinsics(Vec<Extrinsic>), - } - - impl<Extrinsic> Body<Extrinsic> where Extrinsic: Codec { - /// Extracts extrinsic from the body. - pub fn to_extrinsics(self) -> Vec<Extrinsic> { - match self { - Body::Extrinsics(e) => e, - Body::V1(e) => { - e.into_iter().filter_map(|bytes| { - let bytes = bytes.0.encode(); - Decode::decode(&mut bytes.as_slice()) - }).collect() - } - } - } - } + use service::Roles; + use super::{BlockAttributes, RemoteCallResponse, RequestId, Transactions, Direction}; - /// Emulates Poc-1 justification format. - #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] - pub struct V1Justification<H> { - /// The round consensus was reached in. - pub round_number: u32, - /// The hash of the header justified. - pub hash: H, - /// The signatures and signers of the hash. - pub signatures: Vec<([u8; 32], Signature)> - } - - // TODO: remove this after poc-2 - /// Justification back compat - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] - #[serde(untagged)] - pub enum BlockJustification<H> { - /// Poc-1 format. - V1(V1Justification<H>), - /// Poc-2 format. - V2(Justification<H>), - } - - impl<H> BlockJustification<H> { - /// Convert to PoC-2 justification format. - pub fn to_justification(self) -> Justification<H> { - match self { - BlockJustification::V2(j) => j, - BlockJustification::V1(j) => { - Justification { - round_number: j.round_number, - hash: j.hash, - signatures: j.signatures.into_iter().map(|(a, s)| (a.into(), s)).collect(), - } - } - } - } - } /// Block data sent in the response. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub struct BlockData<Header, Hash, Extrinsic> { /// Block header hash. pub hash: Hash, /// Block header if requested. pub header: Option<Header>, /// Block body if requested. - pub body: Option<Body<Extrinsic>>, + pub body: Option<Vec<Extrinsic>>, /// Block receipt if requested. pub receipt: Option<Vec<u8>>, /// Block message queue if requested. pub message_queue: Option<Vec<u8>>, /// Justification if requested. - pub justification: Option<BlockJustification<Hash>>, + pub justification: Option<Justification<Hash>>, + } + + impl<Header: Encode, Hash: Encode, Extrinsic: Encode> Encode for BlockData<Header, Hash, Extrinsic> { + fn encode_to<T: Output>(&self, dest: &mut T) { + dest.push(&self.hash); + dest.push(&self.header); + dest.push(&self.body); + dest.push(&self.receipt); + dest.push(&self.message_queue); + dest.push(&self.justification); + } + } + + impl<Header: Decode, Hash: Decode, Extrinsic: Decode> Decode for BlockData<Header, Hash, Extrinsic> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + Some(BlockData { + hash: Decode::decode(input)?, + header: Decode::decode(input)?, + body: Decode::decode(input)?, + receipt: Decode::decode(input)?, + message_queue: Decode::decode(input)?, + justification: Decode::decode(input)?, + }) + } } /// Identifies starting point of a block sequence. - #[serde(untagged)] - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub enum FromBlock<Hash, Number> { /// Start with given hash. Hash(Hash), @@ -270,8 +196,33 @@ pub mod generic { Number(Number), } + impl<Hash: Encode, Number: Encode> Encode for FromBlock<Hash, Number> { + fn encode_to<T: Output>(&self, dest: &mut T) { + match *self { + FromBlock::Hash(ref h) => { + dest.push_byte(0); + dest.push(h); + } + FromBlock::Number(ref n) => { + dest.push_byte(1); + dest.push(n); + } + } + } + } + + impl<Hash: Decode, Number: Decode> Decode for FromBlock<Hash, Number> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + match input.read_byte()? { + 0 => Some(FromBlock::Hash(Decode::decode(input)?)), + 1 => Some(FromBlock::Number(Decode::decode(input)?)), + _ => None, + } + } + } + /// Communication that can occur between participants in consensus. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub enum BftMessage<Block, Hash> { /// A consensus message (proposal or vote) Consensus(SignedConsensusMessage<Block, Hash>), @@ -279,8 +230,33 @@ pub mod generic { Auxiliary(Justification<Hash>), } + impl<Block: Encode, Hash: Encode> Encode for BftMessage<Block, Hash> { + fn encode_to<T: Output>(&self, dest: &mut T) { + match *self { + BftMessage::Consensus(ref h) => { + dest.push_byte(0); + dest.push(h); + } + BftMessage::Auxiliary(ref n) => { + dest.push_byte(1); + dest.push(n); + } + } + } + } + + impl<Block: Decode, Hash: Decode> Decode for BftMessage<Block, Hash> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + match input.read_byte()? { + 0 => Some(BftMessage::Consensus(Decode::decode(input)?)), + 1 => Some(BftMessage::Auxiliary(Decode::decode(input)?)), + _ => None, + } + } + } + /// BFT Consensus message with parent header hash attached to it. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub struct LocalizedBftMessage<Block, Hash> { /// Consensus message. pub message: BftMessage<Block, Hash>, @@ -288,8 +264,24 @@ pub mod generic { pub parent_hash: Hash, } + impl<Block: Encode, Hash: Encode> Encode for LocalizedBftMessage<Block, Hash> { + fn encode_to<T: Output>(&self, dest: &mut T) { + dest.push(&self.message); + dest.push(&self.parent_hash); + } + } + + impl<Block: Decode, Hash: Decode> Decode for LocalizedBftMessage<Block, Hash> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + Some(LocalizedBftMessage { + message: Decode::decode(input)?, + parent_hash: Decode::decode(input)?, + }) + } + } + /// A localized proposal message. Contains two signed pieces of data. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub struct SignedConsensusProposal<Block, Hash> { /// The round number. pub round_number: u32, @@ -305,8 +297,32 @@ pub mod generic { pub full_signature: ed25519::Signature, } + impl<Block: Encode, Hash: Encode> Encode for SignedConsensusProposal<Block, Hash> { + fn encode_to<T: Output>(&self, dest: &mut T) { + dest.push(&self.round_number); + dest.push(&self.proposal); + dest.push(&self.digest); + dest.push(&self.sender); + dest.push(&self.digest_signature); + dest.push(&self.full_signature); + } + } + + impl<Block: Decode, Hash: Decode> Decode for SignedConsensusProposal<Block, Hash> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + Some(SignedConsensusProposal { + round_number: Decode::decode(input)?, + proposal: Decode::decode(input)?, + digest: Decode::decode(input)?, + sender: Decode::decode(input)?, + digest_signature: Decode::decode(input)?, + full_signature: Decode::decode(input)?, + }) + } + } + /// A localized vote message, including the sender. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub struct SignedConsensusVote<H> { /// The message sent. pub vote: ConsensusVote<H>, @@ -316,8 +332,26 @@ pub mod generic { pub signature: ed25519::Signature, } + impl<Hash: Encode> Encode for SignedConsensusVote<Hash> { + fn encode_to<T: Output>(&self, dest: &mut T) { + dest.push(&self.vote); + dest.push(&self.sender); + dest.push(&self.signature); + } + } + + impl<Hash: Decode> Decode for SignedConsensusVote<Hash> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + Some(SignedConsensusVote { + vote: Decode::decode(input)?, + sender: Decode::decode(input)?, + signature: Decode::decode(input)?, + }) + } + } + /// Votes during a consensus round. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub enum ConsensusVote<H> { /// Prepare to vote for proposal with digest D. Prepare(u32, H), @@ -327,8 +361,40 @@ pub mod generic { AdvanceRound(u32), } + impl<Hash: Encode> Encode for ConsensusVote<Hash> { + fn encode_to<T: Output>(&self, dest: &mut T) { + match *self { + ConsensusVote::Prepare(ref r, ref h) => { + dest.push_byte(0); + dest.push(r); + dest.push(h); + } + ConsensusVote::Commit(ref r, ref h) => { + dest.push_byte(1); + dest.push(r); + dest.push(h); + } + ConsensusVote::AdvanceRound(ref r) => { + dest.push_byte(2); + dest.push(r); + } + } + } + } + + impl<Hash: Decode> Decode for ConsensusVote<Hash> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + match input.read_byte()? { + 0 => Some(ConsensusVote::Prepare(Decode::decode(input)?, Decode::decode(input)?)), + 1 => Some(ConsensusVote::Commit(Decode::decode(input)?, Decode::decode(input)?)), + 2 => Some(ConsensusVote::AdvanceRound(Decode::decode(input)?)), + _ => None, + } + } + } + /// A localized message. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub enum SignedConsensusMessage<Block, Hash> { /// A proposal. Propose(SignedConsensusProposal<Block, Hash>), @@ -336,8 +402,33 @@ pub mod generic { Vote(SignedConsensusVote<Hash>), } + impl<Block: Encode, Hash: Encode> Encode for SignedConsensusMessage<Block, Hash> { + fn encode_to<T: Output>(&self, dest: &mut T) { + match *self { + SignedConsensusMessage::Propose(ref m) => { + dest.push_byte(0); + dest.push(m); + } + SignedConsensusMessage::Vote(ref m) => { + dest.push_byte(1); + dest.push(m); + } + } + } + } + + impl<Block: Decode, Hash: Decode> Decode for SignedConsensusMessage<Block, Hash> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + match input.read_byte()? { + 0 => Some(SignedConsensusMessage::Propose(Decode::decode(input)?)), + 1 => Some(SignedConsensusMessage::Vote(Decode::decode(input)?)), + _ => None, + } + } + } + /// A network message. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub enum Message<Block, Header, Hash, Number, Extrinsic> { /// Status packet. Status(Status<Hash, Number>), @@ -359,13 +450,77 @@ pub mod generic { ChainSpecific(Vec<u8>), } + impl<Block: Encode, Header: Encode, Hash: Encode, Number: Encode, Extrinsic: Encode> Encode + for Message<Block, Header, Hash, Number, Extrinsic> + { + fn encode_to<T: Output>(&self, dest: &mut T) { + match *self { + Message::Status(ref m) => { + dest.push_byte(0); + dest.push(m); + } + Message::BlockRequest(ref m) => { + dest.push_byte(1); + dest.push(m); + } + Message::BlockResponse(ref m) => { + dest.push_byte(2); + dest.push(m); + } + Message::BlockAnnounce(ref m) => { + dest.push_byte(3); + dest.push(m); + } + Message::Transactions(ref m) => { + dest.push_byte(4); + dest.push(m); + } + Message::BftMessage(ref m) => { + dest.push_byte(5); + dest.push(m); + } + Message::RemoteCallRequest(ref m) => { + dest.push_byte(6); + dest.push(m); + } + Message::RemoteCallResponse(ref m) => { + dest.push_byte(7); + dest.push(m); + } + Message::ChainSpecific(ref m) => { + dest.push_byte(255); + dest.push(m); + } + } + } + } + + impl<Block: Decode, Header: Decode, Hash: Decode, Number: Decode, Extrinsic: Decode> Decode + for Message<Block, Header, Hash, Number, Extrinsic> + { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + match input.read_byte()? { + 0 => Some(Message::Status(Decode::decode(input)?)), + 1 => Some(Message::BlockRequest(Decode::decode(input)?)), + 2 => Some(Message::BlockResponse(Decode::decode(input)?)), + 3 => Some(Message::BlockAnnounce(Decode::decode(input)?)), + 4 => Some(Message::Transactions(Decode::decode(input)?)), + 5 => Some(Message::BftMessage(Decode::decode(input)?)), + 6 => Some(Message::RemoteCallResponse(Decode::decode(input)?)), + 7 => Some(Message::RemoteCallResponse(Decode::decode(input)?)), + 255 => Some(Message::ChainSpecific(Decode::decode(input)?)), + _ => None, + } + } + } + /// Status sent on connection. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub struct Status<Hash, Number> { /// Protocol version. pub version: u32, /// Supported roles. - pub roles: Vec<Role>, + pub roles: Roles, /// Best block number. pub best_number: Number, /// Best block hash. @@ -373,23 +528,40 @@ pub mod generic { /// Genesis block hash. pub genesis_hash: Hash, /// Chain-specific status. - #[serde(skip)] pub chain_status: Vec<u8>, - /// Signatue of `best_hash` made with validator address. Required for the validator role. - pub validator_signature: Option<ed25519::Signature>, - /// Validator address. Required for the validator role. - pub validator_id: Option<AuthorityId>, - /// Parachain id. Required for the collator role. - pub parachain_id: Option<u64>, } + impl<Hash: Encode, Number: Encode> Encode for Status<Hash, Number> { + fn encode_to<T: Output>(&self, dest: &mut T) { + dest.push(&self.version); + dest.push_byte(self.roles.bits()); + dest.push(&self.best_number); + dest.push(&self.best_hash); + dest.push(&self.genesis_hash); + dest.push(&self.chain_status); + } + } + + impl<Hash: Decode, Number: Decode> Decode for Status<Hash, Number> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + Some(Status { + version: Decode::decode(input)?, + roles: Roles::from_bits(input.read_byte()?)?, + best_number: Decode::decode(input)?, + best_hash: Decode::decode(input)?, + genesis_hash: Decode::decode(input)?, + chain_status: Decode::decode(input)?, + }) + } + } + /// Request block data from a peer. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub struct BlockRequest<Hash, Number> { /// Unique request id. pub id: RequestId, /// Bits of block data to request. - pub fields: Vec<BlockAttribute>, + pub fields: BlockAttributes, /// Start from this block. pub from: FromBlock<Hash, Number>, /// End at this block. An implementation defined maximum is used when unspecified. @@ -400,8 +572,36 @@ pub mod generic { pub max: Option<u32>, } + impl<Hash: Encode, Number: Encode> Encode for BlockRequest<Hash, Number> { + fn encode_to<T: Output>(&self, dest: &mut T) { + dest.push(&self.id); + dest.push_byte(self.fields.bits()); + dest.push(&self.from); + dest.push(&self.to); + dest.push_byte(self.direction as u8); + dest.push(&self.max); + } + } + + impl<Hash: Decode, Number: Decode> Decode for BlockRequest<Hash, Number> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + Some(BlockRequest { + id: Decode::decode(input)?, + fields: BlockAttributes::from_bits(input.read_byte()?)?, + from: Decode::decode(input)?, + to: Decode::decode(input)?, + direction: match input.read_byte()? { + x if x == Direction::Ascending as u8 => Some(Direction::Ascending), + x if x == Direction::Descending as u8 => Some(Direction::Descending), + _ => None, + }?, + max: Decode::decode(input)?, + }) + } + } + /// Response to `BlockRequest` - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub struct BlockResponse<Header, Hash, Extrinsic> { /// Id of a request this response was made for. pub id: RequestId, @@ -409,14 +609,44 @@ pub mod generic { pub blocks: Vec<BlockData<Header, Hash, Extrinsic>>, } + impl<Header: Encode, Hash: Encode, Extrinsic: Encode> Encode for BlockResponse<Header, Hash, Extrinsic> { + fn encode_to<T: Output>(&self, dest: &mut T) { + dest.push(&self.id); + dest.push(&self.blocks) + } + } + + impl<Header: Decode, Hash: Decode, Extrinsic: Decode> Decode for BlockResponse<Header, Hash, Extrinsic> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + Some(BlockResponse { + id: Decode::decode(input)?, + blocks: Decode::decode(input)?, + }) + } + } + /// Announce a new complete relay chain block on the network. - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + #[derive(Debug, PartialEq, Eq, Clone)] pub struct BlockAnnounce<H> { /// New block header. pub header: H, } - #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] + impl<Header: Encode> Encode for BlockAnnounce<Header> { + fn encode_to<T: Output>(&self, dest: &mut T) { + dest.push(&self.header); + } + } + + impl<Header: Decode> Decode for BlockAnnounce<Header> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + Some(BlockAnnounce { + header: Decode::decode(input)?, + }) + } + } + + #[derive(Debug, PartialEq, Eq, Clone)] /// Remote call request. pub struct RemoteCallRequest<H> { /// Unique request id. @@ -428,4 +658,24 @@ pub mod generic { /// Call data. pub data: Vec<u8>, } + + impl<Hash: Encode> Encode for RemoteCallRequest<Hash> { + fn encode_to<T: Output>(&self, dest: &mut T) { + dest.push(&self.id); + dest.push(&self.block); + dest.push(self.method.as_bytes()); + dest.push(&self.data); + } + } + + impl<Hash: Decode> Decode for RemoteCallRequest<Hash> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + Some(RemoteCallRequest { + id: Decode::decode(input)?, + block: Decode::decode(input)?, + method: String::from_utf8_lossy(&Vec::decode(input)?).into(), + data: Decode::decode(input)?, + }) + } + } } diff --git a/substrate/substrate/network/src/on_demand.rs b/substrate/substrate/network/src/on_demand.rs index 2011462622feb30f7ec17d8b5a060c2050d6cfd7..da022e91b1219aaa99fb1da270f9f9e129f88280 100644 --- a/substrate/substrate/network/src/on_demand.rs +++ b/substrate/substrate/network/src/on_demand.rs @@ -38,7 +38,7 @@ const REQUEST_TIMEOUT: Duration = Duration::from_secs(15); /// On-demand service API. pub trait OnDemandService<Block: BlockT>: Send + Sync { /// When new node is connected. - fn on_connect(&self, peer: PeerId, role: service::Role); + fn on_connect(&self, peer: PeerId, role: service::Roles); /// When node is disconnected. fn on_disconnect(&self, peer: PeerId); @@ -168,8 +168,8 @@ impl<B, E> OnDemandService<B> for OnDemand<B, E> where E: service::ExecuteInContext<B>, B::Header: HeaderT, { - fn on_connect(&self, peer: PeerId, role: service::Role) { - if !role.intersects(service::Role::FULL | service::Role::AUTHORITY) { // TODO: correct? + fn on_connect(&self, peer: PeerId, role: service::Roles) { + if !role.intersects(service::Roles::FULL | service::Roles::AUTHORITY) { // TODO: correct? return; } @@ -326,7 +326,7 @@ mod tests { use client::light::fetcher::{Fetcher, FetchChecker, RemoteCallRequest}; use message; use network_libp2p::PeerId; - use service::{Role, ExecuteInContext}; + use service::{Roles, ExecuteInContext}; use test::TestIo; use super::{REQUEST_TIMEOUT, OnDemand, OnDemandService}; use test_client::runtime::{Block, Hash}; @@ -372,16 +372,16 @@ mod tests { #[test] fn knows_about_peers_roles() { let (_, on_demand) = dummy(true); - on_demand.on_connect(0, Role::LIGHT); - on_demand.on_connect(1, Role::FULL); - on_demand.on_connect(2, Role::AUTHORITY); + on_demand.on_connect(0, Roles::LIGHT); + on_demand.on_connect(1, Roles::FULL); + on_demand.on_connect(2, Roles::AUTHORITY); assert_eq!(vec![1, 2], on_demand.core.lock().idle_peers.iter().cloned().collect::<Vec<_>>()); } #[test] fn disconnects_from_idle_peer() { let (_, on_demand) = dummy(true); - on_demand.on_connect(0, Role::FULL); + on_demand.on_connect(0, Roles::FULL); assert_eq!(1, total_peers(&*on_demand)); on_demand.on_disconnect(0); assert_eq!(0, total_peers(&*on_demand)); @@ -393,8 +393,8 @@ mod tests { let queue = RwLock::new(VecDeque::new()); let mut network = TestIo::new(&queue, None); - on_demand.on_connect(0, Role::FULL); - on_demand.on_connect(1, Role::FULL); + on_demand.on_connect(0, Roles::FULL); + on_demand.on_connect(1, Roles::FULL); assert_eq!(vec![0, 1], on_demand.core.lock().idle_peers.iter().cloned().collect::<Vec<_>>()); assert!(on_demand.core.lock().active_peers.is_empty()); @@ -414,7 +414,7 @@ mod tests { let (_x, on_demand) = dummy(true); let queue = RwLock::new(VecDeque::new()); let mut network = TestIo::new(&queue, None); - on_demand.on_connect(0, Role::FULL); + on_demand.on_connect(0, Roles::FULL); on_demand.remote_call(RemoteCallRequest { block: Default::default(), method: "test".into(), call_data: vec![] }); receive_call_response(&*on_demand, &mut network, 0, 1); @@ -429,7 +429,7 @@ mod tests { let mut network = TestIo::new(&queue, None); on_demand.remote_call(RemoteCallRequest { block: Default::default(), method: "test".into(), call_data: vec![] }); - on_demand.on_connect(0, Role::FULL); + on_demand.on_connect(0, Roles::FULL); receive_call_response(&*on_demand, &mut network, 0, 0); assert!(network.to_disconnect.contains(&0)); assert_eq!(on_demand.core.lock().pending_requests.len(), 1); @@ -440,7 +440,7 @@ mod tests { let (_x, on_demand) = dummy(true); let queue = RwLock::new(VecDeque::new()); let mut network = TestIo::new(&queue, None); - on_demand.on_connect(0, Role::FULL); + on_demand.on_connect(0, Roles::FULL); receive_call_response(&*on_demand, &mut network, 0, 0); assert!(network.to_disconnect.contains(&0)); @@ -451,7 +451,7 @@ mod tests { let (_x, on_demand) = dummy(true); let queue = RwLock::new(VecDeque::new()); let mut network = TestIo::new(&queue, None); - on_demand.on_connect(0, Role::FULL); + on_demand.on_connect(0, Roles::FULL); let response = on_demand.remote_call(RemoteCallRequest { block: Default::default(), method: "test".into(), call_data: vec![] }); let thread = ::std::thread::spawn(move || { diff --git a/substrate/substrate/network/src/protocol.rs b/substrate/substrate/network/src/protocol.rs index a328c8bb4c6633df049b1e6c9021802396922569..ff35f6a190defda42f42073fd2f022e7491fb61d 100644 --- a/substrate/substrate/network/src/protocol.rs +++ b/substrate/substrate/network/src/protocol.rs @@ -19,16 +19,16 @@ use std::{mem, cmp}; use std::sync::Arc; use std::time; use parking_lot::RwLock; -use serde_json; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Hash, HashFor, As}; use runtime_primitives::generic::BlockId; use network_libp2p::PeerId; +use codec::{Encode, Decode}; use message::{self, Message}; use message::generic::Message as GenericMessage; use specialization::Specialization; use sync::{ChainSync, Status as SyncStatus, SyncState}; -use service::{Role, TransactionPool}; +use service::{Roles, TransactionPool}; use config::ProtocolConfig; use chain::Client; use on_demand::OnDemandService; @@ -38,7 +38,7 @@ use error; const REQUEST_TIMEOUT_SEC: u64 = 40; /// Current protocol version. -pub (crate) const CURRENT_VERSION: u32 = 0; +pub (crate) const CURRENT_VERSION: u32 = 1; /// Current packet count. pub (crate) const CURRENT_PACKET_COUNT: u8 = 1; @@ -74,7 +74,7 @@ struct Peer<B: BlockT> { /// Protocol version protocol_version: u32, /// Roles - roles: Role, + roles: Roles, /// Peer best block hash best_hash: B::Hash, /// Peer best block number @@ -95,7 +95,7 @@ struct Peer<B: BlockT> { #[derive(Debug)] pub struct PeerInfo<B: BlockT> { /// Roles - pub roles: Role, + pub roles: Roles, /// Protocol version pub protocol_version: u32, /// Peer best block hash @@ -233,12 +233,12 @@ impl<B: BlockT, S: Specialization<B>> Protocol<B, S> { } } - pub fn handle_packet(&self, io: &mut SyncIo, peer_id: PeerId, data: &[u8]) { - let message: Message<B> = match serde_json::from_slice(data) { - Ok(m) => m, - Err(e) => { - trace!(target: "sync", "Invalid packet: {}", String::from_utf8_lossy(data)); - io.disable_peer(peer_id, &format!("Peer sent us a packet with invalid format ({})", e)); + pub fn handle_packet(&self, io: &mut SyncIo, peer_id: PeerId, mut data: &[u8]) { + let message: Message<B> = match Decode::decode(&mut data) { + Some(m) => m, + None => { + trace!(target: "sync", "Invalid packet from {}", peer_id); + io.disable_peer(peer_id, "Peer sent us a packet with invalid format"); return; } }; @@ -319,16 +319,9 @@ impl<B: BlockT, S: Specialization<B>> Protocol<B, S> { }; let max = cmp::min(request.max.unwrap_or(u32::max_value()), MAX_BLOCK_DATA_RESPONSE) as usize; // TODO: receipts, etc. - let (mut get_header, mut get_body, mut get_justification) = (false, false, false); - for a in request.fields { - match a { - message::BlockAttribute::Header => get_header = true, - message::BlockAttribute::Body => get_body = true, - message::BlockAttribute::Receipt => unimplemented!(), - message::BlockAttribute::MessageQueue => unimplemented!(), - message::BlockAttribute::Justification => get_justification = true, - } - } + let get_header = request.fields.contains(message::BlockAttributes::HEADER); + let get_body = request.fields.contains(message::BlockAttributes::BODY); + let get_justification = request.fields.contains(message::BlockAttributes::JUSTIFICATION); while let Some(header) = self.context_data.chain.header(&id).unwrap_or(None) { if blocks.len() >= max{ break; @@ -339,10 +332,10 @@ impl<B: BlockT, S: Specialization<B>> Protocol<B, S> { let block_data = message::generic::BlockData { hash: hash, header: if get_header { Some(header) } else { None }, - body: (if get_body { self.context_data.chain.body(&BlockId::Hash(hash)).unwrap_or(None) } else { None }).map(|body| message::Body::Extrinsics(body)), + body: if get_body { self.context_data.chain.body(&BlockId::Hash(hash)).unwrap_or(None) } else { None }, receipt: None, message_queue: None, - justification: justification.map(|j| message::generic::BlockJustification::V2(j)), + justification, }; blocks.push(block_data); match request.direction { @@ -435,7 +428,7 @@ impl<B: BlockT, S: Specialization<B>> Protocol<B, S> { let peer = Peer { protocol_version: status.version, - roles: message::Role::as_flags(&status.roles), + roles: status.roles, best_hash: status.best_hash, best_number: status.best_number, block_request: None, @@ -452,7 +445,7 @@ impl<B: BlockT, S: Specialization<B>> Protocol<B, S> { let mut context = ProtocolContext::new(&self.context_data, io); self.sync.write().new_peer(&mut context, peer_id); self.specialization.write().on_connect(&mut context, peer_id, status.clone()); - self.on_demand.as_ref().map(|s| s.on_connect(peer_id, message::Role::as_flags(&status.roles))); + self.on_demand.as_ref().map(|s| s.on_connect(peer_id, status.roles)); } /// Called when peer sends us new extrinsics @@ -521,10 +514,6 @@ impl<B: BlockT, S: Specialization<B>> Protocol<B, S> { best_number: info.chain.best_number, best_hash: info.chain.best_hash, chain_status: self.specialization.read().status(), - - parachain_id: None, - validator_id: None, - validator_signature: None, }; self.send_message(io, peer_id, GenericMessage::Status(status)) } @@ -562,7 +551,7 @@ impl<B: BlockT, S: Specialization<B>> Protocol<B, S> { ); // blocks are not announced by light clients - if self.config.roles & Role::LIGHT == Role::LIGHT { + if self.config.roles & Roles::LIGHT == Roles::LIGHT { return; } @@ -621,7 +610,7 @@ fn send_message<B: BlockT>(peers: &RwLock<HashMap<PeerId, Peer<B>>>, io: &mut Sy }, _ => (), } - let data = serde_json::to_vec(&message).expect("Serializer is infallible; qed"); + let data = message.encode(); if let Err(e) = io.send(peer_id, data) { debug!(target:"sync", "Error sending message: {:?}", e); io.disconnect_peer(peer_id); @@ -630,6 +619,6 @@ fn send_message<B: BlockT>(peers: &RwLock<HashMap<PeerId, Peer<B>>>, io: &mut Sy /// Hash a message. pub(crate) fn hash_message<B: BlockT>(message: &Message<B>) -> B::Hash { - let data = serde_json::to_vec(&message).expect("Serializer is infallible; qed"); + let data = message.encode(); HashFor::<B>::hash(&data) } diff --git a/substrate/substrate/network/src/service.rs b/substrate/substrate/network/src/service.rs index 8bcd800371835fcf646c7c1518ee393d6a2dbcfb..ea990a304a58cf04b398e0cd1633010800d5f49e 100644 --- a/substrate/substrate/network/src/service.rs +++ b/substrate/substrate/network/src/service.rs @@ -46,7 +46,7 @@ const PROPAGATE_TIMEOUT: Duration = Duration::from_millis(5000); bitflags! { /// Node roles bitmask. - pub struct Role: u32 { + pub struct Roles: u8 { /// No network. const NONE = 0b00000000; /// Full node, does not participate in consensus. diff --git a/substrate/substrate/network/src/sync.rs b/substrate/substrate/network/src/sync.rs index 620ef966b0ccfeaa7eed455d2821c148c17a38eb..a54b920a39693c0a2d1a93f9a00a7e3e04b777f3 100644 --- a/substrate/substrate/network/src/sync.rs +++ b/substrate/substrate/network/src/sync.rs @@ -22,7 +22,7 @@ use blocks::{self, BlockCollection}; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberFor}; use runtime_primitives::generic::BlockId; use message::{self, generic::Message as GenericMessage}; -use service::Role; +use service::Roles; // Maximum blocks to request in a single packet. const MAX_BLOCKS_TO_REQUEST: usize = 128; @@ -50,7 +50,7 @@ pub struct ChainSync<B: BlockT> { blocks: BlockCollection<B>, best_queued_number: NumberFor<B>, best_queued_hash: B::Hash, - required_block_attributes: Vec<message::BlockAttribute>, + required_block_attributes: message::BlockAttributes, } /// Reported sync state. @@ -73,13 +73,10 @@ pub struct Status<B: BlockT> { impl<B: BlockT> ChainSync<B> { /// Create a new instance. - pub(crate) fn new(role: Role, info: &ClientInfo<B>) -> Self { - let mut required_block_attributes = vec![ - message::BlockAttribute::Header, - message::BlockAttribute::Justification - ]; - if role.intersects(Role::FULL) { - required_block_attributes.push(message::BlockAttribute::Body); + pub(crate) fn new(role: Roles, info: &ClientInfo<B>) -> Self { + let mut required_block_attributes = message::BlockAttributes::HEADER | message::BlockAttributes::JUSTIFICATION; + if role.intersects(Roles::FULL) { + required_block_attributes |= message::BlockAttributes::BODY; } ChainSync { @@ -88,7 +85,7 @@ impl<B: BlockT> ChainSync<B> { blocks: BlockCollection::new(), best_queued_hash: info.best_queued_hash.unwrap_or(info.chain.best_hash), best_queued_number: info.best_queued_number.unwrap_or(info.chain.best_number), - required_block_attributes: required_block_attributes, + required_block_attributes, } } @@ -253,8 +250,8 @@ impl<B: BlockT> ChainSync<B> { let result = protocol.client().import( is_best, header, - justification.to_justification(), - block.body.map(|b| b.to_extrinsics()), + justification, + block.body, ); match result { Ok(ImportResult::AlreadyInChain) => { @@ -447,7 +444,7 @@ impl<B: BlockT> ChainSync<B> { trace!(target: "sync", "Requesting ancestry block #{} from {}", block, peer_id); let request = message::generic::BlockRequest { id: 0, - fields: vec![message::BlockAttribute::Header, message::BlockAttribute::Justification], + fields: message::BlockAttributes::HEADER | message::BlockAttributes::JUSTIFICATION, from: message::FromBlock::Number(block), to: None, direction: message::Direction::Ascending, diff --git a/substrate/substrate/network/src/test/sync.rs b/substrate/substrate/network/src/test/sync.rs index d67d530cce935dabd53cf9e3982987057dc4a941..7297c239f39686a02886fc34f6248edcc893347d 100644 --- a/substrate/substrate/network/src/test/sync.rs +++ b/substrate/substrate/network/src/test/sync.rs @@ -17,11 +17,10 @@ use client::backend::Backend; use client::blockchain::HeaderBackend as BlockchainHeaderBackend; use sync::SyncState; -use {Role}; +use Roles; use super::*; #[test] -#[ignore] fn sync_from_two_peers_works() { ::env_logger::init().ok(); let mut net = TestNet::new(3); @@ -34,7 +33,6 @@ fn sync_from_two_peers_works() { } #[test] -#[ignore] fn sync_from_two_peers_with_ancestry_search_works() { ::env_logger::init().ok(); let mut net = TestNet::new(3); @@ -47,7 +45,6 @@ fn sync_from_two_peers_with_ancestry_search_works() { } #[test] -#[ignore] fn sync_long_chain_works() { let mut net = TestNet::new(2); net.peer(1).push_blocks(500, false); @@ -68,7 +65,6 @@ fn sync_no_common_longer_chain_fails() { } #[test] -#[ignore] fn sync_after_fork_works() { ::env_logger::init().ok(); let mut net = TestNet::new(3); @@ -99,7 +95,7 @@ fn blocks_are_not_announced_by_light_nodes() { // full peer0 is connected to light peer // light peer1 is connected to full peer2 let mut light_config = ProtocolConfig::default(); - light_config.roles = Role::LIGHT; + light_config.roles = Roles::LIGHT; net.add_peer(&ProtocolConfig::default()); net.add_peer(&light_config); net.add_peer(&ProtocolConfig::default()); diff --git a/substrate/substrate/service/src/config.rs b/substrate/substrate/service/src/config.rs index 9f47bf0c441a05a8a30ba94b3e01f4346f07d731..58a3db7052e69acff0038dba5ab23d8aaf72ae7a 100644 --- a/substrate/substrate/service/src/config.rs +++ b/substrate/substrate/service/src/config.rs @@ -19,7 +19,7 @@ use extrinsic_pool; use chain_spec::ChainSpec; pub use client::ExecutionStrategy; -pub use network::Role; +pub use network::Roles; pub use network::NetworkConfiguration; pub use client_db::PruningMode; use runtime_primitives::BuildStorage; @@ -28,7 +28,7 @@ use serde::{Serialize, de::DeserializeOwned}; /// Service configuration. pub struct Configuration<G: Serialize + DeserializeOwned + BuildStorage> { /// Node roles. - pub roles: Role, + pub roles: Roles, /// Extrinsic pool configuration. pub extrinsic_pool: extrinsic_pool::txpool::Options, /// Network configuration. @@ -57,7 +57,7 @@ impl<G: Serialize + DeserializeOwned + BuildStorage> Configuration<G> { let mut configuration = Configuration { chain_spec, name: Default::default(), - roles: Role::FULL, + roles: Roles::FULL, extrinsic_pool: Default::default(), network: Default::default(), keystore_path: Default::default(), diff --git a/substrate/substrate/service/src/lib.rs b/substrate/substrate/service/src/lib.rs index c4c641a9520cd6385891d83c80a6a939547940b2..311b256e1a4bcb74a3368a7fd496d3eaaa405f6e 100644 --- a/substrate/substrate/service/src/lib.rs +++ b/substrate/substrate/service/src/lib.rs @@ -59,7 +59,7 @@ use exit_future::Signal; use tokio::runtime::TaskExecutor; pub use self::error::{ErrorKind, Error}; -pub use config::{Configuration, Role, PruningMode}; +pub use config::{Configuration, Roles, PruningMode}; pub use chain_spec::ChainSpec; pub use extrinsic_pool::txpool::{Options as ExtrinsicPoolOptions}; pub use extrinsic_pool::api::{ExtrinsicPool as ExtrinsicPoolApi};