2017-01-25 18:51:41 +01:00
|
|
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
2016-02-05 13:40:41 +01:00
|
|
|
// This file is part of Parity.
|
|
|
|
|
|
|
|
// Parity 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.
|
|
|
|
|
|
|
|
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2016-04-06 10:07:24 +02:00
|
|
|
//! A queue of blocks. Sits between network or other I/O and the `BlockChain`.
|
2016-01-21 23:33:52 +01:00
|
|
|
//! Sorts them ready for blockchain insertion.
|
2016-09-27 16:50:24 +02:00
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
use std::thread::{self, JoinHandle};
|
2016-10-04 20:09:54 +02:00
|
|
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrdering};
|
2017-07-29 21:56:42 +02:00
|
|
|
use std::sync::{Condvar as SCondvar, Mutex as SMutex, Arc};
|
2017-07-29 17:12:07 +02:00
|
|
|
use std::cmp;
|
|
|
|
use std::collections::{VecDeque, HashSet, HashMap};
|
2017-08-30 16:04:47 +02:00
|
|
|
use heapsize::HeapSizeOf;
|
2018-01-10 13:35:18 +01:00
|
|
|
use ethereum_types::{H256, U256};
|
2017-09-02 20:09:13 +02:00
|
|
|
use parking_lot::{Condvar, Mutex, RwLock};
|
2016-08-05 10:32:04 +02:00
|
|
|
use io::*;
|
2016-01-11 13:42:32 +01:00
|
|
|
use error::*;
|
2017-09-26 14:19:08 +02:00
|
|
|
use engines::EthEngine;
|
2018-03-13 11:49:57 +01:00
|
|
|
use client::ClientIoMessage;
|
2016-01-09 10:16:35 +01:00
|
|
|
|
2016-12-23 18:43:40 +01:00
|
|
|
use self::kind::{BlockLike, Kind};
|
2016-09-27 16:50:24 +02:00
|
|
|
|
|
|
|
pub use types::verification_queue_info::VerificationQueueInfo as QueueInfo;
|
2016-07-07 09:39:32 +02:00
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
pub mod kind;
|
2016-02-25 14:09:39 +01:00
|
|
|
|
2016-02-25 17:14:45 +01:00
|
|
|
const MIN_MEM_LIMIT: usize = 16384;
|
|
|
|
const MIN_QUEUE_LIMIT: usize = 512;
|
|
|
|
|
2016-11-17 16:00:23 +01:00
|
|
|
// maximum possible number of verification threads.
|
|
|
|
const MAX_VERIFIERS: usize = 8;
|
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
/// Type alias for block queue convenience.
|
|
|
|
pub type BlockQueue = VerificationQueue<self::kind::Blocks>;
|
|
|
|
|
|
|
|
/// Type alias for header queue convenience.
|
|
|
|
pub type HeaderQueue = VerificationQueue<self::kind::Headers>;
|
|
|
|
|
|
|
|
/// Verification queue configuration
|
2016-09-06 15:31:13 +02:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
2016-09-27 16:50:24 +02:00
|
|
|
pub struct Config {
|
|
|
|
/// Maximum number of items to keep in unverified queue.
|
2016-02-25 14:09:39 +01:00
|
|
|
/// When the limit is reached, is_full returns true.
|
|
|
|
pub max_queue_size: usize,
|
|
|
|
/// Maximum heap memory to use.
|
|
|
|
/// When the limit is reached, is_full returns true.
|
|
|
|
pub max_mem_use: usize,
|
2016-12-02 18:21:54 +01:00
|
|
|
/// Settings for the number of verifiers and adaptation strategy.
|
|
|
|
pub verifier_settings: VerifierSettings,
|
2016-02-25 14:09:39 +01:00
|
|
|
}
|
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
impl Default for Config {
|
2016-02-25 14:09:39 +01:00
|
|
|
fn default() -> Self {
|
2016-09-27 16:50:24 +02:00
|
|
|
Config {
|
2016-02-25 14:09:39 +01:00
|
|
|
max_queue_size: 30000,
|
|
|
|
max_mem_use: 50 * 1024 * 1024,
|
2016-12-02 18:21:54 +01:00
|
|
|
verifier_settings: VerifierSettings::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Verifier settings.
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub struct VerifierSettings {
|
|
|
|
/// Whether to scale amount of verifiers according to load.
|
|
|
|
// Todo: replace w/ strategy enum?
|
|
|
|
pub scale_verifiers: bool,
|
|
|
|
/// Beginning amount of verifiers.
|
|
|
|
pub num_verifiers: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for VerifierSettings {
|
|
|
|
fn default() -> Self {
|
|
|
|
VerifierSettings {
|
|
|
|
scale_verifiers: false,
|
|
|
|
num_verifiers: MAX_VERIFIERS,
|
2016-02-25 14:09:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
// pool states
|
|
|
|
enum State {
|
|
|
|
// all threads with id < inner value are to work.
|
|
|
|
Work(usize),
|
|
|
|
Exit,
|
2016-10-03 19:41:00 +02:00
|
|
|
}
|
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
/// An item which is in the process of being verified.
|
|
|
|
pub struct Verifying<K: Kind> {
|
|
|
|
hash: H256,
|
|
|
|
output: Option<K::Verified>,
|
|
|
|
}
|
2016-01-22 04:54:38 +01:00
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
impl<K: Kind> HeapSizeOf for Verifying<K> {
|
|
|
|
fn heap_size_of_children(&self) -> usize {
|
|
|
|
self.output.heap_size_of_children()
|
2016-02-08 12:14:48 +01:00
|
|
|
}
|
2016-09-27 16:50:24 +02:00
|
|
|
}
|
2016-02-08 12:14:48 +01:00
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
/// Status of items in the queue.
|
|
|
|
pub enum Status {
|
|
|
|
/// Currently queued.
|
|
|
|
Queued,
|
|
|
|
/// Known to be bad.
|
|
|
|
Bad,
|
|
|
|
/// Unknown.
|
|
|
|
Unknown,
|
2016-01-25 18:56:36 +01:00
|
|
|
}
|
|
|
|
|
2017-07-12 13:09:17 +02:00
|
|
|
impl Into<::block_status::BlockStatus> for Status {
|
|
|
|
fn into(self) -> ::block_status::BlockStatus {
|
|
|
|
use ::block_status::BlockStatus;
|
|
|
|
match self {
|
|
|
|
Status::Queued => BlockStatus::Queued,
|
|
|
|
Status::Bad => BlockStatus::Bad,
|
|
|
|
Status::Unknown => BlockStatus::Unknown,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-20 17:19:31 +02:00
|
|
|
// the internal queue sizes.
|
|
|
|
struct Sizes {
|
|
|
|
unverified: AtomicUsize,
|
|
|
|
verifying: AtomicUsize,
|
|
|
|
verified: AtomicUsize,
|
|
|
|
}
|
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
/// A queue of items to be verified. Sits between network or other I/O and the `BlockChain`.
|
|
|
|
/// Keeps them in the same order as inserted, minus invalid items.
|
|
|
|
pub struct VerificationQueue<K: Kind> {
|
2017-09-26 14:19:08 +02:00
|
|
|
engine: Arc<EthEngine>,
|
2016-07-27 11:39:24 +02:00
|
|
|
more_to_verify: Arc<SCondvar>,
|
2016-09-27 16:50:24 +02:00
|
|
|
verification: Arc<Verification<K>>,
|
2016-01-17 23:07:58 +01:00
|
|
|
deleting: Arc<AtomicBool>,
|
|
|
|
ready_signal: Arc<QueueSignal>,
|
2016-07-27 11:39:24 +02:00
|
|
|
empty: Arc<SCondvar>,
|
2016-12-23 18:43:40 +01:00
|
|
|
processing: RwLock<HashMap<H256, U256>>, // hash to difficulty
|
2016-10-04 20:09:54 +02:00
|
|
|
ticks_since_adjustment: AtomicUsize,
|
2016-02-25 14:09:39 +01:00
|
|
|
max_queue_size: usize,
|
|
|
|
max_mem_use: usize,
|
2016-12-02 18:21:54 +01:00
|
|
|
scale_verifiers: bool,
|
2016-12-19 17:15:54 +01:00
|
|
|
verifier_handles: Vec<JoinHandle<()>>,
|
2016-12-05 18:18:56 +01:00
|
|
|
state: Arc<(Mutex<State>, Condvar)>,
|
2016-12-23 18:43:40 +01:00
|
|
|
total_difficulty: RwLock<U256>,
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
struct QueueSignal {
|
2016-04-07 00:20:03 +02:00
|
|
|
deleting: Arc<AtomicBool>,
|
2016-01-17 23:07:58 +01:00
|
|
|
signalled: AtomicBool,
|
2016-10-30 09:56:34 +01:00
|
|
|
message_channel: Mutex<IoChannel<ClientIoMessage>>,
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl QueueSignal {
|
2016-10-20 14:49:12 +02:00
|
|
|
fn set_sync(&self) {
|
2016-04-07 00:20:03 +02:00
|
|
|
// Do not signal when we are about to close
|
|
|
|
if self.deleting.load(AtomicOrdering::Relaxed) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-17 23:07:58 +01:00
|
|
|
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
|
2016-10-30 09:56:34 +01:00
|
|
|
let channel = self.message_channel.lock().clone();
|
|
|
|
if let Err(e) = channel.send_sync(ClientIoMessage::BlockVerified) {
|
2016-10-20 14:49:12 +02:00
|
|
|
debug!("Error sending BlockVerified message: {:?}", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_async(&self) {
|
2016-04-07 00:20:03 +02:00
|
|
|
// Do not signal when we are about to close
|
|
|
|
if self.deleting.load(AtomicOrdering::Relaxed) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-17 23:07:58 +01:00
|
|
|
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
|
2016-10-30 09:56:34 +01:00
|
|
|
let channel = self.message_channel.lock().clone();
|
|
|
|
if let Err(e) = channel.send(ClientIoMessage::BlockVerified) {
|
2016-06-21 15:56:00 +02:00
|
|
|
debug!("Error sending BlockVerified message: {:?}", e);
|
|
|
|
}
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
|
|
|
}
|
2016-04-07 00:20:03 +02:00
|
|
|
|
2016-01-17 23:07:58 +01:00
|
|
|
fn reset(&self) {
|
|
|
|
self.signalled.store(false, AtomicOrdering::Relaxed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
struct Verification<K: Kind> {
|
2016-02-22 00:36:59 +01:00
|
|
|
// All locks must be captured in the order declared here.
|
2016-09-27 16:50:24 +02:00
|
|
|
unverified: Mutex<VecDeque<K::Unverified>>,
|
|
|
|
verifying: Mutex<VecDeque<Verifying<K>>>,
|
2016-10-20 14:49:12 +02:00
|
|
|
verified: Mutex<VecDeque<K::Verified>>,
|
2016-02-21 19:46:29 +01:00
|
|
|
bad: Mutex<HashSet<H256>>,
|
2016-07-27 11:39:24 +02:00
|
|
|
more_to_verify: SMutex<()>,
|
|
|
|
empty: SMutex<()>,
|
2016-10-20 17:19:31 +02:00
|
|
|
sizes: Sizes,
|
2016-11-17 13:00:24 +01:00
|
|
|
check_seal: bool,
|
2016-01-11 13:42:32 +01:00
|
|
|
}
|
2016-01-09 10:16:35 +01:00
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
impl<K: Kind> VerificationQueue<K> {
|
2016-01-10 23:37:09 +01:00
|
|
|
/// Creates a new queue instance.
|
2017-09-26 14:19:08 +02:00
|
|
|
pub fn new(config: Config, engine: Arc<EthEngine>, message_channel: IoChannel<ClientIoMessage>, check_seal: bool) -> Self {
|
2016-02-21 19:46:29 +01:00
|
|
|
let verification = Arc::new(Verification {
|
|
|
|
unverified: Mutex::new(VecDeque::new()),
|
|
|
|
verifying: Mutex::new(VecDeque::new()),
|
2016-10-20 14:49:12 +02:00
|
|
|
verified: Mutex::new(VecDeque::new()),
|
2016-02-21 19:46:29 +01:00
|
|
|
bad: Mutex::new(HashSet::new()),
|
2016-07-27 11:39:24 +02:00
|
|
|
more_to_verify: SMutex::new(()),
|
|
|
|
empty: SMutex::new(()),
|
2016-10-20 17:19:31 +02:00
|
|
|
sizes: Sizes {
|
|
|
|
unverified: AtomicUsize::new(0),
|
|
|
|
verifying: AtomicUsize::new(0),
|
|
|
|
verified: AtomicUsize::new(0),
|
2016-11-17 13:00:24 +01:00
|
|
|
},
|
|
|
|
check_seal: check_seal,
|
2016-02-21 19:46:29 +01:00
|
|
|
});
|
2016-07-27 11:39:24 +02:00
|
|
|
let more_to_verify = Arc::new(SCondvar::new());
|
2016-01-17 23:07:58 +01:00
|
|
|
let deleting = Arc::new(AtomicBool::new(false));
|
2016-04-07 00:20:03 +02:00
|
|
|
let ready_signal = Arc::new(QueueSignal {
|
|
|
|
deleting: deleting.clone(),
|
|
|
|
signalled: AtomicBool::new(false),
|
2016-10-30 09:56:34 +01:00
|
|
|
message_channel: Mutex::new(message_channel),
|
2016-04-07 00:20:03 +02:00
|
|
|
});
|
2016-07-27 11:39:24 +02:00
|
|
|
let empty = Arc::new(SCondvar::new());
|
2016-12-02 18:21:54 +01:00
|
|
|
let scale_verifiers = config.verifier_settings.scale_verifiers;
|
2016-01-17 23:07:58 +01:00
|
|
|
|
2016-12-02 18:21:54 +01:00
|
|
|
let num_cpus = ::num_cpus::get();
|
2017-07-29 17:12:07 +02:00
|
|
|
let max_verifiers = cmp::min(num_cpus, MAX_VERIFIERS);
|
|
|
|
let default_amount = cmp::max(1, cmp::min(max_verifiers, config.verifier_settings.num_verifiers));
|
2016-12-19 17:15:54 +01:00
|
|
|
let state = Arc::new((Mutex::new(State::Work(default_amount)), Condvar::new()));
|
2016-12-05 18:18:56 +01:00
|
|
|
let mut verifier_handles = Vec::with_capacity(max_verifiers);
|
2016-11-17 16:00:23 +01:00
|
|
|
|
|
|
|
debug!(target: "verification", "Allocating {} verifiers, {} initially active", max_verifiers, default_amount);
|
2016-12-02 18:21:54 +01:00
|
|
|
debug!(target: "verification", "Verifier auto-scaling {}", if scale_verifiers { "enabled" } else { "disabled" });
|
2016-11-17 16:00:23 +01:00
|
|
|
|
|
|
|
for i in 0..max_verifiers {
|
|
|
|
debug!(target: "verification", "Adding verification thread #{}", i);
|
|
|
|
|
|
|
|
let verification = verification.clone();
|
|
|
|
let engine = engine.clone();
|
|
|
|
let wait = more_to_verify.clone();
|
|
|
|
let ready = ready_signal.clone();
|
|
|
|
let empty = empty.clone();
|
2016-12-05 18:18:56 +01:00
|
|
|
let state = state.clone();
|
|
|
|
|
|
|
|
let handle = thread::Builder::new()
|
|
|
|
.name(format!("Verifier #{}", i))
|
|
|
|
.spawn(move || {
|
2017-06-22 19:00:53 +02:00
|
|
|
VerificationQueue::verify(
|
|
|
|
verification,
|
|
|
|
engine,
|
|
|
|
wait,
|
|
|
|
ready,
|
|
|
|
empty,
|
|
|
|
state,
|
|
|
|
i,
|
|
|
|
)
|
2016-12-05 18:18:56 +01:00
|
|
|
})
|
|
|
|
.expect("Failed to create verifier thread.");
|
|
|
|
verifier_handles.push(handle);
|
2016-11-17 16:00:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
VerificationQueue {
|
2016-01-11 13:42:32 +01:00
|
|
|
engine: engine,
|
2016-10-03 19:41:00 +02:00
|
|
|
ready_signal: ready_signal,
|
|
|
|
more_to_verify: more_to_verify,
|
|
|
|
verification: verification,
|
|
|
|
deleting: deleting,
|
2016-12-23 18:43:40 +01:00
|
|
|
processing: RwLock::new(HashMap::new()),
|
2016-10-03 19:41:00 +02:00
|
|
|
empty: empty,
|
2016-10-04 20:09:54 +02:00
|
|
|
ticks_since_adjustment: AtomicUsize::new(0),
|
2017-07-29 17:12:07 +02:00
|
|
|
max_queue_size: cmp::max(config.max_queue_size, MIN_QUEUE_LIMIT),
|
|
|
|
max_mem_use: cmp::max(config.max_mem_use, MIN_MEM_LIMIT),
|
2016-12-02 18:21:54 +01:00
|
|
|
scale_verifiers: scale_verifiers,
|
2016-12-05 18:18:56 +01:00
|
|
|
verifier_handles: verifier_handles,
|
|
|
|
state: state,
|
2016-12-23 18:43:40 +01:00
|
|
|
total_difficulty: RwLock::new(0.into()),
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-17 16:00:23 +01:00
|
|
|
fn verify(
|
|
|
|
verification: Arc<Verification<K>>,
|
2017-09-26 14:19:08 +02:00
|
|
|
engine: Arc<EthEngine>,
|
2016-11-17 16:00:23 +01:00
|
|
|
wait: Arc<SCondvar>,
|
|
|
|
ready: Arc<QueueSignal>,
|
|
|
|
empty: Arc<SCondvar>,
|
2016-12-05 18:18:56 +01:00
|
|
|
state: Arc<(Mutex<State>, Condvar)>,
|
|
|
|
id: usize,
|
2016-11-17 16:00:23 +01:00
|
|
|
) {
|
2016-12-05 18:18:56 +01:00
|
|
|
loop {
|
|
|
|
// check current state.
|
2016-11-17 16:00:23 +01:00
|
|
|
{
|
2016-12-05 18:18:56 +01:00
|
|
|
let mut cur_state = state.0.lock();
|
|
|
|
while let State::Work(x) = *cur_state {
|
|
|
|
// sleep until this thread is required.
|
|
|
|
if id < x { break }
|
|
|
|
|
|
|
|
debug!(target: "verification", "verifier {} sleeping", id);
|
|
|
|
state.1.wait(&mut cur_state);
|
2016-12-19 17:15:54 +01:00
|
|
|
debug!(target: "verification", "verifier {} waking up", id);
|
2016-12-05 18:18:56 +01:00
|
|
|
}
|
2016-11-17 16:00:23 +01:00
|
|
|
|
2016-12-19 17:15:54 +01:00
|
|
|
if let State::Exit = *cur_state {
|
|
|
|
debug!(target: "verification", "verifier {} exiting", id);
|
2016-12-05 18:18:56 +01:00
|
|
|
break;
|
2016-11-17 16:00:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
// wait for work if empty.
|
2016-01-17 23:07:58 +01:00
|
|
|
{
|
2016-07-27 11:39:24 +02:00
|
|
|
let mut more_to_verify = verification.more_to_verify.lock().unwrap();
|
2016-01-25 19:20:34 +01:00
|
|
|
|
2016-07-27 11:39:24 +02:00
|
|
|
if verification.unverified.lock().is_empty() && verification.verifying.lock().is_empty() {
|
2016-01-25 19:20:34 +01:00
|
|
|
empty.notify_all();
|
|
|
|
}
|
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
while verification.unverified.lock().is_empty() {
|
|
|
|
if let State::Exit = *state.0.lock() {
|
|
|
|
debug!(target: "verification", "verifier {} exiting", id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-27 11:39:24 +02:00
|
|
|
more_to_verify = wait.wait(more_to_verify).unwrap();
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
2016-02-10 12:50:27 +01:00
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
if let State::Exit = *state.0.lock() {
|
2016-12-19 17:15:54 +01:00
|
|
|
debug!(target: "verification", "verifier {} exiting", id);
|
2016-01-17 23:07:58 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
// do work.
|
2016-09-27 16:50:24 +02:00
|
|
|
let item = {
|
|
|
|
// acquire these locks before getting the item to verify.
|
2016-07-13 19:59:59 +02:00
|
|
|
let mut unverified = verification.unverified.lock();
|
|
|
|
let mut verifying = verification.verifying.lock();
|
2016-09-27 16:50:24 +02:00
|
|
|
|
|
|
|
let item = match unverified.pop_front() {
|
|
|
|
Some(item) => item,
|
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
|
2016-10-20 17:19:31 +02:00
|
|
|
verification.sizes.unverified.fetch_sub(item.heap_size_of_children(), AtomicOrdering::SeqCst);
|
2016-09-27 16:50:24 +02:00
|
|
|
verifying.push_back(Verifying { hash: item.hash(), output: None });
|
|
|
|
item
|
2016-01-17 23:07:58 +01:00
|
|
|
};
|
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
let hash = item.hash();
|
2016-11-17 13:00:24 +01:00
|
|
|
let is_ready = match K::verify(item, &*engine, verification.check_seal) {
|
2016-01-17 23:07:58 +01:00
|
|
|
Ok(verified) => {
|
2016-07-13 19:59:59 +02:00
|
|
|
let mut verifying = verification.verifying.lock();
|
2016-09-27 16:50:24 +02:00
|
|
|
let mut idx = None;
|
|
|
|
for (i, e) in verifying.iter_mut().enumerate() {
|
|
|
|
if e.hash == hash {
|
|
|
|
idx = Some(i);
|
2016-10-20 17:19:31 +02:00
|
|
|
|
|
|
|
verification.sizes.verifying.fetch_add(verified.heap_size_of_children(), AtomicOrdering::SeqCst);
|
2016-09-27 16:50:24 +02:00
|
|
|
e.output = Some(verified);
|
2016-01-17 23:07:58 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-09-27 16:50:24 +02:00
|
|
|
|
|
|
|
if idx == Some(0) {
|
2016-01-17 23:07:58 +01:00
|
|
|
// we're next!
|
2016-07-13 19:59:59 +02:00
|
|
|
let mut verified = verification.verified.lock();
|
|
|
|
let mut bad = verification.bad.lock();
|
2016-11-17 18:10:09 +01:00
|
|
|
VerificationQueue::drain_verifying(&mut verifying, &mut verified, &mut bad, &verification.sizes);
|
2016-10-20 14:49:12 +02:00
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
|
|
|
},
|
2016-09-27 16:50:24 +02:00
|
|
|
Err(_) => {
|
2016-07-13 19:59:59 +02:00
|
|
|
let mut verifying = verification.verifying.lock();
|
|
|
|
let mut verified = verification.verified.lock();
|
|
|
|
let mut bad = verification.bad.lock();
|
2016-09-27 16:50:24 +02:00
|
|
|
|
|
|
|
bad.insert(hash.clone());
|
|
|
|
verifying.retain(|e| e.hash != hash);
|
|
|
|
|
|
|
|
if verifying.front().map_or(false, |x| x.output.is_some()) {
|
2016-11-17 18:10:09 +01:00
|
|
|
VerificationQueue::drain_verifying(&mut verifying, &mut verified, &mut bad, &verification.sizes);
|
2016-10-20 14:49:12 +02:00
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
2016-09-27 16:50:24 +02:00
|
|
|
}
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
2016-10-20 14:49:12 +02:00
|
|
|
};
|
|
|
|
if is_ready {
|
|
|
|
// Import the block immediately
|
|
|
|
ready.set_sync();
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-04 20:09:54 +02:00
|
|
|
fn drain_verifying(
|
|
|
|
verifying: &mut VecDeque<Verifying<K>>,
|
|
|
|
verified: &mut VecDeque<K::Verified>,
|
|
|
|
bad: &mut HashSet<H256>,
|
2016-11-17 13:00:24 +01:00
|
|
|
sizes: &Sizes,
|
2016-10-04 20:09:54 +02:00
|
|
|
) {
|
2016-10-20 17:19:31 +02:00
|
|
|
let mut removed_size = 0;
|
|
|
|
let mut inserted_size = 0;
|
2016-11-17 13:00:24 +01:00
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
while let Some(output) = verifying.front_mut().and_then(|x| x.output.take()) {
|
|
|
|
assert!(verifying.pop_front().is_some());
|
2016-10-20 17:19:31 +02:00
|
|
|
let size = output.heap_size_of_children();
|
|
|
|
removed_size += size;
|
2016-09-27 16:50:24 +02:00
|
|
|
|
|
|
|
if bad.contains(&output.parent_hash()) {
|
|
|
|
bad.insert(output.hash());
|
|
|
|
} else {
|
2016-10-20 17:19:31 +02:00
|
|
|
inserted_size += size;
|
2016-09-27 16:50:24 +02:00
|
|
|
verified.push_back(output);
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
2016-01-11 13:42:32 +01:00
|
|
|
}
|
2016-10-04 20:09:54 +02:00
|
|
|
|
2016-10-20 17:19:31 +02:00
|
|
|
sizes.verifying.fetch_sub(removed_size, AtomicOrdering::SeqCst);
|
|
|
|
sizes.verified.fetch_add(inserted_size, AtomicOrdering::SeqCst);
|
2016-01-09 10:16:35 +01:00
|
|
|
}
|
|
|
|
|
2016-01-10 23:37:09 +01:00
|
|
|
/// Clear the queue and stop verification activity.
|
2016-02-21 19:46:29 +01:00
|
|
|
pub fn clear(&self) {
|
2016-07-13 19:59:59 +02:00
|
|
|
let mut unverified = self.verification.unverified.lock();
|
|
|
|
let mut verifying = self.verification.verifying.lock();
|
|
|
|
let mut verified = self.verification.verified.lock();
|
2016-02-21 19:46:29 +01:00
|
|
|
unverified.clear();
|
|
|
|
verifying.clear();
|
|
|
|
verified.clear();
|
2016-10-20 17:19:31 +02:00
|
|
|
|
|
|
|
let sizes = &self.verification.sizes;
|
|
|
|
sizes.unverified.store(0, AtomicOrdering::Release);
|
|
|
|
sizes.verifying.store(0, AtomicOrdering::Release);
|
|
|
|
sizes.verified.store(0, AtomicOrdering::Release);
|
2016-12-23 18:43:40 +01:00
|
|
|
*self.total_difficulty.write() = 0.into();
|
2016-10-20 17:19:31 +02:00
|
|
|
|
2016-07-13 19:59:59 +02:00
|
|
|
self.processing.write().clear();
|
2016-01-09 10:16:35 +01:00
|
|
|
}
|
|
|
|
|
2016-02-21 19:46:29 +01:00
|
|
|
/// Wait for unverified queue to be empty
|
|
|
|
pub fn flush(&self) {
|
2016-07-27 11:39:24 +02:00
|
|
|
let mut lock = self.verification.empty.lock().unwrap();
|
|
|
|
while !self.verification.unverified.lock().is_empty() || !self.verification.verifying.lock().is_empty() {
|
|
|
|
lock = self.empty.wait(lock).unwrap();
|
2016-01-25 23:24:51 +01:00
|
|
|
}
|
2016-01-25 19:20:34 +01:00
|
|
|
}
|
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
/// Check if the item is currently in the queue
|
|
|
|
pub fn status(&self, hash: &H256) -> Status {
|
2016-12-23 18:43:40 +01:00
|
|
|
if self.processing.read().contains_key(hash) {
|
2016-09-27 16:50:24 +02:00
|
|
|
return Status::Queued;
|
2016-02-02 12:12:32 +01:00
|
|
|
}
|
2016-07-26 20:31:25 +02:00
|
|
|
if self.verification.bad.lock().contains(hash) {
|
2016-09-27 16:50:24 +02:00
|
|
|
return Status::Bad;
|
2016-02-02 12:12:32 +01:00
|
|
|
}
|
2016-09-27 16:50:24 +02:00
|
|
|
Status::Unknown
|
2016-02-02 12:12:32 +01:00
|
|
|
}
|
|
|
|
|
2016-01-10 23:37:09 +01:00
|
|
|
/// Add a block to the queue.
|
2016-09-27 16:50:24 +02:00
|
|
|
pub fn import(&self, input: K::Input) -> ImportResult {
|
|
|
|
let h = input.hash();
|
2016-01-17 23:07:58 +01:00
|
|
|
{
|
2016-12-23 18:43:40 +01:00
|
|
|
if self.processing.read().contains_key(&h) {
|
2018-04-19 11:52:54 +02:00
|
|
|
bail!(ErrorKind::Import(ImportErrorKind::AlreadyQueued));
|
2016-02-21 19:46:29 +01:00
|
|
|
}
|
2016-03-02 01:24:06 +01:00
|
|
|
|
2016-07-13 19:59:59 +02:00
|
|
|
let mut bad = self.verification.bad.lock();
|
2016-02-21 19:46:29 +01:00
|
|
|
if bad.contains(&h) {
|
2018-04-19 11:52:54 +02:00
|
|
|
bail!(ErrorKind::Import(ImportErrorKind::KnownBad));
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
if bad.contains(&input.parent_hash()) {
|
2016-02-21 19:46:29 +01:00
|
|
|
bad.insert(h.clone());
|
2018-04-19 11:52:54 +02:00
|
|
|
bail!(ErrorKind::Import(ImportErrorKind::KnownBad));
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
match K::create(input, &*self.engine) {
|
|
|
|
Ok(item) => {
|
2016-10-20 17:19:31 +02:00
|
|
|
self.verification.sizes.unverified.fetch_add(item.heap_size_of_children(), AtomicOrdering::SeqCst);
|
|
|
|
|
2016-12-23 18:43:40 +01:00
|
|
|
self.processing.write().insert(h.clone(), item.difficulty());
|
|
|
|
{
|
|
|
|
let mut td = self.total_difficulty.write();
|
|
|
|
*td = *td + item.difficulty();
|
|
|
|
}
|
2016-09-27 16:50:24 +02:00
|
|
|
self.verification.unverified.lock().push_back(item);
|
2016-01-17 23:07:58 +01:00
|
|
|
self.more_to_verify.notify_all();
|
2016-01-27 13:28:15 +01:00
|
|
|
Ok(h)
|
2016-01-17 23:07:58 +01:00
|
|
|
},
|
|
|
|
Err(err) => {
|
2016-12-19 14:47:48 +01:00
|
|
|
match err {
|
|
|
|
// Don't mark future blocks as bad.
|
2018-04-19 11:52:54 +02:00
|
|
|
Error(ErrorKind::Block(BlockError::TemporarilyInvalid(_)), _) => {},
|
2016-12-19 14:47:48 +01:00
|
|
|
_ => {
|
|
|
|
self.verification.bad.lock().insert(h.clone());
|
|
|
|
}
|
|
|
|
}
|
2016-03-01 00:02:48 +01:00
|
|
|
Err(err)
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
|
|
|
}
|
2016-01-09 10:16:35 +01:00
|
|
|
}
|
2016-01-15 12:26:04 +01:00
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
/// Mark given item and all its children as bad. pauses verification
|
|
|
|
/// until complete.
|
|
|
|
pub fn mark_as_bad(&self, hashes: &[H256]) {
|
|
|
|
if hashes.is_empty() {
|
2016-03-10 00:21:07 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-07-13 19:59:59 +02:00
|
|
|
let mut verified_lock = self.verification.verified.lock();
|
2017-10-15 15:10:20 +02:00
|
|
|
let verified = &mut *verified_lock;
|
2016-07-13 19:59:59 +02:00
|
|
|
let mut bad = self.verification.bad.lock();
|
|
|
|
let mut processing = self.processing.write();
|
2016-09-27 16:50:24 +02:00
|
|
|
bad.reserve(hashes.len());
|
|
|
|
for hash in hashes {
|
2016-02-29 18:11:59 +01:00
|
|
|
bad.insert(hash.clone());
|
2016-12-23 18:43:40 +01:00
|
|
|
if let Some(difficulty) = processing.remove(hash) {
|
|
|
|
let mut td = self.total_difficulty.write();
|
|
|
|
*td = *td - difficulty;
|
|
|
|
}
|
2016-02-24 17:01:29 +01:00
|
|
|
}
|
|
|
|
|
2016-01-17 23:07:58 +01:00
|
|
|
let mut new_verified = VecDeque::new();
|
2016-10-20 17:19:31 +02:00
|
|
|
let mut removed_size = 0;
|
2016-09-27 16:50:24 +02:00
|
|
|
for output in verified.drain(..) {
|
|
|
|
if bad.contains(&output.parent_hash()) {
|
2016-10-20 17:19:31 +02:00
|
|
|
removed_size += output.heap_size_of_children();
|
2016-09-27 16:50:24 +02:00
|
|
|
bad.insert(output.hash());
|
2016-12-23 18:43:40 +01:00
|
|
|
if let Some(difficulty) = processing.remove(&output.hash()) {
|
|
|
|
let mut td = self.total_difficulty.write();
|
|
|
|
*td = *td - difficulty;
|
|
|
|
}
|
2016-02-24 17:01:29 +01:00
|
|
|
} else {
|
2016-09-27 16:50:24 +02:00
|
|
|
new_verified.push_back(output);
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
|
|
|
}
|
2016-10-20 17:19:31 +02:00
|
|
|
|
|
|
|
self.verification.sizes.verified.fetch_sub(removed_size, AtomicOrdering::SeqCst);
|
2016-02-21 19:46:29 +01:00
|
|
|
*verified = new_verified;
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
|
|
|
|
2016-10-20 14:49:12 +02:00
|
|
|
/// Mark given item as processed.
|
|
|
|
/// Returns true if the queue becomes empty.
|
|
|
|
pub fn mark_as_good(&self, hashes: &[H256]) -> bool {
|
2016-09-27 16:50:24 +02:00
|
|
|
if hashes.is_empty() {
|
2016-10-20 14:49:12 +02:00
|
|
|
return self.processing.read().is_empty();
|
2016-03-10 00:21:07 +01:00
|
|
|
}
|
2016-07-13 19:59:59 +02:00
|
|
|
let mut processing = self.processing.write();
|
2016-09-27 16:50:24 +02:00
|
|
|
for hash in hashes {
|
2016-12-23 18:43:40 +01:00
|
|
|
if let Some(difficulty) = processing.remove(hash) {
|
|
|
|
let mut td = self.total_difficulty.write();
|
|
|
|
*td = *td - difficulty;
|
|
|
|
}
|
2016-02-02 12:12:32 +01:00
|
|
|
}
|
2016-10-20 14:49:12 +02:00
|
|
|
processing.is_empty()
|
2016-02-02 12:12:32 +01:00
|
|
|
}
|
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
/// Removes up to `max` verified items from the queue
|
|
|
|
pub fn drain(&self, max: usize) -> Vec<K::Verified> {
|
2016-07-13 19:59:59 +02:00
|
|
|
let mut verified = self.verification.verified.lock();
|
2017-07-29 17:12:07 +02:00
|
|
|
let count = cmp::min(max, verified.len());
|
2016-09-27 16:50:24 +02:00
|
|
|
let result = verified.drain(..count).collect::<Vec<_>>();
|
|
|
|
|
2016-10-20 17:19:31 +02:00
|
|
|
let drained_size = result.iter().map(HeapSizeOf::heap_size_of_children).fold(0, |a, c| a + c);
|
|
|
|
self.verification.sizes.verified.fetch_sub(drained_size, AtomicOrdering::SeqCst);
|
2016-10-04 20:09:54 +02:00
|
|
|
|
2016-01-17 23:07:58 +01:00
|
|
|
self.ready_signal.reset();
|
2016-02-21 19:46:29 +01:00
|
|
|
if !verified.is_empty() {
|
2016-10-20 14:49:12 +02:00
|
|
|
self.ready_signal.set_async();
|
2016-01-22 04:54:38 +01:00
|
|
|
}
|
2016-01-17 23:07:58 +01:00
|
|
|
result
|
|
|
|
}
|
2016-01-22 04:54:38 +01:00
|
|
|
|
|
|
|
/// Get queue status.
|
2016-09-27 16:50:24 +02:00
|
|
|
pub fn queue_info(&self) -> QueueInfo {
|
2016-10-20 17:19:31 +02:00
|
|
|
use std::mem::size_of;
|
|
|
|
|
2016-02-29 18:11:59 +01:00
|
|
|
let (unverified_len, unverified_bytes) = {
|
2016-10-20 17:19:31 +02:00
|
|
|
let len = self.verification.unverified.lock().len();
|
|
|
|
let size = self.verification.sizes.unverified.load(AtomicOrdering::Acquire);
|
|
|
|
|
|
|
|
(len, size + len * size_of::<K::Unverified>())
|
2016-02-29 18:11:59 +01:00
|
|
|
};
|
|
|
|
let (verifying_len, verifying_bytes) = {
|
2016-10-20 17:19:31 +02:00
|
|
|
let len = self.verification.verifying.lock().len();
|
|
|
|
let size = self.verification.sizes.verifying.load(AtomicOrdering::Acquire);
|
|
|
|
(len, size + len * size_of::<Verifying<K>>())
|
2016-02-29 18:11:59 +01:00
|
|
|
};
|
|
|
|
let (verified_len, verified_bytes) = {
|
2016-10-20 17:19:31 +02:00
|
|
|
let len = self.verification.verified.lock().len();
|
|
|
|
let size = self.verification.sizes.verified.load(AtomicOrdering::Acquire);
|
|
|
|
(len, size + len * size_of::<K::Verified>())
|
2016-02-29 18:11:59 +01:00
|
|
|
};
|
2016-09-27 16:50:24 +02:00
|
|
|
|
|
|
|
QueueInfo {
|
2016-02-29 18:11:59 +01:00
|
|
|
unverified_queue_size: unverified_len,
|
|
|
|
verifying_queue_size: verifying_len,
|
|
|
|
verified_queue_size: verified_len,
|
2016-02-25 14:09:39 +01:00
|
|
|
max_queue_size: self.max_queue_size,
|
|
|
|
max_mem_use: self.max_mem_use,
|
2016-10-20 14:49:12 +02:00
|
|
|
mem_used: unverified_bytes
|
|
|
|
+ verifying_bytes
|
|
|
|
+ verified_bytes
|
2016-01-22 04:54:38 +01:00
|
|
|
}
|
|
|
|
}
|
2016-02-25 14:09:39 +01:00
|
|
|
|
2016-12-23 18:43:40 +01:00
|
|
|
/// Get the total difficulty of all the blocks in the queue.
|
|
|
|
pub fn total_difficulty(&self) -> U256 {
|
|
|
|
self.total_difficulty.read().clone()
|
|
|
|
}
|
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
/// Get the current number of working verifiers.
|
|
|
|
pub fn num_verifiers(&self) -> usize {
|
|
|
|
match *self.state.0.lock() {
|
|
|
|
State::Work(x) => x,
|
|
|
|
State::Exit => panic!("state only set to exit on drop; queue live now; qed"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-03 19:41:00 +02:00
|
|
|
/// Optimise memory footprint of the heap fields, and adjust the number of threads
|
|
|
|
/// to better suit the workload.
|
2016-03-09 11:38:53 +01:00
|
|
|
pub fn collect_garbage(&self) {
|
2016-10-03 20:36:49 +02:00
|
|
|
// number of ticks to average queue stats over
|
|
|
|
// when deciding whether to change the number of verifiers.
|
2016-11-21 14:23:34 +01:00
|
|
|
#[cfg(not(test))]
|
2016-11-17 13:10:33 +01:00
|
|
|
const READJUSTMENT_PERIOD: usize = 12;
|
2016-10-03 19:41:00 +02:00
|
|
|
|
2016-11-21 14:23:34 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
const READJUSTMENT_PERIOD: usize = 1;
|
|
|
|
|
2016-11-17 18:10:09 +01:00
|
|
|
let (u_len, v_len) = {
|
|
|
|
let u_len = {
|
|
|
|
let mut q = self.verification.unverified.lock();
|
|
|
|
q.shrink_to_fit();
|
|
|
|
q.len()
|
|
|
|
};
|
2016-07-13 19:59:59 +02:00
|
|
|
self.verification.verifying.lock().shrink_to_fit();
|
2016-11-17 18:10:09 +01:00
|
|
|
|
|
|
|
let v_len = {
|
|
|
|
let mut q = self.verification.verified.lock();
|
|
|
|
q.shrink_to_fit();
|
|
|
|
q.len()
|
|
|
|
};
|
|
|
|
|
|
|
|
(u_len as isize, v_len as isize)
|
|
|
|
};
|
2016-10-03 19:41:00 +02:00
|
|
|
|
2016-07-13 19:59:59 +02:00
|
|
|
self.processing.write().shrink_to_fit();
|
2016-10-03 19:41:00 +02:00
|
|
|
|
2016-12-02 18:21:54 +01:00
|
|
|
if !self.scale_verifiers { return }
|
|
|
|
|
2016-11-21 14:23:34 +01:00
|
|
|
if self.ticks_since_adjustment.fetch_add(1, AtomicOrdering::SeqCst) + 1 >= READJUSTMENT_PERIOD {
|
2016-10-04 20:09:54 +02:00
|
|
|
self.ticks_since_adjustment.store(0, AtomicOrdering::SeqCst);
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
let current = self.num_verifiers();
|
2016-10-03 20:36:49 +02:00
|
|
|
|
2016-11-17 18:10:09 +01:00
|
|
|
let diff = (v_len - u_len).abs();
|
|
|
|
let total = v_len + u_len;
|
2016-10-05 12:10:28 +02:00
|
|
|
|
2016-11-17 18:10:09 +01:00
|
|
|
self.scale_verifiers(
|
|
|
|
if u_len < 20 {
|
|
|
|
1
|
|
|
|
} else if diff <= total / 10 {
|
|
|
|
current
|
|
|
|
} else if v_len > u_len {
|
|
|
|
current - 1
|
|
|
|
} else {
|
|
|
|
current + 1
|
|
|
|
}
|
|
|
|
);
|
2016-10-03 19:41:00 +02:00
|
|
|
}
|
|
|
|
|
2016-11-17 16:00:23 +01:00
|
|
|
// wake up or sleep verifiers to get as close to the target as
|
|
|
|
// possible, never going over the amount of initially allocated threads
|
|
|
|
// or below 1.
|
|
|
|
fn scale_verifiers(&self, target: usize) {
|
2016-12-05 18:18:56 +01:00
|
|
|
let current = self.num_verifiers();
|
2017-07-29 17:12:07 +02:00
|
|
|
let target = cmp::min(self.verifier_handles.len(), target);
|
|
|
|
let target = cmp::max(1, target);
|
2016-10-03 19:41:00 +02:00
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
debug!(target: "verification", "Scaling from {} to {} verifiers", current, target);
|
2016-10-03 19:41:00 +02:00
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
*self.state.0.lock() = State::Work(target);
|
|
|
|
self.state.1.notify_all();
|
2016-01-22 04:54:38 +01:00
|
|
|
}
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
2016-02-10 12:50:27 +01:00
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
impl<K: Kind> Drop for VerificationQueue<K> {
|
2016-01-17 23:07:58 +01:00
|
|
|
fn drop(&mut self) {
|
2016-09-27 16:50:24 +02:00
|
|
|
trace!(target: "shutdown", "[VerificationQueue] Closing...");
|
2016-01-17 23:07:58 +01:00
|
|
|
self.clear();
|
2016-12-05 18:18:56 +01:00
|
|
|
self.deleting.store(true, AtomicOrdering::SeqCst);
|
2016-10-03 19:41:00 +02:00
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
// set exit state; should be done before `more_to_verify` notification.
|
|
|
|
*self.state.0.lock() = State::Exit;
|
|
|
|
self.state.1.notify_all();
|
2016-10-03 19:41:00 +02:00
|
|
|
|
2016-12-19 17:15:54 +01:00
|
|
|
// acquire this lock to force threads to reach the waiting point
|
|
|
|
// if they're in-between the exit check and the more_to_verify wait.
|
|
|
|
{
|
|
|
|
let _more = self.verification.more_to_verify.lock().unwrap();
|
|
|
|
self.more_to_verify.notify_all();
|
|
|
|
}
|
2016-10-03 19:41:00 +02:00
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
// wait for all verifier threads to join.
|
|
|
|
for thread in self.verifier_handles.drain(..) {
|
|
|
|
thread.join().expect("Propagating verifier thread panic on shutdown");
|
2016-01-17 23:07:58 +01:00
|
|
|
}
|
2016-10-03 19:41:00 +02:00
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
trace!(target: "shutdown", "[VerificationQueue] Closed.");
|
2016-01-15 12:26:04 +01:00
|
|
|
}
|
2016-01-09 10:16:35 +01:00
|
|
|
}
|
|
|
|
|
2016-01-18 00:24:20 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2016-08-05 10:32:04 +02:00
|
|
|
use io::*;
|
2018-03-12 18:05:52 +01:00
|
|
|
use spec::Spec;
|
2016-12-05 18:18:56 +01:00
|
|
|
use super::{BlockQueue, Config, State};
|
2016-09-27 16:50:24 +02:00
|
|
|
use super::kind::blocks::Unverified;
|
2018-04-09 16:14:33 +02:00
|
|
|
use test_helpers::{get_good_dummy_block_seq, get_good_dummy_block};
|
2016-01-28 19:14:07 +01:00
|
|
|
use error::*;
|
2018-04-16 15:52:12 +02:00
|
|
|
use views::BlockView;
|
2016-01-28 19:14:07 +01:00
|
|
|
|
2016-12-02 18:21:54 +01:00
|
|
|
// create a test block queue.
|
|
|
|
// auto_scaling enables verifier adjustment.
|
|
|
|
fn get_test_queue(auto_scale: bool) -> BlockQueue {
|
2018-03-12 18:05:52 +01:00
|
|
|
let spec = Spec::new_test();
|
2016-04-09 19:20:35 +02:00
|
|
|
let engine = spec.engine;
|
2016-12-02 18:21:54 +01:00
|
|
|
|
|
|
|
let mut config = Config::default();
|
|
|
|
config.verifier_settings.scale_verifiers = auto_scale;
|
|
|
|
BlockQueue::new(config, engine, IoChannel::disconnected(), true)
|
2016-01-28 19:14:07 +01:00
|
|
|
}
|
2016-01-18 00:24:20 +01:00
|
|
|
|
|
|
|
#[test]
|
2016-01-28 19:14:07 +01:00
|
|
|
fn can_be_created() {
|
2016-01-18 00:24:20 +01:00
|
|
|
// TODO better test
|
|
|
|
let spec = Spec::new_test();
|
2016-04-09 19:20:35 +02:00
|
|
|
let engine = spec.engine;
|
2016-10-24 16:31:37 +02:00
|
|
|
let _ = BlockQueue::new(Config::default(), engine, IoChannel::disconnected(), true);
|
2016-01-18 00:24:20 +01:00
|
|
|
}
|
2016-01-28 19:14:07 +01:00
|
|
|
|
|
|
|
#[test]
|
2016-01-28 19:43:57 +01:00
|
|
|
fn can_import_blocks() {
|
2016-12-02 18:21:54 +01:00
|
|
|
let queue = get_test_queue(false);
|
2016-09-27 16:50:24 +02:00
|
|
|
if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) {
|
2016-01-28 19:14:07 +01:00
|
|
|
panic!("error importing block that is valid by definition({:?})", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn returns_error_for_duplicates() {
|
2016-12-02 18:21:54 +01:00
|
|
|
let queue = get_test_queue(false);
|
2016-09-27 16:50:24 +02:00
|
|
|
if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) {
|
2016-01-28 19:14:07 +01:00
|
|
|
panic!("error importing block that is valid by definition({:?})", e);
|
|
|
|
}
|
2016-01-28 19:43:57 +01:00
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
let duplicate_import = queue.import(Unverified::new(get_good_dummy_block()));
|
2016-01-28 19:43:57 +01:00
|
|
|
match duplicate_import {
|
|
|
|
Err(e) => {
|
|
|
|
match e {
|
2018-04-19 11:52:54 +02:00
|
|
|
Error(ErrorKind::Import(ImportErrorKind::AlreadyQueued), _) => {},
|
2016-01-28 19:43:57 +01:00
|
|
|
_ => { panic!("must return AlreadyQueued error"); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(_) => { panic!("must produce error"); }
|
|
|
|
}
|
|
|
|
}
|
2016-01-28 19:14:07 +01:00
|
|
|
|
2016-12-23 18:43:40 +01:00
|
|
|
#[test]
|
|
|
|
fn returns_total_difficulty() {
|
|
|
|
let queue = get_test_queue(false);
|
|
|
|
let block = get_good_dummy_block();
|
2018-04-16 15:52:12 +02:00
|
|
|
let hash = view!(BlockView, &block).header().hash().clone();
|
2016-12-23 18:43:40 +01:00
|
|
|
if let Err(e) = queue.import(Unverified::new(block)) {
|
|
|
|
panic!("error importing block that is valid by definition({:?})", e);
|
|
|
|
}
|
|
|
|
queue.flush();
|
|
|
|
assert_eq!(queue.total_difficulty(), 131072.into());
|
|
|
|
queue.drain(10);
|
|
|
|
assert_eq!(queue.total_difficulty(), 131072.into());
|
|
|
|
queue.mark_as_good(&[ hash ]);
|
|
|
|
assert_eq!(queue.total_difficulty(), 0.into());
|
|
|
|
}
|
|
|
|
|
2016-01-28 19:43:57 +01:00
|
|
|
#[test]
|
2016-02-01 16:18:32 +01:00
|
|
|
fn returns_ok_for_drained_duplicates() {
|
2016-12-02 18:21:54 +01:00
|
|
|
let queue = get_test_queue(false);
|
2016-02-02 21:06:21 +01:00
|
|
|
let block = get_good_dummy_block();
|
2018-04-16 15:52:12 +02:00
|
|
|
let hash = view!(BlockView, &block).header().hash().clone();
|
2016-09-27 16:50:24 +02:00
|
|
|
if let Err(e) = queue.import(Unverified::new(block)) {
|
2016-01-28 19:43:57 +01:00
|
|
|
panic!("error importing block that is valid by definition({:?})", e);
|
|
|
|
}
|
|
|
|
queue.flush();
|
2016-02-01 16:18:32 +01:00
|
|
|
queue.drain(10);
|
2016-02-02 21:06:21 +01:00
|
|
|
queue.mark_as_good(&[ hash ]);
|
2016-01-28 19:43:57 +01:00
|
|
|
|
2016-09-27 16:50:24 +02:00
|
|
|
if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) {
|
2016-02-01 16:18:32 +01:00
|
|
|
panic!("error importing block that has already been drained ({:?})", e);
|
2016-01-28 19:14:07 +01:00
|
|
|
}
|
|
|
|
}
|
2016-02-06 23:15:53 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn returns_empty_once_finished() {
|
2016-12-02 18:21:54 +01:00
|
|
|
let queue = get_test_queue(false);
|
2016-09-27 16:50:24 +02:00
|
|
|
queue.import(Unverified::new(get_good_dummy_block()))
|
|
|
|
.expect("error importing block that is valid by definition");
|
2016-02-06 23:15:53 +01:00
|
|
|
queue.flush();
|
|
|
|
queue.drain(1);
|
|
|
|
|
2016-02-08 12:35:51 +01:00
|
|
|
assert!(queue.queue_info().is_empty());
|
2016-02-06 23:15:53 +01:00
|
|
|
}
|
2016-02-25 17:14:45 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_mem_limit() {
|
2018-03-12 18:05:52 +01:00
|
|
|
let spec = Spec::new_test();
|
2016-04-09 19:20:35 +02:00
|
|
|
let engine = spec.engine;
|
2016-09-27 16:50:24 +02:00
|
|
|
let mut config = Config::default();
|
2016-02-25 17:14:45 +01:00
|
|
|
config.max_mem_use = super::MIN_MEM_LIMIT; // empty queue uses about 15000
|
2016-10-24 16:31:37 +02:00
|
|
|
let queue = BlockQueue::new(config, engine, IoChannel::disconnected(), true);
|
2016-02-25 17:14:45 +01:00
|
|
|
assert!(!queue.queue_info().is_full());
|
|
|
|
let mut blocks = get_good_dummy_block_seq(50);
|
|
|
|
for b in blocks.drain(..) {
|
2016-09-27 16:50:24 +02:00
|
|
|
queue.import(Unverified::new(b)).unwrap();
|
2016-02-25 17:14:45 +01:00
|
|
|
}
|
|
|
|
assert!(queue.queue_info().is_full());
|
|
|
|
}
|
2016-11-21 14:23:34 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn scaling_limits() {
|
|
|
|
use super::MAX_VERIFIERS;
|
|
|
|
|
2016-12-02 18:21:54 +01:00
|
|
|
let queue = get_test_queue(true);
|
2016-11-21 14:23:34 +01:00
|
|
|
queue.scale_verifiers(MAX_VERIFIERS + 1);
|
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
assert!(queue.num_verifiers() < MAX_VERIFIERS + 1);
|
2016-11-21 14:23:34 +01:00
|
|
|
|
|
|
|
queue.scale_verifiers(0);
|
|
|
|
|
2016-12-05 18:18:56 +01:00
|
|
|
assert!(queue.num_verifiers() == 1);
|
2016-11-21 14:23:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn readjust_verifiers() {
|
2016-12-02 18:21:54 +01:00
|
|
|
let queue = get_test_queue(true);
|
2016-11-21 14:23:34 +01:00
|
|
|
|
2016-12-19 17:15:54 +01:00
|
|
|
// put all the verifiers to sleep to ensure
|
2016-11-21 14:23:34 +01:00
|
|
|
// the test isn't timing sensitive.
|
2016-12-05 18:18:56 +01:00
|
|
|
*queue.state.0.lock() = State::Work(0);
|
2016-12-02 18:21:54 +01:00
|
|
|
|
2016-11-21 14:23:34 +01:00
|
|
|
for block in get_good_dummy_block_seq(5000) {
|
|
|
|
queue.import(Unverified::new(block)).expect("Block good by definition; qed");
|
|
|
|
}
|
|
|
|
|
|
|
|
// almost all unverified == bump verifier count.
|
|
|
|
queue.collect_garbage();
|
2016-12-05 18:18:56 +01:00
|
|
|
assert_eq!(queue.num_verifiers(), 1);
|
2016-11-21 14:23:34 +01:00
|
|
|
|
|
|
|
queue.flush();
|
|
|
|
|
|
|
|
// nothing to verify == use minimum number of verifiers.
|
|
|
|
queue.collect_garbage();
|
2016-12-05 18:18:56 +01:00
|
|
|
assert_eq!(queue.num_verifiers(), 1);
|
2016-11-21 14:23:34 +01:00
|
|
|
}
|
2016-01-18 00:24:20 +01:00
|
|
|
}
|