Merge pull request #236 from ethcore/blockchaintests

Fix import for bcMultiChainTest
This commit is contained in:
Gav Wood 2016-01-27 14:48:01 +01:00
commit 3a8591b107
7 changed files with 55 additions and 38 deletions

View File

@ -200,34 +200,36 @@ impl BlockQueue {
/// Add a block to the queue. /// Add a block to the queue.
pub fn import_block(&mut self, bytes: Bytes) -> ImportResult { pub fn import_block(&mut self, bytes: Bytes) -> ImportResult {
let header = BlockView::new(&bytes).header(); let header = BlockView::new(&bytes).header();
if self.processing.contains(&header.hash()) { let h = header.hash();
if self.processing.contains(&h) {
return Err(ImportError::AlreadyQueued); return Err(ImportError::AlreadyQueued);
} }
{ {
let mut verification = self.verification.lock().unwrap(); let mut verification = self.verification.lock().unwrap();
if verification.bad.contains(&header.hash()) { if verification.bad.contains(&h) {
return Err(ImportError::Bad(None)); return Err(ImportError::Bad(None));
} }
if verification.bad.contains(&header.parent_hash) { if verification.bad.contains(&header.parent_hash) {
verification.bad.insert(header.hash()); verification.bad.insert(h.clone());
return Err(ImportError::Bad(None)); return Err(ImportError::Bad(None));
} }
} }
match verify_block_basic(&header, &bytes, self.engine.deref().deref()) { match verify_block_basic(&header, &bytes, self.engine.deref().deref()) {
Ok(()) => { Ok(()) => {
self.processing.insert(header.hash()); self.processing.insert(h.clone());
self.verification.lock().unwrap().unverified.push_back(UnVerifiedBlock { header: header, bytes: bytes }); self.verification.lock().unwrap().unverified.push_back(UnVerifiedBlock { header: header, bytes: bytes });
self.more_to_verify.notify_all(); self.more_to_verify.notify_all();
Ok(h)
}, },
Err(err) => { Err(err) => {
flushln!("Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err); flushln!("Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err);
warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err); warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err);
self.verification.lock().unwrap().bad.insert(header.hash()); self.verification.lock().unwrap().bad.insert(h.clone());
Err(From::from(err))
} }
} }
Ok(())
} }
/// Mark given block and all its children as bad. Stops verification. /// Mark given block and all its children as bad. Stops verification.

View File

@ -193,7 +193,8 @@ impl Client {
} }
/// This is triggered by a message coming from a block queue when the block is ready for insertion /// This is triggered by a message coming from a block queue when the block is ready for insertion
pub fn import_verified_blocks(&self, _io: &IoChannel<NetSyncMessage>) { pub fn import_verified_blocks(&self, _io: &IoChannel<NetSyncMessage>) -> usize {
let mut ret = 0;
let mut bad = HashSet::new(); let mut bad = HashSet::new();
let _import_lock = self.import_lock.lock(); let _import_lock = self.import_lock.lock();
let blocks = self.block_queue.write().unwrap().drain(128); let blocks = self.block_queue.write().unwrap().drain(128);
@ -211,7 +212,7 @@ impl Client {
warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
self.block_queue.write().unwrap().mark_as_bad(&header.hash()); self.block_queue.write().unwrap().mark_as_bad(&header.hash());
bad.insert(block.header.hash()); bad.insert(block.header.hash());
return; break;
}; };
let parent = match self.chain.read().unwrap().block_header(&header.parent_hash) { let parent = match self.chain.read().unwrap().block_header(&header.parent_hash) {
Some(p) => p, Some(p) => p,
@ -220,7 +221,7 @@ impl Client {
warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash); warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash);
self.block_queue.write().unwrap().mark_as_bad(&header.hash()); self.block_queue.write().unwrap().mark_as_bad(&header.hash());
bad.insert(block.header.hash()); bad.insert(block.header.hash());
return; break;
}, },
}; };
// build last hashes // build last hashes
@ -244,14 +245,14 @@ impl Client {
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
bad.insert(block.header.hash()); bad.insert(block.header.hash());
self.block_queue.write().unwrap().mark_as_bad(&header.hash()); self.block_queue.write().unwrap().mark_as_bad(&header.hash());
return; break;
} }
}; };
if let Err(e) = verify_block_final(&header, result.block().header()) { if let Err(e) = verify_block_final(&header, result.block().header()) {
flushln!("Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); flushln!("Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
self.block_queue.write().unwrap().mark_as_bad(&header.hash()); self.block_queue.write().unwrap().mark_as_bad(&header.hash());
return; break;
} }
self.chain.write().unwrap().insert_block(&block.bytes); //TODO: err here? self.chain.write().unwrap().insert_block(&block.bytes); //TODO: err here?
@ -260,12 +261,14 @@ impl Client {
Ok(_) => (), Ok(_) => (),
Err(e) => { Err(e) => {
warn!(target: "client", "State DB commit failed: {:?}", e); warn!(target: "client", "State DB commit failed: {:?}", e);
return; break;
} }
} }
self.report.write().unwrap().accrue_block(&block); self.report.write().unwrap().accrue_block(&block);
trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); trace!(target: "client", "Imported #{} ({})", header.number(), header.hash());
ret += 1;
} }
ret
} }
/// Clear cached state overlay /// Clear cached state overlay

View File

@ -120,7 +120,9 @@ pub enum BlockError {
/// TODO [arkpar] Please document me /// TODO [arkpar] Please document me
InvalidParentHash(Mismatch<H256>), InvalidParentHash(Mismatch<H256>),
/// TODO [arkpar] Please document me /// TODO [arkpar] Please document me
InvalidNumber(OutOfBounds<BlockNumber>), InvalidNumber(Mismatch<BlockNumber>),
/// Block number isn't sensible.
RidiculousNumber(OutOfBounds<BlockNumber>),
/// TODO [arkpar] Please document me /// TODO [arkpar] Please document me
UnknownParent(H256), UnknownParent(H256),
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
@ -145,7 +147,7 @@ impl From<Error> for ImportError {
} }
/// Result of import block operation. /// Result of import block operation.
pub type ImportResult = Result<(), ImportError>; pub type ImportResult = Result<H256, ImportError>;
#[derive(Debug)] #[derive(Debug)]
/// General error type which should be capable of representing all errors in ethcore. /// General error type which should be capable of representing all errors in ethcore.

View File

@ -415,7 +415,7 @@ impl ChainSync {
Err(ImportError::AlreadyQueued) => { Err(ImportError::AlreadyQueued) => {
trace!(target: "sync", "New block already queued {:?}", h); trace!(target: "sync", "New block already queued {:?}", h);
}, },
Ok(()) => { Ok(_) => {
trace!(target: "sync", "New block queued {:?}", h); trace!(target: "sync", "New block queued {:?}", h);
}, },
Err(e) => { Err(e) => {
@ -680,7 +680,7 @@ impl ChainSync {
self.last_imported_block = headers.0 + i as BlockNumber; self.last_imported_block = headers.0 + i as BlockNumber;
self.last_imported_hash = h.clone(); self.last_imported_hash = h.clone();
}, },
Ok(()) => { Ok(_) => {
trace!(target: "sync", "Block queued {:?}", h); trace!(target: "sync", "Block queued {:?}", h);
self.last_imported_block = headers.0 + i as BlockNumber; self.last_imported_block = headers.0 + i as BlockNumber;
self.last_imported_hash = h.clone(); self.last_imported_hash = h.clone();

View File

@ -114,6 +114,7 @@ impl BlockChainClient for TestBlockChainClient {
fn import_block(&self, b: Bytes) -> ImportResult { fn import_block(&self, b: Bytes) -> ImportResult {
let header = Rlp::new(&b).val_at::<BlockHeader>(0); let header = Rlp::new(&b).val_at::<BlockHeader>(0);
let h = header.hash();
let number: usize = header.number as usize; let number: usize = header.number as usize;
if number > self.blocks.read().unwrap().len() { if number > self.blocks.read().unwrap().len() {
panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().unwrap().len(), number); panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().unwrap().len(), number);
@ -134,9 +135,9 @@ impl BlockChainClient for TestBlockChainClient {
let len = self.numbers.read().unwrap().len(); let len = self.numbers.read().unwrap().len();
if number == len { if number == len {
*self.difficulty.write().unwrap().deref_mut() += header.difficulty; *self.difficulty.write().unwrap().deref_mut() += header.difficulty;
mem::replace(self.last_hash.write().unwrap().deref_mut(), header.hash()); mem::replace(self.last_hash.write().unwrap().deref_mut(), h.clone());
self.blocks.write().unwrap().insert(header.hash(), b); self.blocks.write().unwrap().insert(h.clone(), b);
self.numbers.write().unwrap().insert(number, header.hash()); self.numbers.write().unwrap().insert(number, h.clone());
let mut parent_hash = header.parent_hash; let mut parent_hash = header.parent_hash;
if number > 0 { if number > 0 {
let mut n = number - 1; let mut n = number - 1;
@ -148,9 +149,9 @@ impl BlockChainClient for TestBlockChainClient {
} }
} }
else { else {
self.blocks.write().unwrap().insert(header.hash(), b.to_vec()); self.blocks.write().unwrap().insert(h.clone(), b.to_vec());
} }
Ok(()) Ok(h)
} }
fn queue_info(&self) -> BlockQueueInfo { fn queue_info(&self) -> BlockQueueInfo {

View File

@ -21,7 +21,7 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
flush(format!(" - {}...", name)); flush(format!(" - {}...", name));
let blocks: Vec<Bytes> = test["blocks"].as_array().unwrap().iter().map(|e| xjson!(&e["rlp"])).collect(); let blocks: Vec<(Bytes, bool)> = test["blocks"].as_array().unwrap().iter().map(|e| (xjson!(&e["rlp"]), e.find("blockHeader").is_some())).collect();
let mut spec = ethereum::new_frontier_like_test(); let mut spec = ethereum::new_frontier_like_test();
let s = PodState::from_json(test.find("pre").unwrap()); let s = PodState::from_json(test.find("pre").unwrap());
spec.set_genesis_state(s); spec.set_genesis_state(s);
@ -32,11 +32,20 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
dir.push(H32::random().hex()); dir.push(H32::random().hex());
{ {
let client = Client::new(spec, &dir, IoChannel::disconnected()).unwrap(); let client = Client::new(spec, &dir, IoChannel::disconnected()).unwrap();
for b in blocks.into_iter().filter(|ref b| Block::is_good(b)) { for (b, is_valid) in blocks.into_iter() {
client.import_block(b).unwrap(); let mut hash = H256::new();
if Block::is_good(&b) {
if let Ok(h) = client.import_block(b.clone()) {
hash = h;
}
} }
client.flush_queue(); client.flush_queue();
client.import_verified_blocks(&IoChannel::disconnected()); let imported_ok = client.import_verified_blocks(&IoChannel::disconnected()) > 0;
assert_eq!(imported_ok, is_valid);
if imported_ok {
flushln!("Imported {}; best block {}", hash, client.chain_info().best_block_hash);
}
}
fail_unless(client.chain_info().best_block_hash == H256::from_json(&test["lastblockhash"])); fail_unless(client.chain_info().best_block_hash == H256::from_json(&test["lastblockhash"]));
} }
fs::remove_dir_all(&dir).unwrap(); fs::remove_dir_all(&dir).unwrap();
@ -55,12 +64,12 @@ declare_test!{BlockchainTests_bcForkStressTest, "BlockchainTests/bcForkStressTes
declare_test!{BlockchainTests_bcForkUncle, "BlockchainTests/bcForkUncle"} // STILL FAILS declare_test!{BlockchainTests_bcForkUncle, "BlockchainTests/bcForkUncle"} // STILL FAILS
declare_test!{BlockchainTests_bcGasPricerTest, "BlockchainTests/bcGasPricerTest"} declare_test!{BlockchainTests_bcGasPricerTest, "BlockchainTests/bcGasPricerTest"}
declare_test!{BlockchainTests_bcInvalidHeaderTest, "BlockchainTests/bcInvalidHeaderTest"} declare_test!{BlockchainTests_bcInvalidHeaderTest, "BlockchainTests/bcInvalidHeaderTest"}
declare_test!{BlockchainTests_bcInvalidRLPTest, "BlockchainTests/bcInvalidRLPTest"} // FAILS declare_test!{BlockchainTests_bcInvalidRLPTest, "BlockchainTests/bcInvalidRLPTest"}
declare_test!{BlockchainTests_bcMultiChainTest, "BlockchainTests/bcMultiChainTest"} // FAILS declare_test!{BlockchainTests_bcMultiChainTest, "BlockchainTests/bcMultiChainTest"}
declare_test!{BlockchainTests_bcRPC_API_Test, "BlockchainTests/bcRPC_API_Test"} declare_test!{BlockchainTests_bcRPC_API_Test, "BlockchainTests/bcRPC_API_Test"}
declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"}
declare_test!{BlockchainTests_bcTotalDifficultyTest, "BlockchainTests/bcTotalDifficultyTest"} declare_test!{BlockchainTests_bcTotalDifficultyTest, "BlockchainTests/bcTotalDifficultyTest"} // FAILS AGAIN?
declare_test!{BlockchainTests_bcUncleHeaderValiditiy, "BlockchainTests/bcUncleHeaderValiditiy"} // FAILS declare_test!{BlockchainTests_bcUncleHeaderValiditiy, "BlockchainTests/bcUncleHeaderValiditiy"}
declare_test!{BlockchainTests_bcUncleTest, "BlockchainTests/bcUncleTest"} // FAILS declare_test!{BlockchainTests_bcUncleTest, "BlockchainTests/bcUncleTest"}
declare_test!{BlockchainTests_bcValidBlockTest, "BlockchainTests/bcValidBlockTest"} // FAILS declare_test!{BlockchainTests_bcValidBlockTest, "BlockchainTests/bcValidBlockTest"} // STILL FAILS
declare_test!{BlockchainTests_bcWalletTest, "BlockchainTests/bcWalletTest"} // FAILS declare_test!{BlockchainTests_bcWalletTest, "BlockchainTests/bcWalletTest"}

View File

@ -162,7 +162,7 @@ pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error>
/// Check basic header parameters. /// Check basic header parameters.
fn verify_header(header: &Header, engine: &Engine) -> Result<(), Error> { fn verify_header(header: &Header, engine: &Engine) -> Result<(), Error> {
if header.number >= From::from(BlockNumber::max_value()) { if header.number >= From::from(BlockNumber::max_value()) {
return Err(From::from(BlockError::InvalidNumber(OutOfBounds { max: Some(From::from(BlockNumber::max_value())), min: None, found: header.number }))) 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 { 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 }))); return Err(From::from(BlockError::TooMuchGasUsed(OutOfBounds { max: Some(header.gas_limit), min: None, found: header.gas_used })));
@ -186,8 +186,8 @@ fn verify_parent(header: &Header, parent: &Header) -> Result<(), Error> {
if header.timestamp <= parent.timestamp { if header.timestamp <= parent.timestamp {
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp + 1), found: header.timestamp }))) return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp + 1), found: header.timestamp })))
} }
if header.number <= parent.number { if header.number != parent.number + 1 {
return Err(From::from(BlockError::InvalidNumber(OutOfBounds { max: None, min: Some(parent.number + 1), found: header.number }))); return Err(From::from(BlockError::InvalidNumber(Mismatch { expected: parent.number + 1, found: header.number })));
} }
Ok(()) Ok(())
} }
@ -400,7 +400,7 @@ mod tests {
header = good.clone(); header = good.clone();
header.number = BlockNumber::max_value(); header.number = BlockNumber::max_value();
check_fail(basic_test(&create_test_block(&header), engine.deref()), check_fail(basic_test(&create_test_block(&header), engine.deref()),
InvalidNumber(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 = good.clone();
header.gas_used = header.gas_limit + From::from(1); header.gas_used = header.gas_limit + From::from(1);
@ -443,7 +443,7 @@ mod tests {
header = good.clone(); header = good.clone();
header.number = 9; header.number = 9;
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc), check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc),
InvalidNumber(OutOfBounds { max: None, min: Some(parent.number + 1), found: header.number })); InvalidNumber(Mismatch { expected: parent.number + 1, found: header.number }));
header = good.clone(); header = good.clone();
let mut bad_uncles = good_uncles.clone(); let mut bad_uncles = good_uncles.clone();