Make the block header struct's internals private (#2000)
* Make the block header struct's internals private Currently, this involves a lot of explicit cloning, but we could migrate the return types of the get_* functions to be copies rather than references since they are mostly copy types anyway. I opted to eliminate the constructor in favor of using Default::default() plus calling a bunch of setters. This is similar to the model that a Google Protobuf client uses and I think it looks fine. * Drop some unnecessary cloning by comparing references * Fix compiler errors from callsites in tests.
This commit is contained in:
committed by
Arkadiy Paronyan
parent
2d883c43c9
commit
4389742ca3
@@ -38,7 +38,7 @@ pub struct PreverifiedBlock {
|
||||
/// Phase 1 quick block verification. Only does checks that are cheap. Operates on a single block
|
||||
pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Result<(), Error> {
|
||||
try!(verify_header(&header, engine));
|
||||
try!(verify_block_integrity(bytes, &header.transactions_root, &header.uncles_hash));
|
||||
try!(verify_block_integrity(bytes, &header.transactions_root(), &header.uncles_hash()));
|
||||
try!(engine.verify_block_basic(&header, Some(bytes)));
|
||||
for u in try!(UntrustedRlp::new(bytes).at(2)).iter().map(|rlp| rlp.as_val::<Header>()) {
|
||||
let u = try!(u);
|
||||
@@ -81,7 +81,7 @@ pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) ->
|
||||
/// Phase 3 verification. Check block information against parent and uncles.
|
||||
pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error> {
|
||||
// TODO: verify timestamp
|
||||
let parent = try!(bc.block_header(&header.parent_hash).ok_or_else(|| Error::from(BlockError::UnknownParent(header.parent_hash.clone()))));
|
||||
let parent = try!(bc.block_header(&header.parent_hash()).ok_or_else(|| Error::from(BlockError::UnknownParent(header.parent_hash().clone()))));
|
||||
try!(verify_parent(&header, &parent));
|
||||
try!(engine.verify_block_family(&header, &parent, Some(bytes)));
|
||||
|
||||
@@ -93,7 +93,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
|
||||
|
||||
let mut excluded = HashSet::new();
|
||||
excluded.insert(header.hash());
|
||||
let mut hash = header.parent_hash.clone();
|
||||
let mut hash = header.parent_hash().clone();
|
||||
excluded.insert(hash.clone());
|
||||
for _ in 0..engine.maximum_uncle_age() {
|
||||
match bc.block_details(&hash) {
|
||||
@@ -122,12 +122,12 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
|
||||
// 6 7
|
||||
// (8 Invalid)
|
||||
|
||||
let depth = if header.number > uncle.number { header.number - uncle.number } else { 0 };
|
||||
let depth = if header.number() > uncle.number() { header.number() - uncle.number() } else { 0 };
|
||||
if depth > engine.maximum_uncle_age() as u64 {
|
||||
return Err(From::from(BlockError::UncleTooOld(OutOfBounds { min: Some(header.number - depth), max: Some(header.number - 1), found: uncle.number })));
|
||||
return Err(From::from(BlockError::UncleTooOld(OutOfBounds { min: Some(header.number() - depth), max: Some(header.number() - 1), found: uncle.number() })));
|
||||
}
|
||||
else if depth < 1 {
|
||||
return Err(From::from(BlockError::UncleIsBrother(OutOfBounds { min: Some(header.number - depth), max: Some(header.number - 1), found: uncle.number })));
|
||||
return Err(From::from(BlockError::UncleIsBrother(OutOfBounds { min: Some(header.number() - depth), max: Some(header.number() - 1), found: uncle.number() })));
|
||||
}
|
||||
|
||||
// cB
|
||||
@@ -139,8 +139,8 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
|
||||
// cB.p^6 -----------/ 6
|
||||
// cB.p^7 -------------/
|
||||
// cB.p^8
|
||||
let mut expected_uncle_parent = header.parent_hash.clone();
|
||||
let uncle_parent = try!(bc.block_header(&uncle.parent_hash).ok_or_else(|| Error::from(BlockError::UnknownUncleParent(uncle.parent_hash.clone()))));
|
||||
let mut expected_uncle_parent = header.parent_hash().clone();
|
||||
let uncle_parent = try!(bc.block_header(&uncle.parent_hash()).ok_or_else(|| Error::from(BlockError::UnknownUncleParent(uncle.parent_hash().clone()))));
|
||||
for _ in 0..depth {
|
||||
match bc.block_details(&expected_uncle_parent) {
|
||||
Some(details) => {
|
||||
@@ -162,50 +162,50 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
|
||||
|
||||
/// Phase 4 verification. Check block information against transaction enactment results,
|
||||
pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error> {
|
||||
if expected.gas_used != got.gas_used {
|
||||
return Err(From::from(BlockError::InvalidGasUsed(Mismatch { expected: expected.gas_used, found: got.gas_used })))
|
||||
if expected.gas_used() != got.gas_used() {
|
||||
return Err(From::from(BlockError::InvalidGasUsed(Mismatch { expected: expected.gas_used().clone(), found: got.gas_used().clone() })))
|
||||
}
|
||||
if expected.log_bloom != got.log_bloom {
|
||||
return Err(From::from(BlockError::InvalidLogBloom(Mismatch { expected: expected.log_bloom.clone(), found: got.log_bloom.clone() })))
|
||||
if expected.log_bloom() != got.log_bloom() {
|
||||
return Err(From::from(BlockError::InvalidLogBloom(Mismatch { expected: expected.log_bloom().clone(), found: got.log_bloom().clone() })))
|
||||
}
|
||||
if expected.state_root != got.state_root {
|
||||
return Err(From::from(BlockError::InvalidStateRoot(Mismatch { expected: expected.state_root.clone(), found: got.state_root.clone() })))
|
||||
if expected.state_root() != got.state_root() {
|
||||
return Err(From::from(BlockError::InvalidStateRoot(Mismatch { expected: expected.state_root().clone(), found: got.state_root().clone() })))
|
||||
}
|
||||
if expected.receipts_root != got.receipts_root {
|
||||
return Err(From::from(BlockError::InvalidReceiptsRoot(Mismatch { expected: expected.receipts_root.clone(), found: got.receipts_root.clone() })))
|
||||
if expected.receipts_root() != got.receipts_root() {
|
||||
return Err(From::from(BlockError::InvalidReceiptsRoot(Mismatch { expected: expected.receipts_root().clone(), found: got.receipts_root().clone() })))
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check basic header parameters.
|
||||
fn verify_header(header: &Header, engine: &Engine) -> Result<(), Error> {
|
||||
if header.number >= From::from(BlockNumber::max_value()) {
|
||||
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { max: Some(From::from(BlockNumber::max_value())), min: None, found: header.number })))
|
||||
if header.number() >= From::from(BlockNumber::max_value()) {
|
||||
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { max: Some(From::from(BlockNumber::max_value())), min: None, found: header.number() })))
|
||||
}
|
||||
if header.gas_used > header.gas_limit {
|
||||
return Err(From::from(BlockError::TooMuchGasUsed(OutOfBounds { max: Some(header.gas_limit), min: None, found: header.gas_used })));
|
||||
if header.gas_used() > header.gas_limit() {
|
||||
return Err(From::from(BlockError::TooMuchGasUsed(OutOfBounds { max: Some(header.gas_limit().clone()), min: None, found: header.gas_used().clone() })));
|
||||
}
|
||||
let min_gas_limit = engine.params().min_gas_limit;
|
||||
if header.gas_limit < min_gas_limit {
|
||||
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas_limit), max: None, found: header.gas_limit })));
|
||||
if header.gas_limit() < &min_gas_limit {
|
||||
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas_limit), max: None, found: header.gas_limit().clone() })));
|
||||
}
|
||||
let maximum_extra_data_size = engine.maximum_extra_data_size();
|
||||
if header.number != 0 && header.extra_data.len() > maximum_extra_data_size {
|
||||
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds { min: None, max: Some(maximum_extra_data_size), found: header.extra_data.len() })));
|
||||
if header.number() != 0 && header.extra_data().len() > maximum_extra_data_size {
|
||||
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds { min: None, max: Some(maximum_extra_data_size), found: header.extra_data().len() })));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check header parameters agains parent header.
|
||||
fn verify_parent(header: &Header, parent: &Header) -> Result<(), Error> {
|
||||
if !header.parent_hash.is_zero() && parent.hash() != header.parent_hash {
|
||||
return Err(From::from(BlockError::InvalidParentHash(Mismatch { expected: parent.hash(), found: header.parent_hash.clone() })))
|
||||
if !header.parent_hash().is_zero() && &parent.hash() != header.parent_hash() {
|
||||
return Err(From::from(BlockError::InvalidParentHash(Mismatch { expected: parent.hash(), found: header.parent_hash().clone() })))
|
||||
}
|
||||
if header.timestamp <= parent.timestamp {
|
||||
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp + 1), found: header.timestamp })))
|
||||
if header.timestamp() <= parent.timestamp() {
|
||||
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp() + 1), found: header.timestamp() })))
|
||||
}
|
||||
if header.number != parent.number + 1 {
|
||||
return Err(From::from(BlockError::InvalidNumber(Mismatch { expected: parent.number + 1, found: header.number })));
|
||||
if header.number() != parent.number() + 1 {
|
||||
return Err(From::from(BlockError::InvalidNumber(Mismatch { expected: parent.number() + 1, found: header.number() })));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -307,9 +307,9 @@ mod tests {
|
||||
self.blocks.get(hash).map(|bytes| {
|
||||
let header = BlockView::new(bytes).header();
|
||||
BlockDetails {
|
||||
number: header.number,
|
||||
total_difficulty: header.difficulty,
|
||||
parent: header.parent_hash,
|
||||
number: header.number(),
|
||||
total_difficulty: header.difficulty().clone(),
|
||||
parent: header.parent_hash().clone(),
|
||||
children: Vec::new(),
|
||||
}
|
||||
})
|
||||
@@ -352,9 +352,9 @@ mod tests {
|
||||
let engine = &*spec.engine;
|
||||
|
||||
let min_gas_limit = engine.params().min_gas_limit;
|
||||
good.gas_limit = min_gas_limit;
|
||||
good.timestamp = 40;
|
||||
good.number = 10;
|
||||
good.set_gas_limit(min_gas_limit);
|
||||
good.set_timestamp(40);
|
||||
good.set_number(10);
|
||||
|
||||
let keypair = Random.generate().unwrap();
|
||||
|
||||
@@ -381,31 +381,31 @@ mod tests {
|
||||
let diff_inc = U256::from(0x40);
|
||||
|
||||
let mut parent6 = good.clone();
|
||||
parent6.number = 6;
|
||||
parent6.set_number(6);
|
||||
let mut parent7 = good.clone();
|
||||
parent7.number = 7;
|
||||
parent7.parent_hash = parent6.hash();
|
||||
parent7.difficulty = parent6.difficulty + diff_inc;
|
||||
parent7.timestamp = parent6.timestamp + 10;
|
||||
parent7.set_number(7);
|
||||
parent7.set_parent_hash(parent6.hash());
|
||||
parent7.set_difficulty(parent6.difficulty().clone() + diff_inc);
|
||||
parent7.set_timestamp(parent6.timestamp() + 10);
|
||||
let mut parent8 = good.clone();
|
||||
parent8.number = 8;
|
||||
parent8.parent_hash = parent7.hash();
|
||||
parent8.difficulty = parent7.difficulty + diff_inc;
|
||||
parent8.timestamp = parent7.timestamp + 10;
|
||||
parent8.set_number(8);
|
||||
parent8.set_parent_hash(parent7.hash());
|
||||
parent8.set_difficulty(parent7.difficulty().clone() + diff_inc);
|
||||
parent8.set_timestamp(parent7.timestamp() + 10);
|
||||
|
||||
let mut good_uncle1 = good.clone();
|
||||
good_uncle1.number = 9;
|
||||
good_uncle1.parent_hash = parent8.hash();
|
||||
good_uncle1.difficulty = parent8.difficulty + diff_inc;
|
||||
good_uncle1.timestamp = parent8.timestamp + 10;
|
||||
good_uncle1.extra_data.push(1u8);
|
||||
good_uncle1.set_number(9);
|
||||
good_uncle1.set_parent_hash(parent8.hash());
|
||||
good_uncle1.set_difficulty(parent8.difficulty().clone() + diff_inc);
|
||||
good_uncle1.set_timestamp(parent8.timestamp() + 10);
|
||||
good_uncle1.extra_data_mut().push(1u8);
|
||||
|
||||
let mut good_uncle2 = good.clone();
|
||||
good_uncle2.number = 8;
|
||||
good_uncle2.parent_hash = parent7.hash();
|
||||
good_uncle2.difficulty = parent7.difficulty + diff_inc;
|
||||
good_uncle2.timestamp = parent7.timestamp + 10;
|
||||
good_uncle2.extra_data.push(2u8);
|
||||
good_uncle2.set_number(8);
|
||||
good_uncle2.set_parent_hash(parent7.hash());
|
||||
good_uncle2.set_difficulty(parent7.difficulty().clone() + diff_inc);
|
||||
good_uncle2.set_timestamp(parent7.timestamp() + 10);
|
||||
good_uncle2.extra_data_mut().push(2u8);
|
||||
|
||||
let good_uncles = vec![ good_uncle1.clone(), good_uncle2.clone() ];
|
||||
let mut uncles_rlp = RlpStream::new();
|
||||
@@ -414,14 +414,14 @@ mod tests {
|
||||
let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| encode::<SignedTransaction>(t).to_vec()).collect());
|
||||
|
||||
let mut parent = good.clone();
|
||||
parent.number = 9;
|
||||
parent.timestamp = parent8.timestamp + 10;
|
||||
parent.parent_hash = parent8.hash();
|
||||
parent.difficulty = parent8.difficulty + diff_inc;
|
||||
parent.set_number(9);
|
||||
parent.set_timestamp(parent8.timestamp() + 10);
|
||||
parent.set_parent_hash(parent8.hash());
|
||||
parent.set_difficulty(parent8.difficulty().clone() + diff_inc);
|
||||
|
||||
good.parent_hash = parent.hash();
|
||||
good.difficulty = parent.difficulty + diff_inc;
|
||||
good.timestamp = parent.timestamp + 10;
|
||||
good.set_parent_hash(parent.hash());
|
||||
good.set_difficulty(parent.difficulty().clone() + diff_inc);
|
||||
good.set_timestamp(parent.timestamp() + 10);
|
||||
|
||||
let mut bc = TestBlockChain::new();
|
||||
bc.insert(create_test_block(&good));
|
||||
@@ -433,61 +433,62 @@ mod tests {
|
||||
check_ok(basic_test(&create_test_block(&good), engine));
|
||||
|
||||
let mut header = good.clone();
|
||||
header.transactions_root = good_transactions_root.clone();
|
||||
header.uncles_hash = good_uncles_hash.clone();
|
||||
header.set_transactions_root(good_transactions_root.clone());
|
||||
header.set_uncles_hash(good_uncles_hash.clone());
|
||||
check_ok(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
|
||||
|
||||
header.gas_limit = min_gas_limit - From::from(1);
|
||||
header.set_gas_limit(min_gas_limit - From::from(1));
|
||||
check_fail(basic_test(&create_test_block(&header), engine),
|
||||
InvalidGasLimit(OutOfBounds { min: Some(min_gas_limit), max: None, found: header.gas_limit }));
|
||||
InvalidGasLimit(OutOfBounds { min: Some(min_gas_limit), max: None, found: header.gas_limit().clone() }));
|
||||
|
||||
header = good.clone();
|
||||
header.number = BlockNumber::max_value();
|
||||
header.set_number(BlockNumber::max_value());
|
||||
check_fail(basic_test(&create_test_block(&header), engine),
|
||||
RidiculousNumber(OutOfBounds { max: Some(BlockNumber::max_value()), min: None, found: header.number }));
|
||||
RidiculousNumber(OutOfBounds { max: Some(BlockNumber::max_value()), min: None, found: header.number() }));
|
||||
|
||||
header = good.clone();
|
||||
header.gas_used = header.gas_limit + From::from(1);
|
||||
let gas_used = header.gas_limit().clone() + 1.into();
|
||||
header.set_gas_used(gas_used);
|
||||
check_fail(basic_test(&create_test_block(&header), engine),
|
||||
TooMuchGasUsed(OutOfBounds { max: Some(header.gas_limit), min: None, found: header.gas_used }));
|
||||
TooMuchGasUsed(OutOfBounds { max: Some(header.gas_limit().clone()), min: None, found: header.gas_used().clone() }));
|
||||
|
||||
header = good.clone();
|
||||
header.extra_data.resize(engine.maximum_extra_data_size() + 1, 0u8);
|
||||
header.extra_data_mut().resize(engine.maximum_extra_data_size() + 1, 0u8);
|
||||
check_fail(basic_test(&create_test_block(&header), engine),
|
||||
ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data.len() }));
|
||||
ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data().len() }));
|
||||
|
||||
header = good.clone();
|
||||
header.extra_data.resize(engine.maximum_extra_data_size() + 1, 0u8);
|
||||
header.extra_data_mut().resize(engine.maximum_extra_data_size() + 1, 0u8);
|
||||
check_fail(basic_test(&create_test_block(&header), engine),
|
||||
ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data.len() }));
|
||||
ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data().len() }));
|
||||
|
||||
header = good.clone();
|
||||
header.uncles_hash = good_uncles_hash.clone();
|
||||
header.set_uncles_hash(good_uncles_hash.clone());
|
||||
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine),
|
||||
InvalidTransactionsRoot(Mismatch { expected: good_transactions_root.clone(), found: header.transactions_root }));
|
||||
InvalidTransactionsRoot(Mismatch { expected: good_transactions_root.clone(), found: header.transactions_root().clone() }));
|
||||
|
||||
header = good.clone();
|
||||
header.transactions_root = good_transactions_root.clone();
|
||||
header.set_transactions_root(good_transactions_root.clone());
|
||||
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine),
|
||||
InvalidUnclesHash(Mismatch { expected: good_uncles_hash.clone(), found: header.uncles_hash }));
|
||||
InvalidUnclesHash(Mismatch { expected: good_uncles_hash.clone(), found: header.uncles_hash().clone() }));
|
||||
|
||||
check_ok(family_test(&create_test_block(&good), engine, &bc));
|
||||
check_ok(family_test(&create_test_block_with_data(&good, &good_transactions, &good_uncles), engine, &bc));
|
||||
|
||||
header = good.clone();
|
||||
header.parent_hash = H256::random();
|
||||
header.set_parent_hash(H256::random());
|
||||
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
|
||||
UnknownParent(header.parent_hash));
|
||||
UnknownParent(header.parent_hash().clone()));
|
||||
|
||||
header = good.clone();
|
||||
header.timestamp = 10;
|
||||
header.set_timestamp(10);
|
||||
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
|
||||
InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp + 1), found: header.timestamp }));
|
||||
InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp() + 1), found: header.timestamp() }));
|
||||
|
||||
header = good.clone();
|
||||
header.number = 9;
|
||||
header.set_number(9);
|
||||
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
|
||||
InvalidNumber(Mismatch { expected: parent.number + 1, found: header.number }));
|
||||
InvalidNumber(Mismatch { expected: parent.number() + 1, found: header.number() }));
|
||||
|
||||
header = good.clone();
|
||||
let mut bad_uncles = good_uncles.clone();
|
||||
|
||||
Reference in New Issue
Block a user