From 0221d47544960348d5a2cfc67d45e40da339171e Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 11 Jan 2016 13:42:32 +0100 Subject: [PATCH] Verification integrated into client/queue --- src/client.rs | 53 +++++++++++++++++++-------------------------- src/error.rs | 11 +++++++++- src/lib.rs | 1 + src/queue.rs | 36 +++++++++++++++++------------- src/sync/tests.rs | 12 +++------- src/verification.rs | 6 ++--- 6 files changed, 60 insertions(+), 59 deletions(-) diff --git a/src/client.rs b/src/client.rs index b914dba19..018f99b6f 100644 --- a/src/client.rs +++ b/src/client.rs @@ -5,6 +5,7 @@ use error::*; use header::BlockNumber; use spec::Spec; use engine::Engine; +use queue::BlockQueue; /// General block status pub enum BlockStatus { @@ -18,9 +19,6 @@ pub enum BlockStatus { Unknown, } -/// Result of import block operation. -pub type ImportResult = Result<(), ImportError>; - /// Information about the blockchain gthered together. pub struct BlockChainInfo { /// Blockchain difficulty. @@ -95,28 +93,30 @@ pub trait BlockChainClient : Sync { /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue. pub struct Client { - chain: Arc, + chain: Arc>, _engine: Arc>, + queue: BlockQueue, } impl Client { pub fn new(spec: Spec, path: &Path) -> Result { - let chain = Arc::new(BlockChain::new(&spec.genesis_block(), path)); + let chain = Arc::new(RwLock::new(BlockChain::new(&spec.genesis_block(), path))); let engine = Arc::new(try!(spec.to_engine())); Ok(Client { chain: chain.clone(), - _engine: engine, + _engine: engine.clone(), + queue: BlockQueue::new(chain.clone(), engine.clone()), }) } } impl BlockChainClient for Client { fn block_header(&self, hash: &H256) -> Option { - self.chain.block(hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec()) + self.chain.read().unwrap().block(hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec()) } fn block_body(&self, hash: &H256) -> Option { - self.chain.block(hash).map(|bytes| { + self.chain.read().unwrap().block(hash).map(|bytes| { let rlp = Rlp::new(&bytes); let mut body = RlpStream::new(); body.append_raw(rlp.at(1).as_raw(), 1); @@ -126,34 +126,34 @@ impl BlockChainClient for Client { } fn block(&self, hash: &H256) -> Option { - self.chain.block(hash) + self.chain.read().unwrap().block(hash) } fn block_status(&self, hash: &H256) -> BlockStatus { - if self.chain.is_known(&hash) { BlockStatus::InChain } else { BlockStatus::Unknown } + if self.chain.read().unwrap().is_known(&hash) { BlockStatus::InChain } else { BlockStatus::Unknown } } fn block_header_at(&self, n: BlockNumber) -> Option { - self.chain.block_hash(n).and_then(|h| self.block_header(&h)) + self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_header(&h)) } fn block_body_at(&self, n: BlockNumber) -> Option { - self.chain.block_hash(n).and_then(|h| self.block_body(&h)) + self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_body(&h)) } fn block_at(&self, n: BlockNumber) -> Option { - self.chain.block_hash(n).and_then(|h| self.block(&h)) + self.chain.read().unwrap().block_hash(n).and_then(|h| self.block(&h)) } fn block_status_at(&self, n: BlockNumber) -> BlockStatus { - match self.chain.block_hash(n) { + match self.chain.read().unwrap().block_hash(n) { Some(h) => self.block_status(&h), None => BlockStatus::Unknown } } fn tree_route(&self, from: &H256, to: &H256) -> Option { - self.chain.tree_route(from.clone(), to.clone()) + self.chain.read().unwrap().tree_route(from.clone(), to.clone()) } fn state_data(&self, _hash: &H256) -> Option { @@ -165,17 +165,7 @@ impl BlockChainClient for Client { } fn import_block(&mut self, bytes: &[u8]) -> ImportResult { - //TODO: verify block - { - let block = BlockView::new(bytes); - let header = block.header_view(); - let hash = header.sha3(); - if self.chain.is_known(&hash) { - return Err(ImportError::AlreadyInChain); - } - } - self.chain.insert_block(bytes); - Ok(()) + self.queue.import_block(bytes) } fn queue_status(&self) -> BlockQueueStatus { @@ -188,12 +178,13 @@ impl BlockChainClient for Client { } fn chain_info(&self) -> BlockChainInfo { + let chain = self.chain.read().unwrap(); BlockChainInfo { - total_difficulty: self.chain.best_block_total_difficulty(), - pending_total_difficulty: self.chain.best_block_total_difficulty(), - genesis_hash: self.chain.genesis_hash(), - best_block_hash: self.chain.best_block_hash(), - best_block_number: From::from(self.chain.best_block_number()) + total_difficulty: chain.best_block_total_difficulty(), + pending_total_difficulty: chain.best_block_total_difficulty(), + genesis_hash: chain.genesis_hash(), + best_block_hash: chain.best_block_hash(), + best_block_number: From::from(chain.best_block_number()) } } } diff --git a/src/error.rs b/src/error.rs index 99a64ce7a..c18782502 100644 --- a/src/error.rs +++ b/src/error.rs @@ -45,11 +45,20 @@ pub enum BlockError { #[derive(Debug)] pub enum ImportError { - Bad(BlockError), + Bad(Error), AlreadyInChain, AlreadyQueued, } +impl From for ImportError { + fn from(err: Error) -> ImportError { + ImportError::Bad(err) + } +} + +/// Result of import block operation. +pub type ImportResult = Result<(), ImportError>; + #[derive(Debug)] /// General error type which should be capable of representing all errors in ethcore. pub enum Error { diff --git a/src/lib.rs b/src/lib.rs index f090ba83a..6aab2587a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,4 +106,5 @@ pub mod client; pub mod sync; pub mod block; pub mod verification; +pub mod queue; pub mod ethereum; diff --git a/src/queue.rs b/src/queue.rs index ea212aaf1..721960259 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -1,16 +1,24 @@ -use std::sync::Arc; use util::*; use blockchain::BlockChain; -use client::{QueueStatus, ImportResult}; use views::{BlockView}; +use verification::*; +use error::*; +use engine::Engine; /// A queue of blocks. Sits between network or other I/O and the BlockChain. /// Sorts them ready for blockchain insertion. -pub struct BlockQueue; +pub struct BlockQueue { + bc: Arc>, + engine: Arc>, +} impl BlockQueue { /// Creates a new queue instance. - pub fn new() -> BlockQueue { + pub fn new(bc: Arc>, engine: Arc>) -> BlockQueue { + BlockQueue { + bc: bc, + engine: engine, + } } /// Clear the queue and stop verification activity. @@ -18,18 +26,16 @@ impl BlockQueue { } /// Add a block to the queue. - pub fn import_block(&mut self, bytes: &[u8], bc: &mut BlockChain) -> ImportResult { - //TODO: verify block - { - let block = BlockView::new(bytes); - let header = block.header_view(); - let hash = header.sha3(); - if self.chain.is_known(&hash) { - return ImportResult::Bad; - } + pub fn import_block(&mut self, bytes: &[u8]) -> ImportResult { + let header = BlockView::new(bytes).header(); + if self.bc.read().unwrap().is_known(&header.hash()) { + return Err(ImportError::AlreadyInChain); } - bc.insert_block(bytes); - ImportResult::Queued(QueueStatus::Known) + try!(verify_block_basic(bytes, self.engine.deref().deref())); + try!(verify_block_unordered(bytes, self.engine.deref().deref())); + try!(verify_block_final(bytes, self.engine.deref().deref(), self.bc.read().unwrap().deref())); + self.bc.write().unwrap().insert_block(bytes); + Ok(()) } } diff --git a/src/sync/tests.rs b/src/sync/tests.rs index 6a045fa1e..bc0e171d2 100644 --- a/src/sync/tests.rs +++ b/src/sync/tests.rs @@ -1,13 +1,7 @@ -use std::collections::{HashMap, VecDeque}; -use util::bytes::Bytes; -use util::hash::{H256, FixedHash}; -use util::uint::{U256}; -use util::sha3::Hashable; -use util::rlp::{self, Rlp, RlpStream, View, Stream}; -use util::network::{PeerId, PacketId}; -use util::error::UtilError; -use client::{BlockChainClient, BlockStatus, TreeRoute, BlockQueueStatus, BlockChainInfo, ImportResult}; +use util::*; +use client::{BlockChainClient, BlockStatus, TreeRoute, BlockQueueStatus, BlockChainInfo}; use header::{Header as BlockHeader, BlockNumber}; +use error::*; use sync::io::SyncIo; use sync::chain::ChainSync; diff --git a/src/verification.rs b/src/verification.rs index e27536187..1d34ddff4 100644 --- a/src/verification.rs +++ b/src/verification.rs @@ -10,7 +10,7 @@ use engine::Engine; use blockchain::BlockChain; /// Phase 1 quick block verification. Only does checks that are cheap. Operates on a single block -pub fn verify_block_basic(bytes: &[u8], engine: &mut Engine) -> Result<(), Error> { +pub fn verify_block_basic(bytes: &[u8], engine: &Engine) -> Result<(), Error> { let block = BlockView::new(bytes); let header = block.header(); try!(verify_header(&header)); @@ -26,7 +26,7 @@ pub fn verify_block_basic(bytes: &[u8], engine: &mut Engine) -> Result<(), Error /// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash. /// Still operates on a individual block /// TODO: return cached transactions, header hash. -pub fn verify_block_unordered(bytes: &[u8], engine: &mut Engine) -> Result<(), Error> { +pub fn verify_block_unordered(bytes: &[u8], engine: &Engine) -> Result<(), Error> { let block = BlockView::new(bytes); let header = block.header(); try!(engine.verify_block_unordered(&header, Some(bytes))); @@ -37,7 +37,7 @@ pub fn verify_block_unordered(bytes: &[u8], engine: &mut Engine) -> Result<(), E } /// Phase 3 verification. Check block information against parents and uncles. -pub fn verify_block_final(bytes: &[u8], engine: &mut Engine, bc: &BlockChain) -> Result<(), Error> { +pub fn verify_block_final(bytes: &[u8], engine: &Engine, bc: &BlockChain) -> Result<(), Error> { let block = BlockView::new(bytes); let header = block.header(); let parent = try!(bc.block_header(&header.parent_hash).ok_or::(From::from(BlockError::UnknownParent(header.parent_hash.clone()))));