diff --git a/src/client.rs b/src/client.rs index f67eb0905..9b5d2f26e 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,10 +1,11 @@ +use std::sync::Arc; use std::path::Path; use util::uint::U256; use util::hash::*; -use util::sha3::*; use util::rlp::*; use util::bytes::Bytes; use blockchain::BlockChain; +use queue::BlockQueue; use views::BlockView; /// Status for a block in a queue. @@ -106,7 +107,7 @@ pub trait BlockChainClient : Sync { /// Get block queue information. fn queue_status(&self) -> BlockQueueStatus; - /// Clear block qeueu and abort all import activity. + /// Clear block queue and abort all import activity. fn clear_queue(&mut self); /// Get blockchain information. @@ -115,13 +116,16 @@ 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: BlockChain + chain: Arc, + queue: BlockQueue, } impl Client { pub fn new(genesis: &[u8], path: &Path) -> Client { + let chain = Arc::new(BlockChain::new(genesis, path)); Client { - chain: BlockChain::new(genesis, path) + chain: chain.clone(), + queue: BlockQueue::new(chain) } } } @@ -181,17 +185,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 ImportResult::Bad; - } - } - self.chain.insert_block(bytes); - ImportResult::Queued(QueueStatus::Known) + self.queue.import_block(bytes) } fn queue_status(&self) -> BlockQueueStatus { @@ -201,6 +195,7 @@ impl BlockChainClient for Client { } fn clear_queue(&mut self) { + self.queue.clear(); } fn chain_info(&self) -> BlockChainInfo { diff --git a/src/lib.rs b/src/lib.rs index 1d351444c..80f9b732e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,6 +105,7 @@ pub mod views; pub mod blockchain; pub mod extras; pub mod client; - pub mod sync; +pub mod verification; +pub mod queue; diff --git a/src/queue.rs b/src/queue.rs new file mode 100644 index 000000000..8d427e8a1 --- /dev/null +++ b/src/queue.rs @@ -0,0 +1,37 @@ +use std::sync::Arc; +//use util::bytes::*; +use util::sha3::*; +use blockchain::BlockChain; +use client::{QueueStatus, ImportResult}; +use views::{BlockView}; + + +pub struct BlockQueue { + chain: Arc +} + +impl BlockQueue { + pub fn new(chain: Arc) -> BlockQueue { + BlockQueue { + chain: chain + } + } + + pub fn clear(&mut self) { + } + + pub 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 ImportResult::Bad; + } + } + self.chain.insert_block(bytes); + ImportResult::Queued(QueueStatus::Known) + } +} + diff --git a/src/verification.rs b/src/verification.rs new file mode 100644 index 000000000..95951da53 --- /dev/null +++ b/src/verification.rs @@ -0,0 +1,109 @@ +use util::uint::*; +use util::hash::*; +use util::rlp::*; +use util::sha3::Hashable; +use util::triehash::ordered_trie_root; +use header::Header; +use client::BlockNumber; + +#[derive(Debug)] +pub enum TransactionVerificationError { + OutOfGasBase, + OutOfGasIntrinsic, + NotEnoughCash, + GasPriceTooLow, + BlockGasLimitReached, + FeeTooSmall, + TooMuchGasUsed { + used: U256, + limit: U256 + }, + ExtraDataTooBig, + InvalidSignature, + InvalidTransactionFormat, +} + +#[derive(Debug)] +pub enum BlockVerificationError { + TooMuchGasUsed { + used: U256, + limit: U256, + }, + InvalidBlockFormat, + InvalidUnclesHash { + expected: H256, + got: H256, + }, + TooManyUncles, + UncleTooOld, + UncleIsBrother, + UncleInChain, + UncleParentNotInChain, + InvalidStateRoot, + InvalidGasUsed, + InvalidTransactionsRoot { + expected: H256, + got: H256, + }, + InvalidDifficulty, + InvalidGasLimit, + InvalidReceiptsStateRoot, + InvalidTimestamp, + InvalidLogBloom, + InvalidNonce, + InvalidBlockHeaderItemCount, + InvalidBlockNonce, + InvalidParentHash, + InvalidUncleParentHash, + InvalidNumber, + BlockNotFound, + UnknownParent, +} + + +pub fn verify_header(header: &Header) -> Result<(), BlockVerificationError> { + if header.number > From::from(BlockNumber::max_value()) { + return Err(BlockVerificationError::InvalidNumber) + } + if header.gas_used > header.gas_limit { + return Err(BlockVerificationError::TooMuchGasUsed { + used: header.gas_used, + limit: header.gas_limit, + }); + } + Ok(()) +} + +pub fn verify_parent(header: &Header, parent: &Header) -> Result<(), BlockVerificationError> { + if !header.parent_hash.is_zero() && parent.hash() != header.parent_hash { + return Err(BlockVerificationError::InvalidParentHash) + } + if header.timestamp <= parent.timestamp { + return Err(BlockVerificationError::InvalidTimestamp) + } + if header.number <= parent.number { + return Err(BlockVerificationError::InvalidNumber) + } + Ok(()) +} + +pub fn verify_block_integrity(block: &[u8], transactions_root: &H256, uncles_hash: &H256) -> Result<(), BlockVerificationError> { + let block = Rlp::new(block); + let tx = block.at(1); + let expected_root = ordered_trie_root(tx.iter().map(|r| r.as_raw().to_vec()).collect()); //TODO: get rid of vectors here + if &expected_root != transactions_root { + return Err(BlockVerificationError::InvalidTransactionsRoot { + expected: expected_root.clone(), + got: transactions_root.clone(), + }); + } + let expected_uncles = block.at(2).as_raw().sha3(); + if &expected_uncles != uncles_hash { + return Err(BlockVerificationError::InvalidUnclesHash { + expected: expected_uncles.clone(), + got: uncles_hash.clone(), + }); + } + Ok(()) +} +