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);
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)

View File

@ -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(),
}
}
}

View File

@ -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<NetSyncMessage>) {
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;

View File

@ -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 {

View File

@ -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)
}

View File

@ -158,6 +158,7 @@ impl BlockChainClient for TestBlockChainClient {
full: false,
verified_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 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<String> {
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<String> {
failed
}
declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"}
//declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"}
declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"}