Fix queue flush and add working tests.

This commit is contained in:
Gav Wood 2016-01-25 23:24:51 +01:00
parent a43ca9ae34
commit 41508cbd50
7 changed files with 40 additions and 18 deletions

View File

@ -188,6 +188,7 @@ impl<'x, 'y> OpenBlock<'x, 'y> {
// info!("env_info says gas_used={}", env_info.gas_used); // info!("env_info says gas_used={}", env_info.gas_used);
match self.block.state.apply(&env_info, self.engine, &t) { match self.block.state.apply(&env_info, self.engine, &t) {
Ok(receipt) => { Ok(receipt) => {
flushln!("Transaction executed {:?}", receipt);
self.block.archive_set.insert(h.unwrap_or_else(||t.hash())); self.block.archive_set.insert(h.unwrap_or_else(||t.hash()));
self.block.archive.push(Entry { transaction: t, receipt: receipt }); self.block.archive.push(Entry { transaction: t, receipt: receipt });
Ok(&self.block.archive.last().unwrap().receipt) Ok(&self.block.archive.last().unwrap().receipt)

View File

@ -19,11 +19,16 @@ pub struct BlockQueueInfo {
pub unverified_queue_size: usize, pub unverified_queue_size: usize,
/// Number of verified queued blocks pending import /// Number of verified queued blocks pending import
pub verified_queue_size: usize, pub verified_queue_size: usize,
/// Number of blocks being verified
pub verifying_queue_size: usize,
} }
impl BlockQueueInfo { impl BlockQueueInfo {
/// The total size of the queues. /// The total size of the queues.
pub fn total_queue_size(&self) -> usize { self.unverified_queue_size + self.verified_queue_size } pub fn total_queue_size(&self) -> usize { self.unverified_queue_size + self.verified_queue_size + self.verifying_queue_size }
/// The size of the unverified and verifying queues.
pub fn incomplete_queue_size(&self) -> usize { self.unverified_queue_size + self.verifying_queue_size }
} }
/// A queue of blocks. Sits between network or other I/O and the BlockChain. /// A queue of blocks. Sits between network or other I/O and the BlockChain.
@ -91,7 +96,7 @@ impl BlockQueue {
let ready_signal = ready_signal.clone(); let ready_signal = ready_signal.clone();
let empty = empty.clone(); let empty = empty.clone();
let deleting = deleting.clone(); let deleting = deleting.clone();
verifiers.push(thread::Builder::new().name(format!("Verifier #{}", i)).spawn(move || BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty)) verifiers.push(thread::Builder::new().name(format!("Verifier #{}", i)).spawn(move || BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty))
.expect("Error starting block verification thread")); .expect("Error starting block verification thread"));
} }
BlockQueue { BlockQueue {
@ -115,7 +120,6 @@ impl BlockQueue {
empty.notify_all(); empty.notify_all();
} }
while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Relaxed) { while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Relaxed) {
lock = wait.wait(lock).unwrap(); lock = wait.wait(lock).unwrap();
} }
@ -154,7 +158,6 @@ impl BlockQueue {
}, },
Err(err) => { Err(err) => {
let mut v = verification.lock().unwrap(); let mut v = verification.lock().unwrap();
flushln!("Stage 2 block verification failed for {}\nError: {:?}", block_hash, err);
warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err); warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err);
v.bad.insert(block_hash.clone()); v.bad.insert(block_hash.clone());
v.verifying.retain(|e| e.hash != block_hash); v.verifying.retain(|e| e.hash != block_hash);
@ -187,9 +190,10 @@ impl BlockQueue {
/// Wait for queue to be empty /// Wait for queue to be empty
pub fn flush(&mut self) { pub fn flush(&mut self) {
let mutex: Mutex<()> = Mutex::new(()); let mut verification = self.verification.lock().unwrap();
let lock = mutex.lock().unwrap(); while !verification.unverified.is_empty() && !verification.verifying.is_empty() {
let _ = self.empty.wait(lock).unwrap(); verification = self.empty.wait(verification).unwrap();
}
} }
/// Add a block to the queue. /// Add a block to the queue.
@ -265,6 +269,7 @@ impl BlockQueue {
full: false, full: false,
verified_queue_size: verification.verified.len(), verified_queue_size: verification.verified.len(),
unverified_queue_size: verification.unverified.len(), unverified_queue_size: verification.unverified.len(),
verifying_queue_size: verification.verifying.len(),
} }
} }
} }

View File

@ -181,7 +181,6 @@ impl Client {
/// Flush the block import queue. /// Flush the block import queue.
pub fn flush_queue(&self) { pub fn flush_queue(&self) {
flushln!("Flushing queue {:?}", self.block_queue.read().unwrap().queue_info());
self.block_queue.write().unwrap().flush(); self.block_queue.write().unwrap().flush();
} }
@ -189,9 +188,8 @@ impl Client {
pub fn import_verified_blocks(&self, _io: &IoChannel<NetSyncMessage>) { pub fn import_verified_blocks(&self, _io: &IoChannel<NetSyncMessage>) {
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);
for block in self.block_queue.write().unwrap().drain(128) { for block in blocks {
flushln!("Importing block...");
if bad.contains(&block.header.parent_hash) { if bad.contains(&block.header.parent_hash) {
self.block_queue.write().unwrap().mark_as_bad(&block.header.hash()); self.block_queue.write().unwrap().mark_as_bad(&block.header.hash());
bad.insert(block.header.hash()); bad.insert(block.header.hash());
@ -238,6 +236,7 @@ impl Client {
} }
}; };
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);
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; return;

View File

@ -80,7 +80,7 @@ pub struct Spec {
/// TODO [arkpar] Please document me /// TODO [arkpar] Please document me
pub extra_data: Bytes, pub extra_data: Bytes,
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
pub genesis_state: PodState, genesis_state: PodState,
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
pub seal_fields: usize, pub seal_fields: usize,
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
@ -182,6 +182,17 @@ impl Spec {
self.seal_rlp = seal_rlp; self.seal_rlp = seal_rlp;
self.state_root_memo = RwLock::new(genesis.find("stateRoot").and_then(|_| Some(H256::from_json(&genesis["stateRoot"])))); self.state_root_memo = RwLock::new(genesis.find("stateRoot").and_then(|_| Some(H256::from_json(&genesis["stateRoot"]))));
} }
/// Alter the value of the genesis state.
pub fn set_genesis_state(&mut self, s: PodState) {
self.genesis_state = s;
*self.state_root_memo.write().unwrap() = None;
}
/// Returns `false` if the memoized state root is invalid. `true` otherwise.
pub fn is_state_root_valid(&self) -> bool {
self.state_root_memo.read().unwrap().clone().map_or(true, |sr| sr == self.genesis_state.root())
}
} }
impl FromJson for Spec { impl FromJson for Spec {

View File

@ -146,15 +146,15 @@ impl State {
/// This will change the state accordingly. /// This will change the state accordingly.
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult { pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult {
let old = self.to_pod(); // let old = self.to_pod();
let e = try!(Executive::new(self, env_info, engine).transact(t)); let e = try!(Executive::new(self, env_info, engine).transact(t));
//println!("Executed: {:?}", e); //println!("Executed: {:?}", e);
trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod())); // trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod()));
self.commit(); self.commit();
let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs); let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs);
trace!("Transaction receipt: {:?}", receipt); // trace!("Transaction receipt: {:?}", receipt);
Ok(receipt) Ok(receipt)
} }

View File

@ -158,6 +158,7 @@ impl BlockChainClient for TestBlockChainClient {
full: false, full: false,
verified_queue_size: 0, verified_queue_size: 0,
unverified_queue_size: 0, unverified_queue_size: 0,
verifying_queue_size: 0,
} }
} }

View File

@ -22,8 +22,9 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
let blocks: Vec<Bytes> = test["blocks"].as_array().unwrap().iter().map(|e| xjson!(&e["rlp"])).collect(); let blocks: Vec<Bytes> = test["blocks"].as_array().unwrap().iter().map(|e| xjson!(&e["rlp"])).collect();
let mut spec = ethereum::new_frontier_like_test(); let mut spec = ethereum::new_frontier_like_test();
spec.set_genesis_state(PodState::from_json(test.find("pre").unwrap()));
spec.overwrite_genesis(test.find("genesisBlockHeader").unwrap()); spec.overwrite_genesis(test.find("genesisBlockHeader").unwrap());
spec.genesis_state = PodState::from_json(test.find("pre").unwrap()); assert!(spec.is_state_root_valid());
let mut dir = env::temp_dir(); let mut dir = env::temp_dir();
dir.push(H32::random().hex()); dir.push(H32::random().hex());
@ -32,9 +33,12 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
blocks.into_iter().foreach(|b| { blocks.into_iter().foreach(|b| {
client.import_block(b).unwrap(); client.import_block(b).unwrap();
}); });
flushln!("Imported all");
client.flush_queue(); client.flush_queue();
flushln!("Flushed");
client.import_verified_blocks(&IoChannel::disconnected()); client.import_verified_blocks(&IoChannel::disconnected());
flushln!("Best hash: {}", client.chain_info().best_block_hash); flushln!("Checking...");
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();
} }
@ -46,4 +50,5 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
failed failed
} }
declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} //declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"}
declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"}