From 41508cbd507c4514be48cae43c1eb8d8cef4ab21 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 25 Jan 2016 23:24:51 +0100 Subject: [PATCH] Fix queue flush and add working tests. --- src/block.rs | 1 + src/block_queue.rs | 19 ++++++++++++------- src/client.rs | 7 +++---- src/spec.rs | 13 ++++++++++++- src/state.rs | 6 +++--- src/sync/tests.rs | 1 + src/tests/chain.rs | 11 ++++++++--- 7 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/block.rs b/src/block.rs index 1ff326430..c63f49bd7 100644 --- a/src/block.rs +++ b/src/block.rs @@ -188,6 +188,7 @@ impl<'x, 'y> OpenBlock<'x, 'y> { // info!("env_info says gas_used={}", env_info.gas_used); match self.block.state.apply(&env_info, self.engine, &t) { Ok(receipt) => { + flushln!("Transaction executed {:?}", receipt); self.block.archive_set.insert(h.unwrap_or_else(||t.hash())); self.block.archive.push(Entry { transaction: t, receipt: receipt }); Ok(&self.block.archive.last().unwrap().receipt) diff --git a/src/block_queue.rs b/src/block_queue.rs index a0e46193b..fa091d0c4 100644 --- a/src/block_queue.rs +++ b/src/block_queue.rs @@ -19,11 +19,16 @@ pub struct BlockQueueInfo { pub unverified_queue_size: usize, /// Number of verified queued blocks pending import pub verified_queue_size: usize, + /// Number of blocks being verified + pub verifying_queue_size: usize, } impl BlockQueueInfo { /// 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. @@ -91,7 +96,7 @@ impl BlockQueue { let ready_signal = ready_signal.clone(); let empty = empty.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")); } BlockQueue { @@ -115,7 +120,6 @@ impl BlockQueue { empty.notify_all(); } - while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Relaxed) { lock = wait.wait(lock).unwrap(); } @@ -154,7 +158,6 @@ impl BlockQueue { }, Err(err) => { 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); v.bad.insert(block_hash.clone()); v.verifying.retain(|e| e.hash != block_hash); @@ -187,9 +190,10 @@ impl BlockQueue { /// Wait for queue to be empty pub fn flush(&mut self) { - let mutex: Mutex<()> = Mutex::new(()); - let lock = mutex.lock().unwrap(); - let _ = self.empty.wait(lock).unwrap(); + let mut verification = self.verification.lock().unwrap(); + while !verification.unverified.is_empty() && !verification.verifying.is_empty() { + verification = self.empty.wait(verification).unwrap(); + } } /// Add a block to the queue. @@ -265,6 +269,7 @@ impl BlockQueue { full: false, verified_queue_size: verification.verified.len(), unverified_queue_size: verification.unverified.len(), + verifying_queue_size: verification.verifying.len(), } } } diff --git a/src/client.rs b/src/client.rs index f05819370..2cc6c150d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -181,7 +181,6 @@ impl Client { /// Flush the block import queue. pub fn flush_queue(&self) { - flushln!("Flushing queue {:?}", self.block_queue.read().unwrap().queue_info()); self.block_queue.write().unwrap().flush(); } @@ -189,9 +188,8 @@ impl Client { pub fn import_verified_blocks(&self, _io: &IoChannel) { let mut bad = HashSet::new(); let _import_lock = self.import_lock.lock(); - - for block in self.block_queue.write().unwrap().drain(128) { - flushln!("Importing block..."); + let blocks = self.block_queue.write().unwrap().drain(128); + for block in blocks { if bad.contains(&block.header.parent_hash) { self.block_queue.write().unwrap().mark_as_bad(&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()) { + 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); self.block_queue.write().unwrap().mark_as_bad(&header.hash()); return; diff --git a/src/spec.rs b/src/spec.rs index 9e97595b9..326552524 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -80,7 +80,7 @@ pub struct Spec { /// TODO [arkpar] Please document me pub extra_data: Bytes, /// TODO [Gav Wood] Please document me - pub genesis_state: PodState, + genesis_state: PodState, /// TODO [Gav Wood] Please document me pub seal_fields: usize, /// TODO [Gav Wood] Please document me @@ -182,6 +182,17 @@ impl Spec { self.seal_rlp = seal_rlp; 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 { diff --git a/src/state.rs b/src/state.rs index 6e5d586f3..71ae0ecda 100644 --- a/src/state.rs +++ b/src/state.rs @@ -146,15 +146,15 @@ impl State { /// This will change the state accordingly. 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)); //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(); let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs); - trace!("Transaction receipt: {:?}", receipt); +// trace!("Transaction receipt: {:?}", receipt); Ok(receipt) } diff --git a/src/sync/tests.rs b/src/sync/tests.rs index 7f8a1748b..50d6efab2 100644 --- a/src/sync/tests.rs +++ b/src/sync/tests.rs @@ -158,6 +158,7 @@ impl BlockChainClient for TestBlockChainClient { full: false, verified_queue_size: 0, unverified_queue_size: 0, + verifying_queue_size: 0, } } diff --git a/src/tests/chain.rs b/src/tests/chain.rs index db3e398b0..922def6c7 100644 --- a/src/tests/chain.rs +++ b/src/tests/chain.rs @@ -22,8 +22,9 @@ fn do_json_test(json_data: &[u8]) -> Vec { let blocks: Vec = test["blocks"].as_array().unwrap().iter().map(|e| xjson!(&e["rlp"])).collect(); 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.genesis_state = PodState::from_json(test.find("pre").unwrap()); + assert!(spec.is_state_root_valid()); let mut dir = env::temp_dir(); dir.push(H32::random().hex()); @@ -32,9 +33,12 @@ fn do_json_test(json_data: &[u8]) -> Vec { blocks.into_iter().foreach(|b| { client.import_block(b).unwrap(); }); + flushln!("Imported all"); client.flush_queue(); + flushln!("Flushed"); 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(); } @@ -46,4 +50,5 @@ fn do_json_test(json_data: &[u8]) -> Vec { failed } -declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} +//declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"} +declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"}