more tests

This commit is contained in:
NikVolf 2016-10-19 14:39:58 +03:00
parent 9f49d0c505
commit cb7766ddd6
5 changed files with 128 additions and 2 deletions

1
Cargo.lock generated
View File

@ -530,6 +530,7 @@ dependencies = [
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0",
"serialization 0.1.0",
"test-data 0.1.0",
]
[[package]]

View File

@ -8,3 +8,17 @@ pub fn block1() -> Block {
let block: Block = "01000000ba8b9cda965dd8e536670f9ddec10e53aab14b20bacad27b9137190000000000190760b278fe7b8565fda3b968b918d5fd997f993b23674c0af3b6fde300b38f33a5914ce6ed5b1b01e32f570201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704e6ed5b1b014effffffff0100f2052a01000000434104b68a50eaa0287eff855189f949c1c6e5f58b37c88231373d8a59809cbae83059cc6469d65c665ccfd1cfeb75c6e8e19413bba7fbff9bc762419a76d87b16086eac000000000100000001a6b97044d03da79c005b20ea9c0e1a6d9dc12d9f7b91a5911c9030a439eed8f5000000004948304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501ffffffff0100f2052a010000001976a914404371705fa9bd789a2fcd52d2c580b65d35549d88ac00000000".into();
block
}
// https://webbtc.com/block/00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048
// height 1
pub fn block_h1() -> Block {
let block: Block = "010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e362990101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000".into();
block
}
// https://webbtc.com/block/000000006a625f06636b8bb6ac7b960a8d03705d1ace08b1a19da3fdcc99ddbd.hex
// height 2
pub fn block_h2() -> Block {
let block: Block = "010000004860eb18bf1b1620e37e9490fc8a427514416fd75159ab86688e9a8300000000d5fdcc541e25de1c7a5addedf24858b8bb665c9f36ef744ee42c316022c90f9bb0bc6649ffff001d08d2bd610101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d010bffffffff0100f2052a010000004341047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77ac00000000".into();
block
}

View File

@ -11,3 +11,4 @@ chain = { path = "../chain" }
serialization = { path = "../serialization" }
parking_lot = "0.3"
linked-hash-map = "0.3"
test-data = { path = "../test-data" }

View File

@ -9,6 +9,8 @@ extern crate linked_hash_map;
#[cfg(test)]
extern crate ethcore_devtools as devtools;
#[cfg(test)]
extern crate test_data;
mod queue;
@ -67,6 +69,6 @@ pub enum BlockStatus {
pub type VerificationResult = Result<Chain, Error>;
/// Interface for block verification
pub trait Verify {
pub trait Verify : Send + Sync {
fn verify(&self, block: &chain::Block) -> VerificationResult;
}

View File

@ -7,6 +7,8 @@ use linked_hash_map::LinkedHashMap;
use parking_lot::RwLock;
use std::collections::HashSet;
const MAX_PENDING_PRESET: usize = 128;
pub struct VerifiedBlock {
pub chain: Chain,
pub block: Block,
@ -18,6 +20,15 @@ impl VerifiedBlock {
}
}
#[derive(Debug)]
/// Queue errors
pub enum Error {
/// Queue is currently full
Full,
/// There is already block in the queue
Duplicate,
}
/// Verification queue
pub struct Queue {
verifier: Box<Verify>,
@ -69,24 +80,121 @@ impl Queue {
else if self.items.read().contains_key(hash) { BlockStatus::Pending }
else { BlockStatus::Absent }
}
pub fn max_pending(&self) -> usize {
// todo: later might be calculated with lazy-static here based on memory usage
MAX_PENDING_PRESET
}
pub fn push(&self, block: Block) -> Result<(), Error> {
let hash = block.hash();
if self.block_status(&hash) != BlockStatus::Absent { return Err(Error::Duplicate) }
let mut items = self.items.write();
if items.len() > self.max_pending() { return Err(Error::Full) }
items.insert(hash, block);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::Queue;
use super::super::{BlockStatus, VerificationResult, Verify, Chain};
use super::super::{BlockStatus, VerificationResult, Verify, Chain, Error as VerificationError};
use chain::Block;
use primitives::hash::H256;
use test_data;
struct FacileVerifier;
impl Verify for FacileVerifier {
fn verify(&self, _block: &Block) -> VerificationResult { Ok(Chain::Main) }
}
struct EvilVerifier;
impl Verify for EvilVerifier {
fn verify(&self, _block: &Block) -> VerificationResult { Err(VerificationError::Empty) }
}
#[test]
fn new() {
let queue = Queue::new(Box::new(FacileVerifier));
assert_eq!(queue.block_status(&H256::from(0u8)), BlockStatus::Absent);
}
#[test]
fn push() {
let queue = Queue::new(Box::new(FacileVerifier));
let block = test_data::block1();
let hash = block.hash();
queue.push(block).unwrap();
assert_eq!(queue.block_status(&hash), BlockStatus::Pending);
}
#[test]
fn push_duplicate() {
let queue = Queue::new(Box::new(FacileVerifier));
let block = test_data::block1();
let dup_block = test_data::block1();
queue.push(block).unwrap();
let second_push = queue.push(dup_block);
assert!(second_push.is_err());
}
#[test]
fn process_happy() {
let queue = Queue::new(Box::new(FacileVerifier));
let block = test_data::block1();
let hash = block.hash();
queue.push(block).unwrap();
queue.process();
assert_eq!(queue.block_status(&hash), BlockStatus::Valid);
}
#[test]
fn process_unhappy() {
let queue = Queue::new(Box::new(EvilVerifier));
let block = test_data::block1();
let hash = block.hash();
queue.push(block).unwrap();
queue.process();
assert_eq!(queue.block_status(&hash), BlockStatus::Invalid);
}
#[test]
fn process_async() {
use std::thread;
use std::sync::Arc;
let queue = Arc::new(Queue::new(Box::new(FacileVerifier)));
let t1_queue = queue.clone();
let t1_handle = thread::spawn(move || {
let block_h1 = test_data::block_h1();
t1_queue.push(block_h1).unwrap();
t1_queue.process();
});
let t2_queue = queue.clone();
let t2_handle = thread::spawn(move || {
let block_h2 = test_data::block_h2();
t2_queue.push(block_h2).unwrap();
t2_queue.process();
});
t1_handle.join().unwrap();
t2_handle.join().unwrap();
assert_eq!(queue.block_status(&test_data::block_h1().hash()), BlockStatus::Valid);
assert_eq!(queue.block_status(&test_data::block_h2().hash()), BlockStatus::Valid);
}
}