ensure genesis validator set in DB

This commit is contained in:
Robert Habermeier
2017-04-19 15:35:12 +02:00
parent a278dd5a0a
commit af868a7439
3 changed files with 65 additions and 51 deletions

View File

@@ -49,7 +49,7 @@ use evm::{Factory as EvmFactory, Schedule};
use executive::{Executive, Executed, TransactOptions, contract_address};
use factory::Factories;
use futures::{future, Future};
use header::BlockNumber;
use header::{BlockNumber, Header};
use io::*;
use log_entry::LocalizedLogEntry;
use miner::{Miner, MinerService, TransactionImportResult};
@@ -247,17 +247,29 @@ impl Client {
exit_handler: Mutex::new(None),
});
// prune old states.
{
let state_db = client.state_db.lock().boxed_clone();
let chain = client.chain.read();
client.prune_ancient(state_db, &chain)?;
}
// ensure genesis epoch proof in the DB.
{
let mut batch = DBTransaction::new();
let chain = client.chain.read();
client.generate_epoch_proof(&mut batch, &spec.genesis_header(), 0, &*chain);
client.db.read().write_buffered(batch);
}
if let Some(reg_addr) = client.additional_params().get("registrar").and_then(|s| Address::from_str(s).ok()) {
trace!(target: "client", "Found registrar at {}", reg_addr);
let registrar = Registry::new(reg_addr);
*client.registrar.lock() = Some(registrar);
}
// ensure buffered changes are flushed.
client.db.read().flush().map_err(ClientError::Database)?;
Ok(client)
}
@@ -581,7 +593,7 @@ impl Client {
let entering_new_epoch = {
use engines::EpochChange;
match self.engine.is_epoch_end(block.header(), Some(block_data), Some(&receipts)) {
EpochChange::Yes(e, p) => Some((block.header().clone(), e, p)),
EpochChange::Yes(e, _) => Some((block.header().clone(), e)),
EpochChange::No => None,
EpochChange::Unsure(_) => {
warn!(target: "client", "Detected invalid engine implementation.");
@@ -599,48 +611,8 @@ impl Client {
state.journal_under(&mut batch, number, hash).expect("DB commit failed");
let route = chain.insert_block(&mut batch, block_data, receipts);
if let Some((header, epoch, expected)) = entering_new_epoch {
use std::cell::RefCell;
use std::collections::BTreeSet;
debug!(target: "client", "Generating validation proof for block {}", hash);
// proof is two-part. state items read in lexicographical order,
// and the secondary "proof" part.
let read_values = RefCell::new(BTreeSet::new());
let block_id = BlockId::Hash(hash.clone());
let proof = {
let call = |a, d| {
let tx = self.contract_call_tx(block_id, a, d);
let (result, items) = self.prove_transaction(tx, block_id)
.ok_or_else(|| format!("Unable to make call to generate epoch proof."))?;
read_values.borrow_mut().extend(items);
Ok(result)
};
self.engine.epoch_proof(&header, &call)
};
match proof {
Ok(proof) => {
if proof != expected {
warn!(target: "client", "Extracted epoch change proof different than expected.");
warn!(target: "client", "Using a custom engine implementation?");
}
// insert into database, using the generated proof.
chain.insert_epoch_transition(&mut batch, epoch, EpochTransition {
block_hash: hash.clone(),
proof: proof,
state_proof: read_values.into_inner().into_iter().collect(),
});
}
Err(e) => {
warn!(target: "client", "Error generating epoch change proof for block {}: {}", hash, e);
warn!(target: "client", "Snapshots generated by this node will be incomplete.");
}
}
if let Some((header, epoch)) = entering_new_epoch {
self.generate_epoch_proof(&mut batch, &header, epoch, &chain);
}
self.tracedb.read().import(&mut batch, TraceImportRequest {
@@ -665,6 +637,46 @@ impl Client {
route
}
// generate an epoch transition proof at the given block, and write it into the given blockchain.
fn generate_epoch_proof(&self, batch: &mut DBTransaction, header: &Header, epoch_number: u64, chain: &BlockChain) {
use std::cell::RefCell;
use std::collections::BTreeSet;
let hash = header.hash();
debug!(target: "client", "Generating validation proof for block {}", hash);
// proof is two-part. state items read in lexicographical order,
// and the secondary "proof" part.
let read_values = RefCell::new(BTreeSet::new());
let block_id = BlockId::Hash(hash.clone());
let proof = {
let call = |a, d| {
let tx = self.contract_call_tx(block_id, a, d);
let (result, items) = self.prove_transaction(tx, block_id)
.ok_or_else(|| format!("Unable to make call to generate epoch proof."))?;
read_values.borrow_mut().extend(items);
Ok(result)
};
self.engine.epoch_proof(&header, &call)
};
// insert into database, using the generated proof.
match proof {
Ok(proof) =>
chain.insert_epoch_transition(batch, epoch_number, EpochTransition {
block_hash: hash.clone(),
proof: proof,
state_proof: read_values.into_inner().into_iter().collect(),
}),
Err(e) => {
warn!(target: "client", "Error generating epoch change proof for block {}: {}", hash, e);
warn!(target: "client", "Snapshots generated by this node will be incomplete.");
}
}
}
// prune ancient states until below the memory limit or only the minimum amount remain.
fn prune_ancient(&self, mut state_db: StateDB, chain: &BlockChain) -> Result<(), ClientError> {
let number = match state_db.journal_db().latest_era() {