2016-01-09 19:10:05 +01:00
|
|
|
use util::*;
|
2016-01-09 10:16:35 +01:00
|
|
|
use header::Header;
|
|
|
|
use client::BlockNumber;
|
2016-01-09 19:10:05 +01:00
|
|
|
use engine::{Engine, VerificationMode};
|
|
|
|
use views::BlockView;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct VerificationError {
|
|
|
|
pub block: Option<Bytes>,
|
|
|
|
pub error: VerificationErrorOption,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl VerificationError {
|
|
|
|
pub fn block(error: BlockVerificationError, block: Option<Bytes>) -> VerificationError {
|
|
|
|
VerificationError {
|
|
|
|
block: block,
|
|
|
|
error: VerificationErrorOption::Block(error),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn transaction(error: TransactionVerificationError, block: Option<Bytes>) -> VerificationError {
|
|
|
|
VerificationError {
|
|
|
|
block: block,
|
|
|
|
error: VerificationErrorOption::Transaction(error),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum VerificationErrorOption {
|
|
|
|
Transaction(TransactionVerificationError),
|
|
|
|
Block(BlockVerificationError),
|
|
|
|
}
|
2016-01-09 10:16:35 +01:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum TransactionVerificationError {
|
|
|
|
OutOfGasBase,
|
|
|
|
OutOfGasIntrinsic,
|
|
|
|
NotEnoughCash,
|
|
|
|
GasPriceTooLow,
|
|
|
|
BlockGasLimitReached,
|
|
|
|
FeeTooSmall,
|
|
|
|
TooMuchGasUsed {
|
|
|
|
used: U256,
|
|
|
|
limit: U256
|
|
|
|
},
|
|
|
|
InvalidSignature,
|
|
|
|
InvalidTransactionFormat,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum BlockVerificationError {
|
|
|
|
TooMuchGasUsed {
|
|
|
|
used: U256,
|
|
|
|
limit: U256,
|
|
|
|
},
|
|
|
|
InvalidBlockFormat,
|
2016-01-09 19:10:05 +01:00
|
|
|
ExtraDataTooBig {
|
|
|
|
required: U256,
|
|
|
|
got: U256,
|
|
|
|
},
|
2016-01-09 10:16:35 +01:00
|
|
|
InvalidUnclesHash {
|
2016-01-09 19:10:05 +01:00
|
|
|
required: H256,
|
2016-01-09 10:16:35 +01:00
|
|
|
got: H256,
|
|
|
|
},
|
|
|
|
TooManyUncles,
|
|
|
|
UncleTooOld,
|
|
|
|
UncleIsBrother,
|
|
|
|
UncleInChain,
|
|
|
|
UncleParentNotInChain,
|
|
|
|
InvalidStateRoot,
|
|
|
|
InvalidGasUsed,
|
|
|
|
InvalidTransactionsRoot {
|
2016-01-09 19:10:05 +01:00
|
|
|
required: H256,
|
2016-01-09 10:16:35 +01:00
|
|
|
got: H256,
|
|
|
|
},
|
2016-01-09 19:10:05 +01:00
|
|
|
InvalidDifficulty {
|
|
|
|
required: U256,
|
|
|
|
got: U256,
|
|
|
|
},
|
|
|
|
InvalidGasLimit {
|
|
|
|
min: U256,
|
|
|
|
max: U256,
|
|
|
|
got: U256,
|
|
|
|
},
|
2016-01-09 10:16:35 +01:00
|
|
|
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 {
|
2016-01-09 19:10:05 +01:00
|
|
|
required: expected_root.clone(),
|
2016-01-09 10:16:35 +01:00
|
|
|
got: transactions_root.clone(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
let expected_uncles = block.at(2).as_raw().sha3();
|
|
|
|
if &expected_uncles != uncles_hash {
|
|
|
|
return Err(BlockVerificationError::InvalidUnclesHash {
|
2016-01-09 19:10:05 +01:00
|
|
|
required: expected_uncles.clone(),
|
2016-01-09 10:16:35 +01:00
|
|
|
got: uncles_hash.clone(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-01-09 19:10:05 +01:00
|
|
|
pub fn verify_block_basic(bytes: &[u8], parent: &Header, engine: &mut Engine) -> Result<(), BlockVerificationError> {
|
|
|
|
let block = BlockView::new(bytes);
|
|
|
|
let header = block.header();
|
|
|
|
try!(verify_header(&header));
|
|
|
|
try!(verify_parent(&header, parent));
|
|
|
|
try!(verify_block_integrity(bytes, &header.transactions_root, &header.uncles_hash));
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn verify_block_unordered(block: &[u8]) -> Result<(), BlockVerificationError> {
|
|
|
|
Ok(())
|
|
|
|
}
|