more tests
This commit is contained in:
parent
9f49d0c505
commit
cb7766ddd6
|
@ -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]]
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -11,3 +11,4 @@ chain = { path = "../chain" }
|
|||
serialization = { path = "../serialization" }
|
||||
parking_lot = "0.3"
|
||||
linked-hash-map = "0.3"
|
||||
test-data = { path = "../test-data" }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue