From 9b5a134d01adaf033a03d259f3f89215d5cbe0f8 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 3 Nov 2016 14:37:58 +0300 Subject: [PATCH] initial BlocksWriter version --- sync/src/blocks_writer.rs | 77 +++++++++++++++++++++++++++++++++++++++ sync/src/lib.rs | 17 +++++++++ 2 files changed, 94 insertions(+) create mode 100644 sync/src/blocks_writer.rs diff --git a/sync/src/blocks_writer.rs b/sync/src/blocks_writer.rs new file mode 100644 index 00000000..841490d0 --- /dev/null +++ b/sync/src/blocks_writer.rs @@ -0,0 +1,77 @@ +use std::sync::Arc; +use chain; +use db; +use super::Error; +use verification::{Verify, ChainVerifier}; + +pub struct BlocksWriter { + storage: Arc, + verifier: ChainVerifier, +} + +impl BlocksWriter { + pub fn new(storage: Arc) -> BlocksWriter { + BlocksWriter { + storage: storage.clone(), + verifier: ChainVerifier::new(storage), + } + } + + pub fn append_block(&mut self, block: chain::Block) -> Result<(), Error> { + // TODO: share same verification code with synchronization_client + if self.storage.best_block().map_or(false, |bb| bb.hash != block.block_header.previous_header_hash) { + return Err(Error::OutOfOrderBlock); + } + + match self.verifier.verify(&block) { + Err(err) => Err(Error::Verification(err)), + Ok(_chain) => self.storage.insert_block(&block).map_err(|err| Error::Database(err)), + } + } +} + +#[cfg(test)] +mod tests { + use db; + use db::Store; + use std::sync::Arc; + use super::super::Error; + use super::BlocksWriter; + use chain::RepresentH256; + use test_data; + use verification; + + #[test] + fn blocks_writer_appends_blocks() { + let db = Arc::new(db::TestStorage::with_genesis_block()); + let mut blocks_target = BlocksWriter::new(db.clone()); + blocks_target.append_block(test_data::block_h1()).expect("Expecting no error"); + assert_eq!(db.best_block().expect("Block is inserted").number, 1); + } + + #[test] + fn blocks_writer_verification_error() { + let db = Arc::new(db::TestStorage::with_genesis_block()); + let mut blocks_target = BlocksWriter::new(db.clone()); + match blocks_target.append_block(test_data::block_h2()).unwrap_err() { + Error::OutOfOrderBlock => (), + _ => panic!("Unexpected error"), + }; + assert_eq!(db.best_block().expect("Block is inserted").number, 0); + } + + #[test] + fn blocks_writer_out_of_order_block() { + let db = Arc::new(db::TestStorage::with_genesis_block()); + let mut blocks_target = BlocksWriter::new(db.clone()); + + let wrong_block = test_data::block_builder() + .header().parent(test_data::genesis().hash()).build() + .build(); + match blocks_target.append_block(wrong_block).unwrap_err() { + Error::Verification(verification::Error::Empty) => (), + _ => panic!("Unexpected error"), + }; + assert_eq!(db.best_block().expect("Block is inserted").number, 0); + } +} diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 79533c6b..1a3ee849 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -11,6 +11,7 @@ extern crate time; extern crate verification; extern crate miner; +mod blocks_writer; mod hash_queue; mod inbound_connection; mod inbound_connection_factory; @@ -24,6 +25,22 @@ mod synchronization_server; use std::sync::Arc; use parking_lot::{Mutex, RwLock}; +/// Sync errors. +#[derive(Debug)] +pub enum Error { + /// Out of order block. + OutOfOrderBlock, + /// Database error. + Database(db::Error), + /// Block verification error. + Verification(verification::Error), +} + +/// Create blocks writer. +pub fn create_sync_blocks_writer(db: Arc) -> blocks_writer::BlocksWriter { + blocks_writer::BlocksWriter::new(db) +} + /// Create inbound synchronization connections factory for given `db`. pub fn create_sync_connection_factory(db: Arc) -> p2p::LocalSyncNodeRef { use synchronization_chain::Chain as SyncChain;