store epoch transition proofs in DB

This commit is contained in:
Robert Habermeier 2017-04-19 14:58:19 +02:00
parent 6da6c755a5
commit a278dd5a0a
26 changed files with 234 additions and 69 deletions

10
Cargo.lock generated
View File

@ -339,8 +339,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "elastic-array"
version = "0.6.0"
source = "git+https://github.com/paritytech/elastic-array#346f1ba5982576dab9d0b8fa178b50e1db0a21cd"
version = "0.7.0"
source = "git+https://github.com/paritytech/elastic-array?branch=0.7.0#970a11eca8a6b3591b476155c5896b4757b5c7b8"
dependencies = [
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -713,7 +713,7 @@ version = "1.7.0"
dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
"elastic-array 0.6.0 (git+https://github.com/paritytech/elastic-array)",
"elastic-array 0.7.0 (git+https://github.com/paritytech/elastic-array?branch=0.7.0)",
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"eth-secp256k1 0.5.6 (git+https://github.com/paritytech/rust-secp256k1)",
"ethcore-bigint 0.1.2",
@ -2018,7 +2018,7 @@ name = "rlp"
version = "0.1.0"
dependencies = [
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"elastic-array 0.6.0 (git+https://github.com/paritytech/elastic-array)",
"elastic-array 0.7.0 (git+https://github.com/paritytech/elastic-array?branch=0.7.0)",
"ethcore-bigint 0.1.2",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2790,7 +2790,7 @@ dependencies = [
"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8"
"checksum dtoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5edd69c67b2f8e0911629b7e6b8a34cb3956613cd7c6e6414966dee349c2db4f"
"checksum either 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2b503c86dad62aaf414ecf2b8c527439abedb3f8d812537f0b12bfd6f32a91"
"checksum elastic-array 0.6.0 (git+https://github.com/paritytech/elastic-array)" = "<none>"
"checksum elastic-array 0.7.0 (git+https://github.com/paritytech/elastic-array?branch=0.7.0)" = "<none>"
"checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83"
"checksum eth-secp256k1 0.5.6 (git+https://github.com/paritytech/rust-secp256k1)" = "<none>"
"checksum ethabi 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63df67d0af5e3cb906b667ca1a6e00baffbed87d0d8f5f78468a1f5eb3a66345"

View File

@ -258,7 +258,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
}.fake_sign(req.from);
self.prove_transaction(transaction, id)
.map(|proof| ::request::ExecutionResponse { items: proof })
.map(|(_, proof)| ::request::ExecutionResponse { items: proof })
}
fn ready_transactions(&self) -> Vec<PendingTransaction> {

View File

@ -797,6 +797,24 @@ impl BlockChain {
}
}
/// Insert an epoch transition. Provide an epoch number being transitioned to
/// and epoch transition object.
///
/// The block the transition occurred at should have already been inserted into the chain.
pub fn insert_epoch_transition(&self, batch: &mut DBTransaction, epoch_num: u64, transition: EpochTransition) {
let mut transitions = match self.db.read(db::COL_EXTRA, &epoch_num) {
Some(existing) => existing,
None => EpochTransitions {
number: epoch_num,
candidates: Vec::with_capacity(1),
}
};
transitions.candidates.push(transition);
batch.write(db::COL_EXTRA, &epoch_num, &transitions);
}
/// Add a child to a given block. Assumes that the block hash is in
/// the chain and the child's parent is this block.
///

View File

@ -18,6 +18,7 @@
use bloomchain;
use util::*;
use util::kvdb::PREFIX_LEN as DB_PREFIX_LEN;
use rlp::*;
use header::BlockNumber;
use receipt::Receipt;
@ -37,6 +38,8 @@ pub enum ExtrasIndex {
BlocksBlooms = 3,
/// Block receipts index
BlockReceipts = 4,
/// Epoch transition data index.
EpochTransitions = 5,
}
fn with_index(hash: &H256, i: ExtrasIndex) -> H264 {
@ -134,6 +137,39 @@ impl Key<BlockReceipts> for H256 {
}
}
/// length of epoch keys.
pub const EPOCH_KEY_LEN: usize = DB_PREFIX_LEN + 16;
/// epoch key prefix.
/// used to iterate over all epoch transitions in order from genesis.
pub fn epoch_key_prefix() -> [u8; DB_PREFIX_LEN] {
let mut arr = [0u8; DB_PREFIX_LEN];
arr[0] = ExtrasIndex::EpochTransitions as u8;
arr
}
pub struct EpochTransitionsKey([u8; EPOCH_KEY_LEN]);
impl Deref for EpochTransitionsKey {
type Target = [u8];
fn deref(&self) -> &[u8] { &self.0[..] }
}
impl Key<EpochTransitions> for u64 {
type Target = EpochTransitionsKey;
fn key(&self) -> Self::Target {
let mut arr = [0u8; EPOCH_KEY_LEN];
arr[..DB_PREFIX_LEN].copy_from_slice(&epoch_key_prefix()[..]);
write!(&mut arr[DB_PREFIX_LEN..], "{:016x}", self)
.expect("format arg is valid; no more than 16 chars will be written; qed");
EpochTransitionsKey(arr)
}
}
/// Familial details concerning a block
#[derive(Debug, Clone)]
pub struct BlockDetails {
@ -144,7 +180,7 @@ pub struct BlockDetails {
/// Parent block hash
pub parent: H256,
/// List of children block hashes
pub children: Vec<H256>
pub children: Vec<H256>,
}
impl HeapSizeOf for BlockDetails {
@ -241,6 +277,60 @@ impl HeapSizeOf for BlockReceipts {
}
}
/// Candidate transitions to an epoch with specific number.
#[derive(Clone)]
pub struct EpochTransitions {
pub number: u64,
pub candidates: Vec<EpochTransition>,
}
impl Encodable for EpochTransitions {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(2).append(&self.number).append_list(&self.candidates);
}
}
impl Decodable for EpochTransitions {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
Ok(EpochTransitions {
number: rlp.val_at(0)?,
candidates: rlp.list_at(1)?,
})
}
}
#[derive(Debug, Clone)]
pub struct EpochTransition {
pub block_hash: H256, // block hash at which the transition occurred.
pub proof: Vec<u8>, // "transition/epoch" proof from the engine.
pub state_proof: Vec<DBValue>, // state items necessary to regenerate proof.
}
impl Encodable for EpochTransition {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(3)
.append(&self.block_hash)
.append(&self.proof)
.begin_list(self.state_proof.len());
for item in &self.state_proof {
s.append(&&**item);
}
}
}
impl Decodable for EpochTransition {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
Ok(EpochTransition {
block_hash: rlp.val_at(0)?,
proof: rlp.val_at(1)?,
state_proof: rlp.at(2)?.iter().map(|x| {
Ok(DBValue::from_slice(x.data()?))
}).collect::<Result<Vec<_>, _>>()?,
})
}
}
#[cfg(test)]
mod tests {
use rlp::*;

View File

@ -31,5 +31,6 @@ pub mod generator;
pub use self::blockchain::{BlockProvider, BlockChain};
pub use self::cache::CacheSize;
pub use self::config::Config;
pub use self::extras::EpochTransition;
pub use types::tree_route::TreeRoute;
pub use self::import_route::ImportRoute;

View File

@ -32,13 +32,13 @@ use util::kvdb::*;
// other
use basic_types::Seal;
use block::*;
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
use blockchain::{BlockChain, BlockProvider, EpochTransition, TreeRoute, ImportRoute};
use blockchain::extras::TransactionAddress;
use client::Error as ClientError;
use client::{
BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient,
MiningBlockChainClient, EngineClient, TraceFilter, CallAnalytics, BlockImportError, Mode,
ChainNotify, PruningInfo,
ChainNotify, PruningInfo, ProvingBlockChainClient,
};
use encoded;
use engines::Engine;
@ -578,15 +578,15 @@ impl Client {
// generate validation proof if the engine requires them.
// TODO: make conditional?
let generate_proof = {
let entering_new_epoch = {
use engines::EpochChange;
match self.engine.is_epoch_end(block.header(), Some(block_data), Some(&receipts)) {
EpochChange::Yes(_) => true,
EpochChange::No => false,
EpochChange::Yes(e, p) => Some((block.header().clone(), e, p)),
EpochChange::No => None,
EpochChange::Unsure(_) => {
warn!(target: "client", "Detected invalid engine implementation.");
warn!(target: "client", "Engine claims to require more block data, but everything provided.");
false
None
}
}
};
@ -596,14 +596,53 @@ impl Client {
// TODO: Prove it with a test.
let mut state = block.drain();
if generate_proof {
debug!(target: "client", "Generating validation proof for block {}", hash);
// TODO
}
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.");
}
}
}
self.tracedb.read().import(&mut batch, TraceImportRequest {
traces: traces.into(),
block_hash: hash.clone(),
@ -893,6 +932,20 @@ impl Client {
}
}
}
// transaction for calling contracts from services like engine.
// from the null sender, with 50M gas.
fn contract_call_tx(&self, block_id: BlockId, address: Address, data: Bytes) -> SignedTransaction {
let from = Address::default();
Transaction {
nonce: self.nonce(&from, block_id).unwrap_or_else(|| self.engine.account_start_nonce()),
action: Action::Call(address),
gas: U256::from(50_000_000),
gas_price: U256::default(),
value: U256::default(),
data: data,
}.fake_sign(from)
}
}
impl snapshot::DatabaseRestore for Client {
@ -1483,15 +1536,7 @@ impl BlockChainClient for Client {
}
fn call_contract(&self, block_id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String> {
let from = Address::default();
let transaction = Transaction {
nonce: self.latest_nonce(&from),
action: Action::Call(address),
gas: U256::from(50_000_000),
gas_price: U256::default(),
value: U256::default(),
data: data,
}.fake_sign(from);
let transaction = self.contract_call_tx(block_id, address, data);
self.call(&transaction, block_id, Default::default())
.map_err(|e| format!("{:?}", e))
@ -1643,7 +1688,7 @@ impl MayPanic for Client {
}
}
impl ::client::ProvingBlockChainClient for Client {
impl ProvingBlockChainClient for Client {
fn prove_storage(&self, key1: H256, key2: H256, id: BlockId) -> Option<(Vec<Bytes>, H256)> {
self.state_at(id)
.and_then(move |state| state.prove_storage(key1, key2).ok())
@ -1654,7 +1699,7 @@ impl ::client::ProvingBlockChainClient for Client {
.and_then(move |state| state.prove_account(key1).ok())
}
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<Vec<DBValue>> {
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<(Bytes, Vec<DBValue>)> {
let (state, mut env_info) = match (self.state_at(id), self.env_info(id)) {
(Some(s), Some(e)) => (s, e),
_ => return None,
@ -1669,8 +1714,9 @@ impl ::client::ProvingBlockChainClient for Client {
let res = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(&transaction, options);
match res {
Err(ExecutionError::Internal(_)) => return None,
_ => return Some(state.drop().1.extract_proof()),
Err(ExecutionError::Internal(_)) => None,
Err(_) => Some((Vec::new(), state.drop().1.extract_proof())),
Ok(res) => Some((res.output, state.drop().1.extract_proof())),
}
}
}

View File

@ -767,7 +767,7 @@ impl ProvingBlockChainClient for TestBlockChainClient {
None
}
fn prove_transaction(&self, _: SignedTransaction, _: BlockId) -> Option<Vec<DBValue>> {
fn prove_transaction(&self, _: SignedTransaction, _: BlockId) -> Option<(Bytes, Vec<DBValue>)> {
None
}
}

View File

@ -324,5 +324,7 @@ pub trait ProvingBlockChainClient: BlockChainClient {
fn prove_account(&self, key1: H256, id: BlockId) -> Option<(Vec<Bytes>, BasicAccount)>;
/// Prove execution of a transaction at the given block.
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<Vec<DBValue>>;
/// Returns the output of the call and a vector of database items necessary
/// to reproduce it.
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<(Bytes, Vec<DBValue>)>;
}

View File

@ -133,13 +133,13 @@ pub struct AuthorityRound {
// header-chain validator.
struct EpochVerifier {
epoch_number: U256,
epoch_number: u64,
step: Arc<Step>,
subchain_validators: SimpleList,
}
impl super::EpochVerifier for EpochVerifier {
fn epoch_number(&self) -> U256 { self.epoch_number.clone() }
fn epoch_number(&self) -> u64 { self.epoch_number.clone() }
fn verify_light(&self, header: &Header) -> Result<(), Error> {
// always check the seal since it's fast.
// nothing heavier to do.

View File

@ -52,12 +52,12 @@ impl From<ethjson::spec::BasicAuthorityParams> for BasicAuthorityParams {
}
struct EpochVerifier {
epoch_number: U256,
epoch_number: u64,
list: SimpleList,
}
impl super::EpochVerifier for EpochVerifier {
fn epoch_number(&self) -> U256 { self.epoch_number.clone() }
fn epoch_number(&self) -> u64 { self.epoch_number.clone() }
fn verify_light(&self, header: &Header) -> Result<(), Error> {
verify_external(header, &self.list)
}

View File

@ -18,14 +18,13 @@
use error::Error;
use header::Header;
use util::U256;
/// Verifier for all blocks within an epoch without accessing
///
/// See docs on `Engine` relating to proving functions for more details.
pub trait EpochVerifier: Sync {
/// Get the epoch number.
fn epoch_number(&self) -> U256;
fn epoch_number(&self) -> u64;
/// Lightly verify the next block header.
/// This may not be a header belonging to a different epoch.
@ -41,6 +40,6 @@ pub trait EpochVerifier: Sync {
pub struct NoOp;
impl EpochVerifier for NoOp {
fn epoch_number(&self) -> U256 { 0.into() }
fn epoch_number(&self) -> u64 { 0 }
fn verify_light(&self, _header: &Header) -> Result<(), Error> { Ok(()) }
}

View File

@ -96,7 +96,7 @@ pub enum Seal {
}
/// Type alias for a function we can make calls through synchronously.
pub type Call = Fn(Address, Bytes) -> Result<Bytes, String>;
pub type Call<'a> = Fn(Address, Bytes) -> Result<Bytes, String> + 'a;
/// Results of a query of whether an epoch change occurred at the given block.
#[derive(Debug, Clone, PartialEq)]
@ -105,8 +105,8 @@ pub enum EpochChange {
Unsure(Unsure),
/// No epoch change.
No,
/// Validation proof required, and the expected output
Yes(Bytes),
/// Validation proof required, and the new epoch number and expected proof.
Yes(u64, Bytes),
}
/// More data required to determine if an epoch change occurred at a given block.

View File

@ -76,7 +76,7 @@ impl ValidatorSet for ValidatorContract {
self.validators.epoch_proof(header, caller)
}
fn epoch_set(&self, header: &Header, proof: &[u8]) -> Result<(U256, super::SimpleList), ::error::Error> {
fn epoch_set(&self, header: &Header, proof: &[u8]) -> Result<(u64, super::SimpleList), ::error::Error> {
self.validators.epoch_set(header, proof)
}

View File

@ -23,7 +23,7 @@ mod multi;
use std::sync::Weak;
use ids::BlockId;
use util::{Address, H256, U256};
use util::{Address, H256};
use ethjson::spec::ValidatorSet as ValidatorSpec;
use client::Client;
use header::Header;
@ -97,7 +97,7 @@ pub trait ValidatorSet: Send + Sync {
/// the proof is invalid.
///
/// Returns the epoch number and proof.
fn epoch_set(&self, header: &Header, proof: &[u8]) -> Result<(U256, SimpleList), ::error::Error>;
fn epoch_set(&self, header: &Header, proof: &[u8]) -> Result<(u64, SimpleList), ::error::Error>;
/// Checks if a given address is a validator, with the given function
/// for executing synchronous calls to contracts.

View File

@ -19,7 +19,7 @@
use std::collections::BTreeMap;
use std::sync::Weak;
use engines::{Call, EpochChange};
use util::{H256, Address, RwLock, U256};
use util::{H256, Address, RwLock};
use ids::BlockId;
use header::{BlockNumber, Header};
use client::{Client, BlockChainClient};
@ -75,19 +75,24 @@ impl ValidatorSet for Multi {
fn is_epoch_end(&self, header: &Header, block: Option<&[u8]>, receipts: Option<&[::receipt::Receipt]>)
-> EpochChange
{
self.correct_set_by_number(header.number()).1.is_epoch_end(header, block, receipts)
let (set_block, set) = self.correct_set_by_number(header.number());
match set.is_epoch_end(header, block, receipts) {
EpochChange::Yes(num, proof) => EpochChange::Yes(set_block + num, proof),
other => other,
}
}
fn epoch_proof(&self, header: &Header, caller: &Call) -> Result<Vec<u8>, String> {
self.correct_set_by_number(header.number()).1.epoch_proof(header, caller)
}
fn epoch_set(&self, header: &Header, proof: &[u8]) -> Result<(U256, super::SimpleList), ::error::Error> {
fn epoch_set(&self, header: &Header, proof: &[u8]) -> Result<(u64, super::SimpleList), ::error::Error> {
// "multi" epoch is the inner set's epoch plus the transition block to that set.
// ensures epoch increases monotonically.
let (set_block, set) = self.correct_set_by_number(header.number());
let (inner_epoch, list) = set.epoch_set(header, proof)?;
Ok((U256::from(set_block) + inner_epoch, list))
Ok((set_block + inner_epoch, list))
}
fn contains_with_caller(&self, bh: &H256, address: &Address, caller: &Call) -> bool {

View File

@ -165,8 +165,6 @@ impl ValidatorSet for ValidatorSafeContract {
}
});
// TODO: are multiple transitions per block possible?
match decoded_events.next() {
None => ::engines::EpochChange::No,
Some(matched_event) => {
@ -184,8 +182,11 @@ impl ValidatorSet for ValidatorSafeContract {
);
match (nonce, validators) {
(Some(nonce), Some(validators)) =>
::engines::EpochChange::Yes(encode_proof(nonce, &validators)),
(Some(nonce), Some(validators)) => {
let proof = encode_proof(nonce, &validators);
let new_epoch = nonce.low_u64();
::engines::EpochChange::Yes(new_epoch, proof)
}
_ => {
debug!(target: "engine", "Successfully decoded log turned out to be bad.");
::engines::EpochChange::No
@ -206,11 +207,11 @@ impl ValidatorSet for ValidatorSafeContract {
}
}
fn epoch_set(&self, _header: &Header, proof: &[u8]) -> Result<(U256, SimpleList), ::error::Error> {
fn epoch_set(&self, _header: &Header, proof: &[u8]) -> Result<(u64, SimpleList), ::error::Error> {
use rlp::UntrustedRlp;
let rlp = UntrustedRlp::new(proof);
let nonce: U256 = rlp.val_at(0)?;
let nonce: u64 = rlp.val_at(0)?;
let validators: Vec<Address> = rlp.list_at(1)?;
Ok((nonce, SimpleList::new(validators)))

View File

@ -16,7 +16,7 @@
/// Preconfigured validator list.
use util::{H256, Address, HeapSizeOf, U256};
use util::{H256, Address, HeapSizeOf};
use engines::Call;
use header::Header;
@ -63,8 +63,8 @@ impl ValidatorSet for SimpleList {
Ok(Vec::new())
}
fn epoch_set(&self, _header: &Header, _: &[u8]) -> Result<(U256, SimpleList), ::error::Error> {
Ok((0.into(), self.clone()))
fn epoch_set(&self, _header: &Header, _: &[u8]) -> Result<(u64, SimpleList), ::error::Error> {
Ok((0, self.clone()))
}
fn contains_with_caller(&self, _bh: &H256, address: &Address, _: &Call) -> bool {

View File

@ -158,7 +158,7 @@ impl Ethash {
// in the future, we might move the Ethash epoch
// caching onto this mechanism as well.
impl ::engines::EpochVerifier for Arc<Ethash> {
fn epoch_number(&self) -> U256 { 0.into() }
fn epoch_number(&self) -> u64 { 0 }
fn verify_light(&self, _header: &Header) -> Result<(), Error> { Ok(()) }
fn verify_heavy(&self, header: &Header) -> Result<(), Error> {
self.verify_block_unordered(header, None)

View File

@ -238,7 +238,7 @@ impl Migration for OverlayRecentV7 {
}
let mut count = 0;
for (key, value) in source.iter(None) {
for (key, value) in source.iter(None).into_iter().flat_map(|inner| inner) {
count += 1;
if count == 100_000 {
count = 0;

View File

@ -102,7 +102,7 @@ impl Migration for ToV10 {
fn migrate(&mut self, source: Arc<Database>, config: &Config, dest: &mut Database, col: Option<u32>) -> Result<(), Error> {
let mut batch = Batch::new(config, col);
for (key, value) in source.iter(col) {
for (key, value) in source.iter(col).into_iter().flat_map(|inner| inner) {
self.progress.tick();
batch.insert(key.to_vec(), value.to_vec(), dest)?;
}

View File

@ -59,7 +59,7 @@ impl Migration for ToV9 {
fn migrate(&mut self, source: Arc<Database>, config: &Config, dest: &mut Database, col: Option<u32>) -> Result<(), Error> {
let mut batch = Batch::new(config, self.column);
for (key, value) in source.iter(col) {
for (key, value) in source.iter(col).into_iter().flat_map(|inner| inner) {
self.progress.tick();
match self.extract {
Extract::Header => {

View File

@ -367,7 +367,7 @@ fn transaction_proof() {
data: Vec::new(),
}.fake_sign(address);
let proof = client.prove_transaction(transaction.clone(), BlockId::Latest).unwrap();
let proof = client.prove_transaction(transaction.clone(), BlockId::Latest).unwrap().1;
let backend = state::backend::ProofCheck::new(&proof);
let mut factories = ::factory::Factories::default();

View File

@ -16,7 +16,7 @@ time = "0.1.34"
rocksdb = { git = "https://github.com/paritytech/rust-rocksdb" }
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
rust-crypto = "0.2.34"
elastic-array = { git = "https://github.com/paritytech/elastic-array" }
elastic-array = "0.7.0"
rlp = { path = "rlp" }
heapsize = { version = "0.3", features = ["unstable"] }
itertools = "0.5"

View File

@ -6,7 +6,7 @@ version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
elastic-array = { git = "https://github.com/paritytech/elastic-array" }
elastic-array = "0.7.0"
ethcore-bigint = { path = "../bigint" }
lazy_static = "0.2"
rustc-serialize = "0.3"

View File

@ -125,8 +125,8 @@ pub fn new(backing: Arc<::kvdb::KeyValueDB>, algorithm: Algorithm, col: Option<u
}
// all keys must be at least 12 bytes
const DB_PREFIX_LEN : usize = 12;
const LATEST_ERA_KEY : [u8; DB_PREFIX_LEN] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ];
const DB_PREFIX_LEN : usize = ::kvdb::PREFIX_LEN;
const LATEST_ERA_KEY : [u8; ::kvdb::PREFIX_LEN] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ];
#[cfg(test)]
mod tests {

View File

@ -36,6 +36,9 @@ use std::fs::File;
const DB_BACKGROUND_FLUSHES: i32 = 2;
const DB_BACKGROUND_COMPACTIONS: i32 = 2;
/// Required length of prefixes.
pub const PREFIX_LEN: usize = 12;
/// Write transaction. Batches a sequence of put/delete operations for efficiency.
#[derive(Default, Clone, PartialEq)]
pub struct DBTransaction {