Rewrite the BasiQueue using channels (#1327)

* use channels to implement basic import queue

* async justification import

* better conditional for is_done in tests

* reword the test for presence of link

* fix conditional

* trace instead of panic when no link present

* reword expectations when sending to importers

* fix

* debug justification import error

* update expectations

* use NumberFor

* nits

* add general description

* move error handling into closure
This commit is contained in:
Gregory Terzian
2019-02-17 17:13:14 +08:00
committed by Gav Wood
parent 797de27d2b
commit 72bb8ef4c5
16 changed files with 614 additions and 575 deletions
+6 -4
View File
@@ -258,6 +258,8 @@ pub enum ProtocolMsg<B: BlockT, S: NetworkSpecialization<B>,> {
BlockImportedSync(B::Hash, NumberFor<B>),
/// Tell protocol to request justification for a block.
RequestJustification(B::Hash, NumberFor<B>),
/// Inform protocol whether a justification was successfully imported.
JustificationImportResult(B::Hash, NumberFor<B>, bool),
/// A block has been imported (sent by the client).
BlockImported(B::Hash, B::Header),
/// A block has been finalized (sent by the client).
@@ -274,11 +276,11 @@ pub enum ProtocolMsg<B: BlockT, S: NetworkSpecialization<B>,> {
impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
/// Create a new instance.
pub fn new<I: 'static + ImportQueue<B>>(
pub fn new(
network_chan: NetworkChan<B>,
config: ProtocolConfig,
chain: Arc<Client<B>>,
import_queue: Arc<I>,
import_queue: Box<ImportQueue<B>>,
on_demand: Option<Arc<OnDemandService<B>>>,
transaction_pool: Arc<TransactionPool<H, B>>,
specialization: S,
@@ -403,6 +405,7 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
ProtocolContext::new(&mut self.context_data, &self.network_chan);
self.sync.request_justification(&hash, number, &mut context);
},
ProtocolMsg::JustificationImportResult(hash, number, success) => self.sync.justification_import_result(hash, number, success),
ProtocolMsg::PropagateExtrinsics => self.propagate_extrinsics(),
ProtocolMsg::Tick => self.tick(),
#[cfg(any(test, feature = "test-helpers"))]
@@ -893,8 +896,7 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
fn stop(&mut self) {
// stop processing import requests first (without holding a sync lock)
let import_queue = self.sync.import_queue();
import_queue.stop();
self.sync.stop();
// and then clear all the sync data
self.abort();
+11 -3
View File
@@ -80,6 +80,14 @@ impl<B: BlockT, S: NetworkSpecialization<B>> Link<B> for NetworkLink<B, S> {
let _ = self.protocol_sender.send(ProtocolMsg::BlockImportedSync(hash.clone(), number));
}
fn justification_imported(&self, who: NodeIndex, hash: &B::Hash, number: NumberFor<B>, success: bool) {
let _ = self.protocol_sender.send(ProtocolMsg::JustificationImportResult(hash.clone(), number, success));
if !success {
let reason = Severity::Bad(format!("Invalid justification provided for #{}", hash).to_string());
let _ = self.network_sender.send(NetworkMsg::ReportPeer(who, reason));
}
}
fn request_justification(&self, hash: &B::Hash, number: NumberFor<B>) {
let _ = self.protocol_sender.send(ProtocolMsg::RequestJustification(hash.clone(), number));
}
@@ -119,10 +127,10 @@ pub struct Service<B: BlockT + 'static, S: NetworkSpecialization<B>> {
impl<B: BlockT + 'static, S: NetworkSpecialization<B>> Service<B, S> {
/// Creates and register protocol with the network service
pub fn new<I: 'static + ImportQueue<B>, H: ExHashT>(
pub fn new<H: ExHashT>(
params: Params<B, S, H>,
protocol_id: ProtocolId,
import_queue: Arc<I>,
import_queue: Box<ImportQueue<B>>,
) -> Result<(Arc<Service<B, S>>, NetworkChan<B>), Error> {
let (network_chan, network_port) = network_channel(protocol_id);
let protocol_sender = Protocol::new(
@@ -155,7 +163,7 @@ impl<B: BlockT + 'static, S: NetworkSpecialization<B>> Service<B, S> {
network_sender: network_chan.clone(),
};
import_queue.start(link)?;
import_queue.start(Box::new(link))?;
Ok((service, network_chan))
}
+37 -23
View File
@@ -15,7 +15,6 @@
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use std::collections::{HashMap, HashSet, VecDeque};
use std::sync::Arc;
use std::time::{Duration, Instant};
use log::{trace, debug};
use crate::protocol::Context;
@@ -30,6 +29,7 @@ use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberF
use runtime_primitives::generic::BlockId;
use crate::message::{self, generic::Message as GenericMessage};
use crate::config::Roles;
use std::sync::atomic::{AtomicBool, Ordering};
// Maximum blocks to request in a single packet.
const MAX_BLOCKS_TO_REQUEST: usize = 128;
@@ -197,14 +197,25 @@ impl<B: BlockT> PendingJustifications<B> {
}
}
/// Process the import of a justification.
/// Queues a retry in case the import failed.
fn justification_import_result(&mut self, hash: B::Hash, number: NumberFor<B>, success: bool) {
let request = (hash, number);
if success {
self.justifications.remove(&request);
self.previous_requests.remove(&request);
return;
}
self.pending_requests.push_front(request);
}
/// Processes the response for the request previously sent to the given
/// peer. Queues a retry in case the import fails or the given justification
/// peer. Queues a retry in case the given justification
/// was `None`.
fn on_response(
&mut self,
who: NodeIndex,
justification: Option<Justification>,
protocol: &mut Context<B>,
import_queue: &ImportQueue<B>,
) {
// we assume that the request maps to the given response, this is
@@ -212,23 +223,13 @@ impl<B: BlockT> PendingJustifications<B> {
// messages to chain sync.
if let Some(request) = self.peer_requests.remove(&who) {
if let Some(justification) = justification {
if import_queue.import_justification(request.0, request.1, justification) {
self.justifications.remove(&request);
self.previous_requests.remove(&request);
return;
} else {
protocol.report_peer(
who,
Severity::Bad(format!("Invalid justification provided for #{}", request.0)),
);
}
} else {
self.previous_requests
.entry(request)
.or_insert(Vec::new())
.push((who, Instant::now()));
import_queue.import_justification(who.clone(), request.0, request.1, justification);
return
}
self.previous_requests
.entry(request)
.or_insert(Vec::new())
.push((who, Instant::now()));
self.pending_requests.push_front(request);
}
}
@@ -251,8 +252,9 @@ pub struct ChainSync<B: BlockT> {
best_queued_number: NumberFor<B>,
best_queued_hash: B::Hash,
required_block_attributes: message::BlockAttributes,
import_queue: Arc<ImportQueue<B>>,
justifications: PendingJustifications<B>,
import_queue: Box<ImportQueue<B>>,
is_stopping: AtomicBool,
}
/// Reported sync state.
@@ -293,7 +295,7 @@ impl<B: BlockT> Status<B> {
impl<B: BlockT> ChainSync<B> {
/// Create a new instance.
pub(crate) fn new(role: Roles, info: &ClientInfo<B>, import_queue: Arc<ImportQueue<B>>) -> Self {
pub(crate) fn new(role: Roles, info: &ClientInfo<B>, import_queue: Box<ImportQueue<B>>) -> Self {
let mut required_block_attributes = message::BlockAttributes::HEADER | message::BlockAttributes::JUSTIFICATION;
if role.intersects(Roles::FULL | Roles::AUTHORITY) {
required_block_attributes |= message::BlockAttributes::BODY;
@@ -308,6 +310,7 @@ impl<B: BlockT> ChainSync<B> {
justifications: PendingJustifications::new(),
required_block_attributes,
import_queue,
is_stopping: Default::default(),
}
}
@@ -316,7 +319,7 @@ impl<B: BlockT> ChainSync<B> {
}
/// Returns import queue reference.
pub(crate) fn import_queue(&self) -> Arc<ImportQueue<B>> {
pub(crate) fn import_queue(&self) -> Box<ImportQueue<B>> {
self.import_queue.clone()
}
@@ -536,7 +539,6 @@ impl<B: BlockT> ChainSync<B> {
self.justifications.on_response(
who,
response.justification,
protocol,
&*self.import_queue,
);
},
@@ -558,6 +560,9 @@ impl<B: BlockT> ChainSync<B> {
/// Maintain the sync process (download new blocks, fetch justifications).
pub fn maintain_sync(&mut self, protocol: &mut Context<B>) {
if self.is_stopping.load(Ordering::SeqCst) {
return
}
let peers: Vec<NodeIndex> = self.peers.keys().map(|p| *p).collect();
for peer in peers {
self.download_new(protocol, peer);
@@ -578,6 +583,15 @@ impl<B: BlockT> ChainSync<B> {
self.justifications.dispatch(&mut self.peers, protocol);
}
pub fn justification_import_result(&mut self, hash: B::Hash, number: NumberFor<B>, success: bool) {
self.justifications.justification_import_result(hash, number, success);
}
pub fn stop(&self) {
self.is_stopping.store(true, Ordering::SeqCst);
self.import_queue.stop();
}
/// Notify about successful import of the given block.
pub fn block_imported(&mut self, hash: &B::Hash, number: NumberFor<B>) {
trace!(target: "sync", "Block imported successfully {} ({})", number, hash);
+8 -103
View File
@@ -16,55 +16,15 @@
//! Testing block import logic.
use consensus::import_queue::{import_single_block, process_import_result};
use consensus::import_queue::{AsyncImportQueueData, BasicQueue, BlockImportError, BlockImportResult};
use consensus::import_queue::{import_single_block, BasicQueue, BlockImportError, BlockImportResult};
use test_client::{self, TestClient};
use test_client::runtime::{Block, Hash};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::NumberFor;
use std::cell::Cell;
use super::*;
struct TestLink {
imported: Cell<usize>,
maintains: Cell<usize>,
disconnects: Cell<usize>,
restarts: Cell<usize>,
}
struct TestLink {}
impl TestLink {
fn new() -> TestLink {
TestLink {
imported: Cell::new(0),
maintains: Cell::new(0),
disconnects: Cell::new(0),
restarts: Cell::new(0),
}
}
fn total(&self) -> usize {
self.imported.get() + self.maintains.get() + self.disconnects.get() + self.restarts.get()
}
}
impl Link<Block> for TestLink {
fn block_imported(&self, _hash: &Hash, _number: NumberFor<Block>) {
self.imported.set(self.imported.get() + 1);
}
fn maintain_sync(&self) {
self.maintains.set(self.maintains.get() + 1);
}
fn useless_peer(&self, _: NodeIndex, _: &str) {
self.disconnects.set(self.disconnects.get() + 1);
}
fn note_useless_and_restart_sync(&self, id: NodeIndex, r: &str) {
self.useless_peer(id, r);
self.restart();
}
fn restart(&self) {
self.restarts.set(self.restarts.get() + 1);
}
}
impl Link<Block> for TestLink {}
fn prepare_good_block() -> (client::Client<test_client::Backend, test_client::Executor, Block, test_client::runtime::RuntimeApi>, Hash, u64, IncomingBlock<Block>) {
let client = test_client::new();
@@ -85,19 +45,19 @@ fn prepare_good_block() -> (client::Client<test_client::Backend, test_client::Ex
#[test]
fn import_single_good_block_works() {
let (_, hash, number, block) = prepare_good_block();
let (_, _hash, number, block) = prepare_good_block();
assert_eq!(
import_single_block(&test_client::new(), BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))),
Ok(BlockImportResult::ImportedUnknown(hash, number))
Ok(BlockImportResult::ImportedUnknown(number))
);
}
#[test]
fn import_single_good_known_block_is_ignored() {
let (client, hash, number, block) = prepare_good_block();
let (client, _hash, number, block) = prepare_good_block();
assert_eq!(
import_single_block(&client, BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))),
Ok(BlockImportResult::ImportedKnown(hash, number))
Ok(BlockImportResult::ImportedKnown(number))
);
}
@@ -111,68 +71,13 @@ fn import_single_good_block_without_header_fails() {
);
}
#[test]
fn process_import_result_works() {
let link = TestLink::new();
assert_eq!(process_import_result::<Block>(&link, Ok(BlockImportResult::ImportedKnown(Default::default(), 0))), 1);
assert_eq!(link.total(), 1);
let link = TestLink::new();
assert_eq!(process_import_result::<Block>(&link, Ok(BlockImportResult::ImportedKnown(Default::default(), 0))), 1);
assert_eq!(link.total(), 1);
assert_eq!(link.imported.get(), 1);
let link = TestLink::new();
assert_eq!(process_import_result::<Block>(&link, Ok(BlockImportResult::ImportedUnknown(Default::default(), 0))), 1);
assert_eq!(link.total(), 1);
assert_eq!(link.imported.get(), 1);
let link = TestLink::new();
assert_eq!(process_import_result::<Block>(&link, Err(BlockImportError::IncompleteHeader(Some(0)))), 0);
assert_eq!(link.total(), 2);
assert_eq!(link.disconnects.get(), 1);
assert_eq!(link.restarts.get(), 1);
let link = TestLink::new();
assert_eq!(process_import_result::<Block>(&link, Err(BlockImportError::UnknownParent)), 0);
assert_eq!(link.total(), 1);
assert_eq!(link.restarts.get(), 1);
let link = TestLink::new();
assert_eq!(process_import_result::<Block>(&link, Err(BlockImportError::Error)), 0);
assert_eq!(link.total(), 1);
assert_eq!(link.restarts.get(), 1);
let link = TestLink::new();
assert_eq!(process_import_result::<Block>(&link, Err(BlockImportError::VerificationFailed(Some(0), String::new()))), 0);
assert_eq!(link.total(), 2);
assert_eq!(link.restarts.get(), 1);
assert_eq!(link.disconnects.get(), 1);
}
#[test]
fn import_many_blocks_stops_when_stopping() {
let (_, _, _, block) = prepare_good_block();
let qdata = AsyncImportQueueData::new();
let verifier = Arc::new(PassThroughVerifier(true));
qdata.stop();
let client = test_client::new();
assert!(!import_many_blocks(
&client,
&mut TestLink::new(),
Some(&qdata),
(BlockOrigin::File, vec![block.clone(), block]),
verifier
));
}
#[test]
fn async_import_queue_drops() {
// Perform this test multiple times since it exhibits non-deterministic behavior.
for _ in 0..100 {
let verifier = Arc::new(PassThroughVerifier(true));
let queue = BasicQueue::new(verifier, Arc::new(test_client::new()), None);
queue.start(TestLink::new()).unwrap();
queue.start(Box::new(TestLink{})).unwrap();
drop(queue);
}
}
+31 -145
View File
@@ -23,13 +23,14 @@ mod sync;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use log::trace;
use client;
use client::block_builder::BlockBuilder;
use crate::config::ProtocolConfig;
use consensus::import_queue::{import_many_blocks, ImportQueue, ImportQueueStatus, IncomingBlock};
use consensus::import_queue::{BasicQueue, ImportQueue, IncomingBlock};
use consensus::import_queue::{Link, SharedBlockImport, SharedJustificationImport, Verifier};
use consensus::{Error as ConsensusError, ErrorKind as ConsensusErrorKind};
use consensus::{BlockOrigin, ForkChoiceStrategy, ImportBlock, JustificationImport};
@@ -45,7 +46,7 @@ use parking_lot::Mutex;
use primitives::{H256, Ed25519AuthorityId};
use crate::protocol::{Context, Protocol, ProtocolMsg, ProtocolStatus};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{AuthorityIdFor, Block as BlockT, Digest, DigestItem, Header, Zero, NumberFor};
use runtime_primitives::traits::{AuthorityIdFor, Block as BlockT, Digest, DigestItem, Header, NumberFor};
use runtime_primitives::Justification;
use crate::service::{network_channel, NetworkChan, NetworkLink, NetworkMsg, NetworkPort, TransactionPool};
use crate::specialization::NetworkSpecialization;
@@ -54,34 +55,6 @@ use test_client;
pub use test_client::runtime::{Block, Extrinsic, Hash, Transfer};
pub use test_client::TestClient;
#[cfg(any(test, feature = "test-helpers"))]
use std::cell::RefCell;
#[cfg(any(test, feature = "test-helpers"))]
struct ImportCB<B: BlockT>(RefCell<Option<Box<dyn Fn(BlockOrigin, Vec<IncomingBlock<B>>) -> bool>>>);
#[cfg(any(test, feature = "test-helpers"))]
impl<B: BlockT> ImportCB<B> {
fn new() -> Self {
ImportCB(RefCell::new(None))
}
fn set<F>(&self, cb: Box<F>)
where F: 'static + Fn(BlockOrigin, Vec<IncomingBlock<B>>) -> bool,
{
*self.0.borrow_mut() = Some(cb);
}
fn call(&self, origin: BlockOrigin, data: Vec<IncomingBlock<B>>) -> bool {
let b = self.0.borrow();
b.as_ref().expect("The Callback has been set before. qed.")(origin, data)
}
}
#[cfg(any(test, feature = "test-helpers"))]
unsafe impl<B: BlockT> Send for ImportCB<B> {}
#[cfg(any(test, feature = "test-helpers"))]
unsafe impl<B: BlockT> Sync for ImportCB<B> {}
#[cfg(any(test, feature = "test-helpers"))]
/// A Verifier that accepts all blocks and passes them on with the configured
/// finality to be imported.
@@ -114,101 +87,10 @@ impl<B: BlockT> Verifier<B> for PassThroughVerifier {
}
/// A link implementation that does nothing.
pub struct NoopLink;
pub struct NoopLink { }
impl<B: BlockT> Link<B> for NoopLink { }
/// Blocks import queue that is importing blocks in the same thread.
/// The boolean value indicates whether blocks should be imported without instant finality.
#[cfg(any(test, feature = "test-helpers"))]
pub struct SyncImportQueue<B: BlockT, V: Verifier<B>> {
verifier: Arc<V>,
link: ImportCB<B>,
block_import: SharedBlockImport<B>,
justification_import: Option<SharedJustificationImport<B>>,
}
#[cfg(any(test, feature = "test-helpers"))]
impl<B: 'static + BlockT, V: 'static + Verifier<B>> SyncImportQueue<B, V> {
/// Create a new SyncImportQueue wrapping the given Verifier and block import
/// handle.
pub fn new(verifier: Arc<V>, block_import: SharedBlockImport<B>, justification_import: Option<SharedJustificationImport<B>>) -> Self {
let queue = SyncImportQueue {
verifier,
link: ImportCB::new(),
block_import,
justification_import,
};
let v = queue.verifier.clone();
let import_handle = queue.block_import.clone();
queue.link.set(Box::new(move |origin, new_blocks| {
let verifier = v.clone();
import_many_blocks(
&*import_handle,
&NoopLink,
None,
(origin, new_blocks),
verifier,
)
}));
queue
}
}
#[cfg(any(test, feature = "test-helpers"))]
impl<B: 'static + BlockT, V: 'static + Verifier<B>> ImportQueue<B> for SyncImportQueue<B, V>
{
fn start<L: 'static + Link<B>>(
&self,
link: L,
) -> Result<(), std::io::Error> {
let v = self.verifier.clone();
let import_handle = self.block_import.clone();
self.link.set(Box::new(move |origin, new_blocks| {
let verifier = v.clone();
import_many_blocks(
&*import_handle,
&link,
None,
(origin, new_blocks),
verifier
)
}));
Ok(())
}
fn clear(&self) { }
fn stop(&self) { }
fn status(&self) -> ImportQueueStatus<B> {
ImportQueueStatus {
importing_count: 0,
best_importing_number: Zero::zero(),
}
}
fn is_importing(&self, _hash: &B::Hash) -> bool {
false
}
fn import_blocks(&self, origin: BlockOrigin, blocks: Vec<IncomingBlock<B>>) {
self.link.call(origin, blocks);
}
fn import_justification(
&self,
hash: B::Hash,
number: NumberFor<B>,
justification: Justification,
) -> bool {
self.justification_import.as_ref().map(|justification_import| {
justification_import.import_justification(hash, number, justification).is_ok()
}).unwrap_or(false)
}
}
/// The test specialization.
pub struct DummySpecialization { }
@@ -234,19 +116,20 @@ impl NetworkSpecialization<Block> for DummySpecialization {
pub type PeersClient = client::Client<test_client::Backend, test_client::Executor, Block, test_client::runtime::RuntimeApi>;
pub struct Peer<V: 'static + Verifier<Block>, D> {
pub struct Peer<D> {
client: Arc<PeersClient>,
pub protocol_sender: Sender<ProtocolMsg<Block, DummySpecialization>>,
network_port: Mutex<NetworkPort<Block>>,
import_queue: Arc<SyncImportQueue<Block, V>>,
pub import_queue: Box<ImportQueue<Block>>,
network_sender: NetworkChan<Block>,
pub data: D,
}
impl<V: 'static + Verifier<Block>, D> Peer<V, D> {
impl<D> Peer<D> {
fn new(
client: Arc<PeersClient>,
import_queue: Arc<SyncImportQueue<Block, V>>,
import_queue: Box<ImportQueue<Block>>,
protocol_sender: Sender<ProtocolMsg<Block, DummySpecialization>>,
network_sender: NetworkChan<Block>,
network_port: NetworkPort<Block>,
@@ -276,7 +159,7 @@ impl<V: 'static + Verifier<Block>, D> Peer<V, D> {
network_sender: self.network_sender.clone(),
};
self.import_queue.start(network_link).expect("Test ImportQueue always starts");
self.import_queue.start(Box::new(network_link)).expect("Test ImportQueue always starts");
let _ = self
.protocol_sender
.send(ProtocolMsg::BlockImported(info.chain.best_hash, header));
@@ -327,7 +210,8 @@ impl<V: 'static + Verifier<Block>, D> Peer<V, D> {
/// Whether this peer is done syncing (has no messages to send).
fn is_done(&self) -> bool {
self.network_port.lock().receiver().is_empty()
self.import_queue.status().importing_count == 0 &&
self.network_port.lock().receiver().is_empty()
}
/// Execute a "sync step". This is called for each peer after it sends a packet.
@@ -437,8 +321,6 @@ impl<V: 'static + Verifier<Block>, D> Peer<V, D> {
let header = block.header.clone();
at = BlockId::Hash(hash);
// NOTE: if we use a non-synchronous queue in the test-net in the future,
// this may not work.
self.import_queue.import_blocks(
origin,
vec![IncomingBlock {
@@ -447,8 +329,12 @@ impl<V: 'static + Verifier<Block>, D> Peer<V, D> {
header: Some(header),
body: Some(block.extrinsics),
justification: None,
}
]);
}],
);
// Simulate a synchronous import.
while self.import_queue.status().importing_count > 0 {
thread::sleep(Duration::from_millis(20));
}
}
}
@@ -516,9 +402,9 @@ pub trait TestNetFactory: Sized {
fn make_verifier(&self, client: Arc<PeersClient>, config: &ProtocolConfig) -> Arc<Self::Verifier>;
/// Get reference to peer.
fn peer(&self, i: usize) -> &Peer<Self::Verifier, Self::PeerData>;
fn peers(&self) -> &Vec<Arc<Peer<Self::Verifier, Self::PeerData>>>;
fn mut_peers<F: Fn(&mut Vec<Arc<Peer<Self::Verifier, Self::PeerData>>>)>(&mut self, closure: F);
fn peer(&self, i: usize) -> &Peer<Self::PeerData>;
fn peers(&self) -> &Vec<Arc<Peer<Self::PeerData>>>;
fn mut_peers<F: Fn(&mut Vec<Arc<Peer<Self::PeerData>>>)>(&mut self, closure: F);
fn started(&self) -> bool;
fn set_started(&mut self, now: bool);
@@ -553,8 +439,8 @@ pub trait TestNetFactory: Sized {
let (block_import, justification_import, data) = self.make_block_import(client.clone());
let (network_sender, network_port) = network_channel(ProtocolId::default());
let import_queue = Arc::new(SyncImportQueue::new(verifier, block_import, justification_import));
let specialization = DummySpecialization { };
let import_queue = Box::new(BasicQueue::new(verifier, block_import, justification_import));
let specialization = DummySpecialization {};
let protocol_sender = Protocol::new(
network_sender.clone(),
config.clone(),
@@ -727,8 +613,8 @@ pub trait TestNetFactory: Sized {
}
pub struct TestNet {
peers: Vec<Arc<Peer<PassThroughVerifier, ()>>>,
started: bool
peers: Vec<Arc<Peer<()>>>,
started: bool,
}
impl TestNetFactory for TestNet {
@@ -749,15 +635,15 @@ impl TestNetFactory for TestNet {
Arc::new(PassThroughVerifier(false))
}
fn peer(&self, i: usize) -> &Peer<Self::Verifier, ()> {
fn peer(&self, i: usize) -> &Peer<()> {
&self.peers[i]
}
fn peers(&self) -> &Vec<Arc<Peer<Self::Verifier, ()>>> {
fn peers(&self) -> &Vec<Arc<Peer<()>>> {
&self.peers
}
fn mut_peers<F: Fn(&mut Vec<Arc<Peer<Self::Verifier, ()>>>)>(&mut self, closure: F ) {
fn mut_peers<F: Fn(&mut Vec<Arc<Peer<()>>>)>(&mut self, closure: F) {
closure(&mut self.peers);
}
@@ -802,15 +688,15 @@ impl TestNetFactory for JustificationTestNet {
self.0.make_verifier(client, config)
}
fn peer(&self, i: usize) -> &Peer<Self::Verifier, ()> {
fn peer(&self, i: usize) -> &Peer<Self::PeerData> {
self.0.peer(i)
}
fn peers(&self) -> &Vec<Arc<Peer<Self::Verifier, ()>>> {
fn peers(&self) -> &Vec<Arc<Peer<Self::PeerData>>> {
self.0.peers()
}
fn mut_peers<F: Fn(&mut Vec<Arc<Peer<Self::Verifier, ()>>>)>(&mut self, closure: F ) {
fn mut_peers<F: Fn(&mut Vec<Arc<Peer<Self::PeerData>>>)>(&mut self, closure: F ) {
self.0.mut_peers(closure)
}
+1 -6
View File
@@ -20,7 +20,6 @@ use crate::config::Roles;
use consensus::BlockOrigin;
use network_libp2p::NodeIndex;
use crate::sync::SyncState;
use std::{thread, time};
use std::collections::HashSet;
use super::*;
@@ -55,11 +54,6 @@ fn sync_long_chain_works() {
let mut net = TestNet::new(2);
net.peer(1).push_blocks(500, false);
net.sync();
// Wait for peer 0 to import blocks received over the network.
thread::sleep(time::Duration::from_millis(1000));
net.sync();
// Wait for peers to get up to speed.
thread::sleep(time::Duration::from_millis(1000));
assert!(net.peer(0).client.backend().as_in_memory().blockchain()
.equals_to(net.peer(1).client.backend().as_in_memory().blockchain()));
}
@@ -149,6 +143,7 @@ fn own_blocks_are_announced() {
let header = net.peer(0).client().header(&BlockId::Number(1)).unwrap().unwrap();
net.peer(0).on_block_imported(header.hash(), &header);
net.sync();
assert_eq!(net.peer(0).client.backend().blockchain().info().unwrap().best_number, 1);
assert_eq!(net.peer(1).client.backend().blockchain().info().unwrap().best_number, 1);
let peer0_chain = net.peer(0).client.backend().as_in_memory().blockchain().clone();