2016-11-03 04:37:58 -07:00
|
|
|
use std::sync::Arc;
|
|
|
|
use chain;
|
|
|
|
use db;
|
2016-11-25 09:38:21 -08:00
|
|
|
use network::Magic;
|
2016-11-03 04:37:58 -07:00
|
|
|
use verification::{Verify, ChainVerifier};
|
2016-11-25 09:38:21 -08:00
|
|
|
use super::Error;
|
2016-11-03 04:37:58 -07:00
|
|
|
|
|
|
|
pub struct BlocksWriter {
|
|
|
|
storage: Arc<db::Store>,
|
|
|
|
verifier: ChainVerifier,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BlocksWriter {
|
2016-11-25 09:38:21 -08:00
|
|
|
pub fn new(storage: db::SharedStore, network: Magic) -> BlocksWriter {
|
2016-11-03 04:37:58 -07:00
|
|
|
BlocksWriter {
|
|
|
|
storage: storage.clone(),
|
2016-11-25 09:38:21 -08:00
|
|
|
verifier: ChainVerifier::new(storage, network),
|
2016-11-03 04:37:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)),
|
2016-11-17 07:24:04 -08:00
|
|
|
Ok(_chain) => { try!(self.storage.insert_block(&block).map_err(Error::Database)); Ok(()) }
|
2016-11-03 04:37:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use std::sync::Arc;
|
2016-11-25 09:38:21 -08:00
|
|
|
use db::{self, Store};
|
|
|
|
use network::Magic;
|
|
|
|
use {test_data, verification};
|
2016-11-03 04:37:58 -07:00
|
|
|
use super::super::Error;
|
|
|
|
use super::BlocksWriter;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn blocks_writer_appends_blocks() {
|
|
|
|
let db = Arc::new(db::TestStorage::with_genesis_block());
|
2016-11-25 09:38:21 -08:00
|
|
|
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet);
|
2016-11-03 04:37:58 -07:00
|
|
|
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());
|
2016-11-25 09:38:21 -08:00
|
|
|
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet);
|
2016-11-03 04:37:58 -07:00
|
|
|
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());
|
2016-11-25 09:38:21 -08:00
|
|
|
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet);
|
2016-11-03 04:37:58 -07:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|