Merge branch 'master' into adaptive_queue_threads

This commit is contained in:
Robert Habermeier
2016-11-17 13:00:24 +01:00
1370 changed files with 95224 additions and 15163 deletions

View File

@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Canonical verifier.
use blockchain::BlockProvider;
use engines::Engine;
use error::Error;
@@ -21,6 +23,7 @@ use header::Header;
use super::Verifier;
use super::verification;
/// A canonial verifier -- this does full verification.
pub struct CanonVerifier;
impl Verifier for CanonVerifier {

View File

@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Block verification utilities.
pub mod verification;
pub mod verifier;
pub mod queue;
@@ -31,6 +33,8 @@ pub use self::queue::{BlockQueue, Config as QueueConfig, VerificationQueue, Queu
pub enum VerifierType {
/// Verifies block normally.
Canon,
/// Verifies block normallly, but skips seal verification.
CanonNoSeal,
/// Does not verify block at all.
/// Used in tests.
Noop,
@@ -42,9 +46,20 @@ impl Default for VerifierType {
}
}
/// Create a new verifier based on type.
pub fn new(v: VerifierType) -> Box<Verifier> {
match v {
VerifierType::Canon => Box::new(CanonVerifier),
VerifierType::Canon | VerifierType::CanonNoSeal => Box::new(CanonVerifier),
VerifierType::Noop => Box::new(NoopVerifier),
}
}
impl VerifierType {
/// Check if seal verification is enabled for this verifier type.
pub fn verifying_seal(&self) -> bool {
match *self {
VerifierType::Canon => true,
VerifierType::Noop | VerifierType::CanonNoSeal => false,
}
}
}

View File

@@ -14,12 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! No-op verifier.
use blockchain::BlockProvider;
use engines::Engine;
use error::Error;
use header::Header;
use super::Verifier;
/// A no-op verifier -- this will verify everything it's given immediately.
#[allow(dead_code)]
pub struct NoopVerifier;

View File

@@ -57,7 +57,7 @@ pub trait Kind: 'static + Sized + Send + Sync {
fn create(input: Self::Input, engine: &Engine) -> Result<Self::Unverified, Error>;
/// Attempt to verify the `Unverified` item using the given engine.
fn verify(unverified: Self::Unverified, engine: &Engine) -> Result<Self::Verified, Error>;
fn verify(unverified: Self::Unverified, engine: &Engine, check_seal: bool) -> Result<Self::Verified, Error>;
}
/// The blocks verification module.
@@ -89,9 +89,9 @@ pub mod blocks {
}
}
fn verify(un: Self::Unverified, engine: &Engine) -> Result<Self::Verified, Error> {
fn verify(un: Self::Unverified, engine: &Engine, check_seal: bool) -> Result<Self::Verified, Error> {
let hash = un.hash();
match verify_block_unordered(un.header, un.bytes, engine) {
match verify_block_unordered(un.header, un.bytes, engine, check_seal) {
Ok(verified) => Ok(verified),
Err(e) => {
warn!(target: "client", "Stage 2 block verification failed for {}: {:?}", hash, e);
@@ -176,8 +176,11 @@ pub mod headers {
verify_header_params(&input, engine).map(|_| input)
}
fn verify(unverified: Self::Unverified, engine: &Engine) -> Result<Self::Verified, Error> {
engine.verify_block_unordered(&unverified, None).map(|_| unverified)
fn verify(unverified: Self::Unverified, engine: &Engine, check_seal: bool) -> Result<Self::Verified, Error> {
match check_seal {
true => engine.verify_block_unordered(&unverified, None).map(|_| unverified),
false => Ok(unverified),
}
}
}
}

View File

@@ -101,6 +101,13 @@ pub enum Status {
Unknown,
}
// the internal queue sizes.
struct Sizes {
unverified: AtomicUsize,
verifying: AtomicUsize,
verified: AtomicUsize,
}
/// 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> {
@@ -121,19 +128,35 @@ pub struct VerificationQueue<K: Kind> {
struct QueueSignal {
deleting: Arc<AtomicBool>,
signalled: AtomicBool,
message_channel: IoChannel<ClientIoMessage>,
message_channel: Mutex<IoChannel<ClientIoMessage>>,
}
impl QueueSignal {
#[cfg_attr(feature="dev", allow(bool_comparison))]
fn set(&self) {
fn set_sync(&self) {
// Do not signal when we are about to close
if self.deleting.load(AtomicOrdering::Relaxed) {
return;
}
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
if let Err(e) = self.message_channel.send(ClientIoMessage::BlockVerified) {
let channel = self.message_channel.lock().clone();
if let Err(e) = channel.send_sync(ClientIoMessage::BlockVerified) {
debug!("Error sending BlockVerified message: {:?}", e);
}
}
}
#[cfg_attr(feature="dev", allow(bool_comparison))]
fn set_async(&self) {
// Do not signal when we are about to close
if self.deleting.load(AtomicOrdering::Relaxed) {
return;
}
if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false {
let channel = self.message_channel.lock().clone();
if let Err(e) = channel.send(ClientIoMessage::BlockVerified) {
debug!("Error sending BlockVerified message: {:?}", e);
}
}
@@ -147,36 +170,44 @@ impl QueueSignal {
struct Verification<K: Kind> {
// All locks must be captured in the order declared here.
unverified: Mutex<VecDeque<K::Unverified>>,
verified: Mutex<VecDeque<K::Verified>>,
verifying: Mutex<VecDeque<Verifying<K>>>,
verified: Mutex<VecDeque<K::Verified>>,
bad: Mutex<HashSet<H256>>,
more_to_verify: SMutex<()>,
empty: SMutex<()>,
verified_count: AtomicUsize,
drained: AtomicUsize,
imported: AtomicUsize,
sizes: Sizes,
check_seal: bool,
}
impl<K: Kind> VerificationQueue<K> {
/// Creates a new queue instance.
pub fn new(config: Config, engine: Arc<Engine>, message_channel: IoChannel<ClientIoMessage>) -> Self {
pub fn new(config: Config, engine: Arc<Engine>, message_channel: IoChannel<ClientIoMessage>, check_seal: bool) -> Self {
let verification = Arc::new(Verification {
unverified: Mutex::new(VecDeque::new()),
verified: Mutex::new(VecDeque::new()),
verifying: Mutex::new(VecDeque::new()),
verified: Mutex::new(VecDeque::new()),
bad: Mutex::new(HashSet::new()),
more_to_verify: SMutex::new(()),
empty: SMutex::new(()),
verified_count: AtomicUsize::new(0),
drained: AtomicUsize::new(0),
imported: AtomicUsize::new(0),
sizes: Sizes {
unverified: AtomicUsize::new(0),
verifying: AtomicUsize::new(0),
verified: AtomicUsize::new(0),
},
check_seal: check_seal,
});
let more_to_verify = Arc::new(SCondvar::new());
let deleting = Arc::new(AtomicBool::new(false));
let ready_signal = Arc::new(QueueSignal {
deleting: deleting.clone(),
signalled: AtomicBool::new(false),
message_channel: message_channel
message_channel: Mutex::new(message_channel),
});
let empty = Arc::new(SCondvar::new());
let panic_handler = PanicHandler::new_in_arc();
@@ -232,18 +263,21 @@ impl<K: Kind> VerificationQueue<K> {
None => continue,
};
verification.sizes.unverified.fetch_sub(item.heap_size_of_children(), AtomicOrdering::SeqCst);
verifying.push_back(Verifying { hash: item.hash(), output: None });
item
};
let hash = item.hash();
match K::verify(item, &*engine) {
let is_ready = match K::verify(item, &*engine, verification.check_seal) {
Ok(verified) => {
let mut verifying = verification.verifying.lock();
let mut idx = None;
for (i, e) in verifying.iter_mut().enumerate() {
if e.hash == hash {
idx = Some(i);
verification.sizes.verifying.fetch_add(verified.heap_size_of_children(), AtomicOrdering::SeqCst);
e.output = Some(verified);
break;
}
@@ -253,8 +287,10 @@ impl<K: Kind> VerificationQueue<K> {
// we're next!
let mut verified = verification.verified.lock();
let mut bad = verification.bad.lock();
VerificationQueue::drain_verifying(&mut verifying, &mut verified, &mut bad, &verification.verified_count);
ready.set();
VerificationQueue::drain_verifying(&mut verifying, &mut verified, &mut bad, &verification.verified_count, &verification.sizes);
true
} else {
false
}
},
Err(_) => {
@@ -266,10 +302,16 @@ impl<K: Kind> VerificationQueue<K> {
verifying.retain(|e| e.hash != hash);
if verifying.front().map_or(false, |x| x.output.is_some()) {
VerificationQueue::drain_verifying(&mut verifying, &mut verified, &mut bad, &verification.verified_count);
ready.set();
VerificationQueue::drain_verifying(&mut verifying, &mut verified, &mut bad, &verification.verified_count, &verification.sizes);
true
} else {
false
}
}
};
if is_ready {
// Import the block immediately
ready.set_sync();
}
}
}
@@ -278,20 +320,29 @@ impl<K: Kind> VerificationQueue<K> {
verifying: &mut VecDeque<Verifying<K>>,
verified: &mut VecDeque<K::Verified>,
bad: &mut HashSet<H256>,
v_count: &AtomicUsize
v_count: &AtomicUsize,
sizes: &Sizes,
) {
let start_len = verified.len();
let mut removed_size = 0;
let mut inserted_size = 0;
while let Some(output) = verifying.front_mut().and_then(|x| x.output.take()) {
assert!(verifying.pop_front().is_some());
let size = output.heap_size_of_children();
removed_size += size;
if bad.contains(&output.parent_hash()) {
bad.insert(output.hash());
} else {
inserted_size += size;
verified.push_back(output);
}
}
v_count.fetch_add(verified.len() - start_len, AtomicOrdering::AcqRel);
sizes.verifying.fetch_sub(removed_size, AtomicOrdering::SeqCst);
sizes.verified.fetch_add(inserted_size, AtomicOrdering::SeqCst);
}
/// Clear the queue and stop verification activity.
@@ -302,6 +353,12 @@ impl<K: Kind> VerificationQueue<K> {
unverified.clear();
verifying.clear();
verified.clear();
let sizes = &self.verification.sizes;
sizes.unverified.store(0, AtomicOrdering::Release);
sizes.verifying.store(0, AtomicOrdering::Release);
sizes.verified.store(0, AtomicOrdering::Release);
self.processing.write().clear();
}
@@ -345,6 +402,8 @@ impl<K: Kind> VerificationQueue<K> {
match K::create(input, &*self.engine) {
Ok(item) => {
self.verification.sizes.unverified.fetch_add(item.heap_size_of_children(), AtomicOrdering::SeqCst);
self.processing.write().insert(h.clone());
self.verification.unverified.lock().push_back(item);
self.verification.imported.fetch_add(1, AtomicOrdering::AcqRel);
@@ -375,26 +434,32 @@ impl<K: Kind> VerificationQueue<K> {
}
let mut new_verified = VecDeque::new();
let mut removed_size = 0;
for output in verified.drain(..) {
if bad.contains(&output.parent_hash()) {
removed_size += output.heap_size_of_children();
bad.insert(output.hash());
processing.remove(&output.hash());
} else {
new_verified.push_back(output);
}
}
self.verification.sizes.verified.fetch_sub(removed_size, AtomicOrdering::SeqCst);
*verified = new_verified;
}
/// Mark given item as processed
pub fn mark_as_good(&self, hashes: &[H256]) {
/// Mark given item as processed.
/// Returns true if the queue becomes empty.
pub fn mark_as_good(&self, hashes: &[H256]) -> bool {
if hashes.is_empty() {
return;
return self.processing.read().is_empty();
}
let mut processing = self.processing.write();
for hash in hashes {
processing.remove(hash);
}
processing.is_empty()
}
/// Removes up to `max` verified items from the queue
@@ -403,28 +468,37 @@ impl<K: Kind> VerificationQueue<K> {
let count = min(max, verified.len());
let result = verified.drain(..count).collect::<Vec<_>>();
self.verification.drained.fetch_add(count, AtomicOrdering::AcqRel);
self.verification.drained.fetch_add(result.len(), AtomicOrdering::AcqRel);
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);
self.ready_signal.reset();
if !verified.is_empty() {
self.ready_signal.set();
self.ready_signal.set_async();
}
result
}
/// Get queue status.
pub fn queue_info(&self) -> QueueInfo {
use std::mem::size_of;
let (unverified_len, unverified_bytes) = {
let v = self.verification.unverified.lock();
(v.len(), v.heap_size_of_children())
let len = self.verification.unverified.lock().len();
let size = self.verification.sizes.unverified.load(AtomicOrdering::Acquire);
(len, size + len * size_of::<K::Unverified>())
};
let (verifying_len, verifying_bytes) = {
let v = self.verification.verifying.lock();
(v.len(), v.heap_size_of_children())
let len = self.verification.verifying.lock().len();
let size = self.verification.sizes.verifying.load(AtomicOrdering::Acquire);
(len, size + len * size_of::<Verifying<K>>())
};
let (verified_len, verified_bytes) = {
let v = self.verification.verified.lock();
(v.len(), v.heap_size_of_children())
let len = self.verification.verified.lock().len();
let size = self.verification.sizes.verified.load(AtomicOrdering::Acquire);
(len, size + len * size_of::<K::Verified>())
};
QueueInfo {
@@ -433,12 +507,9 @@ impl<K: Kind> VerificationQueue<K> {
verified_queue_size: verified_len,
max_queue_size: self.max_queue_size,
max_mem_use: self.max_mem_use,
mem_used:
unverified_bytes
+ verifying_bytes
+ verified_bytes
// TODO: https://github.com/servo/heapsize/pull/50
//+ self.processing.read().heap_size_of_children(),
mem_used: unverified_bytes
+ verifying_bytes
+ verified_bytes
}
}
@@ -593,7 +664,7 @@ mod tests {
fn get_test_queue() -> BlockQueue {
let spec = get_test_spec();
let engine = spec.engine;
BlockQueue::new(Config::default(), engine, IoChannel::disconnected())
BlockQueue::new(Config::default(), engine, IoChannel::disconnected(), true)
}
#[test]
@@ -601,7 +672,7 @@ mod tests {
// TODO better test
let spec = Spec::new_test();
let engine = spec.engine;
let _ = BlockQueue::new(Config::default(), engine, IoChannel::disconnected());
let _ = BlockQueue::new(Config::default(), engine, IoChannel::disconnected(), true);
}
#[test]
@@ -665,7 +736,7 @@ mod tests {
let engine = spec.engine;
let mut config = Config::default();
config.max_mem_use = super::MIN_MEM_LIMIT; // empty queue uses about 15000
let queue = BlockQueue::new(config, engine, IoChannel::disconnected());
let queue = BlockQueue::new(config, engine, IoChannel::disconnected(), true);
assert!(!queue.queue_info().is_full());
let mut blocks = get_good_dummy_block_seq(50);
for b in blocks.drain(..) {

View File

@@ -14,17 +14,21 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
/// Block and transaction verification functions
///
/// Block verification is done in 3 steps
/// 1. Quick verification upon adding to the block queue
/// 2. Signatures verification done in the queue.
/// 3. Final verification against the blockchain done before enactment.
//! Block and transaction verification functions
//!
//! Block verification is done in 3 steps
//! 1. Quick verification upon adding to the block queue
//! 2. Signatures verification done in the queue.
//! 3. Final verification against the blockchain done before enactment.
use common::*;
use util::*;
use engines::Engine;
use error::{BlockError, Error};
use blockchain::*;
use header::{BlockNumber, Header};
use rlp::{UntrustedRlp, View};
use transaction::SignedTransaction;
use views::BlockView;
/// Preprocessed block data gathered in `verify_block_unordered` call
pub struct PreverifiedBlock {
@@ -66,10 +70,12 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res
/// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash.
/// Still operates on a individual block
/// Returns a `PreverifiedBlock` structure populated with transactions
pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result<PreverifiedBlock, Error> {
try!(engine.verify_block_unordered(&header, Some(&bytes)));
for u in try!(UntrustedRlp::new(&bytes).at(2)).iter().map(|rlp| rlp.as_val::<Header>()) {
try!(engine.verify_block_unordered(&try!(u), None));
pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine, check_seal: bool) -> Result<PreverifiedBlock, Error> {
if check_seal {
try!(engine.verify_block_unordered(&header, Some(&bytes)));
for u in try!(UntrustedRlp::new(&bytes).at(2)).iter().map(|rlp| rlp.as_val::<Header>()) {
try!(engine.verify_block_unordered(&try!(u), None));
}
}
// Verify transactions.
let mut transactions = Vec::new();
@@ -108,7 +114,8 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
match bc.block_details(&hash) {
Some(details) => {
excluded.insert(details.parent.clone());
let b = bc.block(&hash).unwrap();
let b = bc.block(&hash)
.expect("parent already known to be stored; qed");
excluded.extend(BlockView::new(&b).uncle_hashes());
hash = details.parent;
}
@@ -296,7 +303,7 @@ mod tests {
self.blocks.contains_key(hash)
}
fn first_block(&self) -> H256 {
fn first_block(&self) -> Option<H256> {
unimplemented!()
}
@@ -313,6 +320,10 @@ mod tests {
self.block(hash).map(|b| BlockChain::block_to_body(&b))
}
fn best_ancient_block(&self) -> Option<H256> {
None
}
/// Get the familial details concerning a block.
fn block_details(&self, hash: &H256) -> Option<BlockDetails> {
self.blocks.get(hash).map(|bytes| {
@@ -384,7 +395,7 @@ mod tests {
gas: U256::from(30_000),
gas_price: U256::from(40_000),
nonce: U256::one()
}.sign(keypair.secret());
}.sign(keypair.secret(), None);
let tr2 = Transaction {
action: Action::Create,
@@ -393,7 +404,7 @@ mod tests {
gas: U256::from(30_000),
gas_price: U256::from(40_000),
nonce: U256::from(2)
}.sign(keypair.secret());
}.sign(keypair.secret(), None);
let good_transactions = [ tr1.clone(), tr2.clone() ];

View File

@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! A generic verifier trait.
use blockchain::BlockProvider;
use engines::Engine;
use error::Error;
@@ -21,6 +23,8 @@ use header::Header;
/// Should be used to verify blocks.
pub trait Verifier: Send + Sync {
/// Verify a block relative to its parent and uncles.
fn verify_block_family(&self, header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error>;
/// Do a final verification check for an enacted header vs its expected counterpart.
fn verify_block_final(&self, expected: &Header, got: &Header) -> Result<(), Error>;
}