fix merging bugs

This commit is contained in:
NikVolf 2016-06-30 20:44:24 +03:00
parent 97eb311cb0
commit bad02d65a1

View File

@ -278,7 +278,7 @@ impl Client {
Ok(locked_block) Ok(locked_block)
} }
fn calculate_enacted_retracted(&self, import_results: Vec<ImportRoute>) -> (Vec<H256>, Vec<H256>) { fn calculate_enacted_retracted(&self, import_results: &[ImportRoute]) -> (Vec<H256>, Vec<H256>) {
fn map_to_vec(map: Vec<(H256, bool)>) -> Vec<H256> { fn map_to_vec(map: Vec<(H256, bool)>) -> Vec<H256> {
map.into_iter().map(|(k, _v)| k).collect() map.into_iter().map(|(k, _v)| k).collect()
} }
@ -288,12 +288,12 @@ impl Client {
// could be retracted in import `k+1`. This is why to understand if after all inserts // could be retracted in import `k+1`. This is why to understand if after all inserts
// the block is enacted or retracted we iterate over all routes and at the end final state // the block is enacted or retracted we iterate over all routes and at the end final state
// will be in the hashmap // will be in the hashmap
let map = import_results.into_iter().fold(HashMap::new(), |mut map, route| { let map = import_results.iter().fold(HashMap::new(), |mut map, route| {
for hash in route.enacted { for hash in &route.enacted {
map.insert(hash, true); map.insert(hash.clone(), true);
} }
for hash in route.retracted { for hash in &route.retracted {
map.insert(hash, false); map.insert(hash.clone(), false);
} }
map map
}); });
@ -330,36 +330,10 @@ impl Client {
invalid_blocks.insert(header.hash()); invalid_blocks.insert(header.hash());
continue; continue;
} }
let closed_block = closed_block.unwrap();
imported_blocks.push(header.hash()); imported_blocks.push(header.hash());
// Are we committing an era? let route = self.commit_block(closed_block, &header.hash(), &block.bytes);
let ancient = if header.number() >= HISTORY {
let n = header.number() - HISTORY;
Some((n, self.chain.block_hash(n).unwrap()))
} else {
None
};
// Commit results
let closed_block = closed_block.unwrap();
let receipts = closed_block.block().receipts().clone();
let traces = From::from(closed_block.block().traces().clone().unwrap_or_else(Vec::new));
closed_block.drain()
.commit(header.number(), &header.hash(), ancient)
.expect("State DB commit failed.");
// And update the chain after commit to prevent race conditions
// (when something is in chain but you are not able to fetch details)
let route = self.chain.insert_block(&block.bytes, receipts);
self.tracedb.import(TraceImportRequest {
traces: traces,
block_hash: header.hash(),
block_number: header.number(),
enacted: route.enacted.clone(),
retracted: route.retracted.len()
});
import_results.push(route); import_results.push(route);
self.report.write().unwrap().accrue_block(&block); self.report.write().unwrap().accrue_block(&block);
@ -380,7 +354,7 @@ impl Client {
{ {
if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() { if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() {
let (enacted, retracted) = self.calculate_enacted_retracted(import_results); let (enacted, retracted) = self.calculate_enacted_retracted(&import_results);
if self.queue_info().is_empty() { if self.queue_info().is_empty() {
self.miner.chain_new_blocks(self, &imported_blocks, &invalid_blocks, &enacted, &retracted); self.miner.chain_new_blocks(self, &imported_blocks, &invalid_blocks, &enacted, &retracted);
@ -391,19 +365,50 @@ impl Client {
invalid: invalid_blocks, invalid: invalid_blocks,
enacted: enacted, enacted: enacted,
retracted: retracted, retracted: retracted,
sealed: Vec::new(),
})).unwrap_or_else(|e| warn!("Error sending IO notification: {:?}", e)); })).unwrap_or_else(|e| warn!("Error sending IO notification: {:?}", e));
} }
} }
{
if self.chain_info().best_block_hash != original_best { if self.chain_info().best_block_hash != original_best {
self.miner.update_sealing(self); self.miner.update_sealing(self);
} }
}
imported imported
} }
fn commit_block<B>(&self, block: B, hash: &H256, block_data: &Bytes) -> ImportRoute where B: IsBlock + Drain {
let number = block.header().number();
// Are we committing an era?
let ancient = if number >= HISTORY {
let n = number - HISTORY;
Some((n, self.chain.block_hash(n).unwrap()))
} else {
None
};
// Commit results
let receipts = block.receipts().clone();
let traces = From::from(block.traces().clone().unwrap_or_else(Vec::new));
// CHECK! I *think* this is fine, even if the state_root is equal to another
// already-imported block of the same number.
// TODO: Prove it with a test.
block.drain().commit(number, hash, ancient).expect("State DB commit failed.");
// And update the chain after commit to prevent race conditions
// (when something is in chain but you are not able to fetch details)
let route = self.chain.insert_block(block_data, receipts);
self.tracedb.import(TraceImportRequest {
traces: traces,
block_hash: hash.clone(),
block_number: number,
enacted: route.enacted.clone(),
retracted: route.retracted.len()
});
route
}
/// Import transactions from the IO queue /// Import transactions from the IO queue
pub fn import_queued_transactions(&self, transactions: &[Bytes]) -> usize { pub fn import_queued_transactions(&self, transactions: &[Bytes]) -> usize {
let _timer = PerfTimer::new("import_queued_transactions"); let _timer = PerfTimer::new("import_queued_transactions");
@ -867,6 +872,39 @@ impl MiningBlockChainClient for Client {
fn vm_factory(&self) -> &EvmFactory { fn vm_factory(&self) -> &EvmFactory {
&self.vm_factory &self.vm_factory
} }
fn import_sealed_block(&self, block: SealedBlock) -> ImportResult {
let _import_lock = self.import_lock.lock();
let _timer = PerfTimer::new("import_sealed_block");
let original_best = self.chain_info().best_block_hash;
let h = block.header().hash();
let number = block.header().number();
let block_data = block.rlp_bytes();
let route = self.commit_block(block, &h, &block_data);
trace!(target: "client", "Imported sealed block #{} ({})", number, h);
{
let (enacted, retracted) = self.calculate_enacted_retracted(&[route]);
self.miner.chain_new_blocks(self, &[h.clone()], &[], &enacted, &retracted);
self.io_channel.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks {
imported: vec![h.clone()],
invalid: vec![],
enacted: enacted,
retracted: retracted,
sealed: vec![h.clone()],
})).unwrap_or_else(|e| warn!("Error sending IO notification: {:?}", e));
}
if self.chain_info().best_block_hash != original_best {
self.miner.update_sealing(self);
}
Ok(h)
}
} }
impl MayPanic for Client { impl MayPanic for Client {