From 430e3920e5c045eaeccc0a789a160458a499f028 Mon Sep 17 00:00:00 2001 From: Robert Habermeier <rphmeier@gmail.com> Date: Wed, 22 Aug 2018 10:57:12 +0200 Subject: [PATCH] Rollup of various testnet-related fixes. fix a deadlock when spawning agreement as non-authority fix test compilation for BFT more accurate consensus superseding logic mild revision to `can_build_on` logic block evaluation without redundant initialisation refactor BFT delay: update rhododendron and poll after delaying. (#589) dropping BFT future before poll doesn't lead to service deadlock --- polkadot/api/Cargo.toml | 1 + polkadot/api/src/full.rs | 37 ++++++++++++++++------- polkadot/api/src/lib.rs | 3 ++ polkadot/consensus/src/service.rs | 50 +++++++++++++------------------ 4 files changed, 52 insertions(+), 39 deletions(-) diff --git a/polkadot/api/Cargo.toml b/polkadot/api/Cargo.toml index 7b5015b9913..435e27c146b 100644 --- a/polkadot/api/Cargo.toml +++ b/polkadot/api/Cargo.toml @@ -16,6 +16,7 @@ substrate-client = { path = "../../substrate/client" } substrate-primitives = { path = "../../substrate/primitives" } substrate-executor = { path = "../../substrate/executor" } substrate-state-machine = { path = "../../substrate/state-machine" } +log = "0.3" [dev-dependencies] substrate-keyring = { path = "../../substrate/keyring" } diff --git a/polkadot/api/src/full.rs b/polkadot/api/src/full.rs index ca17188eacf..59b7304e81a 100644 --- a/polkadot/api/src/full.rs +++ b/polkadot/api/src/full.rs @@ -96,18 +96,33 @@ impl<B: LocalBackend<Block>> PolkadotApi for Client<B, LocalCallExecutor<B, Nati fn evaluate_block(&self, at: &BlockId, block: Block) -> Result<bool> { use substrate_executor::error::ErrorKind as ExecErrorKind; - use codec::{Decode, Encode}; - use runtime::Block as RuntimeBlock; + use codec::Encode; + use state_machine::ExecutionManager; + use client::CallExecutor; + + let parent = at; + let res = self.state_at(&parent).map_err(Error::from).and_then(|state| { + let mut overlay = Default::default(); + let execution_manager = || ExecutionManager::Both(|wasm_result, native_result| { + warn!("Consensus error between wasm and native runtime execution at block {:?}", at); + warn!(" While executing block {:?}", (block.header.number, block.header.hash())); + warn!(" Native result {:?}", native_result); + warn!(" Wasm result {:?}", wasm_result); + wasm_result + }); + let (r, _) = self.executor().call_at_state( + &state, + &mut overlay, + "execute_block", + &block.encode(), + execution_manager() + )?; + + Ok(r) + }); - let encoded = block.encode(); - let runtime_block = match RuntimeBlock::decode(&mut &encoded[..]) { - Some(x) => x, - None => return Ok(false), - }; - - let res = with_runtime!(self, at, || ::runtime::Executive::execute_block(runtime_block)); match res { - Ok(()) => Ok(true), + Ok(_) => Ok(true), Err(err) => match err.kind() { &ErrorKind::Executor(ExecErrorKind::Runtime) => Ok(false), _ => Err(err) @@ -230,6 +245,7 @@ mod tests { assert_eq!(block.header.number, 1); assert!(block.header.extrinsics_root != Default::default()); + assert!(client.evaluate_block(&id, block).unwrap()); } #[test] @@ -252,6 +268,7 @@ mod tests { assert_eq!(block.header.number, 1); assert!(block.header.extrinsics_root != Default::default()); + assert!(client.evaluate_block(&id, block).unwrap()); } #[test] diff --git a/polkadot/api/src/lib.rs b/polkadot/api/src/lib.rs index 8c1e4b1de83..1265faf961f 100644 --- a/polkadot/api/src/lib.rs +++ b/polkadot/api/src/lib.rs @@ -32,6 +32,9 @@ extern crate substrate_state_machine as state_machine; #[macro_use] extern crate error_chain; +#[macro_use] +extern crate log; + #[cfg(test)] extern crate substrate_keyring as keyring; diff --git a/polkadot/consensus/src/service.rs b/polkadot/consensus/src/service.rs index d7360bb45a3..7dc252e5c8c 100644 --- a/polkadot/consensus/src/service.rs +++ b/polkadot/consensus/src/service.rs @@ -61,32 +61,26 @@ fn start_bft<F, C>( const DELAY_UNTIL: Duration = Duration::from_millis(5000); let mut handle = LocalThreadHandle::current(); - let work = Delay::new(Instant::now() + DELAY_UNTIL) - .then(move |res| { - if let Err(e) = res { - warn!(target: "bft", "Failed to force delay of consensus: {:?}", e); - } + match bft_service.build_upon(&header) { + Ok(Some(bft_work)) => { + // do not poll work for some amount of time. + let work = Delay::new(Instant::now() + DELAY_UNTIL).then(move |res| { + if let Err(e) = res { + warn!(target: "bft", "Failed to force delay of consensus: {:?}", e); + } - match bft_service.build_upon(&header) { - Ok(maybe_bft_work) => { - if maybe_bft_work.is_some() { - debug!(target: "bft", "Starting agreement. After forced delay for {:?}", - DELAY_UNTIL); - } + debug!(target: "bft", "Starting agreement. After forced delay for {:?}", + DELAY_UNTIL); - maybe_bft_work - } - Err(e) => { - warn!(target: "bft", "BFT agreement error: {}", e); - None - } + bft_work + }); + if let Err(e) = handle.spawn_local(Box::new(work)) { + warn!(target: "bft", "Couldn't initialize BFT agreement: {:?}", e); } - }) - .map(|_| ()); - - if let Err(e) = handle.spawn_local(Box::new(work)) { - debug!(target: "bft", "Couldn't initialize BFT agreement: {:?}", e); - } + } + Ok(None) => trace!(target: "bft", "Could not start agreement on top of {}", header.hash()), + Err(e) => warn!(target: "bft", "BFT agreement error: {}", e), + } } /// Consensus service. Starts working when created. @@ -138,6 +132,7 @@ impl Service { client.import_notification_stream().for_each(move |notification| { if notification.is_new_best { + trace!(target: "bft", "Attempting to start new consensus round after import notification of {:?}", notification.hash); start_bft(notification.header, bft_service.clone()); } Ok(()) @@ -161,15 +156,12 @@ impl Service { let c = client.clone(); let s = bft_service.clone(); - interval.map_err(|e| debug!("Timer error: {:?}", e)).for_each(move |_| { + interval.map_err(|e| debug!(target: "bft", "Timer error: {:?}", e)).for_each(move |_| { if let Ok(best_block) = c.best_block_header() { let hash = best_block.hash(); - let last_agreement = s.last_agreement(); - let can_build_upon = last_agreement - .map_or(true, |x| !x.live || x.parent_hash != hash); - if hash == prev_best && can_build_upon { - debug!("Starting consensus round after a timeout"); + if hash == prev_best { + debug!(target: "bft", "Starting consensus round after a timeout"); start_bft(best_block, s.clone()); } prev_best = hash; -- GitLab