From 6bfcbd6d59b5fa18d5e67d51f933dc939b6d2c63 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 6 Jul 2018 14:17:03 +0200 Subject: [PATCH] Minimal parachains part 2: Parachain statement and data routing (#173) * dynamic inclusion threshold calculator * collators interface * collation helpers * initial proposal-creation future * create proposer when asked to propose * remove local_availability duty * statement table tracks includable parachain count * beginnings of timing future * finish proposal logic * remove stray println * extract shared table to separate module * change ordering * includability tracking * fix doc * initial changes to parachains module * initialise dummy block before API calls * give polkadot control over round proposer based on random seed * propose only after enough candidates * flesh out parachains module a bit more * set_heads * actually introduce set_heads to runtime * update block_builder to accept parachains * split block validity errors from real errors in evaluation * update WASM runtimes * polkadot-api methods for parachains additions * delay evaluation until candidates are ready * comments * fix dynamic inclusion with zero initial * test for includability tracker * wasm validation of parachain candidates * move primitives to primitives crate * remove runtime-std dependency from codec * adjust doc * polkadot-parachain-primitives * kill legacy polkadot-validator crate * basic-add test chain * test for basic_add parachain * move to test-chains dir * use wasm-build * new wasm directory layout * reorganize a bit more * Fix for rh-minimal-parachain (#141) * Remove extern "C" We already encountered such behavior (bug?) in pwasm-std, I believe. * Fix `panic_fmt` signature by adding `_col` Wrong `panic_fmt` signature can inhibit some optimizations in LTO mode. * Add linker flags and use wasm-gc in build script Pass --import-memory to LLD to emit wasm binary with imported memory. Also use wasm-gc instead of wasm-build. * Fix effective_max. I'm not sure why it was the way it was actually. * Recompile wasm. * Fix indent * more basic_add tests * validate parachain WASM * produce statements on receiving statements * tests for reactive statement production * fix build * add OOM lang item to runtime-io * use dynamic_inclusion when evaluating as well * fix update_includable_count * remove dead code * grumbles * actually defer round_proposer logic * update wasm * address a few more grumbles * schedule collation work as soon as BFT is started * impl future in collator * fix comment * governance proposals for adding and removing parachains * bump protocol version * tear out polkadot-specific pieces of substrate-network * extract out polkadot-specific stuff from substrate-network * begin polkadot network subsystem * grumbles * update WASM checkins * parse status from polkadot peer * allow invoke of network specialization * begin statement router implementation * remove dependency on tokio-timer * fix sanity check and have proposer factory create communication streams * pull out statement routing from consensus library * fix comments * adjust typedefs * extract consensus_gossip out of main network protocol handler * port substrate-bft to new tokio * port polkadot-consensus to new tokio * fix typo * start message processing task * initial consensus network implementation * remove known tracking from statement-table crate * extract router into separate module * defer statements until later * double signature is invalid * propagating statements * grumbles * request block data * fix compilation * embed new consensus network into service * port demo CLI to tokio * all test crates compile * some tests for fetching block data * whitespace * adjusting some tokio stuff * update exit-future * remove overly noisy warning * clean up collation work a bit * address review grumbles * fix lock order in protocol handler * rebuild wasm artifacts * tag AuthorityId::from_slice for std only * address formatting grumbles * rename event_loop to executor * some more docs for polkadot-network crate --- polkadot/cli/Cargo.toml | 3 +- polkadot/cli/src/informant.rs | 16 +- polkadot/cli/src/lib.rs | 47 +- polkadot/collator/Cargo.toml | 2 +- polkadot/collator/src/lib.rs | 14 +- polkadot/consensus/Cargo.toml | 7 +- polkadot/consensus/src/collation.rs | 20 +- polkadot/consensus/src/dynamic_inclusion.rs | 7 +- polkadot/consensus/src/error.rs | 2 +- polkadot/consensus/src/lib.rs | 359 +++++----- polkadot/consensus/src/service.rs | 275 ++------ polkadot/consensus/src/shared_table/mod.rs | 247 ++++--- polkadot/network/Cargo.toml | 22 + polkadot/network/src/consensus.rs | 313 +++++++++ polkadot/network/src/lib.rs | 488 +++++++++++++ polkadot/network/src/router.rs | 349 ++++++++++ polkadot/network/src/tests.rs | 204 ++++++ polkadot/primitives/src/parachain.rs | 69 +- polkadot/runtime/src/lib.rs | 7 + polkadot/runtime/src/parachains.rs | 37 +- .../release/polkadot_runtime.compact.wasm | Bin 464533 -> 463102 bytes .../release/polkadot_runtime.wasm | Bin 503094 -> 507189 bytes polkadot/service/Cargo.toml | 4 +- polkadot/service/src/components.rs | 62 +- polkadot/service/src/lib.rs | 117 ++-- polkadot/statement-table/Cargo.toml | 3 + polkadot/statement-table/src/generic.rs | 640 ++++++++---------- polkadot/statement-table/src/lib.rs | 29 +- 28 files changed, 2212 insertions(+), 1131 deletions(-) create mode 100644 polkadot/network/Cargo.toml create mode 100644 polkadot/network/src/consensus.rs create mode 100644 polkadot/network/src/lib.rs create mode 100644 polkadot/network/src/router.rs create mode 100644 polkadot/network/src/tests.rs diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 76a899de7c..6c1ecd2b58 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -18,13 +18,14 @@ lazy_static = "1.0" triehash = "0.1" ed25519 = { path = "../../substrate/ed25519" } app_dirs = "1.2" -tokio-core = "0.1.12" +tokio = "0.1.7" futures = "0.1.17" ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" } fdlimit = "0.1" parking_lot = "0.4" serde_json = "1.0" serde = "1.0" +exit-future = "0.1" substrate-client = { path = "../../substrate/client" } substrate-codec = { path = "../../substrate/codec" } substrate-network = { path = "../../substrate/network" } diff --git a/polkadot/cli/src/informant.rs b/polkadot/cli/src/informant.rs index 26915da32e..6b43d4ffad 100644 --- a/polkadot/cli/src/informant.rs +++ b/polkadot/cli/src/informant.rs @@ -17,9 +17,10 @@ //! Console informant. Prints sync progress and block events. Runs on the calling thread. use std::time::{Duration, Instant}; -use futures::stream::Stream; +use futures::{Future, Stream}; use service::{Service, Components}; -use tokio_core::reactor; +use tokio::runtime::TaskExecutor; +use tokio::timer::Interval; use network::{SyncState, SyncProvider}; use polkadot_primitives::Block; use state_machine; @@ -28,13 +29,12 @@ use client::{self, BlockchainEvents}; const TIMER_INTERVAL_MS: u64 = 5000; /// Spawn informant on the event loop -pub fn start(service: &Service, handle: reactor::Handle) +pub fn start(service: &Service, exit: ::exit_future::Exit, handle: TaskExecutor) where C: Components, client::error::Error: From<<<::Backend as client::backend::Backend>::State as state_machine::Backend>::Error>, { - let interval = reactor::Interval::new_at(Instant::now(), Duration::from_millis(TIMER_INTERVAL_MS), &handle) - .expect("Error creating informant timer"); + let interval = Interval::new(Instant::now(), Duration::from_millis(TIMER_INTERVAL_MS)); let network = service.network(); let client = service.client(); @@ -73,8 +73,8 @@ pub fn start(service: &Service, handle: reactor::Handle) telemetry!("txpool.import"; "mem_usage" => status.mem_usage, "count" => status.transaction_count, "sender" => status.senders); Ok(()) }); - handle.spawn(display_notifications); - handle.spawn(display_block_import); - handle.spawn(display_txpool_import); + + let informant_work = display_notifications.join3(display_block_import, display_txpool_import); + handle.spawn(exit.until(informant_work).map(|_| ())); } diff --git a/polkadot/cli/src/lib.rs b/polkadot/cli/src/lib.rs index f96690f79e..6dcddfc243 100644 --- a/polkadot/cli/src/lib.rs +++ b/polkadot/cli/src/lib.rs @@ -25,7 +25,7 @@ extern crate ansi_term; extern crate regex; extern crate time; extern crate futures; -extern crate tokio_core; +extern crate tokio; extern crate ctrlc; extern crate fdlimit; extern crate ed25519; @@ -50,6 +50,7 @@ extern crate slog; // needed until we can reexport `slog_info` from `substrate_t #[macro_use] extern crate substrate_telemetry; extern crate polkadot_transaction_pool as txpool; +extern crate exit_future; #[macro_use] extern crate lazy_static; @@ -76,9 +77,8 @@ use codec::Slicable; use client::BlockOrigin; use runtime_primitives::generic::SignedBlock; -use futures::sync::mpsc; -use futures::{Sink, Future, Stream}; -use tokio_core::reactor; +use futures::Future; +use tokio::runtime::Runtime; use service::PruningMode; const DEFAULT_TELEMETRY_URL: &str = "ws://telemetry.polkadot.io:1024"; @@ -188,13 +188,14 @@ pub fn run(args: I) -> error::Result<()> where let role = if matches.is_present("collator") { info!("Starting collator"); - service::Role::COLLATOR + // TODO [rob]: collation node implementation + service::Role::FULL } else if matches.is_present("light") { info!("Starting (light)"); service::Role::LIGHT } else if matches.is_present("validator") || matches.is_present("dev") { info!("Starting validator"); - service::Role::VALIDATOR + service::Role::AUTHORITY } else { info!("Starting (heavy)"); service::Role::FULL @@ -231,6 +232,9 @@ pub fn run(args: I) -> error::Result<()> where chain_name: config.chain_spec.name().to_owned(), }; + let mut runtime = Runtime::new()?; + let executor = runtime.executor(); + let _guard = if matches.is_present("telemetry") || matches.value_of("telemetry-url").is_some() { let name = config.name.clone(); let chain_name = config.chain_spec.name().to_owned(); @@ -250,11 +254,14 @@ pub fn run(args: I) -> error::Result<()> where None }; - let core = reactor::Core::new().expect("tokio::Core could not be created"); match role == service::Role::LIGHT { - true => run_until_exit(core, service::new_light(config)?, &matches, sys_conf), - false => run_until_exit(core, service::new_full(config)?, &matches, sys_conf), + true => run_until_exit(&mut runtime, service::new_light(config, executor)?, &matches, sys_conf)?, + false => run_until_exit(&mut runtime, service::new_full(config, executor)?, &matches, sys_conf)?, } + + // TODO: hard exit if this stalls? + runtime.shutdown_on_idle().wait().expect("failed to shut down event loop"); + Ok(()) } fn build_spec(matches: &clap::ArgMatches) -> error::Result<()> { @@ -370,29 +377,37 @@ fn import_blocks(matches: &clap::ArgMatches) -> error::Result<()> { Ok(()) } -fn run_until_exit(mut core: reactor::Core, service: service::Service, matches: &clap::ArgMatches, sys_conf: SystemConfiguration) -> error::Result<()> +fn run_until_exit(runtime: &mut Runtime, service: service::Service, matches: &clap::ArgMatches, sys_conf: SystemConfiguration) -> error::Result<()> where C: service::Components, client::error::Error: From<<<::Backend as client::backend::Backend>::State as state_machine::Backend>::Error>, { let exit = { - // can't use signal directly here because CtrlC takes only `Fn`. - let (exit_send, exit) = mpsc::channel(1); + let (exit_send, exit) = exit_future::signal(); + let exit_send = ::std::cell::RefCell::new(Some(exit_send)); ctrlc::CtrlC::set_handler(move || { - exit_send.clone().send(()).wait().expect("Error sending exit notification"); + let exit_send = exit_send + .try_borrow_mut() + .expect("only borrowed in non-reetrant signal handler; qed") + .take(); + + if let Some(signal) = exit_send { + signal.fire(); + } }); exit }; - informant::start(&service, core.handle()); + let executor = runtime.executor(); + informant::start(&service, exit.clone(), executor.clone()); let _rpc_servers = { let http_address = parse_address("127.0.0.1:9933", "rpc-port", matches)?; let ws_address = parse_address("127.0.0.1:9944", "ws-port", matches)?; let handler = || { - let chain = rpc::apis::chain::Chain::new(service.client(), core.remote()); + let chain = rpc::apis::chain::Chain::new(service.client(), executor.clone()); let author = rpc::apis::author::Author::new(service.client(), service.transaction_pool()); rpc::rpc_handler::( service.client(), @@ -407,7 +422,7 @@ fn run_until_exit(mut core: reactor::Core, service: service::Service, matc ) }; - core.run(exit.into_future()).expect("Error running informant event loop"); + let _ = exit.wait(); Ok(()) } diff --git a/polkadot/collator/Cargo.toml b/polkadot/collator/Cargo.toml index 161121eefa..78e4823d20 100644 --- a/polkadot/collator/Cargo.toml +++ b/polkadot/collator/Cargo.toml @@ -9,5 +9,5 @@ futures = "0.1.17" substrate-codec = { path = "../../substrate/codec", version = "0.1" } substrate-primitives = { path = "../../substrate/primitives", version = "0.1" } polkadot-runtime = { path = "../runtime", version = "0.1" } -polkadot-parachain = { path = "../parachain", version = "0.1" } polkadot-primitives = { path = "../primitives", version = "0.1" } +polkadot-parachain = { path = "../parachain", version = "0.1" } diff --git a/polkadot/collator/src/lib.rs b/polkadot/collator/src/lib.rs index 55eca734d2..94fda9ceda 100644 --- a/polkadot/collator/src/lib.rs +++ b/polkadot/collator/src/lib.rs @@ -85,7 +85,7 @@ pub trait RelayChainContext { /// Collate the necessary ingress queue using the given context. pub fn collate_ingress<'a, R>(relay_context: R) - -> Box + 'a> + -> impl Future + 'a where R: RelayChainContext, R::Error: 'a, @@ -106,7 +106,7 @@ pub fn collate_ingress<'a, R>(relay_context: R) // and then by the parachain ID. // // then transform that into the consolidated egress queue. - Box::new(stream::futures_unordered(egress_fetch) + stream::futures_unordered(egress_fetch) .fold(BTreeMap::new(), |mut map, (routing_id, egresses)| { for (depth, egress) in egresses.into_iter().rev().enumerate() { let depth = -(depth as i64); @@ -117,19 +117,19 @@ pub fn collate_ingress<'a, R>(relay_context: R) }) .map(|ordered| ordered.into_iter().map(|((_, id), egress)| (id, egress))) .map(|i| i.collect::>()) - .map(ConsolidatedIngress)) + .map(ConsolidatedIngress) } /// Produce a candidate for the parachain. -pub fn collate<'a, R, P>(local_id: ParaId, relay_context: R, para_context: P) - -> Box + 'a> +pub fn collate<'a, R: 'a, P>(local_id: ParaId, relay_context: R, para_context: P) + -> impl Future + 'a where R: RelayChainContext, R::Error: 'a, R::FutureEgress: 'a, P: ParachainContext + 'a, { - Box::new(collate_ingress(relay_context).map(move |ingress| { + collate_ingress(relay_context).map(move |ingress| { let (block_data, _, signature) = para_context.produce_candidate( ingress.0.iter().flat_map(|&(id, ref msgs)| msgs.iter().cloned().map(move |msg| (id, msg))) ); @@ -140,7 +140,7 @@ pub fn collate<'a, R, P>(local_id: ParaId, relay_context: R, para_context: P) block: block_data, unprocessed_ingress: ingress, } - })) + }) } #[cfg(test)] diff --git a/polkadot/consensus/Cargo.toml b/polkadot/consensus/Cargo.toml index fefa67de45..91501f2692 100644 --- a/polkadot/consensus/Cargo.toml +++ b/polkadot/consensus/Cargo.toml @@ -6,7 +6,7 @@ authors = ["Parity Technologies "] [dependencies] futures = "0.1.17" parking_lot = "0.4" -tokio-core = "0.1.12" +tokio = "0.1.7" ed25519 = { path = "../../substrate/ed25519" } error-chain = "0.12" log = "0.3" @@ -22,7 +22,8 @@ substrate-bft = { path = "../../substrate/bft" } substrate-codec = { path = "../../substrate/codec" } substrate-primitives = { path = "../../substrate/primitives" } substrate-runtime-support = { path = "../../substrate/runtime-support" } -substrate-network = { path = "../../substrate/network" } -substrate-keyring = { path = "../../substrate/keyring" } substrate-client = { path = "../../substrate/client" } substrate-runtime-primitives = { path = "../../substrate/runtime/primitives" } + +[dev-dependencies] +substrate-keyring = { path = "../../substrate/keyring" } diff --git a/polkadot/consensus/src/collation.rs b/polkadot/consensus/src/collation.rs index f0b1f626c6..d2cd297ce3 100644 --- a/polkadot/consensus/src/collation.rs +++ b/polkadot/consensus/src/collation.rs @@ -23,7 +23,7 @@ use std::sync::Arc; use polkadot_api::PolkadotApi; use polkadot_primitives::{Hash, AccountId, BlockId}; -use polkadot_primitives::parachain::{Id as ParaId, Chain, BlockData, Extrinsic, CandidateReceipt}; +use polkadot_primitives::parachain::{Id as ParaId, BlockData, Extrinsic, CandidateReceipt}; use futures::prelude::*; @@ -55,7 +55,7 @@ pub trait Collators: Clone { /// /// This future is fused. pub struct CollationFetch { - parachain: Option, + parachain: ParaId, relay_parent_hash: Hash, relay_parent: BlockId, collators: C, @@ -65,16 +65,13 @@ pub struct CollationFetch { impl CollationFetch { /// Create a new collation fetcher for the given chain. - pub fn new(parachain: Chain, relay_parent: BlockId, relay_parent_hash: Hash, collators: C, client: Arc

) -> Self { + pub fn new(parachain: ParaId, relay_parent: BlockId, relay_parent_hash: Hash, collators: C, client: Arc

) -> Self { CollationFetch { relay_parent_hash, relay_parent, collators, client, - parachain: match parachain { - Chain::Parachain(id) => Some(id), - Chain::Relay => None, - }, + parachain, live_fetch: None, } } @@ -85,26 +82,19 @@ impl Future for CollationFetch { type Error = C::Error; fn poll(&mut self) -> Poll<(Collation, Extrinsic), C::Error> { - let parachain = match self.parachain.as_ref() { - Some(p) => p.clone(), - None => return Ok(Async::NotReady), - }; - loop { let x = { + let parachain = self.parachain.clone(); let (r, c) = (self.relay_parent_hash, &self.collators); let poll = self.live_fetch .get_or_insert_with(move || c.collate(parachain, r).into_future()) .poll(); - if let Err(_) = poll { self.parachain = None } try_ready!(poll) }; match validate_collation(&*self.client, &self.relay_parent, &x) { Ok(()) => { - self.parachain = None; - // TODO: generate extrinsic while verifying. return Ok(Async::Ready((x, Extrinsic))); } diff --git a/polkadot/consensus/src/dynamic_inclusion.rs b/polkadot/consensus/src/dynamic_inclusion.rs index d48e486274..bec2bd0fa8 100644 --- a/polkadot/consensus/src/dynamic_inclusion.rs +++ b/polkadot/consensus/src/dynamic_inclusion.rs @@ -61,7 +61,7 @@ impl DynamicInclusion { /// would be enough, or `None` if it is sufficient now. /// /// Panics if `now` is earlier than the `start`. - pub fn acceptable_in(&self, now: Instant, included: usize) -> Option { + pub fn acceptable_in(&self, now: Instant, included: usize) -> Option { let elapsed = now.duration_since(self.start); let elapsed = duration_to_micros(&elapsed); @@ -70,7 +70,8 @@ impl DynamicInclusion { if elapsed >= valid_after { None } else { - Some(Duration::from_millis((valid_after - elapsed) as u64 / 1000)) + let until = Duration::from_millis((valid_after - elapsed) as u64 / 1000); + Some(now + until) } } } @@ -104,7 +105,7 @@ mod tests { Duration::from_millis(4000), ); - assert_eq!(dynamic.acceptable_in(now, 5), Some(Duration::from_millis(2000))); + assert_eq!(dynamic.acceptable_in(now, 5), Some(now + Duration::from_millis(2000))); assert!(dynamic.acceptable_in(now + Duration::from_millis(2000), 5).is_none()); assert!(dynamic.acceptable_in(now + Duration::from_millis(3000), 5).is_none()); assert!(dynamic.acceptable_in(now + Duration::from_millis(4000), 5).is_none()); diff --git a/polkadot/consensus/src/error.rs b/polkadot/consensus/src/error.rs index acafa88f5e..397fdee52c 100644 --- a/polkadot/consensus/src/error.rs +++ b/polkadot/consensus/src/error.rs @@ -37,7 +37,7 @@ error_chain! { description("Proposer destroyed before finishing proposing or evaluating"), display("Proposer destroyed before finishing proposing or evaluating"), } - Timer(e: String) { + Timer(e: ::tokio::timer::Error) { description("Failed to register or resolve async timer."), display("Timer failed: {}", e), } diff --git a/polkadot/consensus/src/lib.rs b/polkadot/consensus/src/lib.rs index c75d8ac6ee..2fabf48088 100644 --- a/polkadot/consensus/src/lib.rs +++ b/polkadot/consensus/src/lib.rs @@ -44,11 +44,10 @@ extern crate substrate_codec as codec; extern crate substrate_primitives as primitives; extern crate substrate_runtime_support as runtime_support; extern crate substrate_runtime_primitives as runtime_primitives; -extern crate substrate_network; +extern crate substrate_client as client; extern crate exit_future; -extern crate tokio_core; -extern crate substrate_client as client; +extern crate tokio; #[macro_use] extern crate error_chain; @@ -67,33 +66,32 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use codec::Slicable; -use table::generic::Statement as GenericStatement; -use runtime_support::Hashable; use polkadot_api::PolkadotApi; -use polkadot_primitives::{Hash, Block, BlockId, BlockNumber, Header, Timestamp}; -use polkadot_primitives::parachain::{Id as ParaId, Chain, DutyRoster, BlockData, Extrinsic as ParachainExtrinsic, CandidateReceipt}; -use polkadot_runtime::BareExtrinsic; +use polkadot_primitives::{Hash, Block, BlockId, BlockNumber, Header, Timestamp, SessionKey}; +use polkadot_primitives::parachain::{Id as ParaId, Chain, DutyRoster, BlockData, Extrinsic as ParachainExtrinsic, CandidateReceipt, CandidateSignature}; use primitives::AuthorityId; -use transaction_pool::{TransactionPool}; -use tokio_core::reactor::{Handle, Timeout, Interval}; +use transaction_pool::TransactionPool; +use tokio::runtime::TaskExecutor; +use tokio::timer::{Delay, Interval}; use futures::prelude::*; -use futures::future::{self, Shared}; +use futures::future; use collation::CollationFetch; use dynamic_inclusion::DynamicInclusion; -pub use self::collation::{Collators, Collation}; +pub use self::collation::{validate_collation, Collators, Collation}; pub use self::error::{ErrorKind, Error}; -pub use self::shared_table::{SharedTable, StatementSource, StatementProducer, ProducedStatements}; +pub use self::shared_table::{SharedTable, StatementProducer, ProducedStatements, Statement, SignedStatement, GenericStatement}; pub use service::Service; -mod collation; mod dynamic_inclusion; mod evaluation; mod error; mod service; mod shared_table; +pub mod collation; + // block size limit. const MAX_TRANSACTIONS_SIZE: usize = 4 * 1024 * 1024; @@ -108,8 +106,9 @@ pub trait TableRouter: Clone { /// Future that resolves when extrinsic candidate data is fetched. type FetchExtrinsic: IntoFuture; - /// Note local candidate data, making it available on the network to other validators. - fn local_candidate_data(&self, hash: Hash, block_data: BlockData, extrinsic: ParachainExtrinsic); + /// Call with local candidate data. This will make the data available on the network, + /// and sign, import, and broadcast a statement about the candidate. + fn local_candidate(&self, candidate: CandidateReceipt, block_data: BlockData, extrinsic: ParachainExtrinsic); /// Fetch block data for a specific candidate. fn fetch_block_data(&self, candidate: &CandidateReceipt) -> Self::FetchCandidate; @@ -118,23 +117,28 @@ pub trait TableRouter: Clone { fn fetch_extrinsic_data(&self, candidate: &CandidateReceipt) -> Self::FetchExtrinsic; } -/// A long-lived network which can create statement table routing instances. +/// A long-lived network which can create parachain statement and BFT message routing processes on demand. pub trait Network { /// The table router type. This should handle importing of any statements, /// routing statements to peers, and driving completion of any `StatementProducers`. type TableRouter: TableRouter; + /// The input stream of BFT messages. Should never logically conclude. + type Input: Stream,Error=Error>; + /// The output sink of BFT messages. Messages sent here should eventually pass to all + /// current authorities. + type Output: Sink,SinkError=Error>; - /// Instantiate a table router using the given shared table. - fn table_router(&self, table: Arc) -> Self::TableRouter; + /// Instantiate a table router using the given shared table and task executor. + fn communication_for(&self, validators: &[SessionKey], table: Arc, task_executor: TaskExecutor) -> (Self::TableRouter, Self::Input, Self::Output); } /// Information about a specific group. #[derive(Debug, Clone, Default)] pub struct GroupInfo { /// Authorities meant to check validity of candidates. - pub validity_guarantors: HashSet, + pub validity_guarantors: HashSet, /// Authorities meant to check availability of candidate data. - pub availability_guarantors: HashSet, + pub availability_guarantors: HashSet, /// Number of votes needed for validity. pub needed_validity: usize, /// Number of votes needed for availability. @@ -144,20 +148,21 @@ pub struct GroupInfo { /// Sign a table statement against a parent hash. /// The actual message signed is the encoded statement concatenated with the /// parent hash. -pub fn sign_table_statement(statement: &table::Statement, key: &ed25519::Pair, parent_hash: &Hash) -> ed25519::Signature { - use polkadot_primitives::parachain::Statement as RawStatement; - - let raw = match *statement { - GenericStatement::Candidate(ref c) => RawStatement::Candidate(c.clone()), - GenericStatement::Valid(h) => RawStatement::Valid(h), - GenericStatement::Invalid(h) => RawStatement::Invalid(h), - GenericStatement::Available(h) => RawStatement::Available(h), - }; - - let mut encoded = raw.encode(); +pub fn sign_table_statement(statement: &Statement, key: &ed25519::Pair, parent_hash: &Hash) -> CandidateSignature { + let mut encoded = statement.encode(); encoded.extend(&parent_hash.0); - key.sign(&encoded) + key.sign(&encoded).into() +} + +/// Check signature on table statement. +pub fn check_statement(statement: &Statement, signature: &CandidateSignature, signer: SessionKey, parent_hash: &Hash) -> bool { + use runtime_primitives::traits::Verify; + + let mut encoded = statement.encode(); + encoded.extend(&parent_hash.0); + + signature.verify(&encoded[..], &signer.into()) } fn make_group_info(roster: DutyRoster, authorities: &[AuthorityId], local_id: AuthorityId) -> Result<(HashMap, LocalDuty), Error> { @@ -217,41 +222,43 @@ fn make_group_info(roster: DutyRoster, authorities: &[AuthorityId], local_id: Au } } -fn timer_error(e: &::std::io::Error) -> Error { - ErrorKind::Timer(format!("{}", e)).into() -} - /// Polkadot proposer factory. pub struct ProposerFactory { /// The client instance. - pub client: Arc, + pub client: Arc

, /// The transaction pool. - pub transaction_pool: Arc>, + pub transaction_pool: Arc>, /// The backing network handle. pub network: N, /// Parachain collators. - pub collators: P, - /// The timer used to schedule proposal intervals. - pub handle: Handle, + pub collators: C, + /// handle to remote task executor + pub handle: TaskExecutor, /// The duration after which parachain-empty blocks will be allowed. pub parachain_empty_duration: Duration, } -impl bft::ProposerFactory for ProposerFactory +impl bft::Environment for ProposerFactory where - C: PolkadotApi + Send + Sync, + C: Collators + Send + 'static, N: Network, - P: Collators, + P: PolkadotApi + Send + Sync + 'static, + ::Future: Send + 'static, + N::TableRouter: Send + 'static, { - type Proposer = Proposer; + type Proposer = Proposer

; + type Input = N::Input; + type Output = N::Output; type Error = Error; - fn init(&self, parent_header: &Header, authorities: &[AuthorityId], sign_with: Arc) -> Result { - use std::time::Duration; - + fn init(&self, + parent_header: &Header, + authorities: &[AuthorityId], + sign_with: Arc + ) -> Result<(Self::Proposer, Self::Input, Self::Output), Error> { const DELAY_UNTIL: Duration = Duration::from_millis(5000); - let parent_hash = parent_header.blake2_256().into(); + let parent_hash = parent_header.hash().into(); let id = BlockId::hash(parent_hash); let duty_roster = self.client.duty_roster(&id)?; @@ -267,70 +274,116 @@ impl bft::ProposerFactory for ProposerFactory let n_parachains = active_parachains.len(); let table = Arc::new(SharedTable::new(group_info, sign_with.clone(), parent_hash)); - let router = self.network.table_router(table.clone()); - let dynamic_inclusion = DynamicInclusion::new( - n_parachains, - Instant::now(), - self.parachain_empty_duration.clone(), + let (router, input, output) = self.network.communication_for( + authorities, + table.clone(), + self.handle.clone() ); - let timeout = Timeout::new(DELAY_UNTIL, &self.handle) - .map_err(|e| timer_error(&e))?; + let now = Instant::now(); + let dynamic_inclusion = DynamicInclusion::new( + n_parachains, + now, + self.parachain_empty_duration.clone(), + ); debug!(target: "bft", "Initialising consensus proposer. Refusing to evaluate for {:?} from now.", DELAY_UNTIL); - // TODO [PoC-2]: kick off collation process. - Ok(Proposer { + let validation_para = match local_duty.validation { + Chain::Relay => None, + Chain::Parachain(id) => Some(id), + }; + + let collation_work = validation_para.map(|para| CollationFetch::new( + para, + id.clone(), + parent_hash.clone(), + self.collators.clone(), + self.client.clone(), + )); + let drop_signal = dispatch_collation_work( + router.clone(), + &self.handle, + collation_work, + ); + + let proposer = Proposer { client: self.client.clone(), - collators: self.collators.clone(), - delay: timeout.shared(), - handle: self.handle.clone(), dynamic_inclusion, - local_duty, local_key: sign_with, + minimum_delay: now + DELAY_UNTIL, parent_hash, parent_id: id, parent_number: parent_header.number, random_seed, - router, table, transaction_pool: self.transaction_pool.clone(), - }) + _drop_signal: drop_signal, + }; + + Ok((proposer, input, output)) } } +// dispatch collation work to be done in the background. returns a signal object +// that should fire when the collation work is no longer necessary (e.g. when the proposer object is dropped) +fn dispatch_collation_work( + router: R, + handle: &TaskExecutor, + work: Option>, +) -> exit_future::Signal where + C: Collators + Send + 'static, + P: PolkadotApi + Send + Sync + 'static, + ::Future: Send + 'static, + R: TableRouter + Send + 'static, +{ + let (signal, exit) = exit_future::signal(); + let handled_work = work.then(move |result| match result { + Ok(Some((collation, extrinsic))) => { + router.local_candidate(collation.receipt, collation.block_data, extrinsic); + Ok(()) + } + Ok(None) => Ok(()), + Err(_e) => { + warn!(target: "consensus", "Failed to collate candidate"); + Ok(()) + } + }); + + let cancellable_work = handled_work.select(exit).then(|_| Ok(())); + + // spawn onto thread pool. + handle.spawn(cancellable_work); + signal +} + struct LocalDuty { validation: Chain, } /// The Polkadot proposer logic. -pub struct Proposer { +pub struct Proposer { client: Arc, - collators: P, - delay: Shared, dynamic_inclusion: DynamicInclusion, - handle: Handle, - local_duty: LocalDuty, local_key: Arc, + minimum_delay: Instant, parent_hash: Hash, parent_id: BlockId, parent_number: BlockNumber, random_seed: Hash, - router: R, table: Arc, transaction_pool: Arc>, + _drop_signal: exit_future::Signal, } -impl bft::Proposer for Proposer +impl bft::Proposer for Proposer where C: PolkadotApi + Send + Sync, - R: TableRouter, - P: Collators, { type Error = Error; type Create = future::Either< - CreateProposal, + CreateProposal, future::FutureResult, >; type Evaluate = Box>; @@ -339,32 +392,24 @@ impl bft::Proposer for Proposer const ATTEMPT_PROPOSE_EVERY: Duration = Duration::from_millis(100); let initial_included = self.table.includable_count(); + let now = Instant::now(); let enough_candidates = self.dynamic_inclusion.acceptable_in( - Instant::now(), + now, initial_included, - ).unwrap_or_default(); + ).unwrap_or_else(|| now + Duration::from_millis(1)); - let timing = { - let delay = self.delay.clone(); - let dynamic_inclusion = self.dynamic_inclusion.clone(); - let make_timing = move |handle| -> Result { - let attempt_propose = Interval::new(ATTEMPT_PROPOSE_EVERY, handle)?; - let enough_candidates = Timeout::new(enough_candidates, handle)?; - Ok(ProposalTiming { - attempt_propose, - enough_candidates, - dynamic_inclusion, - minimum_delay: Some(delay), - last_included: initial_included, - }) - }; + let minimum_delay = if self.minimum_delay > now + ATTEMPT_PROPOSE_EVERY { + Some(Delay::new(self.minimum_delay)) + } else { + None + }; - match make_timing(&self.handle) { - Ok(timing) => timing, - Err(e) => { - return future::Either::B(future::err(timer_error(&e))); - } - } + let timing = ProposalTiming { + attempt_propose: Interval::new(now + ATTEMPT_PROPOSE_EVERY, ATTEMPT_PROPOSE_EVERY), + enough_candidates: Delay::new(enough_candidates), + dynamic_inclusion: self.dynamic_inclusion.clone(), + minimum_delay, + last_included: initial_included, }; future::Either::A(CreateProposal { @@ -373,15 +418,7 @@ impl bft::Proposer for Proposer parent_id: self.parent_id.clone(), client: self.client.clone(), transaction_pool: self.transaction_pool.clone(), - collation: CollationFetch::new( - self.local_duty.validation, - self.parent_id.clone(), - self.parent_hash.clone(), - self.collators.clone(), - self.client.clone() - ), table: self.table.clone(), - router: self.router.clone(), timing, }) } @@ -415,9 +452,7 @@ impl bft::Proposer for Proposer }; let vote_delays = { - // delay casting vote until able (according to minimum block time) - let minimum_delay = self.delay.clone() - .map_err(|e| timer_error(&*e)); + let now = Instant::now(); let included_candidate_hashes = proposal .parachain_heads() @@ -431,33 +466,35 @@ impl bft::Proposer for Proposer // the duration at which the given number of parachains is acceptable. let count_delay = self.dynamic_inclusion.acceptable_in( - Instant::now(), + now, proposal.parachain_heads().len(), ); // the duration until the given timestamp is current let proposed_timestamp = proposal.timestamp(); let timestamp_delay = if proposed_timestamp > current_timestamp { - Some(Duration::from_secs(proposed_timestamp - current_timestamp)) + Some(now + Duration::from_secs(proposed_timestamp - current_timestamp)) } else { None }; + // delay casting vote until able according to minimum block time, + // timestamp delay, and count delay. // construct a future from the maximum of the two durations. - let temporary_delay = match ::std::cmp::max(timestamp_delay, count_delay) { - Some(duration) => { - let maybe_timeout = Timeout::new(duration, &self.handle); + let max_delay = [timestamp_delay, count_delay, Some(self.minimum_delay)] + .iter() + .cloned() + .max() + .expect("iterator not empty; thus max returns `Some`; qed"); - let f = future::result(maybe_timeout) - .and_then(|timeout| timeout) - .map_err(|e| timer_error(&e)); - - future::Either::A(f) - } + let temporary_delay = match max_delay { + Some(duration) => future::Either::A( + Delay::new(duration).map_err(|e| Error::from(ErrorKind::Timer(e))) + ), None => future::Either::B(future::ok(())), }; - minimum_delay.join3(includability_tracker, temporary_delay) + includability_tracker.join(temporary_delay) }; // evaluate whether the block is actually valid. @@ -497,7 +534,7 @@ impl bft::Proposer for Proposer use bft::generic::Misbehavior as GenericMisbehavior; use runtime_primitives::bft::{MisbehaviorKind, MisbehaviorReport}; use runtime_primitives::MaybeUnsigned; - use polkadot_runtime::{Call, Extrinsic, UncheckedExtrinsic, ConsensusCall}; + use polkadot_runtime::{Call, Extrinsic, BareExtrinsic, UncheckedExtrinsic, ConsensusCall}; let local_id = self.local_key.public().0.into(); let mut next_index = { @@ -569,71 +606,59 @@ fn current_timestamp() -> Timestamp { struct ProposalTiming { attempt_propose: Interval, dynamic_inclusion: DynamicInclusion, - enough_candidates: Timeout, - minimum_delay: Option>, + enough_candidates: Delay, + minimum_delay: Option, last_included: usize, } impl ProposalTiming { // whether it's time to attempt a proposal. // shouldn't be called outside of the context of a task. - fn poll(&mut self, included: usize) -> Poll<(), Error> { + fn poll(&mut self, included: usize) -> Poll<(), ErrorKind> { // first drain from the interval so when the minimum delay is up // we don't have any notifications built up. // // this interval is just meant to produce periodic task wakeups // that lead to the `dynamic_inclusion` getting updated as necessary. - if let Async::Ready(x) = self.attempt_propose.poll() - .map_err(|e| timer_error(&e))? - { + if let Async::Ready(x) = self.attempt_propose.poll().map_err(ErrorKind::Timer)? { x.expect("timer still alive; intervals never end; qed"); } if let Some(ref mut min) = self.minimum_delay { - try_ready!(min.poll().map_err(|e| timer_error(&*e))); + try_ready!(min.poll().map_err(ErrorKind::Timer)); } self.minimum_delay = None; // after this point, the future must have completed. if included == self.last_included { - return self.enough_candidates.poll().map_err(|e| timer_error(&e)); + return self.enough_candidates.poll().map_err(ErrorKind::Timer); } // the amount of includable candidates has changed. schedule a wakeup // if it's not sufficient anymore. - let now = Instant::now(); - match self.dynamic_inclusion.acceptable_in(now, included) { - Some(duration) => { + match self.dynamic_inclusion.acceptable_in(Instant::now(), included) { + Some(instant) => { self.last_included = included; - self.enough_candidates.reset(now + duration); - self.enough_candidates.poll().map_err(|e| timer_error(&e)) - } - None => { - Ok(Async::Ready(())) + self.enough_candidates.reset(instant); + self.enough_candidates.poll().map_err(ErrorKind::Timer) } + None => Ok(Async::Ready(())), } } } /// Future which resolves upon the creation of a proposal. -pub struct CreateProposal { +pub struct CreateProposal { parent_hash: Hash, parent_number: BlockNumber, parent_id: BlockId, client: Arc, transaction_pool: Arc>, - collation: CollationFetch, - router: R, table: Arc, timing: ProposalTiming, } -impl CreateProposal - where - C: PolkadotApi, - R: TableRouter, - P: Collators, -{ +impl CreateProposal where C: PolkadotApi { fn propose_with(&self, candidates: Vec) -> Result { use polkadot_api::BlockBuilder; use runtime_primitives::traits::{Hashing, BlakeTwo256}; @@ -702,35 +727,17 @@ impl CreateProposal } } -impl Future for CreateProposal - where - C: PolkadotApi, - R: TableRouter, - P: Collators, -{ +impl Future for CreateProposal where C: PolkadotApi { type Item = Block; type Error = Error; fn poll(&mut self) -> Poll { - // 1. poll local collation future. - match self.collation.poll() { - Ok(Async::Ready((collation, extrinsic))) => { - let hash = collation.receipt.hash(); - self.router.local_candidate_data(hash, collation.block_data, extrinsic); - - // TODO: if we are an availability guarantor also, we should produce an availability statement. - self.table.sign_and_import(&self.router, GenericStatement::Candidate(collation.receipt)); - } - Ok(Async::NotReady) => {}, - Err(_) => {}, // TODO: handle this failure to collate. - } - - // 2. try to propose if we have enough includable candidates and other + // 1. try to propose if we have enough includable candidates and other // delays have concluded. let included = self.table.includable_count(); try_ready!(self.timing.poll(included)); - // 3. propose + // 2. propose let proposed_candidates = self.table.with_proposal(|proposed_set| { proposed_set.into_iter().cloned().collect() }); @@ -738,3 +745,21 @@ impl Future for CreateProposal self.propose_with(proposed_candidates).map(Async::Ready) } } + +#[cfg(test)] +mod tests { + use super::*; + use substrate_keyring::Keyring; + + #[test] + fn sign_and_check_statement() { + let statement: Statement = GenericStatement::Valid([1; 32].into()); + let parent_hash = [2; 32].into(); + + let sig = sign_table_statement(&statement, &Keyring::Alice.pair(), &parent_hash); + + assert!(check_statement(&statement, &sig, Keyring::Alice.to_raw_public().into(), &parent_hash)); + assert!(!check_statement(&statement, &sig, Keyring::Alice.to_raw_public().into(), &[0xff; 32].into())); + assert!(!check_statement(&statement, &sig, Keyring::Bob.to_raw_public().into(), &parent_hash)); + } +} diff --git a/polkadot/consensus/src/service.rs b/polkadot/consensus/src/service.rs index 494e785809..0145164fea 100644 --- a/polkadot/consensus/src/service.rs +++ b/polkadot/consensus/src/service.rs @@ -18,6 +18,10 @@ /// Consensus service. A long runnung service that manages BFT agreement and parachain /// candidate agreement over the network. +/// +/// This uses a handle to an underlying thread pool to dispatch heavy work +/// such as candidate verification while performing event-driven work +/// on a local event loop. use std::thread; use std::time::{Duration, Instant}; @@ -27,197 +31,37 @@ use bft::{self, BftService}; use client::{BlockchainEvents, ChainHead}; use ed25519; use futures::prelude::*; -use futures::{future, Canceled}; use polkadot_api::LocalPolkadotApi; -use polkadot_primitives::{BlockId, Block, Header, Hash, AccountId}; -use polkadot_primitives::parachain::{Id as ParaId, BlockData, Extrinsic, CandidateReceipt}; -use primitives::AuthorityId; -use runtime_support::Hashable; -use substrate_network as net; -use tokio_core::reactor; +use polkadot_primitives::{Block, Header}; use transaction_pool::TransactionPool; -use super::{TableRouter, SharedTable, ProposerFactory}; +use tokio::executor::current_thread::TaskExecutor as LocalThreadHandle; +use tokio::runtime::TaskExecutor as ThreadPoolHandle; +use tokio::runtime::current_thread::Runtime as LocalRuntime; +use tokio::timer::Interval; + +use super::{Network, Collators, ProposerFactory}; use error; const TIMER_DELAY_MS: u64 = 5000; const TIMER_INTERVAL_MS: u64 = 500; -struct BftSink { - network: Arc>, - parent_hash: Hash, - _e: ::std::marker::PhantomData, -} - -struct Messages { - network_stream: net::BftMessageStream, - local_id: AuthorityId, - authorities: Vec, -} - -impl Stream for Messages { - type Item = bft::Communication; - type Error = bft::Error; - - fn poll(&mut self) -> Poll, Self::Error> { - // check the network - loop { - match self.network_stream.poll() { - Err(_) => return Err(bft::InputStreamConcluded.into()), - Ok(Async::NotReady) => return Ok(Async::NotReady), - Ok(Async::Ready(None)) => return Ok(Async::NotReady), // the input stream for agreements is never meant to logically end. - Ok(Async::Ready(Some(message))) => { - match process_message(message, &self.local_id, &self.authorities) { - Ok(Some(message)) => return Ok(Async::Ready(Some(message))), - Ok(None) => {} // ignored local message. - Err(e) => { - debug!("Message validation failed: {:?}", e); - } - } - } - } - } - } -} - -fn process_message(msg: net::LocalizedBftMessage, local_id: &AuthorityId, authorities: &[AuthorityId]) -> Result>, bft::Error> { - Ok(Some(match msg.message { - net::generic_message::BftMessage::Consensus(c) => bft::generic::Communication::Consensus(match c { - net::generic_message::SignedConsensusMessage::Propose(proposal) => bft::generic::LocalizedMessage::Propose({ - if &proposal.sender == local_id { return Ok(None) } - let proposal = bft::generic::LocalizedProposal { - round_number: proposal.round_number as usize, - proposal: proposal.proposal, - digest: proposal.digest, - sender: proposal.sender, - digest_signature: ed25519::LocalizedSignature { - signature: proposal.digest_signature, - signer: proposal.sender.into(), - }, - full_signature: ed25519::LocalizedSignature { - signature: proposal.full_signature, - signer: proposal.sender.into(), - } - }; - bft::check_proposal(authorities, &msg.parent_hash, &proposal)?; - - trace!(target: "bft", "importing proposal message for round {} from {}", proposal.round_number, proposal.sender); - proposal - }), - net::generic_message::SignedConsensusMessage::Vote(vote) => bft::generic::LocalizedMessage::Vote({ - if &vote.sender == local_id { return Ok(None) } - let vote = bft::generic::LocalizedVote { - sender: vote.sender, - signature: ed25519::LocalizedSignature { - signature: vote.signature, - signer: vote.sender.into(), - }, - vote: match vote.vote { - net::generic_message::ConsensusVote::Prepare(r, h) => bft::generic::Vote::Prepare(r as usize, h), - net::generic_message::ConsensusVote::Commit(r, h) => bft::generic::Vote::Commit(r as usize, h), - net::generic_message::ConsensusVote::AdvanceRound(r) => bft::generic::Vote::AdvanceRound(r as usize), - } - }; - bft::check_vote::(authorities, &msg.parent_hash, &vote)?; - - trace!(target: "bft", "importing vote {:?} from {}", vote.vote, vote.sender); - vote - }), - }), - net::generic_message::BftMessage::Auxiliary(a) => { - let justification = bft::UncheckedJustification::::from(a); - // TODO: get proper error - let justification: Result<_, bft::Error> = bft::check_prepare_justification::(authorities, msg.parent_hash, justification) - .map_err(|_| bft::ErrorKind::InvalidJustification.into()); - bft::generic::Communication::Auxiliary(justification?) - }, - })) -} - -impl Sink for BftSink { - type SinkItem = bft::Communication; - // TODO: replace this with the ! type when that's stabilized - type SinkError = E; - - fn start_send(&mut self, message: bft::Communication) -> ::futures::StartSend, E> { - let network_message = net::generic_message::LocalizedBftMessage { - message: match message { - bft::generic::Communication::Consensus(c) => net::generic_message::BftMessage::Consensus(match c { - bft::generic::LocalizedMessage::Propose(proposal) => net::generic_message::SignedConsensusMessage::Propose(net::generic_message::SignedConsensusProposal { - round_number: proposal.round_number as u32, - proposal: proposal.proposal, - digest: proposal.digest, - sender: proposal.sender, - digest_signature: proposal.digest_signature.signature, - full_signature: proposal.full_signature.signature, - }), - bft::generic::LocalizedMessage::Vote(vote) => net::generic_message::SignedConsensusMessage::Vote(net::generic_message::SignedConsensusVote { - sender: vote.sender, - signature: vote.signature.signature, - vote: match vote.vote { - bft::generic::Vote::Prepare(r, h) => net::generic_message::ConsensusVote::Prepare(r as u32, h), - bft::generic::Vote::Commit(r, h) => net::generic_message::ConsensusVote::Commit(r as u32, h), - bft::generic::Vote::AdvanceRound(r) => net::generic_message::ConsensusVote::AdvanceRound(r as u32), - } - }), - }), - bft::generic::Communication::Auxiliary(justification) => net::generic_message::BftMessage::Auxiliary(justification.uncheck().into()), - }, - parent_hash: self.parent_hash, - }; - self.network.send_bft_message(network_message); - Ok(::futures::AsyncSink::Ready) - } - - fn poll_complete(&mut self) -> ::futures::Poll<(), E> { - Ok(Async::Ready(())) - } -} - -struct Network(Arc>); - -impl super::Network for Network { - type TableRouter = Router; - fn table_router(&self, _table: Arc) -> Self::TableRouter { - Router { - network: self.0.clone() - } - } -} - +// spin up an instance of BFT agreement on the current thread's executor. +// panics if there is no current thread executor. fn start_bft( header: &Header, - handle: reactor::Handle, - client: &bft::Authorities, - network: Arc>, bft_service: &BftService, ) where - F: bft::ProposerFactory + 'static, + F: bft::Environment + 'static, C: bft::BlockImport + bft::Authorities + 'static, - >::Error: ::std::fmt::Debug, + F::Error: ::std::fmt::Debug, >::Error: ::std::fmt::Display + Into, { - let parent_hash = header.hash(); - if bft_service.live_agreement().map_or(false, |h| h == parent_hash) { - return; - } - let authorities = match client.authorities(&BlockId::hash(parent_hash)) { - Ok(authorities) => authorities, - Err(e) => { - debug!("Error reading authorities: {:?}", e); - return; - } - }; - - let input = Messages { - network_stream: network.bft_messages(parent_hash), - local_id: bft_service.local_id(), - authorities, - }; - - let output = BftSink { network: network, parent_hash: parent_hash, _e: Default::default() }; - match bft_service.build_upon(&header, input.map_err(Into::into), output) { - Ok(Some(bft)) => handle.spawn(bft), + let mut handle = LocalThreadHandle::current(); + match bft_service.build_upon(&header) { + Ok(Some(bft)) => if let Err(e) = handle.spawn_local(Box::new(bft)) { + debug!(target: "bft", "Couldn't initialize BFT agreement: {:?}", e); + }, Ok(None) => {}, Err(e) => debug!(target: "bft", "BFT agreement error: {:?}", e), } @@ -231,54 +75,56 @@ pub struct Service { impl Service { /// Create and start a new instance. - pub fn new( + pub fn new( client: Arc, api: Arc, - network: Arc>, + network: N, transaction_pool: Arc>, + thread_pool: ThreadPoolHandle, parachain_empty_duration: Duration, key: ed25519::Pair, ) -> Service where A: LocalPolkadotApi + Send + Sync + 'static, C: BlockchainEvents + ChainHead + bft::BlockImport + bft::Authorities + Send + Sync + 'static, + N: Network + Collators + Send + 'static, + N::TableRouter: Send + 'static, + ::Future: Send + 'static, { let (signal, exit) = ::exit_future::signal(); let thread = thread::spawn(move || { - let mut core = reactor::Core::new().expect("tokio::Core could not be created"); + let mut runtime = LocalRuntime::new().expect("Could not create local runtime"); let key = Arc::new(key); let factory = ProposerFactory { client: api.clone(), transaction_pool: transaction_pool.clone(), - network: Network(network.clone()), - collators: NoCollators, + collators: network.clone(), + network, parachain_empty_duration, - handle: core.handle(), + handle: thread_pool, }; let bft_service = Arc::new(BftService::new(client.clone(), key, factory)); let notifications = { - let handle = core.handle(); - let network = network.clone(); let client = client.clone(); let bft_service = bft_service.clone(); client.import_notification_stream().for_each(move |notification| { if notification.is_new_best { - start_bft(¬ification.header, handle.clone(), &*client, network.clone(), &*bft_service); + start_bft(¬ification.header, &*bft_service); } Ok(()) }) }; - let interval = reactor::Interval::new_at( + let interval = Interval::new( Instant::now() + Duration::from_millis(TIMER_DELAY_MS), Duration::from_millis(TIMER_INTERVAL_MS), - &core.handle(), - ).expect("it is always possible to create an interval with valid params"); + ); + let mut prev_best = match client.best_block_header() { - Ok(header) => header.blake2_256(), + Ok(header) => header.hash(), Err(e) => { warn!("Cant's start consensus service. Error reading best block header: {:?}", e); return; @@ -288,15 +134,13 @@ impl Service { let timed = { let c = client.clone(); let s = bft_service.clone(); - let n = network.clone(); - let handle = core.handle(); interval.map_err(|e| debug!("Timer error: {:?}", e)).for_each(move |_| { if let Ok(best_block) = c.best_block_header() { - let hash = best_block.blake2_256(); + let hash = best_block.hash(); if hash == prev_best { debug!("Starting consensus round after a timeout"); - start_bft(&best_block, handle.clone(), &*c, n.clone(), &*s); + start_bft(&best_block, &*s); } prev_best = hash; } @@ -304,9 +148,9 @@ impl Service { }) }; - core.handle().spawn(notifications); - core.handle().spawn(timed); - if let Err(e) = core.run(exit) { + runtime.spawn(notifications); + runtime.spawn(timed); + if let Err(e) = runtime.block_on(exit) { debug!("BFT event loop error {:?}", e); } }); @@ -328,42 +172,3 @@ impl Drop for Service { } } } - -// Collators implementation which never collates anything. -// TODO: do a real implementation. -#[derive(Clone, Copy)] -struct NoCollators; - -impl ::collation::Collators for NoCollators { - type Error = (); - type Collation = future::Empty<::collation::Collation, ()>; - - fn collate(&self, _parachain: ParaId, _relay_parent: Hash) -> Self::Collation { - future::empty() - } - - fn note_bad_collator(&self, _collator: AccountId) { } -} - -#[derive(Clone)] -struct Router { - network: Arc>, -} - -impl TableRouter for Router { - type Error = Canceled; - type FetchCandidate = future::Empty; - type FetchExtrinsic = future::FutureResult; - - fn local_candidate_data(&self, _hash: Hash, _block_data: BlockData, _extrinsic: Extrinsic) { - // TODO - } - - fn fetch_block_data(&self, _candidate: &CandidateReceipt) -> Self::FetchCandidate { - future::empty() - } - - fn fetch_extrinsic_data(&self, _candidate: &CandidateReceipt) -> Self::FetchExtrinsic { - future::ok(Extrinsic) - } -} diff --git a/polkadot/consensus/src/shared_table/mod.rs b/polkadot/consensus/src/shared_table/mod.rs index 1c46b67b09..15116c5cfb 100644 --- a/polkadot/consensus/src/shared_table/mod.rs +++ b/polkadot/consensus/src/shared_table/mod.rs @@ -21,11 +21,9 @@ use std::collections::{HashMap, HashSet}; use std::sync::Arc; use table::{self, Table, Context as TableContextTrait}; -use table::generic::Statement as GenericStatement; use collation::Collation; -use polkadot_primitives::Hash; +use polkadot_primitives::{Hash, SessionKey}; use polkadot_primitives::parachain::{Id as ParaId, BlockData, Extrinsic, CandidateReceipt}; -use primitives::AuthorityId; use parking_lot::Mutex; use futures::{future, prelude::*}; @@ -36,6 +34,8 @@ use self::includable::IncludabilitySender; mod includable; pub use self::includable::Includable; +pub use table::{SignedStatement, Statement}; +pub use table::generic::Statement as GenericStatement; struct TableContext { parent_hash: Hash, @@ -44,11 +44,11 @@ struct TableContext { } impl table::Context for TableContext { - fn is_member_of(&self, authority: &AuthorityId, group: &ParaId) -> bool { + fn is_member_of(&self, authority: &SessionKey, group: &ParaId) -> bool { self.groups.get(group).map_or(false, |g| g.validity_guarantors.contains(authority)) } - fn is_availability_guarantor_of(&self, authority: &AuthorityId, group: &ParaId) -> bool { + fn is_availability_guarantor_of(&self, authority: &SessionKey, group: &ParaId) -> bool { self.groups.get(group).map_or(false, |g| g.availability_guarantors.contains(authority)) } @@ -61,7 +61,7 @@ impl table::Context for TableContext { } impl TableContext { - fn local_id(&self) -> AuthorityId { + fn local_id(&self) -> SessionKey { self.key.public().into() } @@ -76,14 +76,6 @@ impl TableContext { } } -/// Source of statements -pub enum StatementSource { - /// Locally produced statement. - Local, - /// Received statement from remote source, with optional sender. - Remote(Option), -} - // A shared table object. struct SharedTableInner { table: Table, @@ -96,28 +88,21 @@ struct SharedTableInner { impl SharedTableInner { // Import a single statement. Provide a handle to a table router and a function // used to determine if a referenced candidate is valid. - fn import_statement bool>( + // + // the statement producer, if any, will produce only statements concerning the same candidate + // as the one just imported + fn import_remote_statement( &mut self, context: &TableContext, router: &R, statement: table::SignedStatement, - statement_source: StatementSource, - check_candidate: C, - ) -> StatementProducer< + ) -> Option::Future, ::Future, - C, - > { - // this blank producer does nothing until we attach some futures - // and set a candidate digest. - let received_from = match statement_source { - StatementSource::Local => return Default::default(), - StatementSource::Remote(from) => from, - }; - - let summary = match self.table.import_statement(context, statement, received_from) { + >> { + let summary = match self.table.import_statement(context, statement) { Some(summary) => summary, - None => return Default::default(), + None => return None, }; self.update_trackers(&summary.candidate, context); @@ -159,7 +144,6 @@ impl SharedTableInner { fetch_block_data, fetch_extrinsic, evaluate: checking_validity, - check_candidate, }) } } @@ -167,10 +151,10 @@ impl SharedTableInner { None }; - StatementProducer { + work.map(|work| StatementProducer { produced_statements: Default::default(), - work, - } + work + }) } fn update_trackers(&mut self, candidate: &Hash, context: &TableContext) { @@ -199,71 +183,78 @@ pub struct ProducedStatements { } /// Future that produces statements about a specific candidate. -pub struct StatementProducer { +pub struct StatementProducer { produced_statements: ProducedStatements, - work: Option>, + work: Work, } -struct Work { - candidate_receipt: CandidateReceipt, - fetch_block_data: future::Fuse, - fetch_extrinsic: Option>, - evaluate: bool, - check_candidate: C -} - -impl Default for StatementProducer { - fn default() -> Self { - StatementProducer { - produced_statements: Default::default(), - work: None, +impl StatementProducer { + /// Attach a function for verifying fetched collation to the statement producer. + /// This will transform it into a future. + /// + /// The collation-checking function should return `true` if known to be valid, + /// `false` if known to be invalid, and `None` if unable to determine. + pub fn prime Option>(self, check_candidate: C) -> PrimedStatementProducer { + PrimedStatementProducer { + inner: self, + check_candidate, } } } -impl Future for StatementProducer +struct Work { + candidate_receipt: CandidateReceipt, + fetch_block_data: future::Fuse, + fetch_extrinsic: Option>, + evaluate: bool, +} + +/// Primed statement producer. +pub struct PrimedStatementProducer { + inner: StatementProducer, + check_candidate: C, +} + +impl Future for PrimedStatementProducer where D: Future, E: Future, - C: FnMut(Collation) -> bool, + C: FnMut(Collation) -> Option, { type Item = ProducedStatements; type Error = Err; fn poll(&mut self) -> Poll { - let work = match self.work { - Some(ref mut work) => work, - None => return Ok(Async::Ready(::std::mem::replace(&mut self.produced_statements, Default::default()))), - }; + let work = &mut self.inner.work; if let Async::Ready(block_data) = work.fetch_block_data.poll()? { - self.produced_statements.block_data = Some(block_data.clone()); + self.inner.produced_statements.block_data = Some(block_data.clone()); if work.evaluate { - let is_good = (work.check_candidate)(Collation { + let is_good = (self.check_candidate)(Collation { block_data, receipt: work.candidate_receipt.clone(), }); let hash = work.candidate_receipt.hash(); - self.produced_statements.validity = Some(if is_good { - GenericStatement::Valid(hash) - } else { - GenericStatement::Invalid(hash) - }); + self.inner.produced_statements.validity = match is_good { + Some(true) => Some(GenericStatement::Valid(hash)), + Some(false) => Some(GenericStatement::Invalid(hash)), + None => None, + }; } } if let Some(ref mut fetch_extrinsic) = work.fetch_extrinsic { if let Async::Ready(extrinsic) = fetch_extrinsic.poll()? { - self.produced_statements.extrinsic = Some(extrinsic); + self.inner.produced_statements.extrinsic = Some(extrinsic); } } - let done = self.produced_statements.block_data.is_some() && { + let done = self.inner.produced_statements.block_data.is_some() && { if work.evaluate { true - } else if self.produced_statements.extrinsic.is_some() { - self.produced_statements.availability = + } else if self.inner.produced_statements.extrinsic.is_some() { + self.inner.produced_statements.availability = Some(GenericStatement::Available(work.candidate_receipt.hash())); true @@ -273,7 +264,7 @@ impl Future for StatementProducer }; if done { - Ok(Async::Ready(::std::mem::replace(&mut self.produced_statements, Default::default()))) + Ok(Async::Ready(::std::mem::replace(&mut self.inner.produced_statements, Default::default()))) } else { Ok(Async::NotReady) } @@ -313,29 +304,60 @@ impl SharedTable { } } + /// Get the parent hash this table should hold statements localized to. + pub fn consensus_parent_hash(&self) -> &Hash { + &self.context.parent_hash + } + + /// Get the local validator session key. + pub fn session_key(&self) -> SessionKey { + self.context.local_id() + } + /// Get group info. pub fn group_info(&self) -> &HashMap { &self.context.groups } - /// Import a single statement. Provide a handle to a table router - /// for dispatching any other requests which come up. - pub fn import_statement bool>( + /// Import a single statement with remote source, whose signature has already been checked. + /// + /// The statement producer, if any, will produce only statements concerning the same candidate + /// as the one just imported + pub fn import_remote_statement( &self, router: &R, statement: table::SignedStatement, - received_from: StatementSource, - check_candidate: C, - ) -> StatementProducer<::Future, ::Future, C> { - self.inner.lock().import_statement(&*self.context, router, statement, received_from, check_candidate) + ) -> Option::Future, + ::Future, + >> { + self.inner.lock().import_remote_statement(&*self.context, router, statement) + } + + /// Import many statements at once. + /// + /// Provide an iterator yielding remote, pre-checked statements. + /// + /// The statement producer, if any, will produce only statements concerning the same candidate + /// as the one just imported + pub fn import_remote_statements(&self, router: &R, iterable: I) -> U + where + R: TableRouter, + I: IntoIterator, + U: ::std::iter::FromIterator::Future, + ::Future, + >>>, + { + let mut inner = self.inner.lock(); + + iterable.into_iter().map(move |statement| { + inner.import_remote_statement(&*self.context, router, statement) + }).collect() } /// Sign and import a local statement. - pub fn sign_and_import( - &self, - router: &R, - statement: table::Statement, - ) { + pub fn sign_and_import(&self, statement: table::Statement) -> SignedStatement { let proposed_digest = match statement { GenericStatement::Candidate(ref c) => Some(c.hash()), _ => None, @@ -348,36 +370,8 @@ impl SharedTable { inner.proposed_digest = proposed_digest; } - let producer = inner.import_statement( - &*self.context, - router, - signed_statement, - StatementSource::Local, - |_| true, - ); - - assert!(producer.work.is_none(), "local statement import never leads to additional work; qed"); - } - - /// Import many statements at once. - /// - /// Provide an iterator yielding pairs of (statement, statement_source). - pub fn import_statements(&self, router: &R, iterable: I) -> U - where - R: TableRouter, - I: IntoIterator, - C: FnMut(Collation) -> bool, - U: ::std::iter::FromIterator::Future, - ::Future, - C, - >>, - { - let mut inner = self.inner.lock(); - - iterable.into_iter().map(move |(statement, statement_source, check_candidate)| { - inner.import_statement(&*self.context, router, statement, statement_source, check_candidate) - }).collect() + inner.table.import_statement(&*self.context, signed_statement.clone()); + signed_statement } /// Execute a closure using a specific candidate. @@ -406,15 +400,10 @@ impl SharedTable { } /// Get all witnessed misbehavior. - pub fn get_misbehavior(&self) -> HashMap { + pub fn get_misbehavior(&self) -> HashMap { self.inner.lock().table.get_misbehavior().clone() } - /// Fill a statement batch. - pub fn fill_batch(&self, batch: &mut B) { - self.inner.lock().table.fill_batch(batch); - } - /// Track includability of a given set of candidate hashes. pub fn track_includability(&self, iterable: I) -> Includable where I: IntoIterator @@ -446,17 +435,12 @@ mod tests { type FetchCandidate = ::futures::future::Empty; type FetchExtrinsic = ::futures::future::Empty; - /// Note local candidate data, making it available on the network to other validators. - fn local_candidate_data(&self, _hash: Hash, _block_data: BlockData, _extrinsic: Extrinsic) { + fn local_candidate(&self, _candidate: CandidateReceipt, _block_data: BlockData, _extrinsic: Extrinsic) { } - - /// Fetch block data for a specific candidate. fn fetch_block_data(&self, _candidate: &CandidateReceipt) -> Self::FetchCandidate { ::futures::future::empty() } - - /// Fetch extrinsic data for a specific candidate. fn fetch_extrinsic_data(&self, _candidate: &CandidateReceipt) -> Self::FetchExtrinsic { ::futures::future::empty() } @@ -490,6 +474,7 @@ mod tests { balance_uploads: Vec::new(), egress_queue_roots: Vec::new(), fees: 1_000_000, + block_data_hash: [2; 32].into(), }; let candidate_statement = GenericStatement::Candidate(candidate); @@ -501,15 +486,13 @@ mod tests { sender: validity_other, }; - let producer = shared_table.import_statement( + let producer = shared_table.import_remote_statement( &DummyRouter, signed_statement, - StatementSource::Remote(None), - |_| true, - ); + ).expect("candidate and local validity group are same"); - assert!(producer.work.is_some(), "candidate and local validity group are same"); - assert!(producer.work.as_ref().unwrap().evaluate, "should evaluate validity"); + assert!(producer.work.evaluate, "should evaluate validity"); + assert!(producer.work.fetch_extrinsic.is_none(), "should not fetch extrinsic"); } #[test] @@ -540,6 +523,7 @@ mod tests { balance_uploads: Vec::new(), egress_queue_roots: Vec::new(), fees: 1_000_000, + block_data_hash: [2; 32].into(), }; let candidate_statement = GenericStatement::Candidate(candidate); @@ -551,15 +535,12 @@ mod tests { sender: validity_other, }; - let producer = shared_table.import_statement( + let producer = shared_table.import_remote_statement( &DummyRouter, signed_statement, - StatementSource::Remote(None), - |_| true, - ); + ).expect("should produce work"); - assert!(producer.work.is_some(), "candidate and local availability group are same"); - assert!(producer.work.as_ref().unwrap().fetch_extrinsic.is_some(), "should fetch extrinsic when guaranteeing availability"); - assert!(!producer.work.as_ref().unwrap().evaluate, "should not evaluate validity"); + assert!(producer.work.fetch_extrinsic.is_some(), "should fetch extrinsic when guaranteeing availability"); + assert!(!producer.work.evaluate, "should not evaluate validity"); } } diff --git a/polkadot/network/Cargo.toml b/polkadot/network/Cargo.toml new file mode 100644 index 0000000000..ad07af5c12 --- /dev/null +++ b/polkadot/network/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "polkadot-network" +version = "0.1.0" +authors = ["Parity Technologies "] +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" } +polkadot-primitives = { path = "../primitives" } +substrate-bft = { path = "../../substrate/bft" } +substrate-codec = { path = "../../substrate/codec" } +substrate-network = { path = "../../substrate/network" } +substrate-primitives = { path = "../../substrate/primitives" } +ed25519 = { path = "../../substrate/ed25519" } +futures = "0.1" +tokio = "0.1.7" +log = "0.4" diff --git a/polkadot/network/src/consensus.rs b/polkadot/network/src/consensus.rs new file mode 100644 index 0000000000..b575856739 --- /dev/null +++ b/polkadot/network/src/consensus.rs @@ -0,0 +1,313 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! The "consensus" networking code built on top of the base network service. +//! This fulfills the `polkadot_consensus::Network` trait, providing a hook to be called +//! each time consensus begins on a new chain head. + +use bft; +use ed25519; +use substrate_network::{self as net, generic_message as msg}; +use substrate_network::consensus_gossip::ConsensusMessage; +use polkadot_api::{PolkadotApi, LocalPolkadotApi}; +use polkadot_consensus::{Network, SharedTable, Collators, Collation}; +use polkadot_primitives::{AccountId, Block, Hash, SessionKey}; +use polkadot_primitives::parachain::Id as ParaId; + +use futures::{future, prelude::*}; +use futures::sync::mpsc; + +use std::sync::Arc; + +use tokio::runtime::TaskExecutor; +use parking_lot::Mutex; + +use super::{Message, NetworkService, Knowledge, CurrentConsensus}; +use router::Router; + +/// Sink for output BFT messages. +pub struct BftSink { + network: Arc, + parent_hash: Hash, + _marker: ::std::marker::PhantomData, +} + +impl Sink for BftSink { + type SinkItem = bft::Communication; + // TODO: replace this with the ! type when that's stabilized + type SinkError = E; + + fn start_send(&mut self, message: bft::Communication) -> ::futures::StartSend, E> { + let network_message = net::LocalizedBftMessage { + message: match message { + bft::generic::Communication::Consensus(c) => msg::BftMessage::Consensus(match c { + bft::generic::LocalizedMessage::Propose(proposal) => msg::SignedConsensusMessage::Propose(msg::SignedConsensusProposal { + round_number: proposal.round_number as u32, + proposal: proposal.proposal, + digest: proposal.digest, + sender: proposal.sender, + digest_signature: proposal.digest_signature.signature, + full_signature: proposal.full_signature.signature, + }), + bft::generic::LocalizedMessage::Vote(vote) => msg::SignedConsensusMessage::Vote(msg::SignedConsensusVote { + sender: vote.sender, + signature: vote.signature.signature, + vote: match vote.vote { + bft::generic::Vote::Prepare(r, h) => msg::ConsensusVote::Prepare(r as u32, h), + bft::generic::Vote::Commit(r, h) => msg::ConsensusVote::Commit(r as u32, h), + bft::generic::Vote::AdvanceRound(r) => msg::ConsensusVote::AdvanceRound(r as u32), + } + }), + }), + bft::generic::Communication::Auxiliary(justification) => msg::BftMessage::Auxiliary(justification.uncheck().into()), + }, + parent_hash: self.parent_hash, + }; + self.network.with_spec( + move |spec, ctx| spec.consensus_gossip.multicast_bft_message(ctx, network_message) + ); + Ok(::futures::AsyncSink::Ready) + } + + fn poll_complete(&mut self) -> ::futures::Poll<(), E> { + Ok(Async::Ready(())) + } +} + +// check signature and authority validity of message. +fn process_bft_message(msg: msg::LocalizedBftMessage, local_id: &SessionKey, authorities: &[SessionKey]) -> Result>, bft::Error> { + Ok(Some(match msg.message { + msg::BftMessage::Consensus(c) => bft::generic::Communication::Consensus(match c { + msg::SignedConsensusMessage::Propose(proposal) => bft::generic::LocalizedMessage::Propose({ + if &proposal.sender == local_id { return Ok(None) } + let proposal = bft::generic::LocalizedProposal { + round_number: proposal.round_number as usize, + proposal: proposal.proposal, + digest: proposal.digest, + sender: proposal.sender, + digest_signature: ed25519::LocalizedSignature { + signature: proposal.digest_signature, + signer: ed25519::Public(proposal.sender.into()), + }, + full_signature: ed25519::LocalizedSignature { + signature: proposal.full_signature, + signer: ed25519::Public(proposal.sender.into()), + } + }; + bft::check_proposal(authorities, &msg.parent_hash, &proposal)?; + + trace!(target: "bft", "importing proposal message for round {} from {}", proposal.round_number, Hash::from(proposal.sender.0)); + proposal + }), + msg::SignedConsensusMessage::Vote(vote) => bft::generic::LocalizedMessage::Vote({ + if &vote.sender == local_id { return Ok(None) } + let vote = bft::generic::LocalizedVote { + sender: vote.sender, + signature: ed25519::LocalizedSignature { + signature: vote.signature, + signer: ed25519::Public(vote.sender.0), + }, + vote: match vote.vote { + msg::ConsensusVote::Prepare(r, h) => bft::generic::Vote::Prepare(r as usize, h), + msg::ConsensusVote::Commit(r, h) => bft::generic::Vote::Commit(r as usize, h), + msg::ConsensusVote::AdvanceRound(r) => bft::generic::Vote::AdvanceRound(r as usize), + } + }; + bft::check_vote::(authorities, &msg.parent_hash, &vote)?; + + trace!(target: "bft", "importing vote {:?} from {}", vote.vote, Hash::from(vote.sender.0)); + vote + }), + }), + msg::BftMessage::Auxiliary(a) => { + let justification = bft::UncheckedJustification::from(a); + // TODO: get proper error + let justification: Result<_, bft::Error> = bft::check_prepare_justification::(authorities, msg.parent_hash, justification) + .map_err(|_| bft::ErrorKind::InvalidJustification.into()); + bft::generic::Communication::Auxiliary(justification?) + }, + })) +} + +// task that processes all gossipped consensus messages, +// checking signatures +struct MessageProcessTask { + inner_stream: mpsc::UnboundedReceiver>, + bft_messages: mpsc::UnboundedSender>, + validators: Vec, + table_router: Router

, +} + +impl MessageProcessTask

{ + fn process_message(&self, msg: ConsensusMessage) -> Option> { + match msg { + ConsensusMessage::Bft(msg) => { + let local_id = self.table_router.session_key(); + match process_bft_message(msg, &local_id, &self.validators[..]) { + Ok(Some(msg)) => { + if let Err(_) = self.bft_messages.unbounded_send(msg) { + // if the BFT receiving stream has ended then + // we should just bail. + trace!(target: "bft", "BFT message stream appears to have closed"); + return Some(Async::Ready(())); + } + } + Ok(None) => {} // ignored local message + Err(e) => { + debug!("Message validation failed: {:?}", e); + } + } + } + ConsensusMessage::ChainSpecific(msg, _) => { + if let Ok(Message::Statement(parent_hash, statement)) = ::serde_json::from_slice(&msg) { + if ::polkadot_consensus::check_statement(&statement.statement, &statement.signature, statement.sender, &parent_hash) { + self.table_router.import_statement(statement); + } + } + } + } + + None + } +} + +impl Future for MessageProcessTask

{ + type Item = (); + type Error = (); + + fn poll(&mut self) -> Poll<(), ()> { + loop { + match self.inner_stream.poll() { + Ok(Async::Ready(Some(val))) => if let Some(async) = self.process_message(val) { + return Ok(async); + }, + Ok(Async::Ready(None)) => return Ok(Async::Ready(())), + Ok(Async::NotReady) => (), + Err(e) => debug!(target: "p_net", "Error getting consensus message: {:?}", e), + } + } + } +} + +/// Input stream from the consensus network. +pub struct InputAdapter { + input: mpsc::UnboundedReceiver>, +} + +impl Stream for InputAdapter { + type Item = bft::Communication; + type Error = ::polkadot_consensus::Error; + + fn poll(&mut self) -> Poll, Self::Error> { + match self.input.poll() { + Err(_) | Ok(Async::Ready(None)) => Err(bft::InputStreamConcluded.into()), + Ok(x) => Ok(x) + } + } +} + +/// Wrapper around the network service +pub struct ConsensusNetwork

{ + network: Arc, + api: Arc

, +} + +impl

ConsensusNetwork

{ + /// Create a new consensus networking object. + pub fn new(network: Arc, api: Arc

) -> Self { + ConsensusNetwork { network, api } + } +} + +impl

Clone for ConsensusNetwork

{ + fn clone(&self) -> Self { + ConsensusNetwork { + network: self.network.clone(), + api: self.api.clone(), + } + } +} + +/// A long-lived network which can create parachain statement and BFT message routing processes on demand. +impl Network for ConsensusNetwork

{ + type TableRouter = Router

; + /// The input stream of BFT messages. Should never logically conclude. + type Input = InputAdapter; + /// The output sink of BFT messages. Messages sent here should eventually pass to all + /// current validators. + type Output = BftSink<::polkadot_consensus::Error>; + + /// Instantiate a table router using the given shared table. + fn communication_for(&self, validators: &[SessionKey], table: Arc, task_executor: TaskExecutor) -> (Self::TableRouter, Self::Input, Self::Output) { + let parent_hash = table.consensus_parent_hash().clone(); + + let sink = BftSink { + network: self.network.clone(), + parent_hash, + _marker: Default::default(), + }; + + let (bft_send, bft_recv) = mpsc::unbounded(); + + let knowledge = Arc::new(Mutex::new(Knowledge::new())); + + let local_session_key = table.session_key(); + let table_router = Router::new( + table, + self.network.clone(), + self.api.clone(), + task_executor.clone(), + parent_hash, + knowledge.clone(), + ); + + // spin up a task in the background that processes all incoming statements + // TODO: propagate statements on a timer? + let process_task = self.network.with_spec(|spec, ctx| { + spec.new_consensus(ctx, CurrentConsensus { + knowledge, + parent_hash, + local_session_key, + session_keys: Default::default(), + }); + + MessageProcessTask { + inner_stream: spec.consensus_gossip.messages_for(parent_hash), + bft_messages: bft_send, + validators: validators.to_vec(), + table_router: table_router.clone(), + } + }); + + match process_task { + Some(task) => task_executor.spawn(task), + None => warn!(target: "p_net", "Cannot process incoming messages: network appears to be down"), + } + + (table_router, InputAdapter { input: bft_recv }, sink) + } +} + +impl Collators for ConsensusNetwork

{ + type Error = (); + type Collation = future::Empty; + + fn collate(&self, _parachain: ParaId, _relay_parent: Hash) -> Self::Collation { + future::empty() + } + + fn note_bad_collator(&self, _collator: AccountId) { } +} diff --git a/polkadot/network/src/lib.rs b/polkadot/network/src/lib.rs new file mode 100644 index 0000000000..f909d0581b --- /dev/null +++ b/polkadot/network/src/lib.rs @@ -0,0 +1,488 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Polkadot-specific network implementation. +//! +//! This manages gossip of consensus messages for BFT and for parachain statements, +//! 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; +extern crate substrate_primitives; + +extern crate polkadot_api; +extern crate polkadot_consensus; +extern crate polkadot_primitives; + +extern crate ed25519; +extern crate futures; +extern crate parking_lot; +extern crate tokio; + +#[macro_use] +extern crate log; + +mod router; +pub mod consensus; + +use codec::Slicable; +use futures::sync::oneshot; +use parking_lot::Mutex; +use polkadot_consensus::{Statement, SignedStatement, GenericStatement}; +use polkadot_primitives::{Block, SessionKey, Hash}; +use polkadot_primitives::parachain::{Id as ParaId, BlockData, Extrinsic, CandidateReceipt}; +use substrate_network::{PeerId, RequestId, Context}; +use substrate_network::consensus_gossip::ConsensusGossip; +use substrate_network::{message, generic_message}; +use substrate_network::specialization::Specialization; +use substrate_network::StatusMessage as GenericFullStatus; + +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; + +#[cfg(test)] +mod tests; + +/// Polkadot protocol id. +pub const DOT_PROTOCOL_ID: ::substrate_network::ProtocolId = *b"dot"; + +type FullStatus = GenericFullStatus; + +/// Specialization of the network service for the polkadot protocol. +pub type NetworkService = ::substrate_network::Service; + +/// Status of a Polkadot node. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Status { + collating_for: Option, +} + +impl Slicable for Status { + fn encode(&self) -> Vec { + let mut v = Vec::new(); + match self.collating_for { + Some(ref id) => { + v.push(1); + id.using_encoded(|s| v.extend(s)); + } + None => { + v.push(0); + } + } + v + } + + fn decode(input: &mut I) -> Option { + let collating_for = match input.read_byte()? { + 0 => None, + 1 => Some(ParaId::decode(input)?), + _ => return None, + }; + Some(Status { collating_for }) + } +} + +struct BlockDataRequest { + attempted_peers: HashSet, + consensus_parent: Hash, + candidate_hash: Hash, + block_data_hash: Hash, + sender: oneshot::Sender, +} + +struct PeerInfo { + status: Status, + validator: bool, + session_keys: HashMap, +} + +#[derive(Default)] +struct KnowledgeEntry { + knows_block_data: Vec, + knows_extrinsic: Vec, + block_data: Option, + extrinsic: Option, +} + +/// Tracks knowledge of peers. +struct Knowledge { + candidates: HashMap, +} + +impl Knowledge { + pub fn new() -> Self { + Knowledge { + candidates: HashMap::new(), + } + } + + fn note_statement(&mut self, from: SessionKey, statement: &Statement) { + match *statement { + GenericStatement::Candidate(ref c) => { + let mut entry = self.candidates.entry(c.hash()).or_insert_with(Default::default); + entry.knows_block_data.push(from); + entry.knows_extrinsic.push(from); + } + GenericStatement::Available(ref hash) => { + let mut entry = self.candidates.entry(*hash).or_insert_with(Default::default); + entry.knows_block_data.push(from); + entry.knows_extrinsic.push(from); + } + GenericStatement::Valid(ref hash) | GenericStatement::Invalid(ref hash) => self.candidates.entry(*hash) + .or_insert_with(Default::default) + .knows_block_data + .push(from), + } + } + + fn note_candidate(&mut self, hash: Hash, block_data: Option, extrinsic: Option) { + let entry = self.candidates.entry(hash).or_insert_with(Default::default); + entry.block_data = entry.block_data.take().or(block_data); + entry.extrinsic = entry.extrinsic.take().or(extrinsic); + } +} + +struct CurrentConsensus { + knowledge: Arc>, + parent_hash: Hash, + session_keys: HashMap, + local_session_key: SessionKey, +} + +impl CurrentConsensus { + // get locally stored block data for a candidate. + fn block_data(&self, hash: &Hash) -> Option { + self.knowledge.lock().candidates.get(hash) + .and_then(|entry| entry.block_data.clone()) + } + + fn peer_disconnected(&mut self, peer: &PeerInfo) { + if let Some(key) = peer.session_keys.get(&self.parent_hash) { + self.session_keys.remove(key); + } + } +} + +/// Polkadot-specific messages. +#[derive(Serialize, Deserialize)] +pub enum Message { + /// signed statement and localized parent hash. + Statement(Hash, SignedStatement), + /// Tell the peer your session key for the current block. + // TODO: do this with a random challenge protocol + SessionKey(Hash, SessionKey), + /// Requesting parachain block data by candidate hash. + RequestBlockData(RequestId, Hash), + /// Provide block data by candidate hash or nothing if unknown. + BlockData(RequestId, Option), +} + +fn send_polkadot_message(ctx: &mut Context, to: PeerId, message: Message) { + let encoded = ::serde_json::to_vec(&message).expect("serialization of messages infallible; qed"); + ctx.send_message(to, generic_message::Message::ChainSpecific(encoded)) +} + +/// Polkadot protocol attachment for substrate. +pub struct PolkadotProtocol { + peers: HashMap, + consensus_gossip: ConsensusGossip, + collators: HashMap>, + collating_for: Option, + live_consensus: Option, + in_flight: HashMap<(RequestId, PeerId), BlockDataRequest>, + pending: Vec, + next_req_id: u64, +} + +impl PolkadotProtocol { + /// Instantiate a polkadot protocol handler. + pub fn new() -> Self { + PolkadotProtocol { + peers: HashMap::new(), + consensus_gossip: ConsensusGossip::new(), + collators: HashMap::new(), + collating_for: None, + live_consensus: None, + in_flight: HashMap::new(), + pending: Vec::new(), + next_req_id: 1, + } + } + + /// Send a statement to a validator. + fn send_statement(&mut self, ctx: &mut Context, _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"); + + self.consensus_gossip.multicast_chain_specific(ctx, raw, parent_hash); + } + + /// Fetch block data by candidate receipt. + fn fetch_block_data(&mut self, ctx: &mut Context, candidate: &CandidateReceipt, relay_parent: Hash) -> oneshot::Receiver { + let (tx, rx) = oneshot::channel(); + + self.pending.push(BlockDataRequest { + attempted_peers: Default::default(), + consensus_parent: relay_parent, + candidate_hash: candidate.hash(), + block_data_hash: candidate.block_data_hash, + sender: tx, + }); + + self.dispatch_pending_requests(ctx); + rx + } + + /// Note new consensus session. + fn new_consensus(&mut self, ctx: &mut Context, mut consensus: CurrentConsensus) { + let parent_hash = consensus.parent_hash; + let old_parent = self.live_consensus.as_ref().map(|c| c.parent_hash); + + for (id, info) in self.peers.iter_mut().filter(|&(_, ref info)| info.validator) { + send_polkadot_message( + ctx, + *id, + Message::SessionKey(parent_hash, consensus.local_session_key) + ); + + if let Some(key) = info.session_keys.get(&parent_hash) { + consensus.session_keys.insert(*key, *id); + } + + if let Some(ref old_parent) = old_parent { + info.session_keys.remove(old_parent); + } + } + + self.live_consensus = Some(consensus); + self.consensus_gossip.collect_garbage(old_parent.as_ref()); + } + + fn dispatch_pending_requests(&mut self, ctx: &mut Context) { + let consensus = match self.live_consensus { + Some(ref mut c) => c, + None => { + self.pending.clear(); + return; + } + }; + + let knowledge = consensus.knowledge.lock(); + let mut new_pending = Vec::new(); + for mut pending in ::std::mem::replace(&mut self.pending, Vec::new()) { + if pending.consensus_parent != consensus.parent_hash { continue } + + if let Some(entry) = knowledge.candidates.get(&pending.candidate_hash) { + // answer locally + if let Some(ref data) = entry.block_data { + let _ = pending.sender.send(data.clone()); + continue; + } + + let next_peer = entry.knows_block_data.iter() + .filter_map(|x| consensus.session_keys.get(x).map(|id| (*x, *id))) + .find(|&(ref key, _)| pending.attempted_peers.insert(*key)) + .map(|(_, id)| id); + + // dispatch to peer + if let Some(peer_id) = next_peer { + let req_id = self.next_req_id; + self.next_req_id += 1; + + send_polkadot_message( + ctx, + peer_id, + Message::RequestBlockData(req_id, pending.candidate_hash) + ); + + self.in_flight.insert((req_id, peer_id), pending); + + continue; + } + } + + new_pending.push(pending); + } + + self.pending = new_pending; + } + + fn on_polkadot_message(&mut self, ctx: &mut Context, peer_id: PeerId, raw: Vec, msg: Message) { + match msg { + Message::Statement(parent_hash, _statement) => + self.consensus_gossip.on_chain_specific(ctx, peer_id, raw, parent_hash), + Message::SessionKey(parent_hash, key) => { + { + let info = match self.peers.get_mut(&peer_id) { + Some(peer) => peer, + None => return, + }; + + if !info.validator { + ctx.disable_peer(peer_id); + return; + } + + match self.live_consensus { + Some(ref mut consensus) if consensus.parent_hash == parent_hash => { + consensus.session_keys.insert(key, peer_id); + } + _ => {} + } + + info.session_keys.insert(parent_hash, key); + } + self.dispatch_pending_requests(ctx); + } + Message::RequestBlockData(req_id, hash) => { + let block_data = self.live_consensus.as_ref() + .and_then(|c| c.block_data(&hash)); + + send_polkadot_message(ctx, peer_id, Message::BlockData(req_id, block_data)); + } + Message::BlockData(req_id, data) => self.on_block_data(ctx, peer_id, req_id, data), + } + } + + fn on_block_data(&mut self, ctx: &mut Context, peer_id: PeerId, req_id: RequestId, data: Option) { + match self.in_flight.remove(&(req_id, peer_id)) { + Some(req) => { + if let Some(data) = data { + if data.hash() == req.block_data_hash { + let _ = req.sender.send(data); + return + } + } + + self.pending.push(req); + self.dispatch_pending_requests(ctx); + } + None => ctx.disable_peer(peer_id), + } + } +} + +impl Specialization for PolkadotProtocol { + fn status(&self) -> Vec { + Status { collating_for: self.collating_for.clone() }.encode() + } + + fn on_connect(&mut self, ctx: &mut Context, peer_id: PeerId, status: FullStatus) { + let local_status = match Status::decode(&mut &status.chain_status[..]) { + Some(status) => status, + None => { + ctx.disable_peer(peer_id); + return; + } + }; + + if let Some(ref para_id) = local_status.collating_for { + self.collators.entry(para_id.clone()) + .or_insert_with(Vec::new) + .push(peer_id); + } + + let validator = status.roles.iter().any(|r| *r == message::Role::Authority); + self.peers.insert(peer_id, PeerInfo { + status: local_status, + session_keys: Default::default(), + validator, + }); + + self.consensus_gossip.new_peer(ctx, peer_id, &status.roles); + + if let (true, &Some(ref consensus)) = (validator, &self.live_consensus) { + send_polkadot_message( + ctx, + peer_id, + Message::SessionKey(consensus.parent_hash, consensus.local_session_key) + ); + } + + self.dispatch_pending_requests(ctx); + } + + fn on_disconnect(&mut self, ctx: &mut Context, peer_id: PeerId) { + if let Some(info) = self.peers.remove(&peer_id) { + if let Some(collators) = info.status.collating_for.and_then(|id| self.collators.get_mut(&id)) { + if let Some(pos) = collators.iter().position(|x| x == &peer_id) { + collators.swap_remove(pos); + } + } + + if let (true, &mut Some(ref mut consensus)) = (info.validator, &mut self.live_consensus) { + consensus.peer_disconnected(&info); + } + + { + let pending = &mut self.pending; + self.in_flight.retain(|&(_, ref peer), val| { + let retain = peer != &peer_id; + if !retain { + let (sender, _) = oneshot::channel(); + pending.push(::std::mem::replace(val, BlockDataRequest { + attempted_peers: Default::default(), + consensus_parent: Default::default(), + candidate_hash: Default::default(), + block_data_hash: Default::default(), + sender, + })); + } + + retain + }); + } + self.consensus_gossip.peer_disconnected(ctx, peer_id); + self.dispatch_pending_requests(ctx); + } + } + + fn on_message(&mut self, ctx: &mut Context, peer_id: PeerId, message: message::Message) { + match message { + generic_message::Message::BftMessage(msg) => { + // TODO: check signature here? what if relevant block is unknown? + 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); + } + } + } + _ => {} + } + } + + fn on_abort(&mut self) { + self.consensus_gossip.abort(); + } + + fn maintain_peers(&mut self, ctx: &mut Context) { + self.consensus_gossip.collect_garbage(None); + self.dispatch_pending_requests(ctx); + } +} diff --git a/polkadot/network/src/router.rs b/polkadot/network/src/router.rs new file mode 100644 index 0000000000..ff90502a31 --- /dev/null +++ b/polkadot/network/src/router.rs @@ -0,0 +1,349 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Statement routing and consensus table router implementation. +//! +//! During the consensus process, validators exchange statements on validity and availability +//! of parachain candidates. +//! The `Router` in this file hooks into the underlying network to fulfill +//! the `TableRouter` trait from `polkadot-consensus`, which is expected to call into a shared statement table +//! and dispatch evaluation work as necessary when new statements come in. + +use polkadot_api::{PolkadotApi, LocalPolkadotApi}; +use polkadot_consensus::{SharedTable, TableRouter, SignedStatement, GenericStatement, StatementProducer}; +use polkadot_primitives::{Hash, BlockId, SessionKey}; +use polkadot_primitives::parachain::{BlockData, Extrinsic, CandidateReceipt, Id as ParaId}; + +use futures::prelude::*; +use tokio::runtime::TaskExecutor; +use parking_lot::Mutex; + +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; + +use super::{NetworkService, Knowledge}; + +/// Table routing implementation. +pub struct Router { + table: Arc, + network: Arc, + api: Arc

, + task_executor: TaskExecutor, + parent_hash: Hash, + knowledge: Arc>, + deferred_statements: Arc>, +} + +impl Router

{ + pub(crate) fn new( + table: Arc, + network: Arc, + api: Arc

, + task_executor: TaskExecutor, + parent_hash: Hash, + knowledge: Arc>, + ) -> Self { + Router { + table, + network, + api, + task_executor, + parent_hash, + knowledge, + deferred_statements: Arc::new(Mutex::new(DeferredStatements::new())), + } + } + + pub(crate) fn session_key(&self) -> SessionKey { + self.table.session_key() + } +} + +impl Clone for Router

{ + fn clone(&self) -> Self { + Router { + table: self.table.clone(), + network: self.network.clone(), + api: self.api.clone(), + task_executor: self.task_executor.clone(), + parent_hash: self.parent_hash.clone(), + deferred_statements: self.deferred_statements.clone(), + knowledge: self.knowledge.clone(), + } + } +} + +impl Router

{ + /// Import a statement whose signature has been checked already. + pub(crate) fn import_statement(&self, statement: SignedStatement) { + // defer any statements for which we haven't imported the candidate yet + let (c_hash, parachain_index) = { + let candidate_data = match statement.statement { + GenericStatement::Candidate(ref c) => Some((c.hash(), c.parachain_index)), + GenericStatement::Valid(ref hash) + | GenericStatement::Invalid(ref hash) + | GenericStatement::Available(ref hash) + => self.table.with_candidate(hash, |c| c.map(|c| (*hash, c.parachain_index))), + }; + match candidate_data { + Some(x) => x, + None => { + self.deferred_statements.lock().push(statement); + return; + } + } + }; + + // import all statements pending on this candidate + let (mut statements, _traces) = if let GenericStatement::Candidate(_) = statement.statement { + self.deferred_statements.lock().get_deferred(&c_hash) + } else { + (Vec::new(), Vec::new()) + }; + + // prepend the candidate statement. + statements.insert(0, statement); + let producers: Vec<_> = self.table.import_remote_statements( + self, + statements.iter().cloned(), + ); + // dispatch future work as necessary. + for (producer, statement) in producers.into_iter().zip(statements) { + let producer = match producer { + Some(p) => p, + None => continue, // statement redundant + }; + + self.knowledge.lock().note_statement(statement.sender, &statement.statement); + self.dispatch_work(c_hash, producer, parachain_index); + } + } + + fn dispatch_work(&self, candidate_hash: Hash, producer: StatementProducer, parachain: ParaId) where + D: Future + Send + 'static, + E: Future + Send + 'static, + { + let parent_hash = self.parent_hash.clone(); + + let api = self.api.clone(); + let validate = move |collation| -> Option { + let id = BlockId::hash(parent_hash); + match ::polkadot_consensus::validate_collation(&*api, &id, &collation) { + Ok(()) => Some(true), + Err(e) => { + debug!(target: "p_net", "Encountered bad collation: {}", e); + Some(false) + } + } + }; + + let table = self.table.clone(); + let network = self.network.clone(); + let knowledge = self.knowledge.clone(); + + let work = producer.prime(validate).map(move |produced| { + // store the data before broadcasting statements, so other peers can fetch. + knowledge.lock().note_candidate(candidate_hash, produced.block_data, produced.extrinsic); + + // propagate the statements + if let Some(validity) = produced.validity { + let signed = table.sign_and_import(validity.clone()); + route_statement(&*network, &*table, parachain, parent_hash, signed); + } + + if let Some(availability) = produced.availability { + let signed = table.sign_and_import(availability); + route_statement(&*network, &*table, parachain, parent_hash, signed); + } + }); + + self.task_executor.spawn(work); + } +} + +impl TableRouter for Router

{ + type Error = (); + type FetchCandidate = BlockDataReceiver; + type FetchExtrinsic = Result; + + fn local_candidate(&self, receipt: CandidateReceipt, block_data: BlockData, extrinsic: Extrinsic) { + // give to network to make available. + let hash = receipt.hash(); + let para_id = receipt.parachain_index; + let signed = self.table.sign_and_import(GenericStatement::Candidate(receipt)); + + self.knowledge.lock().note_candidate(hash, Some(block_data), Some(extrinsic)); + route_statement(&*self.network, &*self.table, para_id, self.parent_hash, signed); + } + + fn fetch_block_data(&self, candidate: &CandidateReceipt) -> BlockDataReceiver { + let parent_hash = self.parent_hash; + let rx = self.network.with_spec(|spec, ctx| { spec.fetch_block_data(ctx, candidate, parent_hash) }); + BlockDataReceiver { inner: rx } + } + + fn fetch_extrinsic_data(&self, _candidate: &CandidateReceipt) -> Self::FetchExtrinsic { + Ok(Extrinsic) + } +} + +/// Receiver for block data. +pub struct BlockDataReceiver { + inner: Option<::futures::sync::oneshot::Receiver>, +} + +impl Future for BlockDataReceiver { + type Item = BlockData; + type Error = (); + + fn poll(&mut self) -> Poll { + match self.inner { + Some(ref mut inner) => inner.poll().map_err(|_| ()), + None => return Err(()), + } + } +} + +// get statement to relevant validators. +fn route_statement(network: &NetworkService, table: &SharedTable, para_id: ParaId, parent_hash: Hash, statement: SignedStatement) { + let broadcast = |i: &mut Iterator| { + let local_key = table.session_key(); + network.with_spec(|spec, ctx| { + for val in i.filter(|&x| x != &local_key) { + spec.send_statement(ctx, *val, parent_hash, statement.clone()); + } + }); + }; + + let g_info = table + .group_info() + .get(¶_id) + .expect("statements only produced about groups which exist"); + + match statement.statement { + GenericStatement::Candidate(_) => + broadcast(&mut g_info.validity_guarantors.iter().chain(g_info.availability_guarantors.iter())), + GenericStatement::Valid(_) | GenericStatement::Invalid(_) => + broadcast(&mut g_info.validity_guarantors.iter()), + GenericStatement::Available(_) => + broadcast(&mut g_info.availability_guarantors.iter()), + } +} + +// A unique trace for valid statements issued by a validator. +#[derive(Hash, PartialEq, Eq, Clone, Debug)] +enum StatementTrace { + Valid(SessionKey, Hash), + Invalid(SessionKey, Hash), + Available(SessionKey, Hash), +} + +// helper for deferring statements whose associated candidate is unknown. +struct DeferredStatements { + deferred: HashMap>, + known_traces: HashSet, +} + +impl DeferredStatements { + fn new() -> Self { + DeferredStatements { + deferred: HashMap::new(), + known_traces: HashSet::new(), + } + } + + fn push(&mut self, statement: SignedStatement) { + let (hash, trace) = match statement.statement { + GenericStatement::Candidate(_) => return, + GenericStatement::Valid(hash) => (hash, StatementTrace::Valid(statement.sender, hash)), + GenericStatement::Invalid(hash) => (hash, StatementTrace::Invalid(statement.sender, hash)), + GenericStatement::Available(hash) => (hash, StatementTrace::Available(statement.sender, hash)), + }; + + if self.known_traces.insert(trace) { + self.deferred.entry(hash).or_insert_with(Vec::new).push(statement); + } + } + + fn get_deferred(&mut self, hash: &Hash) -> (Vec, Vec) { + match self.deferred.remove(hash) { + None => (Vec::new(), Vec::new()), + Some(deferred) => { + let mut traces = Vec::new(); + for statement in deferred.iter() { + let trace = match statement.statement { + GenericStatement::Candidate(_) => continue, + GenericStatement::Valid(hash) => StatementTrace::Valid(statement.sender, hash), + GenericStatement::Invalid(hash) => StatementTrace::Invalid(statement.sender, hash), + GenericStatement::Available(hash) => StatementTrace::Available(statement.sender, hash), + }; + + self.known_traces.remove(&trace); + traces.push(trace); + } + + (deferred, traces) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use substrate_primitives::H512; + + #[test] + fn deferred_statements_works() { + let mut deferred = DeferredStatements::new(); + let hash = [1; 32].into(); + let sig = H512([2; 64]).into(); + let sender = [255; 32].into(); + + let statement = SignedStatement { + statement: GenericStatement::Valid(hash), + sender, + signature: sig, + }; + + // pre-push. + { + let (signed, traces) = deferred.get_deferred(&hash); + assert!(signed.is_empty()); + assert!(traces.is_empty()); + } + + deferred.push(statement.clone()); + deferred.push(statement.clone()); + + // draining: second push should have been ignored. + { + let (signed, traces) = deferred.get_deferred(&hash); + assert_eq!(signed.len(), 1); + + assert_eq!(traces.len(), 1); + assert_eq!(signed[0].clone(), statement); + assert_eq!(traces[0].clone(), StatementTrace::Valid(sender, hash)); + } + + // after draining + { + let (signed, traces) = deferred.get_deferred(&hash); + assert!(signed.is_empty()); + assert!(traces.is_empty()); + } + } +} diff --git a/polkadot/network/src/tests.rs b/polkadot/network/src/tests.rs new file mode 100644 index 0000000000..feb83a416e --- /dev/null +++ b/polkadot/network/src/tests.rs @@ -0,0 +1,204 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Tests for polkadot and consensus network. + +use super::{PolkadotProtocol, Status, CurrentConsensus, Knowledge, Message, FullStatus}; + +use parking_lot::Mutex; +use polkadot_consensus::GenericStatement; +use polkadot_primitives::{Block, Hash, SessionKey}; +use polkadot_primitives::parachain::{CandidateReceipt, HeadData, BlockData}; +use codec::Slicable; +use substrate_network::{PeerId, PeerInfo, ClientHandle, Context, message::Message as SubstrateMessage, message::Role, specialization::Specialization, generic_message::Message as GenericMessage}; + +use std::sync::Arc; +use futures::Future; + +#[derive(Default)] +struct TestContext { + disabled: Vec, + disconnected: Vec, + messages: Vec<(PeerId, SubstrateMessage)>, +} + +impl Context for TestContext { + fn client(&self) -> &ClientHandle { + unimplemented!() + } + + fn disable_peer(&mut self, peer: PeerId) { + self.disabled.push(peer); + } + + fn disconnect_peer(&mut self, peer: PeerId) { + self.disconnected.push(peer); + } + + fn peer_info(&self, _peer: PeerId) -> Option> { + unimplemented!() + } + + fn send_message(&mut self, peer_id: PeerId, data: SubstrateMessage) { + self.messages.push((peer_id, data)) + } +} + +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(); + self.messages.iter().any(|&(ref peer, ref msg)| match msg { + GenericMessage::ChainSpecific(ref data) => peer == &to && data == &encoded, + _ => false, + }) + } +} + +fn make_status(status: &Status, roles: Vec) -> FullStatus { + FullStatus { + version: 1, + roles, + best_number: 0, + best_hash: Default::default(), + genesis_hash: Default::default(), + chain_status: status.encode(), + } +} + +fn make_consensus(parent_hash: Hash, local_key: SessionKey) -> (CurrentConsensus, Arc>) { + let knowledge = Arc::new(Mutex::new(Knowledge::new())); + let c = CurrentConsensus { + knowledge: knowledge.clone(), + parent_hash, + session_keys: Default::default(), + local_session_key: local_key, + }; + + (c, knowledge) +} + +fn on_message(protocol: &mut PolkadotProtocol, ctx: &mut TestContext, from: PeerId, message: Message) { + let encoded = ::serde_json::to_vec(&message).unwrap(); + protocol.on_message(ctx, from, GenericMessage::ChainSpecific(encoded)); +} + +#[test] +fn sends_session_key() { + let mut protocol = PolkadotProtocol::new(); + + let peer_a = 1; + let peer_b = 2; + let parent_hash = [0; 32].into(); + let local_key = [1; 32].into(); + + let status = Status { collating_for: None }; + + { + let mut ctx = TestContext::default(); + protocol.on_connect(&mut ctx, peer_a, make_status(&status, vec![Role::Authority])); + assert!(ctx.messages.is_empty()); + } + + { + let mut ctx = TestContext::default(); + let (consensus, _knowledge) = make_consensus(parent_hash, local_key); + protocol.new_consensus(&mut ctx, consensus); + + assert!(ctx.has_message(peer_a, Message::SessionKey(parent_hash, local_key))); + } + + { + let mut ctx = TestContext::default(); + protocol.on_connect(&mut ctx, peer_b, make_status(&status, vec![Role::Authority])); + assert!(ctx.has_message(peer_b, Message::SessionKey(parent_hash, local_key))); + } +} + +#[test] +fn fetches_from_those_with_knowledge() { + let mut protocol = PolkadotProtocol::new(); + + let peer_a = 1; + let peer_b = 2; + let parent_hash = [0; 32].into(); + let local_key = [1; 32].into(); + + let block_data = BlockData(vec![1, 2, 3, 4]); + let block_data_hash = block_data.hash(); + let candidate_receipt = CandidateReceipt { + parachain_index: 5.into(), + collator: [255; 32].into(), + head_data: HeadData(vec![9, 9, 9]), + balance_uploads: Vec::new(), + egress_queue_roots: Vec::new(), + fees: 1_000_000, + block_data_hash, + }; + + let candidate_hash = candidate_receipt.hash(); + let a_key = [3; 32].into(); + let b_key = [4; 32].into(); + + let status = Status { collating_for: None }; + + let (consensus, knowledge) = make_consensus(parent_hash, local_key); + protocol.new_consensus(&mut TestContext::default(), consensus); + + knowledge.lock().note_statement(a_key, &GenericStatement::Valid(candidate_hash)); + let recv = protocol.fetch_block_data(&mut TestContext::default(), &candidate_receipt, parent_hash); + + // connect peer A + { + let mut ctx = TestContext::default(); + protocol.on_connect(&mut ctx, peer_a, make_status(&status, vec![Role::Authority])); + assert!(ctx.has_message(peer_a, Message::SessionKey(parent_hash, local_key))); + } + + // peer A gives session key and gets asked for data. + { + let mut ctx = TestContext::default(); + on_message(&mut protocol, &mut ctx, peer_a, Message::SessionKey(parent_hash, a_key)); + assert!(ctx.has_message(peer_a, Message::RequestBlockData(1, candidate_hash))); + } + + knowledge.lock().note_statement(b_key, &GenericStatement::Valid(candidate_hash)); + + // 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])); + 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))); + + } + + // peer A disconnects, triggering reassignment + { + let mut ctx = TestContext::default(); + protocol.on_disconnect(&mut ctx, peer_a); + assert!(ctx.has_message(peer_b, Message::RequestBlockData(2, candidate_hash))); + } + + // peer B comes back with block data. + { + let mut ctx = TestContext::default(); + on_message(&mut protocol, &mut ctx, peer_b, Message::BlockData(2, Some(block_data.clone()))); + drop(protocol); + assert_eq!(recv.wait().unwrap(), block_data); + } +} diff --git a/polkadot/primitives/src/parachain.rs b/polkadot/primitives/src/parachain.rs index 9f803810e4..79b12aeecd 100644 --- a/polkadot/primitives/src/parachain.rs +++ b/polkadot/primitives/src/parachain.rs @@ -172,6 +172,8 @@ pub struct CandidateReceipt { pub egress_queue_roots: Vec<(Id, Hash)>, /// Fees paid from the chain to the relay chain validators pub fees: u64, + /// blake2-256 Hash of block data. + pub block_data_hash: Hash, } impl Slicable for CandidateReceipt { @@ -184,6 +186,7 @@ impl Slicable for CandidateReceipt { self.balance_uploads.using_encoded(|s| v.extend(s)); self.egress_queue_roots.using_encoded(|s| v.extend(s)); self.fees.using_encoded(|s| v.extend(s)); + self.block_data_hash.using_encoded(|s| v.extend(s)); v } @@ -196,6 +199,7 @@ impl Slicable for CandidateReceipt { balance_uploads: Slicable::decode(input)?, egress_queue_roots: Slicable::decode(input)?, fees: Slicable::decode(input)?, + block_data_hash: Slicable::decode(input)?, }) } } @@ -243,6 +247,15 @@ pub struct ConsolidatedIngress(pub Vec<(Id, Vec)>); #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] pub struct BlockData(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec); +impl BlockData { + /// Compute hash of block data. + #[cfg(feature = "std")] + pub fn hash(&self) -> Hash { + use runtime_primitives::traits::{BlakeTwo256, Hashing}; + BlakeTwo256::hash(&self.0[..]) + } +} + /// Parachain header raw bytes wrapper type. #[derive(PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] @@ -273,19 +286,9 @@ impl Slicable for Activity { } } -#[derive(Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] -#[repr(u8)] -enum StatementKind { - Candidate = 1, - Valid = 2, - Invalid = 3, - Available = 4, -} - /// Statements which can be made about parachain candidates. #[derive(Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Debug))] +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] pub enum Statement { /// Proposal of a parachain candidate. Candidate(CandidateReceipt), @@ -296,47 +299,3 @@ pub enum Statement { /// Vote to advance round after inactive primary. Available(Hash), } - -impl Slicable for Statement { - fn encode(&self) -> Vec { - let mut v = Vec::new(); - match *self { - Statement::Candidate(ref candidate) => { - v.push(StatementKind::Candidate as u8); - candidate.using_encoded(|s| v.extend(s)); - } - Statement::Valid(ref hash) => { - v.push(StatementKind::Valid as u8); - hash.using_encoded(|s| v.extend(s)); - } - Statement::Invalid(ref hash) => { - v.push(StatementKind::Invalid as u8); - hash.using_encoded(|s| v.extend(s)); - } - Statement::Available(ref hash) => { - v.push(StatementKind::Available as u8); - hash.using_encoded(|s| v.extend(s)); - } - } - - v - } - - fn decode(value: &mut I) -> Option { - match value.read_byte() { - Some(x) if x == StatementKind::Candidate as u8 => { - Slicable::decode(value).map(Statement::Candidate) - } - Some(x) if x == StatementKind::Valid as u8 => { - Slicable::decode(value).map(Statement::Valid) - } - Some(x) if x == StatementKind::Invalid as u8 => { - Slicable::decode(value).map(Statement::Invalid) - } - Some(x) if x == StatementKind::Available as u8 => { - Slicable::decode(value).map(Statement::Available) - } - _ => None, - } - } -} diff --git a/polkadot/runtime/src/lib.rs b/polkadot/runtime/src/lib.rs index c6a7cfdc83..b74e5754e0 100644 --- a/polkadot/runtime/src/lib.rs +++ b/polkadot/runtime/src/lib.rs @@ -218,6 +218,7 @@ impl_outer_dispatch! { Democracy = 5, Council = 6, CouncilVoting = 7, + Parachains = 8, } } @@ -395,4 +396,10 @@ mod tests { let v = Slicable::encode(&xt); assert_eq!(Extrinsic::decode(&mut &v[..]).unwrap(), xt); } + + #[test] + fn parachain_calls_are_privcall() { + let _register = PrivCall::Parachains(parachains::PrivCall::register_parachain(0.into(), vec![1, 2, 3], vec![])); + let _deregister = PrivCall::Parachains(parachains::PrivCall::deregister_parachain(0.into())); + } } diff --git a/polkadot/runtime/src/parachains.rs b/polkadot/runtime/src/parachains.rs index 3625633adf..0ac9522ea0 100644 --- a/polkadot/runtime/src/parachains.rs +++ b/polkadot/runtime/src/parachains.rs @@ -16,15 +16,14 @@ //! Main parachains logic. For now this is just the determination of which validators do what. -use primitives; use rstd::prelude::*; -use codec::{Slicable, Joiner}; +use codec::Slicable; -use runtime_primitives::traits::{Executable, RefInto, MaybeEmpty}; +use runtime_primitives::traits::{Hashing, BlakeTwo256, Executable, RefInto, MaybeEmpty}; use primitives::parachain::{Id, Chain, DutyRoster, CandidateReceipt}; use {system, session}; -use substrate_runtime_support::{Hashable, StorageValue, StorageMap}; +use substrate_runtime_support::{StorageValue, StorageMap}; use substrate_runtime_support::dispatch::Result; #[cfg(any(feature = "std", test))] @@ -33,7 +32,7 @@ use rstd::marker::PhantomData; #[cfg(any(feature = "std", test))] use {runtime_io, runtime_primitives}; -pub trait Trait: session::Trait { +pub trait Trait: system::Trait + session::Trait { /// The position of the set_heads call in the block. const SET_POSITION: u32; @@ -43,13 +42,19 @@ pub trait Trait: session::Trait { decl_module! { /// Parachains module. pub struct Module; - /// Call type for parachains. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum Call where aux: ::PublicAux { // provide candidate receipts for parachains, in ascending order by id. fn set_heads(aux, heads: Vec) -> Result = 0; } + + /// Private calls for parachains. + #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] + pub enum PrivCall { + fn register_parachain(id: Id, code: Vec, initial_head_data: Vec) -> Result = 0; + fn deregister_parachain(id: Id) -> Result = 1; + } } decl_storage! { @@ -83,8 +88,9 @@ impl Module { let mut roles_gua = roles_val.clone(); - let random_seed = system::Module::::random_seed(); - let mut seed = random_seed.to_vec().and(b"validator_role_pairs").blake2_256(); + let mut random_seed = system::Module::::random_seed().to_vec(); + random_seed.extend(b"validator_role_pairs"); + let mut seed = BlakeTwo256::hash(&random_seed); // shuffle for i in 0..(validator_count - 1) { @@ -100,7 +106,7 @@ impl Module { if offset == 24 { // into the last 8 bytes - rehash to gather new entropy - seed = seed.blake2_256(); + seed = BlakeTwo256::hash(&seed); } // exchange last item with randomly chosen first. @@ -116,20 +122,22 @@ impl Module { /// Register a parachain with given code. /// Fails if given ID is already used. - pub fn register_parachain(id: Id, code: Vec, initial_head_data: Vec) { + pub fn register_parachain(id: Id, code: Vec, initial_head_data: Vec) -> Result { let mut parachains = Self::active_parachains(); match parachains.binary_search(&id) { - Ok(_) => panic!("Parachain with id {} already exists", id.into_inner()), + Ok(_) => fail!("Parachain already exists"), Err(idx) => parachains.insert(idx, id), } >::insert(id, code); >::put(parachains); >::insert(id, initial_head_data); + + Ok(()) } /// Deregister a parachain with given id - pub fn deregister_parachain(id: Id) { + pub fn deregister_parachain(id: Id) -> Result { let mut parachains = Self::active_parachains(); match parachains.binary_search(&id) { Ok(idx) => { parachains.remove(idx); } @@ -139,6 +147,7 @@ impl Module { >::remove(id); >::remove(id); >::put(parachains); + Ok(()) } fn set_heads(aux: &::PublicAux, heads: Vec) -> Result { @@ -317,12 +326,12 @@ mod tests { assert_eq!(Parachains::parachain_code(&5u32.into()), Some(vec![1,2,3])); assert_eq!(Parachains::parachain_code(&100u32.into()), Some(vec![4,5,6])); - Parachains::register_parachain(99u32.into(), vec![7,8,9], vec![1, 1, 1]); + Parachains::register_parachain(99u32.into(), vec![7,8,9], vec![1, 1, 1]).unwrap(); assert_eq!(Parachains::active_parachains(), vec![5u32.into(), 99u32.into(), 100u32.into()]); assert_eq!(Parachains::parachain_code(&99u32.into()), Some(vec![7,8,9])); - Parachains::deregister_parachain(5u32.into()); + Parachains::deregister_parachain(5u32.into()).unwrap(); assert_eq!(Parachains::active_parachains(), vec![99u32.into(), 100u32.into()]); assert_eq!(Parachains::parachain_code(&5u32.into()), None); diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm index 7082ac45b4fc4b1eb5a4199c3ebbf33dd3a3f63a..a522d9b0624b06abded5703909257c4394dd4542 100644 GIT binary patch delta 152151 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 F{|D8{(;EN) delta 153106 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 diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm index 4505fd75188b8a59ce3129b70e23e4474e7e2419..6a7103ef4e54b4f16bc144c1d96b842177b880d9 100755 GIT binary patch delta 148099 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 delta 145685 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 MWYqVFQ5;_XKX42GivR!s diff --git a/polkadot/service/Cargo.toml b/polkadot/service/Cargo.toml index cd8992c855..f17c50b0d9 100644 --- a/polkadot/service/Cargo.toml +++ b/polkadot/service/Cargo.toml @@ -6,13 +6,12 @@ authors = ["Parity Technologies "] [dependencies] futures = "0.1.17" parking_lot = "0.4" -tokio-timer = "0.1.2" error-chain = "0.12" lazy_static = "1.0" log = "0.3" slog = "^2" clap = "2.27" -tokio-core = "0.1.12" +tokio = "0.1.7" exit-future = "0.1" serde = "1.0" serde_json = "1.0" @@ -25,6 +24,7 @@ polkadot-consensus = { path = "../consensus" } polkadot-executor = { path = "../executor" } polkadot-api = { path = "../api" } polkadot-transaction-pool = { path = "../transaction-pool" } +polkadot-network = { path = "../network" } substrate-keystore = { path = "../../substrate/keystore" } substrate-runtime-io = { path = "../../substrate/runtime-io" } substrate-runtime-primitives = { path = "../../substrate/runtime/primitives" } diff --git a/polkadot/service/src/components.rs b/polkadot/service/src/components.rs index b6709b111f..b7b5c3c96a 100644 --- a/polkadot/service/src/components.rs +++ b/polkadot/service/src/components.rs @@ -18,20 +18,22 @@ use std::collections::HashMap; use std::sync::Arc; -use client::{self, Client}; +use chain_spec::ChainSpec; use client_db; +use client::{self, Client}; use codec::{self, Slicable}; use consensus; +use error; use keystore::Store as Keystore; -use network; +use network::{self, OnDemand}; use polkadot_api; use polkadot_executor::Executor as LocalDispatch; +use polkadot_network::NetworkService; use polkadot_primitives::{Block, BlockId, Hash}; use state_machine; use substrate_executor::NativeExecutor; use transaction_pool::{self, TransactionPool}; -use error; -use chain_spec::ChainSpec; +use tokio::runtime::TaskExecutor; /// Code executor. pub type CodeExecutor = NativeExecutor; @@ -49,7 +51,7 @@ pub trait Components { /// Create client. fn build_client(&self, settings: client_db::DatabaseSettings, executor: CodeExecutor, chain_spec: &ChainSpec) - -> Result<(Arc>, Option>>>), error::Error>; + -> Result<(Arc>, Option>>), error::Error>; /// Create api. fn build_api(&self, client: Arc>) -> Arc; @@ -59,7 +61,14 @@ pub trait Components { -> Arc>; /// Create consensus service. - fn build_consensus(&self, client: Arc>, network: Arc>, tx_pool: Arc>, keystore: &Keystore) + fn build_consensus( + &self, + client: Arc>, + network: Arc, + tx_pool: Arc>, + keystore: &Keystore, + task_executor: TaskExecutor, + ) -> Result, error::Error>; } @@ -75,7 +84,7 @@ impl Components for FullComponents { type Executor = client::LocalCallExecutor, NativeExecutor>; fn build_client(&self, db_settings: client_db::DatabaseSettings, executor: CodeExecutor, chain_spec: &ChainSpec) - -> Result<(Arc>, Option>>>), error::Error> { + -> Result<(Arc>, Option>>), error::Error> { Ok((Arc::new(client_db::new_client(db_settings, executor, chain_spec)?), None)) } @@ -92,20 +101,31 @@ impl Components for FullComponents { }) } - fn build_consensus(&self, client: Arc>, network: Arc>, tx_pool: Arc>, keystore: &Keystore) - -> Result, error::Error> { + fn build_consensus( + &self, + client: Arc>, + network: Arc, + tx_pool: Arc>, + keystore: &Keystore, + task_executor: TaskExecutor, + ) + -> Result, error::Error> + { if !self.is_validator { return Ok(None); } // Load the first available key let key = keystore.load(&keystore.contents()?[0], "")?; - info!("Using authority key: {}", key.public()); + info!("Using authority key {}", key.public()); + + let consensus_net = ::polkadot_network::consensus::ConsensusNetwork::new(network, client.clone()); Ok(Some(consensus::Service::new( client.clone(), client.clone(), - network.clone(), + consensus_net, tx_pool.clone(), + task_executor, ::std::time::Duration::from_millis(4000), // TODO: dynamic key, ))) @@ -116,14 +136,14 @@ impl Components for FullComponents { pub struct LightComponents; impl Components for LightComponents { - type Backend = client::light::backend::Backend, network::OnDemand>>; + type Backend = client::light::backend::Backend, network::OnDemand>; type Api = polkadot_api::light::RemotePolkadotApiWrapper; type Executor = client::light::call_executor::RemoteCallExecutor< - client::light::blockchain::Blockchain, network::OnDemand>>, - network::OnDemand>>; + client::light::blockchain::Blockchain, network::OnDemand>, + network::OnDemand>; fn build_client(&self, db_settings: client_db::DatabaseSettings, executor: CodeExecutor, spec: &ChainSpec) - -> Result<(Arc>, Option>>>), error::Error> { + -> Result<(Arc>, Option>>), error::Error> { let db_storage = client_db::light::LightStorage::new(db_settings)?; let light_blockchain = client::light::new_light_blockchain(db_storage); let fetch_checker = Arc::new(client::light::new_fetch_checker(light_blockchain.clone(), executor)); @@ -146,8 +166,16 @@ impl Components for LightComponents { }) } - fn build_consensus(&self, _client: Arc>, _network: Arc>, _tx_pool: Arc>, _keystore: &Keystore) - -> Result, error::Error> { + fn build_consensus( + &self, + _client: Arc>, + _network: Arc, + _tx_pool: Arc>, + _keystore: &Keystore, + _task_executor: TaskExecutor, + ) + -> Result, error::Error> + { Ok(None) } } diff --git a/polkadot/service/src/lib.rs b/polkadot/service/src/lib.rs index 7e62712917..6a613f99f4 100644 --- a/polkadot/service/src/lib.rs +++ b/polkadot/service/src/lib.rs @@ -21,7 +21,6 @@ extern crate futures; extern crate ed25519; extern crate clap; extern crate exit_future; -extern crate tokio_timer; extern crate serde; extern crate serde_json; extern crate polkadot_primitives; @@ -30,18 +29,17 @@ extern crate polkadot_executor; extern crate polkadot_api; extern crate polkadot_consensus as consensus; extern crate polkadot_transaction_pool as transaction_pool; +extern crate polkadot_network; extern crate substrate_keystore as keystore; -extern crate substrate_runtime_io as runtime_io; extern crate substrate_primitives as primitives; extern crate substrate_runtime_primitives as runtime_primitives; extern crate substrate_network as network; extern crate substrate_codec as codec; extern crate substrate_executor; extern crate substrate_state_machine as state_machine; - -extern crate tokio_core; extern crate substrate_client as client; extern crate substrate_client_db as client_db; +extern crate tokio; #[macro_use] extern crate substrate_telemetry; @@ -62,9 +60,7 @@ mod config; mod chain_spec; use std::sync::Arc; -use std::thread; use futures::prelude::*; -use tokio_core::reactor::Core; use transaction_pool::TransactionPool; use keystore::Store as Keystore; use polkadot_api::PolkadotApi; @@ -72,6 +68,8 @@ use polkadot_primitives::{Block, BlockId, Hash}; use client::{Client, BlockchainEvents}; use network::ManageNetwork; use exit_future::Signal; +use polkadot_network::{NetworkService, PolkadotProtocol}; +use tokio::runtime::TaskExecutor; pub use self::error::{ErrorKind, Error}; pub use self::components::{Components, FullComponents, LightComponents}; @@ -80,23 +78,22 @@ pub use chain_spec::ChainSpec; /// Polkadot service. pub struct Service { - thread: Option>, client: Arc>, - network: Arc>, + network: Arc, transaction_pool: Arc>, signal: Option, _consensus: Option, } /// Creates light client and register protocol with the network service -pub fn new_light(config: Configuration) -> Result, error::Error> { - Service::new(components::LightComponents, config) +pub fn new_light(config: Configuration, executor: TaskExecutor) -> Result, error::Error> { + Service::new(components::LightComponents, config, executor) } /// Creates full client and register protocol with the network service -pub fn new_full(config: Configuration) -> Result, error::Error> { - let is_validator = (config.roles & Role::VALIDATOR) == Role::VALIDATOR; - Service::new(components::FullComponents { is_validator }, config) +pub fn new_full(config: Configuration, executor: TaskExecutor) -> Result, error::Error> { + let is_validator = (config.roles & Role::AUTHORITY) == Role::AUTHORITY; + Service::new(components::FullComponents { is_validator }, config, executor) } /// Creates bare client without any networking. @@ -112,7 +109,7 @@ pub fn new_client(config: Configuration) -> Result Service client::error::Error: From<<<::Backend as client::backend::Backend>::State as state_machine::Backend>::Error>, { /// Creates and register protocol with the network service - fn new(components: Components, config: Configuration) -> Result { - use std::sync::Barrier; - + fn new(components: Components, config: Configuration, task_executor: TaskExecutor) -> Result { let (signal, exit) = ::exit_future::signal(); // Create client @@ -165,61 +160,55 @@ impl Service chain: client.clone(), on_demand: on_demand.clone().map(|d| d as Arc>), transaction_pool: transaction_pool_adapter, + specialization: PolkadotProtocol::new(), }; - let network = network::Service::new(network_params)?; - let barrier = ::std::sync::Arc::new(Barrier::new(2)); + + let network = network::Service::new(network_params, ::polkadot_network::DOT_PROTOCOL_ID)?; on_demand.map(|on_demand| on_demand.set_service_link(Arc::downgrade(&network))); - let thread = { - let client = client.clone(); + network.start_network(); + + { + // block notifications let network = network.clone(); let txpool = transaction_pool.clone(); - let thread_barrier = barrier.clone(); - thread::spawn(move || { - network.start_network(); + let events = client.import_notification_stream() + .for_each(move |notification| { + network.on_block_imported(notification.hash, ¬ification.header); + prune_imported(&*txpool, notification.hash); + Ok(()) + }) + .select(exit.clone()) + .then(|_| Ok(())); + task_executor.spawn(events); + } - thread_barrier.wait(); - let mut core = Core::new().expect("tokio::Core could not be created"); + { + // transaction notifications + let network = network.clone(); + let events = transaction_pool.import_notification_stream() + // TODO [ToDr] Consider throttling? + .for_each(move |_| { + network.trigger_repropagate(); + Ok(()) + }) + .select(exit.clone()) + .then(|_| Ok(())); - // block notifications - let network1 = network.clone(); - let txpool1 = txpool.clone(); - - let events = client.import_notification_stream() - .for_each(move |notification| { - network1.on_block_imported(notification.hash, ¬ification.header); - prune_imported(&*txpool1, notification.hash); - - Ok(()) - }); - core.handle().spawn(events); - - // transaction notifications - let events = txpool.import_notification_stream() - // TODO [ToDr] Consider throttling? - .for_each(move |_| { - network.trigger_repropagate(); - Ok(()) - }); - core.handle().spawn(events); - - if let Err(e) = core.run(exit) { - debug!("Polkadot service event loop shutdown with {:?}", e); - } - debug!("Polkadot service shutdown"); - }) - }; - - // wait for the network to start up before starting the consensus - // service. - barrier.wait(); + task_executor.spawn(events); + } // Spin consensus service if configured - let consensus_service = components.build_consensus(client.clone(), network.clone(), transaction_pool.clone(), &keystore)?; + let consensus_service = components.build_consensus( + client.clone(), + network.clone(), + transaction_pool.clone(), + &keystore, + task_executor, + )?; Ok(Service { - thread: Some(thread), client: client, network: network, transaction_pool: transaction_pool, @@ -234,7 +223,7 @@ impl Service } /// Get shared network instance. - pub fn network(&self) -> Arc> { + pub fn network(&self) -> Arc { self.network.clone() } @@ -260,14 +249,12 @@ pub fn prune_imported(pool: &TransactionPool, hash: Hash) impl Drop for Service where Components: components::Components { fn drop(&mut self) { + debug!(target: "service", "Polkadot service shutdown"); + self.network.stop_network(); if let Some(signal) = self.signal.take() { signal.fire(); } - - if let Some(thread) = self.thread.take() { - thread.join().expect("The service thread has panicked"); - } } } diff --git a/polkadot/statement-table/Cargo.toml b/polkadot/statement-table/Cargo.toml index 5c8a61e81d..2e9120a4f0 100644 --- a/polkadot/statement-table/Cargo.toml +++ b/polkadot/statement-table/Cargo.toml @@ -4,5 +4,8 @@ version = "0.1.0" authors = ["Parity Technologies "] [dependencies] +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 4436730b3e..8e7fa48e2e 100644 --- a/polkadot/statement-table/src/generic.rs +++ b/polkadot/statement-table/src/generic.rs @@ -27,26 +27,11 @@ //! propose and attest to validity of candidates, and those who can only attest //! to availability. -use std::collections::HashSet; use std::collections::hash_map::{HashMap, Entry}; use std::hash::Hash; use std::fmt::Debug; -/// A batch of statements to send out. -pub trait StatementBatch { - /// Get the target authorities of these statements. - fn targets(&self) -> &[V]; - - /// If the batch is empty. - fn is_empty(&self) -> bool; - - /// Push a statement onto the batch. Returns false when the batch is full. - /// - /// This is meant to do work like incrementally serializing the statements - /// into a vector of bytes while making sure the length is below a certain - /// amount. - fn push(&mut self, statement: T) -> bool; -} +use codec::{Slicable, Input}; /// Context for the statement table. pub trait Context { @@ -85,7 +70,7 @@ pub trait Context { } /// Statements circulated among peers. -#[derive(PartialEq, Eq, Debug, Clone)] +#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] pub enum Statement { /// Broadcast by a authority to indicate that this is his candidate for /// inclusion. @@ -103,8 +88,61 @@ pub enum Statement { Invalid(D), } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +enum StatementKind { + Candidate = 1, + Valid = 2, + Invalid = 3, + Available = 4, +} + +impl Slicable for Statement { + fn encode(&self) -> Vec { + let mut v = Vec::new(); + match *self { + Statement::Candidate(ref candidate) => { + v.push(StatementKind::Candidate as u8); + candidate.using_encoded(|s| v.extend(s)); + } + Statement::Valid(ref digest) => { + v.push(StatementKind::Valid as u8); + digest.using_encoded(|s| v.extend(s)); + } + Statement::Invalid(ref digest) => { + v.push(StatementKind::Invalid as u8); + digest.using_encoded(|s| v.extend(s)); + } + Statement::Available(ref digest) => { + v.push(StatementKind::Available as u8); + digest.using_encoded(|s| v.extend(s)); + } + } + + v + } + + fn decode(value: &mut I) -> Option { + match value.read_byte() { + Some(x) if x == StatementKind::Candidate as u8 => { + Slicable::decode(value).map(Statement::Candidate) + } + Some(x) if x == StatementKind::Valid as u8 => { + Slicable::decode(value).map(Statement::Valid) + } + Some(x) if x == StatementKind::Invalid as u8 => { + Slicable::decode(value).map(Statement::Invalid) + } + Some(x) if x == StatementKind::Available as u8 => { + Slicable::decode(value).map(Statement::Available) + } + _ => None, + } + } +} + /// A signed statement. -#[derive(PartialEq, Eq, Debug, Clone)] +#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] pub struct SignedStatement { /// The statement. pub statement: Statement, @@ -114,26 +152,6 @@ pub struct SignedStatement { pub sender: V, } -// A unique trace for a class of valid statements issued by a authority. -// -// We keep track of which statements we have received or sent to other authorities -// in order to prevent relaying the same data multiple times. -// -// The signature of the statement is replaced by the authority because the authority -// is unique while signatures are not (at least under common schemes like -// Schnorr or ECDSA). -#[derive(Hash, PartialEq, Eq, Clone)] -enum StatementTrace { - /// The candidate proposed by the authority. - Candidate(V), - /// A validity statement from that authority about the given digest. - Valid(V, D), - /// An invalidity statement from that authority about the given digest. - Invalid(V, D), - /// An availability statement from that authority about the given digest. - Available(V, D), -} - /// Misbehavior: voting more than one way on candidate validity. /// /// Since there are three possible ways to vote, a double vote is possible in @@ -148,6 +166,19 @@ pub enum ValidityDoubleVote { ValidityAndInvalidity(D, S, S), } +/// Misbehavior: multiple signatures on same statement. +#[derive(PartialEq, Eq, Debug, Clone)] +pub enum DoubleSign { + /// On candidate. + Candidate(C, S, S), + /// On validity. + Validity(D, S, S), + /// On invalidity. + Invalidity(D, S, S), + /// On availability. + Availability(D, S, S), +} + /// Misbehavior: declaring multiple candidates. #[derive(PartialEq, Eq, Debug, Clone)] pub struct MultipleCandidates { @@ -172,20 +203,14 @@ pub enum Misbehavior { ValidityDoubleVote(ValidityDoubleVote), /// Submitted multiple candidates. MultipleCandidates(MultipleCandidates), - /// Submitted a message withou + /// Submitted a message that was unauthorized. UnauthorizedStatement(UnauthorizedStatement), + /// Submitted two valid signatures for the same message. + DoubleSign(DoubleSign), } -/// Fancy work-around for a type alias of context-based misbehavior -/// without producing compiler warnings. -pub trait ResolveMisbehavior { - /// The misbehavior type. - type Misbehavior; -} - -impl ResolveMisbehavior for C { - type Misbehavior = Misbehavior; -} +/// Type alias for misbehavior corresponding to context type. +pub type MisbehaviorFor = Misbehavior<::Candidate, ::Digest, ::AuthorityId, ::Signature>; // kinds of votes for validity #[derive(Clone, PartialEq, Eq)] @@ -251,22 +276,26 @@ impl CandidateData { // authority metadata struct AuthorityData { proposal: Option<(C::Digest, C::Signature)>, - known_statements: HashSet>, } impl Default for AuthorityData { fn default() -> Self { AuthorityData { proposal: None, - known_statements: HashSet::default(), } } } +/// Type alias for the result of a statement import. +pub type ImportResult = Result< + Option::Digest, ::GroupId>>, + MisbehaviorFor +>; + /// Stores votes pub struct Table { authority_data: HashMap>, - detected_misbehavior: HashMap::Misbehavior>, + detected_misbehavior: HashMap>, candidate_votes: HashMap>, includable_count: HashMap, } @@ -328,26 +357,17 @@ impl Table { } /// Import a signed statement. Signatures should be checked for validity, and the - /// sender should be checked to actually be a authority. + /// sender should be checked to actually be an authority. /// - /// This can note the origin of the statement to indicate that he has - /// seen it already. + /// If this returns `None`, the statement was either duplicate or invalid. pub fn import_statement( &mut self, context: &C, statement: SignedStatement, - from: Option ) -> Option> { let SignedStatement { statement, signature, sender: signer } = statement; - let trace = match statement { - Statement::Candidate(_) => StatementTrace::Candidate(signer.clone()), - Statement::Valid(ref d) => StatementTrace::Valid(signer.clone(), d.clone()), - Statement::Invalid(ref d) => StatementTrace::Invalid(signer.clone(), d.clone()), - Statement::Available(ref d) => StatementTrace::Available(signer.clone(), d.clone()), - }; - - let (maybe_misbehavior, maybe_summary) = match statement { + let res = match statement { Statement::Candidate(candidate) => self.import_candidate( context, signer.clone(), @@ -374,19 +394,15 @@ impl Table { ), }; - if let Some(misbehavior) = maybe_misbehavior { - // all misbehavior in agreement is provable and actively malicious. - // punishments are not cumulative. - self.detected_misbehavior.insert(signer, misbehavior); - } else { - if let Some(from) = from { - self.note_trace_seen(trace.clone(), from); + match res { + Ok(maybe_summary) => maybe_summary, + Err(misbehavior) => { + // all misbehavior in agreement is provable and actively malicious. + // punishments are not cumulative. + self.detected_misbehavior.insert(signer, misbehavior); + None } - - self.note_trace_seen(trace, signer); } - - maybe_summary } /// Get a candidate by digest. @@ -396,7 +412,7 @@ impl Table { /// Access all witnessed misbehavior. pub fn get_misbehavior(&self) - -> &HashMap::Misbehavior> + -> &HashMap> { &self.detected_misbehavior } @@ -406,155 +422,22 @@ impl Table { self.includable_count.len() } - /// Fill a statement batch and note messages as seen by the targets. - pub fn fill_batch(&mut self, batch: &mut B) - where B: StatementBatch< - C::AuthorityId, - SignedStatement, - > - { - // naively iterate all statements so far, taking any that - // at least one of the targets has not seen. - - // workaround for the fact that it's inconvenient to borrow multiple - // entries out of a hashmap mutably -- we just move them out and - // replace them when we're done. - struct SwappedTargetData<'a, C: 'a + Context> { - authority_data: &'a mut HashMap>, - target_data: Vec<(C::AuthorityId, AuthorityData)>, - } - - impl<'a, C: 'a + Context> Drop for SwappedTargetData<'a, C> { - fn drop(&mut self) { - for (id, data) in self.target_data.drain(..) { - self.authority_data.insert(id, data); - } - } - } - - // pre-fetch authority data for all the targets. - let mut target_data = { - let authority_data = &mut self.authority_data; - let mut target_data = Vec::with_capacity(batch.targets().len()); - for target in batch.targets() { - let active_data = match authority_data.get_mut(target) { - None => Default::default(), - Some(x) => ::std::mem::replace(x, Default::default()), - }; - - target_data.push((target.clone(), active_data)); - } - - SwappedTargetData { - authority_data, - target_data - } - }; - - let target_data = &mut target_data.target_data; - - macro_rules! attempt_send { - ($trace:expr, sender=$sender:expr, sig=$sig:expr, statement=$statement:expr) => {{ - let trace = $trace; - let can_send = target_data.iter() - .any(|t| !t.1.known_statements.contains(&trace)); - - if can_send { - let statement = SignedStatement { - statement: $statement, - signature: $sig, - sender: $sender, - }; - - if batch.push(statement) { - for target in target_data.iter_mut() { - target.1.known_statements.insert(trace.clone()); - } - } else { - return; - } - } - }} - } - - // reconstruct statements for anything whose trace passes the filter. - for (digest, candidate) in self.candidate_votes.iter() { - let issuance_iter = candidate.validity_votes.iter() - .filter(|&(_, x)| if let ValidityVote::Issued(_) = *x { true } else { false }); - - let validity_iter = candidate.validity_votes.iter() - .filter(|&(_, x)| if let ValidityVote::Issued(_) = *x { false } else { true }); - - // send issuance statements before votes. - for (sender, vote) in issuance_iter.chain(validity_iter) { - match *vote { - ValidityVote::Issued(ref sig) => { - attempt_send!( - StatementTrace::Candidate(sender.clone()), - sender = sender.clone(), - sig = sig.clone(), - statement = Statement::Candidate(candidate.candidate.clone()) - ) - } - ValidityVote::Valid(ref sig) => { - attempt_send!( - StatementTrace::Valid(sender.clone(), digest.clone()), - sender = sender.clone(), - sig = sig.clone(), - statement = Statement::Valid(digest.clone()) - ) - } - ValidityVote::Invalid(ref sig) => { - attempt_send!( - StatementTrace::Invalid(sender.clone(), digest.clone()), - sender = sender.clone(), - sig = sig.clone(), - statement = Statement::Invalid(digest.clone()) - ) - } - } - }; - - - // and lastly send availability. - for (sender, sig) in candidate.availability_votes.iter() { - attempt_send!( - StatementTrace::Available(sender.clone(), digest.clone()), - sender = sender.clone(), - sig = sig.clone(), - statement = Statement::Available(digest.clone()) - ) - } - } - - } - - fn note_trace_seen(&mut self, trace: StatementTrace, known_by: C::AuthorityId) { - self.authority_data.entry(known_by).or_insert_with(|| AuthorityData { - proposal: None, - known_statements: HashSet::default(), - }).known_statements.insert(trace); - } - fn import_candidate( &mut self, context: &C, from: C::AuthorityId, candidate: C::Candidate, signature: C::Signature, - ) -> (Option<::Misbehavior>, Option>) { + ) -> ImportResult { let group = C::candidate_group(&candidate); if !context.is_member_of(&from, &group) { - return ( - Some(Misbehavior::UnauthorizedStatement(UnauthorizedStatement { - statement: SignedStatement { - signature, - statement: Statement::Candidate(candidate), - sender: from, - }, - })), - None, - ); + return Err(Misbehavior::UnauthorizedStatement(UnauthorizedStatement { + statement: SignedStatement { + signature, + statement: Statement::Candidate(candidate), + sender: from, + }, + })); } // check that authority hasn't already specified another candidate. @@ -578,13 +461,10 @@ impl Table { .candidate .clone(); - return ( - Some(Misbehavior::MultipleCandidates(MultipleCandidates { - first: (old_candidate, old_sig.clone()), - second: (candidate, signature.clone()), - })), - None, - ); + return Err(Misbehavior::MultipleCandidates(MultipleCandidates { + first: (old_candidate, old_sig.clone()), + second: (candidate, signature.clone()), + })); } false @@ -596,7 +476,6 @@ impl Table { Entry::Vacant(vacant) => { vacant.insert(AuthorityData { proposal: Some((digest.clone(), signature.clone())), - known_statements: HashSet::new(), }); true } @@ -628,9 +507,9 @@ impl Table { from: C::AuthorityId, digest: C::Digest, vote: ValidityVote, - ) -> (Option<::Misbehavior>, Option>) { + ) -> ImportResult { let votes = match self.candidate_votes.get_mut(&digest) { - None => return (None, None), // TODO: queue up but don't get DoS'ed + None => return Ok(None), Some(votes) => votes, }; @@ -647,50 +526,56 @@ impl Table { checking group membership of issuer; qed"), }; - return ( - Some(Misbehavior::UnauthorizedStatement(UnauthorizedStatement { - statement: SignedStatement { - signature: sig, - sender: from, - statement: if valid { - Statement::Valid(digest) - } else { - Statement::Invalid(digest) - } + return Err(Misbehavior::UnauthorizedStatement(UnauthorizedStatement { + statement: SignedStatement { + signature: sig, + sender: from, + statement: if valid { + Statement::Valid(digest) + } else { + Statement::Invalid(digest) } - })), - None, - ); + } + })); } // check for double votes. match votes.validity_votes.entry(from.clone()) { Entry::Occupied(occ) => { - if occ.get() != &vote { - let double_vote_proof = match (occ.get().clone(), vote) { + let make_vdv = |v| Misbehavior::ValidityDoubleVote(v); + let make_ds = |ds| Misbehavior::DoubleSign(ds); + return if occ.get() != &vote { + Err(match (occ.get().clone(), vote) { + // valid vote conflicting with candidate statement (ValidityVote::Issued(iss), ValidityVote::Valid(good)) | (ValidityVote::Valid(good), ValidityVote::Issued(iss)) => - ValidityDoubleVote::IssuedAndValidity((votes.candidate.clone(), iss), (digest, good)), + make_vdv(ValidityDoubleVote::IssuedAndValidity((votes.candidate.clone(), iss), (digest, good))), + + // invalid vote conflicting with candidate statement (ValidityVote::Issued(iss), ValidityVote::Invalid(bad)) | (ValidityVote::Invalid(bad), ValidityVote::Issued(iss)) => - ValidityDoubleVote::IssuedAndInvalidity((votes.candidate.clone(), iss), (digest, bad)), + make_vdv(ValidityDoubleVote::IssuedAndInvalidity((votes.candidate.clone(), iss), (digest, bad))), + + // valid vote conflicting with invalid vote (ValidityVote::Valid(good), ValidityVote::Invalid(bad)) | (ValidityVote::Invalid(bad), ValidityVote::Valid(good)) => - ValidityDoubleVote::ValidityAndInvalidity(digest, good, bad), - _ => { - // this would occur if two different but valid signatures - // on the same kind of vote occurred. - return (None, None); - } - }; + make_vdv(ValidityDoubleVote::ValidityAndInvalidity(digest, good, bad)), - return ( - Some(Misbehavior::ValidityDoubleVote(double_vote_proof)), - None, - ) + // two signatures on same candidate + (ValidityVote::Issued(a), ValidityVote::Issued(b)) => + make_ds(DoubleSign::Candidate(votes.candidate.clone(), a, b)), + + // two signatures on same validity vote + (ValidityVote::Valid(a), ValidityVote::Valid(b)) => + make_ds(DoubleSign::Validity(digest, a, b)), + + // two signature on same invalidity vote + (ValidityVote::Invalid(a), ValidityVote::Invalid(b)) => + make_ds(DoubleSign::Invalidity(digest, a, b)), + }) + } else { + Ok(None) } - - return (None, None); } Entry::Vacant(vacant) => { if let ValidityVote::Invalid(_) = vote { @@ -704,7 +589,7 @@ impl Table { let is_includable = votes.can_be_included(v_threshold, a_threshold); update_includable_count(&mut self.includable_count, &votes.group_id, was_includable, is_includable); - (None, Some(votes.summary(digest))) + Ok(Some(votes.summary(digest))) } fn availability_vote( @@ -713,9 +598,9 @@ impl Table { from: C::AuthorityId, digest: C::Digest, signature: C::Signature, - ) -> (Option<::Misbehavior>, Option>) { + ) -> ImportResult { let votes = match self.candidate_votes.get_mut(&digest) { - None => return (None, None), // TODO: queue up but don't get DoS'ed + None => return Ok(None), Some(votes) => votes, }; @@ -724,24 +609,26 @@ impl Table { // check that this authority actually can vote in this group. if !context.is_availability_guarantor_of(&from, &votes.group_id) { - return ( - Some(Misbehavior::UnauthorizedStatement(UnauthorizedStatement { - statement: SignedStatement { - signature: signature.clone(), - statement: Statement::Available(digest), - sender: from, - } - })), - None - ); + return Err(Misbehavior::UnauthorizedStatement(UnauthorizedStatement { + statement: SignedStatement { + signature: signature, + statement: Statement::Available(digest), + sender: from, + } + })); } - votes.availability_votes.insert(from, signature); + match votes.availability_votes.entry(from) { + Entry::Occupied(ref occ) if occ.get() != &signature => return Err( + Misbehavior::DoubleSign(DoubleSign::Availability(digest, signature, occ.get().clone())) + ), + entry => { let _ = entry.or_insert(signature); }, + } let is_includable = votes.can_be_included(v_threshold, a_threshold); update_includable_count(&mut self.includable_count, &votes.group_id, was_includable, is_includable); - (None, Some(votes.summary(digest))) + Ok(Some(votes.summary(digest))) } } @@ -765,26 +652,6 @@ mod tests { use super::*; use std::collections::HashMap; - #[derive(Debug, Clone)] - struct VecBatch { - pub max_len: usize, - pub targets: Vec, - pub items: Vec, - } - - impl ::generic::StatementBatch for VecBatch { - fn targets(&self) -> &[V] { &self.targets } - fn is_empty(&self) -> bool { self.items.is_empty() } - fn push(&mut self, item: T) -> bool { - if self.items.len() == self.max_len { - false - } else { - self.items.push(item); - true - } - } - } - fn create() -> Table { Table::default() } @@ -878,10 +745,10 @@ mod tests { sender: AuthorityId(1), }; - table.import_statement(&context, statement_a, None); + table.import_statement(&context, statement_a); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); - table.import_statement(&context, statement_b, None); + table.import_statement(&context, statement_b); assert_eq!( table.detected_misbehavior.get(&AuthorityId(1)).unwrap(), &Misbehavior::MultipleCandidates(MultipleCandidates { @@ -908,7 +775,7 @@ mod tests { sender: AuthorityId(1), }; - table.import_statement(&context, statement, None); + table.import_statement(&context, statement); assert_eq!( table.detected_misbehavior.get(&AuthorityId(1)).unwrap(), @@ -949,8 +816,8 @@ mod tests { }; let candidate_b_digest = Digest(987); - table.import_statement(&context, candidate_a, None); - table.import_statement(&context, candidate_b, None); + table.import_statement(&context, candidate_a); + table.import_statement(&context, candidate_b); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2))); @@ -960,7 +827,7 @@ mod tests { signature: Signature(1), sender: AuthorityId(1), }; - table.import_statement(&context, bad_availability_vote, None); + table.import_statement(&context, bad_availability_vote); assert_eq!( table.detected_misbehavior.get(&AuthorityId(1)).unwrap(), @@ -979,7 +846,7 @@ mod tests { signature: Signature(2), sender: AuthorityId(2), }; - table.import_statement(&context, bad_validity_vote, None); + table.import_statement(&context, bad_validity_vote); assert_eq!( table.detected_misbehavior.get(&AuthorityId(2)).unwrap(), @@ -1012,7 +879,7 @@ mod tests { }; let candidate_digest = Digest(100); - table.import_statement(&context, statement, None); + table.import_statement(&context, statement); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); let valid_statement = SignedStatement { @@ -1027,10 +894,10 @@ mod tests { sender: AuthorityId(2), }; - table.import_statement(&context, valid_statement, None); + table.import_statement(&context, valid_statement); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2))); - table.import_statement(&context, invalid_statement, None); + table.import_statement(&context, invalid_statement); assert_eq!( table.detected_misbehavior.get(&AuthorityId(2)).unwrap(), @@ -1042,6 +909,102 @@ mod tests { ); } + #[test] + fn candidate_double_signature_is_misbehavior() { + let context = TestContext { + authorities: { + let mut map = HashMap::new(); + map.insert(AuthorityId(1), (GroupId(2), GroupId(455))); + map.insert(AuthorityId(2), (GroupId(2), GroupId(246))); + map + } + }; + + let mut table = create(); + let statement = SignedStatement { + statement: Statement::Candidate(Candidate(2, 100)), + signature: Signature(1), + sender: AuthorityId(1), + }; + + table.import_statement(&context, statement); + assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); + + let invalid_statement = SignedStatement { + statement: Statement::Candidate(Candidate(2, 100)), + signature: Signature(999), + sender: AuthorityId(1), + }; + + table.import_statement(&context, invalid_statement); + assert!(table.detected_misbehavior.contains_key(&AuthorityId(1))); + } + + #[test] + fn validity_invalidity_double_signature_is_misbehavior() { + let context = TestContext { + authorities: { + let mut map = HashMap::new(); + map.insert(AuthorityId(1), (GroupId(2), GroupId(455))); + map.insert(AuthorityId(2), (GroupId(2), GroupId(246))); + map.insert(AuthorityId(3), (GroupId(2), GroupId(222))); + map + } + }; + + let mut table = create(); + let statement = SignedStatement { + statement: Statement::Candidate(Candidate(2, 100)), + signature: Signature(1), + sender: AuthorityId(1), + }; + + table.import_statement(&context, statement); + assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); + + // insert two validity votes from authority 2 with different signatures + { + let statement = SignedStatement { + statement: Statement::Valid(Digest(100)), + signature: Signature(2), + sender: AuthorityId(2), + }; + + table.import_statement(&context, statement); + assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2))); + + let invalid_statement = SignedStatement { + statement: Statement::Valid(Digest(100)), + signature: Signature(222), + sender: AuthorityId(2), + }; + + table.import_statement(&context, invalid_statement); + assert!(table.detected_misbehavior.contains_key(&AuthorityId(2))); + } + + // insert two invalidity votes from authority 2 with different signatures + { + let statement = SignedStatement { + statement: Statement::Invalid(Digest(100)), + signature: Signature(3), + sender: AuthorityId(3), + }; + + table.import_statement(&context, statement); + assert!(!table.detected_misbehavior.contains_key(&AuthorityId(3))); + + let invalid_statement = SignedStatement { + statement: Statement::Invalid(Digest(100)), + signature: Signature(333), + sender: AuthorityId(3), + }; + + table.import_statement(&context, invalid_statement); + assert!(table.detected_misbehavior.contains_key(&AuthorityId(3))); + } + } + #[test] fn issue_and_vote_is_misbehavior() { let context = TestContext { @@ -1060,7 +1023,7 @@ mod tests { }; let candidate_digest = Digest(100); - table.import_statement(&context, statement, None); + table.import_statement(&context, statement); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); let extra_vote = SignedStatement { @@ -1069,7 +1032,7 @@ mod tests { sender: AuthorityId(1), }; - table.import_statement(&context, extra_vote, None); + table.import_statement(&context, extra_vote); assert_eq!( table.detected_misbehavior.get(&AuthorityId(1)).unwrap(), &Misbehavior::ValidityDoubleVote(ValidityDoubleVote::IssuedAndValidity( @@ -1133,7 +1096,7 @@ mod tests { }; let candidate_digest = Digest(100); - table.import_statement(&context, statement, None); + table.import_statement(&context, statement); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); assert!(!table.candidate_includable(&candidate_digest, &context)); assert!(table.includable_count.is_empty()); @@ -1144,7 +1107,7 @@ mod tests { sender: AuthorityId(2), }; - table.import_statement(&context, vote, None); + table.import_statement(&context, vote); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2))); assert!(!table.candidate_includable(&candidate_digest, &context)); assert!(table.includable_count.is_empty()); @@ -1156,7 +1119,7 @@ mod tests { sender: AuthorityId(4), }; - table.import_statement(&context, vote, None); + table.import_statement(&context, vote); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(4))); assert!(table.candidate_includable(&candidate_digest, &context)); assert!(table.includable_count.get(&GroupId(2)).is_some()); @@ -1168,7 +1131,7 @@ mod tests { sender: AuthorityId(3), }; - table.import_statement(&context, vote, None); + table.import_statement(&context, vote); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2))); assert!(!table.candidate_includable(&candidate_digest, &context)); assert!(table.includable_count.is_empty()); @@ -1191,7 +1154,7 @@ mod tests { sender: AuthorityId(1), }; - let summary = table.import_statement(&context, statement, None) + let summary = table.import_statement(&context, statement) .expect("candidate import to give summary"); assert_eq!(summary.candidate, Digest(100)); @@ -1219,7 +1182,7 @@ mod tests { }; let candidate_digest = Digest(100); - table.import_statement(&context, statement, None); + table.import_statement(&context, statement); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); let vote = SignedStatement { @@ -1228,7 +1191,7 @@ mod tests { sender: AuthorityId(2), }; - let summary = table.import_statement(&context, vote, None) + let summary = table.import_statement(&context, vote) .expect("candidate vote to give summary"); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2))); @@ -1258,7 +1221,7 @@ mod tests { }; let candidate_digest = Digest(100); - table.import_statement(&context, statement, None); + table.import_statement(&context, statement); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1))); let vote = SignedStatement { @@ -1267,7 +1230,7 @@ mod tests { sender: AuthorityId(2), }; - let summary = table.import_statement(&context, vote, None) + let summary = table.import_statement(&context, vote) .expect("candidate vote to give summary"); assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2))); @@ -1277,55 +1240,4 @@ mod tests { assert_eq!(summary.validity_votes, 1); assert_eq!(summary.availability_votes, 1); } - - #[test] - fn filling_batch_sets_known_flag() { - let context = TestContext { - authorities: { - let mut map = HashMap::new(); - for i in 1..10 { - map.insert(AuthorityId(i), (GroupId(2), GroupId(400 + i))); - } - map - } - }; - - let mut table = create(); - let statement = SignedStatement { - statement: Statement::Candidate(Candidate(2, 100)), - signature: Signature(1), - sender: AuthorityId(1), - }; - - table.import_statement(&context, statement, None); - - for i in 2..10 { - let statement = SignedStatement { - statement: Statement::Valid(Digest(100)), - signature: Signature(i), - sender: AuthorityId(i), - }; - - table.import_statement(&context, statement, None); - } - - let mut batch = VecBatch { - max_len: 5, - targets: (1..10).map(AuthorityId).collect(), - items: Vec::new(), - }; - - // 9 statements in the table, each seen by one. - table.fill_batch(&mut batch); - assert_eq!(batch.items.len(), 5); - - // 9 statements in the table, 5 of which seen by all targets. - batch.items.clear(); - table.fill_batch(&mut batch); - assert_eq!(batch.items.len(), 4); - - batch.items.clear(); - table.fill_batch(&mut batch); - assert!(batch.items.is_empty()); - } } diff --git a/polkadot/statement-table/src/lib.rs b/polkadot/statement-table/src/lib.rs index 86b95b0d90..779a7fc2df 100644 --- a/polkadot/statement-table/src/lib.rs +++ b/polkadot/statement-table/src/lib.rs @@ -14,9 +14,14 @@ //! propose and attest to validity of candidates, and those who can only attest //! to availability. +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; @@ -82,27 +87,3 @@ impl generic::Context for C { Context::requisite_votes(self, group) } } - -/// A batch of statements to send out. -pub trait StatementBatch { - /// Get the target authorities of these statements. - fn targets(&self) -> &[SessionKey]; - - /// If the batch is empty. - fn is_empty(&self) -> bool; - - /// Push a statement onto the batch. Returns false when the batch is full. - /// - /// This is meant to do work like incrementally serializing the statements - /// into a vector of bytes while making sure the length is below a certain - /// amount. - fn push(&mut self, statement: SignedStatement) -> bool; -} - -impl generic::StatementBatch for T { - fn targets(&self) -> &[SessionKey] { StatementBatch::targets(self ) } - fn is_empty(&self) -> bool { StatementBatch::is_empty(self) } - fn push(&mut self, statement: SignedStatement) -> bool { - StatementBatch::push(self, statement) - } -}