Started block verification

This commit is contained in:
arkpar 2016-01-09 10:16:35 +01:00
parent b272595183
commit f1cdc0a17d
4 changed files with 158 additions and 16 deletions

View File

@ -1,10 +1,11 @@
use std::sync::Arc;
use std::path::Path; use std::path::Path;
use util::uint::U256; use util::uint::U256;
use util::hash::*; use util::hash::*;
use util::sha3::*;
use util::rlp::*; use util::rlp::*;
use util::bytes::Bytes; use util::bytes::Bytes;
use blockchain::BlockChain; use blockchain::BlockChain;
use queue::BlockQueue;
use views::BlockView; use views::BlockView;
/// Status for a block in a queue. /// Status for a block in a queue.
@ -106,7 +107,7 @@ pub trait BlockChainClient : Sync {
/// Get block queue information. /// Get block queue information.
fn queue_status(&self) -> BlockQueueStatus; 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); fn clear_queue(&mut self);
/// Get blockchain information. /// 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. /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
pub struct Client { pub struct Client {
chain: BlockChain chain: Arc<BlockChain>,
queue: BlockQueue,
} }
impl Client { impl Client {
pub fn new(genesis: &[u8], path: &Path) -> Client { pub fn new(genesis: &[u8], path: &Path) -> Client {
let chain = Arc::new(BlockChain::new(genesis, path));
Client { 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 { fn import_block(&mut self, bytes: &[u8]) -> ImportResult {
//TODO: verify block self.queue.import_block(bytes)
{
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)
} }
fn queue_status(&self) -> BlockQueueStatus { fn queue_status(&self) -> BlockQueueStatus {
@ -201,6 +195,7 @@ impl BlockChainClient for Client {
} }
fn clear_queue(&mut self) { fn clear_queue(&mut self) {
self.queue.clear();
} }
fn chain_info(&self) -> BlockChainInfo { fn chain_info(&self) -> BlockChainInfo {

View File

@ -105,6 +105,7 @@ pub mod views;
pub mod blockchain; pub mod blockchain;
pub mod extras; pub mod extras;
pub mod client; pub mod client;
pub mod sync; pub mod sync;
pub mod verification;
pub mod queue;

37
src/queue.rs Normal file
View File

@ -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<BlockChain>
}
impl BlockQueue {
pub fn new(chain: Arc<BlockChain>) -> 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)
}
}

109
src/verification.rs Normal file
View File

@ -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(())
}