Make HashDB generic (#8739)

The `patricia_trie` crate is generic over the hasher (by way of HashDB) and node encoding scheme. Adds a new `patricia_trie_ethereum` crate with concrete impls for Keccak/RLP.
This commit is contained in:
David
2018-07-02 18:50:05 +02:00
committed by GitHub
parent 202c54d423
commit 9caa868603
89 changed files with 1962 additions and 1282 deletions

View File

@@ -15,12 +15,13 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! DB backend wrapper for Account trie
use std::collections::HashMap;
use hash::{KECCAK_NULL_RLP, keccak};
use ethereum_types::H256;
use hash::{KECCAK_NULL_RLP, keccak};
use hashdb::{HashDB, AsHashDB};
use keccak_hasher::KeccakHasher;
use kvdb::DBValue;
use hashdb::HashDB;
use rlp::NULL_RLP;
use std::collections::HashMap;
#[cfg(test)]
use ethereum_types::Address;
@@ -44,7 +45,7 @@ fn combine_key<'a>(address_hash: &'a H256, key: &'a H256) -> H256 {
/// A factory for different kinds of account dbs.
#[derive(Debug, Clone)]
pub enum Factory {
/// Mangle hashes based on address.
/// Mangle hashes based on address. This is the default.
Mangled,
/// Don't mangle hashes.
Plain,
@@ -57,7 +58,7 @@ impl Default for Factory {
impl Factory {
/// Create a read-only accountdb.
/// This will panic when write operations are called.
pub fn readonly<'db>(&self, db: &'db HashDB, address_hash: H256) -> Box<HashDB + 'db> {
pub fn readonly<'db>(&self, db: &'db HashDB<KeccakHasher>, address_hash: H256) -> Box<HashDB<KeccakHasher> + 'db> {
match *self {
Factory::Mangled => Box::new(AccountDB::from_hash(db, address_hash)),
Factory::Plain => Box::new(Wrapping(db)),
@@ -65,7 +66,7 @@ impl Factory {
}
/// Create a new mutable hashdb.
pub fn create<'db>(&self, db: &'db mut HashDB, address_hash: H256) -> Box<HashDB + 'db> {
pub fn create<'db>(&self, db: &'db mut HashDB<KeccakHasher>, address_hash: H256) -> Box<HashDB<KeccakHasher> + 'db> {
match *self {
Factory::Mangled => Box::new(AccountDBMut::from_hash(db, address_hash)),
Factory::Plain => Box::new(WrappingMut(db)),
@@ -77,19 +78,19 @@ impl Factory {
/// DB backend wrapper for Account trie
/// Transforms trie node keys for the database
pub struct AccountDB<'db> {
db: &'db HashDB,
db: &'db HashDB<KeccakHasher>,
address_hash: H256,
}
impl<'db> AccountDB<'db> {
/// Create a new AccountDB from an address.
#[cfg(test)]
pub fn new(db: &'db HashDB, address: &Address) -> Self {
pub fn new(db: &'db HashDB<KeccakHasher>, address: &Address) -> Self {
Self::from_hash(db, keccak(address))
}
/// Create a new AcountDB from an address' hash.
pub fn from_hash(db: &'db HashDB, address_hash: H256) -> Self {
pub fn from_hash(db: &'db HashDB<KeccakHasher>, address_hash: H256) -> Self {
AccountDB {
db: db,
address_hash: address_hash,
@@ -97,7 +98,12 @@ impl<'db> AccountDB<'db> {
}
}
impl<'db> HashDB for AccountDB<'db>{
impl<'db> AsHashDB<KeccakHasher> for AccountDB<'db> {
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
}
impl<'db> HashDB<KeccakHasher> for AccountDB<'db> {
fn keys(&self) -> HashMap<H256, i32> {
unimplemented!()
}
@@ -131,19 +137,19 @@ impl<'db> HashDB for AccountDB<'db>{
/// DB backend wrapper for Account trie
pub struct AccountDBMut<'db> {
db: &'db mut HashDB,
db: &'db mut HashDB<KeccakHasher>,
address_hash: H256,
}
impl<'db> AccountDBMut<'db> {
/// Create a new AccountDB from an address.
#[cfg(test)]
pub fn new(db: &'db mut HashDB, address: &Address) -> Self {
pub fn new(db: &'db mut HashDB<KeccakHasher>, address: &Address) -> Self {
Self::from_hash(db, keccak(address))
}
/// Create a new AcountDB from an address' hash.
pub fn from_hash(db: &'db mut HashDB, address_hash: H256) -> Self {
pub fn from_hash(db: &'db mut HashDB<KeccakHasher>, address_hash: H256) -> Self {
AccountDBMut {
db: db,
address_hash: address_hash,
@@ -156,7 +162,7 @@ impl<'db> AccountDBMut<'db> {
}
}
impl<'db> HashDB for AccountDBMut<'db>{
impl<'db> HashDB<KeccakHasher> for AccountDBMut<'db>{
fn keys(&self) -> HashMap<H256, i32> {
unimplemented!()
}
@@ -202,9 +208,19 @@ impl<'db> HashDB for AccountDBMut<'db>{
}
}
struct Wrapping<'db>(&'db HashDB);
impl<'db> AsHashDB<KeccakHasher> for AccountDBMut<'db> {
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
}
impl<'db> HashDB for Wrapping<'db> {
struct Wrapping<'db>(&'db HashDB<KeccakHasher>);
impl<'db> AsHashDB<KeccakHasher> for Wrapping<'db> {
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
}
impl<'db> HashDB<KeccakHasher> for Wrapping<'db> {
fn keys(&self) -> HashMap<H256, i32> {
unimplemented!()
}
@@ -236,9 +252,13 @@ impl<'db> HashDB for Wrapping<'db> {
}
}
struct WrappingMut<'db>(&'db mut HashDB);
struct WrappingMut<'db>(&'db mut HashDB<KeccakHasher>);
impl<'db> AsHashDB<KeccakHasher> for WrappingMut<'db> {
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
}
impl<'db> HashDB for WrappingMut<'db>{
impl<'db> HashDB<KeccakHasher> for WrappingMut<'db>{
fn keys(&self) -> HashMap<H256, i32> {
unimplemented!()
}

View File

@@ -17,28 +17,27 @@
//! Blockchain block.
use std::cmp;
use std::sync::Arc;
use std::collections::HashSet;
use hash::{keccak, KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP};
use triehash::ordered_trie_root;
use std::sync::Arc;
use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError, encode_list};
use ethereum_types::{H256, U256, Address, Bloom};
use bytes::Bytes;
use unexpected::{Mismatch, OutOfBounds};
use vm::{EnvInfo, LastHashes};
use engines::EthEngine;
use error::{Error, BlockError};
use ethereum_types::{H256, U256, Address, Bloom};
use factory::Factories;
use hash::{keccak, KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP};
use header::{Header, ExtendedHeader};
use receipt::{Receipt, TransactionOutcome};
use state::State;
use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError, encode_list};
use state_db::StateDB;
use state::State;
use trace::Tracing;
use transaction::{UnverifiedTransaction, SignedTransaction, Error as TransactionError};
use triehash::ordered_trie_root;
use unexpected::{Mismatch, OutOfBounds};
use verification::PreverifiedBlock;
use views::BlockView;
use vm::{EnvInfo, LastHashes};
/// A block, encoded as it is on the block chain.
#[derive(Default, Debug, Clone, PartialEq)]

View File

@@ -17,37 +17,38 @@
//! Blockchain database.
use std::collections::{HashMap, HashSet};
use std::{mem, io};
use std::path::Path;
use std::sync::Arc;
use std::{mem, io};
use itertools::Itertools;
use blooms_db;
use heapsize::HeapSizeOf;
use ethereum_types::{H256, Bloom, BloomRef, U256};
use parking_lot::{Mutex, RwLock};
use bytes::Bytes;
use rlp::RlpStream;
use rlp_compress::{compress, decompress, blocks_swapper};
use header::*;
use transaction::*;
use views::{BlockView, HeaderView};
use log_entry::{LogEntry, LocalizedLogEntry};
use receipt::Receipt;
use ansi_term::Colour;
use blockchain::{CacheSize, ImportRoute, Config};
use blockchain::best_block::{BestBlock, BestAncientBlock};
use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData};
use blockchain::extras::{BlockReceipts, BlockDetails, TransactionAddress, EPOCH_KEY_PREFIX, EpochTransitions};
use blockchain::update::{ExtrasUpdate, ExtrasInsert};
use blooms_db;
use bytes::Bytes;
use cache_manager::CacheManager;
use db::{self, Writable, Readable, CacheUpdatePolicy};
use encoded;
use engines::epoch::{Transition as EpochTransition, PendingTransition as PendingEpochTransition};
use engines::ForkChoice;
use ethereum_types::{H256, Bloom, BloomRef, U256};
use header::*;
use heapsize::HeapSizeOf;
use itertools::Itertools;
use kvdb::{DBTransaction, KeyValueDB};
use log_entry::{LogEntry, LocalizedLogEntry};
use parking_lot::{Mutex, RwLock};
use rayon::prelude::*;
use receipt::Receipt;
use rlp_compress::{compress, decompress, blocks_swapper};
use rlp::RlpStream;
use transaction::*;
use types::blockchain_info::BlockChainInfo;
use types::tree_route::TreeRoute;
use blockchain::update::{ExtrasUpdate, ExtrasInsert};
use blockchain::{CacheSize, ImportRoute, Config};
use db::{self, Writable, Readable, CacheUpdatePolicy};
use cache_manager::CacheManager;
use encoded;
use engines::ForkChoice;
use engines::epoch::{Transition as EpochTransition, PendingTransition as PendingEpochTransition};
use rayon::prelude::*;
use ansi_term::Colour;
use kvdb::{DBTransaction, KeyValueDB};
use views::{BlockView, HeaderView};
/// Database backing `BlockChain`.
pub trait BlockChainDB: Send + Sync {

View File

@@ -16,18 +16,18 @@
//! Blockchain DB extras.
use std::ops;
use std::io::Write;
use std::ops;
use db::Key;
use engines::epoch::{Transition as EpochTransition};
use ethereum_types::{H256, H264, U256};
use header::BlockNumber;
use heapsize::HeapSizeOf;
use kvdb::PREFIX_LEN as DB_PREFIX_LEN;
use receipt::Receipt;
use rlp;
use heapsize::HeapSizeOf;
use ethereum_types::{H256, H264, U256};
use kvdb::PREFIX_LEN as DB_PREFIX_LEN;
/// Represents index of extra data in database
#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)]
pub enum ExtrasIndex {
@@ -252,6 +252,7 @@ pub struct EpochTransitions {
#[cfg(test)]
mod tests {
use rlp::*;
use super::BlockReceipts;
#[test]

View File

@@ -1713,7 +1713,7 @@ impl BlockChainClient for Client {
fn list_storage(&self, id: BlockId, account: &Address, after: Option<&H256>, count: u64) -> Option<Vec<H256>> {
if !self.factories.trie.is_fat() {
trace!(target: "fatdb", "list_stroage: Not a fat DB");
trace!(target: "fatdb", "list_storage: Not a fat DB");
return None;
}

View File

@@ -16,7 +16,7 @@
use std::fmt::{Display, Formatter, Error as FmtError};
use util_error::UtilError;
use trie::TrieError;
use ethtrie::TrieError;
/// Client configuration errors.
#[derive(Debug)]

View File

@@ -25,12 +25,13 @@ use {state, state_db, client, executive, trace, transaction, db, spec, pod_state
use factory::Factories;
use evm::{VMType, FinalizationResult};
use vm::{self, ActionParams};
use ethtrie;
/// EVM test Error.
#[derive(Debug)]
pub enum EvmTestError {
/// Trie integrity error.
Trie(trie::TrieError),
Trie(Box<ethtrie::TrieError>),
/// EVM error.
Evm(vm::Error),
/// Initialization error.

View File

@@ -52,7 +52,6 @@ use miner::{self, Miner, MinerService};
use spec::Spec;
use types::basic_account::BasicAccount;
use types::pruning_info::PruningInfo;
use verification::queue::QueueInfo;
use block::{OpenBlock, SealedBlock, ClosedBlock};
use executive::Executed;
@@ -62,7 +61,7 @@ use state_db::StateDB;
use header::Header;
use encoded;
use engines::EthEngine;
use trie;
use ethtrie;
use state::StateInfo;
use views::BlockView;
@@ -581,10 +580,10 @@ impl Call for TestBlockChainClient {
}
impl StateInfo for () {
fn nonce(&self, _address: &Address) -> trie::Result<U256> { unimplemented!() }
fn balance(&self, _address: &Address) -> trie::Result<U256> { unimplemented!() }
fn storage_at(&self, _address: &Address, _key: &H256) -> trie::Result<H256> { unimplemented!() }
fn code(&self, _address: &Address) -> trie::Result<Option<Arc<Bytes>>> { unimplemented!() }
fn nonce(&self, _address: &Address) -> ethtrie::Result<U256> { unimplemented!() }
fn balance(&self, _address: &Address) -> ethtrie::Result<U256> { unimplemented!() }
fn storage_at(&self, _address: &Address, _key: &H256) -> ethtrie::Result<H256> { unimplemented!() }
fn code(&self, _address: &Address) -> ethtrie::Result<Option<Arc<Bytes>>> { unimplemented!() }
}
impl StateClient for TestBlockChainClient {

View File

@@ -34,12 +34,9 @@ use ethjson;
use machine::{AuxiliaryData, Call, EthereumMachine};
use hash::keccak;
use header::{Header, BlockNumber, ExtendedHeader};
use super::signer::EngineSigner;
use super::validator_set::{ValidatorSet, SimpleList, new_validator_set};
use self::finality::RollingFinality;
use ethkey::{self, Password, Signature};
use io::{IoContext, IoHandler, TimerToken, IoService};
use itertools::{self, Itertools};

View File

@@ -16,15 +16,15 @@
//! Tendermint message handling.
use std::cmp;
use hash::keccak;
use ethereum_types::{H256, H520, Address};
use bytes::Bytes;
use super::{Height, View, BlockHash, Step};
use error::Error;
use ethereum_types::{H256, H520, Address};
use ethkey::{recover, public_to_address};
use hash::keccak;
use header::Header;
use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError};
use ethkey::{recover, public_to_address};
use std::cmp;
use super::{Height, View, BlockHash, Step};
use super::super::vote_collector::Message;
/// Message transmitted between consensus participants.

View File

@@ -145,7 +145,7 @@ impl <F> super::EpochVerifier<EthereumMachine> for EpochVerifier<F>
fn check_finality_proof(&self, proof: &[u8]) -> Option<Vec<H256>> {
match ::rlp::decode(proof) {
Ok(header) => self.verify_light(&header).ok().map(|_| vec![header.hash()]),
Err(_) => None // REVIEW: log perhaps? Not sure what the policy is.
Err(_) => None
}
}
}

View File

@@ -16,27 +16,23 @@
/// Validator set maintained in a contract, updated using `getValidators` method.
use std::sync::{Weak, Arc};
use hash::keccak;
use ethereum_types::{H256, U256, Address, Bloom};
use parking_lot::RwLock;
use bytes::Bytes;
use memory_cache::MemoryLruCache;
use unexpected::Mismatch;
use rlp::{Rlp, RlpStream};
use kvdb::DBValue;
use client::EngineClient;
use machine::{AuxiliaryData, Call, EthereumMachine, AuxiliaryRequest};
use ethereum_types::{H256, U256, Address, Bloom};
use hash::keccak;
use header::Header;
use ids::BlockId;
use kvdb::DBValue;
use log_entry::LogEntry;
use machine::{AuxiliaryData, Call, EthereumMachine, AuxiliaryRequest};
use memory_cache::MemoryLruCache;
use parking_lot::RwLock;
use receipt::Receipt;
use rlp::{Rlp, RlpStream};
use std::sync::{Weak, Arc};
use super::{SystemCall, ValidatorSet};
use super::simple_list::SimpleList;
use unexpected::Mismatch;
use_contract!(validator_set, "ValidatorSet", "res/contracts/validator_set.json");

View File

@@ -22,7 +22,7 @@ use ethereum_types::{H256, U256, Address, Bloom};
use util_error::{self, UtilError};
use snappy::InvalidInput;
use unexpected::{Mismatch, OutOfBounds};
use trie::TrieError;
use ethtrie::TrieError;
use io::*;
use header::BlockNumber;
use client::Error as ClientError;

View File

@@ -18,7 +18,7 @@
use ethereum_types::{U256, U512, Address};
use bytes::Bytes;
use trie;
use ethtrie;
use vm;
use trace::{VMTrace, FlatTrace};
use log_entry::LogEntry;
@@ -117,9 +117,14 @@ pub enum ExecutionError {
TransactionMalformed(String),
}
impl From<Box<trie::TrieError>> for ExecutionError {
fn from(err: Box<trie::TrieError>) -> Self {
ExecutionError::Internal(format!("{}", err))
impl From<Box<ethtrie::TrieError>> for ExecutionError {
fn from(err: Box<ethtrie::TrieError>) -> Self {
ExecutionError::Internal(format!("{:?}", err))
}
}
impl From<ethtrie::TrieError> for ExecutionError {
fn from(err: ethtrie::TrieError) -> Self {
ExecutionError::Internal(format!("{:?}", err))
}
}

View File

@@ -15,10 +15,12 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use trie::TrieFactory;
use ethtrie::RlpCodec;
use account_db::Factory as AccountFactory;
use evm::{Factory as EvmFactory, VMType};
use vm::{Vm, ActionParams, Schedule};
use wasm::WasmInterpreter;
use keccak_hasher::KeccakHasher;
const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm";
@@ -54,7 +56,7 @@ pub struct Factories {
/// factory for evm.
pub vm: VmFactory,
/// factory for tries.
pub trie: TrieFactory,
pub trie: TrieFactory<KeccakHasher, RlpCodec>,
/// factory for account databases.
pub accountdb: AccountFactory,
}

View File

@@ -31,7 +31,7 @@ use ethjson;
use trace::{Tracer, NoopTracer};
use trace::{VMTracer, NoopVMTracer};
use bytes::{Bytes, BytesRef};
use trie;
use ethtrie;
use rlp::RlpStream;
use hash::keccak;
use machine::EthereumMachine as Machine;
@@ -93,7 +93,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B>
address: Address,
tracer: &'a mut T,
vm_tracer: &'a mut V,
) -> trie::Result<Self> {
) -> ethtrie::Result<Self> {
let static_call = false;
Ok(TestExt {
nonce: state.nonce(&address)?,

View File

@@ -16,8 +16,10 @@
use ethjson;
use trie::{TrieFactory, TrieSpec};
use ethtrie::RlpCodec;
use ethereum_types::H256;
use memorydb::MemoryDB;
use keccak_hasher::KeccakHasher;
use super::HookType;
@@ -28,13 +30,13 @@ pub use self::secure::run_test_file as run_secure_test_file;
fn test_trie<H: FnMut(&str, HookType)>(json: &[u8], trie: TrieSpec, start_stop_hook: &mut H) -> Vec<String> {
let tests = ethjson::trie::Test::load(json).unwrap();
let factory = TrieFactory::new(trie);
let factory = TrieFactory::<_, RlpCodec>::new(trie);
let mut result = vec![];
for (name, test) in tests.into_iter() {
start_stop_hook(&name, HookType::OnStart);
let mut memdb = MemoryDB::new();
let mut memdb = MemoryDB::<KeccakHasher>::new();
let mut root = H256::default();
let mut t = factory.create(&mut memdb, &mut root);

View File

@@ -91,9 +91,11 @@ extern crate rayon;
extern crate rlp;
extern crate rlp_compress;
extern crate keccak_hash as hash;
extern crate keccak_hasher;
extern crate heapsize;
extern crate memorydb;
extern crate patricia_trie as trie;
extern crate patricia_trie_ethereum as ethtrie;
extern crate triehash;
extern crate ansi_term;
extern crate unexpected;

View File

@@ -20,9 +20,11 @@ use itertools::Itertools;
use hash::{keccak};
use ethereum_types::{H256, U256};
use hashdb::HashDB;
use keccak_hasher::KeccakHasher;
use triehash::sec_trie_root;
use bytes::Bytes;
use trie::TrieFactory;
use ethtrie::RlpCodec;
use state::Account;
use ethjson;
use types::account_diff::*;
@@ -65,7 +67,7 @@ impl PodAccount {
}
/// Place additional data into given hash DB.
pub fn insert_additional(&self, db: &mut HashDB, factory: &TrieFactory) {
pub fn insert_additional(&self, db: &mut HashDB<KeccakHasher>, factory: &TrieFactory<KeccakHasher, RlpCodec>) {
match self.code {
Some(ref c) if !c.is_empty() => { db.insert(c); }
_ => {}

View File

@@ -18,16 +18,15 @@
use account_db::{AccountDB, AccountDBMut};
use basic_account::BasicAccount;
use snapshot::Error;
use hash::{KECCAK_EMPTY, KECCAK_NULL_RLP};
use ethereum_types::{H256, U256};
use hashdb::HashDB;
use bytes::Bytes;
use trie::{TrieDB, Trie};
use ethereum_types::{H256, U256};
use ethtrie::{TrieDB, TrieDBMut};
use hash::{KECCAK_EMPTY, KECCAK_NULL_RLP};
use hashdb::HashDB;
use rlp::{RlpStream, Rlp};
use snapshot::Error;
use std::collections::HashSet;
use trie::{Trie, TrieMut};
// An empty account -- these were replaced with RLP null data for a space optimization in v1.
const ACC_EMPTY: BasicAccount = BasicAccount {
@@ -151,7 +150,6 @@ pub fn from_fat_rlp(
rlp: Rlp,
mut storage_root: H256,
) -> Result<(BasicAccount, Option<Bytes>), Error> {
use trie::{TrieDBMut, TrieMut};
// check for special case of empty account.
if rlp.is_empty() {

View File

@@ -19,7 +19,6 @@
use block::Block;
use header::Header;
use hash::keccak;
use views::BlockView;
use rlp::{DecoderError, RlpStream, Rlp};
use ethereum_types::H256;

View File

@@ -38,6 +38,7 @@ use ethereum_types::{H256, U256};
use kvdb::KeyValueDB;
use bytes::Bytes;
/// Snapshot creation and restoration for PoA chains.
/// Chunk format:
///

View File

@@ -21,7 +21,7 @@ use std::fmt;
use ids::BlockId;
use ethereum_types::H256;
use trie::TrieError;
use ethtrie::TrieError;
use rlp::DecoderError;
/// Snapshot-related errors.

View File

@@ -32,13 +32,15 @@ use ids::BlockId;
use ethereum_types::{H256, U256};
use hashdb::HashDB;
use keccak_hasher::KeccakHasher;
use kvdb::DBValue;
use snappy;
use bytes::Bytes;
use parking_lot::Mutex;
use journaldb::{self, Algorithm, JournalDB};
use kvdb::KeyValueDB;
use trie::{TrieDB, TrieDBMut, Trie, TrieMut};
use trie::{Trie, TrieMut};
use ethtrie::{TrieDB, TrieDBMut};
use rlp::{RlpStream, Rlp};
use bloom_journal::Bloom;
@@ -126,7 +128,7 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(
engine: &EthEngine,
chain: &BlockChain,
block_at: H256,
state_db: &HashDB,
state_db: &HashDB<KeccakHasher>,
writer: W,
p: &Progress
) -> Result<(), Error> {
@@ -264,7 +266,7 @@ impl<'a> StateChunker<'a> {
///
/// Returns a list of hashes of chunks created, or any error it may
/// have encountered.
pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex<SnapshotWriter + 'a>, progress: &'a Progress) -> Result<Vec<H256>, Error> {
pub fn chunk_state<'a>(db: &HashDB<KeccakHasher>, root: &H256, writer: &Mutex<SnapshotWriter + 'a>, progress: &'a Progress) -> Result<Vec<H256>, Error> {
let account_trie = TrieDB::new(db, &root)?;
let mut chunker = StateChunker {
@@ -414,7 +416,7 @@ struct RebuiltStatus {
// rebuild a set of accounts and their storage.
// returns a status detailing newly-loaded code and accounts missing code.
fn rebuild_accounts(
db: &mut HashDB,
db: &mut HashDB<KeccakHasher>,
account_fat_rlps: Rlp,
out_chunk: &mut [(H256, Bytes)],
known_code: &HashMap<H256, H256>,

View File

@@ -36,8 +36,10 @@ use rand::Rng;
use kvdb::DBValue;
use ethereum_types::H256;
use hashdb::HashDB;
use keccak_hasher::KeccakHasher;
use journaldb;
use trie::{SecTrieDBMut, TrieMut, TrieDB, TrieDBMut, Trie};
use trie::{TrieMut, Trie};
use ethtrie::{SecTrieDBMut, TrieDB, TrieDBMut};
use self::trie_standardmap::{Alphabet, StandardMap, ValueMode};
// the proportion of accounts we will alter each tick.
@@ -60,7 +62,7 @@ impl StateProducer {
/// Tick the state producer. This alters the state, writing new data into
/// the database.
pub fn tick<R: Rng>(&mut self, rng: &mut R, db: &mut HashDB) {
pub fn tick<R: Rng>(&mut self, rng: &mut R, db: &mut HashDB<KeccakHasher>) {
// modify existing accounts.
let mut accounts_to_modify: Vec<_> = {
let trie = TrieDB::new(&*db, &self.state_root).unwrap();
@@ -129,7 +131,7 @@ pub fn fill_storage(mut db: AccountDBMut, root: &mut H256, seed: &mut H256) {
}
/// Compare two state dbs.
pub fn compare_dbs(one: &HashDB, two: &HashDB) {
pub fn compare_dbs(one: &HashDB<KeccakHasher>, two: &HashDB<KeccakHasher>) {
let keys = one.keys();
for key in keys.keys() {

View File

@@ -23,10 +23,11 @@ use hash::{KECCAK_EMPTY, KECCAK_NULL_RLP, keccak};
use ethereum_types::{H256, U256, Address};
use error::Error;
use hashdb::HashDB;
use keccak_hasher::KeccakHasher;
use kvdb::DBValue;
use bytes::{Bytes, ToPretty};
use trie;
use trie::{SecTrieDB, Trie, TrieFactory, TrieError};
use trie::{Trie, Recorder};
use ethtrie::{TrieFactory, TrieDB, SecTrieDB, Result as TrieResult};
use pod_account::*;
use rlp::{RlpStream, encode};
use lru_cache::LruCache;
@@ -199,7 +200,7 @@ impl Account {
/// Get (and cache) the contents of the trie's storage at `key`.
/// Takes modified storage into account.
pub fn storage_at(&self, db: &HashDB, key: &H256) -> trie::Result<H256> {
pub fn storage_at(&self, db: &HashDB<KeccakHasher>, key: &H256) -> TrieResult<H256> {
if let Some(value) = self.cached_storage_at(key) {
return Ok(value);
}
@@ -278,7 +279,7 @@ impl Account {
}
/// Provide a database to get `code_hash`. Should not be called if it is a contract without code.
pub fn cache_code(&mut self, db: &HashDB) -> Option<Arc<Bytes>> {
pub fn cache_code(&mut self, db: &HashDB<KeccakHasher>) -> Option<Arc<Bytes>> {
// TODO: fill out self.code_cache;
trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
@@ -307,7 +308,7 @@ impl Account {
}
/// Provide a database to get `code_size`. Should not be called if it is a contract without code.
pub fn cache_code_size(&mut self, db: &HashDB) -> bool {
pub fn cache_code_size(&mut self, db: &HashDB<KeccakHasher>) -> bool {
// TODO: fill out self.code_cache;
trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
self.code_size.is_some() ||
@@ -374,7 +375,7 @@ impl Account {
}
/// Commit the `storage_changes` to the backing DB and update `storage_root`.
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut HashDB) -> trie::Result<()> {
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut HashDB<KeccakHasher>) -> TrieResult<()> {
let mut t = trie_factory.from_existing(db, &mut self.storage_root)?;
for (k, v) in self.storage_changes.drain() {
// cast key and value to trait type,
@@ -390,7 +391,7 @@ impl Account {
}
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
pub fn commit_code(&mut self, db: &mut HashDB) {
pub fn commit_code(&mut self, db: &mut HashDB<KeccakHasher>) {
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_filth == Filth::Dirty, self.code_cache.is_empty());
match (self.code_filth == Filth::Dirty, self.code_cache.is_empty()) {
(true, true) => {
@@ -472,10 +473,7 @@ impl Account {
/// trie.
/// `storage_key` is the hash of the desired storage key, meaning
/// this will only work correctly under a secure trie.
pub fn prove_storage(&self, db: &HashDB, storage_key: H256) -> Result<(Vec<Bytes>, H256), Box<TrieError>> {
use trie::{Trie, TrieDB};
use trie::recorder::Recorder;
pub fn prove_storage(&self, db: &HashDB<KeccakHasher>, storage_key: H256) -> TrieResult<(Vec<Bytes>, H256)> {
let mut recorder = Recorder::new();
let trie = TrieDB::new(db, &self.storage_root)?;

View File

@@ -29,14 +29,15 @@ use parking_lot::Mutex;
use ethereum_types::{Address, H256};
use memorydb::MemoryDB;
use hashdb::{AsHashDB, HashDB, DBValue};
use keccak_hasher::KeccakHasher;
/// State backend. See module docs for more details.
pub trait Backend: Send {
/// Treat the backend as a read-only hashdb.
fn as_hashdb(&self) -> &HashDB;
fn as_hashdb(&self) -> &HashDB<KeccakHasher>;
/// Treat the backend as a writeable hashdb.
fn as_hashdb_mut(&mut self) -> &mut HashDB;
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher>;
/// Add an account entry to the cache.
fn add_to_account_cache(&mut self, addr: Address, data: Option<Account>, modified: bool);
@@ -75,18 +76,18 @@ pub trait Backend: Send {
// TODO: when account lookup moved into backends, this won't rely as tenuously on intended
// usage.
#[derive(Clone, PartialEq)]
pub struct ProofCheck(MemoryDB);
pub struct ProofCheck(MemoryDB<KeccakHasher>);
impl ProofCheck {
/// Create a new `ProofCheck` backend from the given state items.
pub fn new(proof: &[DBValue]) -> Self {
let mut db = MemoryDB::new();
let mut db = MemoryDB::<KeccakHasher>::new();
for item in proof { db.insert(item); }
ProofCheck(db)
}
}
impl HashDB for ProofCheck {
impl HashDB<KeccakHasher> for ProofCheck {
fn keys(&self) -> HashMap<H256, i32> { self.0.keys() }
fn get(&self, key: &H256) -> Option<DBValue> {
self.0.get(key)
@@ -107,9 +108,14 @@ impl HashDB for ProofCheck {
fn remove(&mut self, _key: &H256) { }
}
impl AsHashDB<KeccakHasher> for ProofCheck {
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
}
impl Backend for ProofCheck {
fn as_hashdb(&self) -> &HashDB { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB { self }
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
fn add_to_account_cache(&mut self, _addr: Address, _data: Option<Account>, _modified: bool) {}
fn cache_code(&self, _hash: H256, _code: Arc<Vec<u8>>) {}
fn get_cached_account(&self, _addr: &Address) -> Option<Option<Account>> { None }
@@ -128,13 +134,18 @@ impl Backend for ProofCheck {
/// The proof-of-execution can be extracted with `extract_proof`.
///
/// This doesn't cache anything or rely on the canonical state caches.
pub struct Proving<H: AsHashDB> {
pub struct Proving<H: AsHashDB<KeccakHasher>> {
base: H, // state we're proving values from.
changed: MemoryDB, // changed state via insertions.
changed: MemoryDB<KeccakHasher>, // changed state via insertions.
proof: Mutex<HashSet<DBValue>>,
}
impl<H: AsHashDB + Send + Sync> HashDB for Proving<H> {
impl<AH: AsHashDB<KeccakHasher> + Send + Sync> AsHashDB<KeccakHasher> for Proving<AH> {
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
}
impl<H: AsHashDB<KeccakHasher> + Send + Sync> HashDB<KeccakHasher> for Proving<H> {
fn keys(&self) -> HashMap<H256, i32> {
let mut keys = self.base.as_hashdb().keys();
keys.extend(self.changed.keys());
@@ -171,14 +182,10 @@ impl<H: AsHashDB + Send + Sync> HashDB for Proving<H> {
}
}
impl<H: AsHashDB + Send + Sync> Backend for Proving<H> {
fn as_hashdb(&self) -> &HashDB {
self
}
impl<H: AsHashDB<KeccakHasher> + Send + Sync> Backend for Proving<H> {
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB {
self
}
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> { self }
fn add_to_account_cache(&mut self, _: Address, _: Option<Account>, _: bool) { }
@@ -197,13 +204,13 @@ impl<H: AsHashDB + Send + Sync> Backend for Proving<H> {
fn is_known_null(&self, _: &Address) -> bool { false }
}
impl<H: AsHashDB> Proving<H> {
impl<H: AsHashDB<KeccakHasher>> Proving<H> {
/// Create a new `Proving` over a base database.
/// This will store all values ever fetched from that base.
pub fn new(base: H) -> Self {
Proving {
base: base,
changed: MemoryDB::new(),
changed: MemoryDB::<KeccakHasher>::new(),
proof: Mutex::new(HashSet::new()),
}
}
@@ -215,7 +222,7 @@ impl<H: AsHashDB> Proving<H> {
}
}
impl<H: AsHashDB + Clone> Clone for Proving<H> {
impl<H: AsHashDB<KeccakHasher> + Clone> Clone for Proving<H> {
fn clone(&self) -> Self {
Proving {
base: self.base.clone(),
@@ -229,12 +236,12 @@ impl<H: AsHashDB + Clone> Clone for Proving<H> {
/// it. Doesn't cache anything.
pub struct Basic<H>(pub H);
impl<H: AsHashDB + Send + Sync> Backend for Basic<H> {
fn as_hashdb(&self) -> &HashDB {
impl<H: AsHashDB<KeccakHasher> + Send + Sync> Backend for Basic<H> {
fn as_hashdb(&self) -> &HashDB<KeccakHasher> {
self.0.as_hashdb()
}
fn as_hashdb_mut(&mut self) -> &mut HashDB {
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> {
self.0.as_hashdb_mut()
}

View File

@@ -44,12 +44,12 @@ use factory::VmFactory;
use ethereum_types::{H256, U256, Address};
use hashdb::{HashDB, AsHashDB};
use keccak_hasher::KeccakHasher;
use kvdb::DBValue;
use bytes::Bytes;
use trie;
use trie::{Trie, TrieError, TrieDB};
use trie::recorder::Recorder;
use trie::{Trie, TrieError, Recorder};
use ethtrie::{TrieDB, Result as TrieResult};
mod account;
mod substate;
@@ -225,7 +225,7 @@ pub fn check_proof(
/// Prove a transaction on the given state.
/// Returns `None` when the transacion could not be proved,
/// and a proof otherwise.
pub fn prove_transaction<H: AsHashDB + Send + Sync>(
pub fn prove_transaction<H: AsHashDB<KeccakHasher> + Send + Sync>(
db: H,
root: H256,
transaction: &SignedTransaction,
@@ -336,23 +336,23 @@ pub enum CleanupMode<'a> {
/// Provides subset of `State` methods to query state information
pub trait StateInfo {
/// Get the nonce of account `a`.
fn nonce(&self, a: &Address) -> trie::Result<U256>;
fn nonce(&self, a: &Address) -> TrieResult<U256>;
/// Get the balance of account `a`.
fn balance(&self, a: &Address) -> trie::Result<U256>;
fn balance(&self, a: &Address) -> TrieResult<U256>;
/// Mutate storage of account `address` so that it is `value` for `key`.
fn storage_at(&self, address: &Address, key: &H256) -> trie::Result<H256>;
fn storage_at(&self, address: &Address, key: &H256) -> TrieResult<H256>;
/// Get accounts' code.
fn code(&self, a: &Address) -> trie::Result<Option<Arc<Bytes>>>;
fn code(&self, a: &Address) -> TrieResult<Option<Arc<Bytes>>>;
}
impl<B: Backend> StateInfo for State<B> {
fn nonce(&self, a: &Address) -> trie::Result<U256> { State::nonce(self, a) }
fn balance(&self, a: &Address) -> trie::Result<U256> { State::balance(self, a) }
fn storage_at(&self, address: &Address, key: &H256) -> trie::Result<H256> { State::storage_at(self, address, key) }
fn code(&self, address: &Address) -> trie::Result<Option<Arc<Bytes>>> { State::code(self, address) }
fn nonce(&self, a: &Address) -> TrieResult<U256> { State::nonce(self, a) }
fn balance(&self, a: &Address) -> TrieResult<U256> { State::balance(self, a) }
fn storage_at(&self, address: &Address, key: &H256) -> TrieResult<H256> { State::storage_at(self, address, key) }
fn code(&self, address: &Address) -> TrieResult<Option<Arc<Bytes>>> { State::code(self, address) }
}
const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \
@@ -379,9 +379,9 @@ impl<B: Backend> State<B> {
}
/// Creates new state with existing state root
pub fn from_existing(db: B, root: H256, account_start_nonce: U256, factories: Factories) -> Result<State<B>, TrieError> {
pub fn from_existing(db: B, root: H256, account_start_nonce: U256, factories: Factories) -> TrieResult<State<B>> {
if !db.as_hashdb().contains(&root) {
return Err(TrieError::InvalidStateRoot(root));
return Err(Box::new(TrieError::InvalidStateRoot(root)));
}
let state = State {
@@ -481,7 +481,7 @@ impl<B: Backend> State<B> {
}
/// Destroy the current object and return single account data.
pub fn into_account(self, account: &Address) -> trie::Result<(Option<Arc<Bytes>>, HashMap<H256, H256>)> {
pub fn into_account(self, account: &Address) -> TrieResult<(Option<Arc<Bytes>>, HashMap<H256, H256>)> {
// TODO: deconstruct without cloning.
let account = self.require(account, true)?;
Ok((account.code().clone(), account.storage_changes().clone()))
@@ -504,43 +504,43 @@ impl<B: Backend> State<B> {
}
/// Determine whether an account exists.
pub fn exists(&self, a: &Address) -> trie::Result<bool> {
pub fn exists(&self, a: &Address) -> TrieResult<bool> {
// Bloom filter does not contain empty accounts, so it is important here to
// check if account exists in the database directly before EIP-161 is in effect.
self.ensure_cached(a, RequireCache::None, false, |a| a.is_some())
}
/// Determine whether an account exists and if not empty.
pub fn exists_and_not_null(&self, a: &Address) -> trie::Result<bool> {
pub fn exists_and_not_null(&self, a: &Address) -> TrieResult<bool> {
self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null()))
}
/// Determine whether an account exists and has code or non-zero nonce.
pub fn exists_and_has_code_or_nonce(&self, a: &Address) -> trie::Result<bool> {
pub fn exists_and_has_code_or_nonce(&self, a: &Address) -> TrieResult<bool> {
self.ensure_cached(a, RequireCache::CodeSize, false,
|a| a.map_or(false, |a| a.code_hash() != KECCAK_EMPTY || *a.nonce() != self.account_start_nonce))
}
/// Get the balance of account `a`.
pub fn balance(&self, a: &Address) -> trie::Result<U256> {
pub fn balance(&self, a: &Address) -> TrieResult<U256> {
self.ensure_cached(a, RequireCache::None, true,
|a| a.as_ref().map_or(U256::zero(), |account| *account.balance()))
}
/// Get the nonce of account `a`.
pub fn nonce(&self, a: &Address) -> trie::Result<U256> {
pub fn nonce(&self, a: &Address) -> TrieResult<U256> {
self.ensure_cached(a, RequireCache::None, true,
|a| a.as_ref().map_or(self.account_start_nonce, |account| *account.nonce()))
}
/// Get the storage root of account `a`.
pub fn storage_root(&self, a: &Address) -> trie::Result<Option<H256>> {
pub fn storage_root(&self, a: &Address) -> TrieResult<Option<H256>> {
self.ensure_cached(a, RequireCache::None, true,
|a| a.as_ref().and_then(|account| account.storage_root().cloned()))
}
/// Mutate storage of account `address` so that it is `value` for `key`.
pub fn storage_at(&self, address: &Address, key: &H256) -> trie::Result<H256> {
pub fn storage_at(&self, address: &Address, key: &H256) -> TrieResult<H256> {
// Storage key search and update works like this:
// 1. If there's an entry for the account in the local cache check for the key and return it if found.
// 2. If there's an entry for the account in the global cache check for the key or load it into that account.
@@ -602,25 +602,25 @@ impl<B: Backend> State<B> {
}
/// Get accounts' code.
pub fn code(&self, a: &Address) -> trie::Result<Option<Arc<Bytes>>> {
pub fn code(&self, a: &Address) -> TrieResult<Option<Arc<Bytes>>> {
self.ensure_cached(a, RequireCache::Code, true,
|a| a.as_ref().map_or(None, |a| a.code().clone()))
}
/// Get an account's code hash.
pub fn code_hash(&self, a: &Address) -> trie::Result<H256> {
pub fn code_hash(&self, a: &Address) -> TrieResult<H256> {
self.ensure_cached(a, RequireCache::None, true,
|a| a.as_ref().map_or(KECCAK_EMPTY, |a| a.code_hash()))
}
/// Get accounts' code size.
pub fn code_size(&self, a: &Address) -> trie::Result<Option<usize>> {
pub fn code_size(&self, a: &Address) -> TrieResult<Option<usize>> {
self.ensure_cached(a, RequireCache::CodeSize, true,
|a| a.as_ref().and_then(|a| a.code_size()))
}
/// Add `incr` to the balance of account `a`.
pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) -> trie::Result<()> {
pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) -> TrieResult<()> {
trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a)?);
let is_value_transfer = !incr.is_zero();
if is_value_transfer || (cleanup_mode == CleanupMode::ForceCreate && !self.exists(a)?) {
@@ -635,7 +635,7 @@ impl<B: Backend> State<B> {
}
/// Subtract `decr` from the balance of account `a`.
pub fn sub_balance(&mut self, a: &Address, decr: &U256, cleanup_mode: &mut CleanupMode) -> trie::Result<()> {
pub fn sub_balance(&mut self, a: &Address, decr: &U256, cleanup_mode: &mut CleanupMode) -> TrieResult<()> {
trace!(target: "state", "sub_balance({}, {}): {}", a, decr, self.balance(a)?);
if !decr.is_zero() || !self.exists(a)? {
self.require(a, false)?.sub_balance(decr);
@@ -647,19 +647,19 @@ impl<B: Backend> State<B> {
}
/// Subtracts `by` from the balance of `from` and adds it to that of `to`.
pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256, mut cleanup_mode: CleanupMode) -> trie::Result<()> {
pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256, mut cleanup_mode: CleanupMode) -> TrieResult<()> {
self.sub_balance(from, by, &mut cleanup_mode)?;
self.add_balance(to, by, cleanup_mode)?;
Ok(())
}
/// Increment the nonce of account `a` by 1.
pub fn inc_nonce(&mut self, a: &Address) -> trie::Result<()> {
pub fn inc_nonce(&mut self, a: &Address) -> TrieResult<()> {
self.require(a, false).map(|mut x| x.inc_nonce())
}
/// Mutate storage of account `a` so that it is `value` for `key`.
pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) -> trie::Result<()> {
pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) -> TrieResult<()> {
trace!(target: "state", "set_storage({}:{:x} to {:x})", a, key, value);
if self.storage_at(a, &key)? != value {
self.require(a, false)?.set_storage(key, value)
@@ -670,13 +670,13 @@ impl<B: Backend> State<B> {
/// Initialise the code of account `a` so that it is `code`.
/// NOTE: Account should have been created with `new_contract`.
pub fn init_code(&mut self, a: &Address, code: Bytes) -> trie::Result<()> {
pub fn init_code(&mut self, a: &Address, code: Bytes) -> TrieResult<()> {
self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{})?.init_code(code);
Ok(())
}
/// Reset the code of account `a` so that it is `code`.
pub fn reset_code(&mut self, a: &Address, code: Bytes) -> trie::Result<()> {
pub fn reset_code(&mut self, a: &Address, code: Bytes) -> TrieResult<()> {
self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{})?.reset_code(code);
Ok(())
}
@@ -753,7 +753,7 @@ impl<B: Backend> State<B> {
}
}
fn touch(&mut self, a: &Address) -> trie::Result<()> {
fn touch(&mut self, a: &Address) -> TrieResult<()> {
self.require(a, false)?;
Ok(())
}
@@ -809,7 +809,7 @@ impl<B: Backend> State<B> {
}
/// Remove any touched empty or dust accounts.
pub fn kill_garbage(&mut self, touched: &HashSet<Address>, remove_empty_touched: bool, min_balance: &Option<U256>, kill_contracts: bool) -> trie::Result<()> {
pub fn kill_garbage(&mut self, touched: &HashSet<Address>, remove_empty_touched: bool, min_balance: &Option<U256>, kill_contracts: bool) -> TrieResult<()> {
let to_kill: HashSet<_> = {
self.cache.borrow().iter().filter_map(|(address, ref entry)|
if touched.contains(address) && // Check all touched accounts
@@ -850,7 +850,7 @@ impl<B: Backend> State<B> {
}
/// Populate a PodAccount map from this state, with another state as the account and storage query.
pub fn to_pod_diff<X: Backend>(&mut self, query: &State<X>) -> trie::Result<PodState> {
pub fn to_pod_diff<X: Backend>(&mut self, query: &State<X>) -> TrieResult<PodState> {
assert!(self.checkpoints.borrow().is_empty());
// Merge PodAccount::to_pod for cache of self and `query`.
@@ -858,7 +858,7 @@ impl<B: Backend> State<B> {
.chain(query.cache.borrow().keys().cloned())
.collect::<BTreeSet<_>>();
Ok(PodState::from(all_addresses.into_iter().fold(Ok(BTreeMap::new()), |m: trie::Result<_>, address| {
Ok(PodState::from(all_addresses.into_iter().fold(Ok(BTreeMap::new()), |m: TrieResult<_>, address| {
let mut m = m?;
let account = self.ensure_cached(&address, RequireCache::Code, true, |acc| {
@@ -886,7 +886,7 @@ impl<B: Backend> State<B> {
})?;
if let Some((balance, nonce, storage_keys, code)) = account {
let storage = storage_keys.into_iter().fold(Ok(BTreeMap::new()), |s: trie::Result<_>, key| {
let storage = storage_keys.into_iter().fold(Ok(BTreeMap::new()), |s: TrieResult<_>, key| {
let mut s = s?;
s.insert(key, self.storage_at(&address, &key)?);
@@ -904,14 +904,14 @@ impl<B: Backend> State<B> {
/// Returns a `StateDiff` describing the difference from `orig` to `self`.
/// Consumes self.
pub fn diff_from<X: Backend>(&self, mut orig: State<X>) -> trie::Result<StateDiff> {
pub fn diff_from<X: Backend>(&self, mut orig: State<X>) -> TrieResult<StateDiff> {
let pod_state_post = self.to_pod();
let pod_state_pre = orig.to_pod_diff(self)?;
Ok(pod_state::diff_pod(&pod_state_pre, &pod_state_post))
}
// load required account data from the databases.
fn update_account_cache(require: RequireCache, account: &mut Account, state_db: &B, db: &HashDB) {
fn update_account_cache(require: RequireCache, account: &mut Account, state_db: &B, db: &HashDB<KeccakHasher>) {
if let RequireCache::None = require {
return;
}
@@ -943,7 +943,7 @@ impl<B: Backend> State<B> {
/// Check caches for required data
/// First searches for account in the local, then the shared cache.
/// Populates local cache if nothing found.
fn ensure_cached<F, U>(&self, a: &Address, require: RequireCache, check_null: bool, f: F) -> trie::Result<U>
fn ensure_cached<F, U>(&self, a: &Address, require: RequireCache, check_null: bool, f: F) -> TrieResult<U>
where F: Fn(Option<&Account>) -> U {
// check local cache first
if let Some(ref mut maybe_acc) = self.cache.borrow_mut().get_mut(a) {
@@ -984,13 +984,13 @@ impl<B: Backend> State<B> {
}
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
fn require<'a>(&'a self, a: &Address, require_code: bool) -> trie::Result<RefMut<'a, Account>> {
fn require<'a>(&'a self, a: &Address, require_code: bool) -> TrieResult<RefMut<'a, Account>> {
self.require_or_from(a, require_code, || Account::new_basic(0u8.into(), self.account_start_nonce), |_|{})
}
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
/// If it doesn't exist, make account equal the evaluation of `default`.
fn require_or_from<'a, F, G>(&'a self, a: &Address, require_code: bool, default: F, not_default: G) -> trie::Result<RefMut<'a, Account>>
fn require_or_from<'a, F, G>(&'a self, a: &Address, require_code: bool, default: F, not_default: G) -> TrieResult<RefMut<'a, Account>>
where F: FnOnce() -> Account, G: FnOnce(&mut Account),
{
let contains_key = self.cache.borrow().contains_key(a);
@@ -1037,7 +1037,7 @@ impl<B: Backend> State<B> {
}
/// Replace account code and storage. Creates account if it does not exist.
pub fn patch_account(&self, a: &Address, code: Arc<Bytes>, storage: HashMap<H256, H256>) -> trie::Result<()> {
pub fn patch_account(&self, a: &Address, code: Arc<Bytes>, storage: HashMap<H256, H256>) -> TrieResult<()> {
Ok(self.require(a, false)?.reset_code_and_storage(code, storage))
}
}
@@ -1049,7 +1049,7 @@ impl<B: Backend> State<B> {
/// If the account doesn't exist in the trie, prove that and return defaults.
/// Requires a secure trie to be used for accurate results.
/// `account_key` == keccak(address)
pub fn prove_account(&self, account_key: H256) -> trie::Result<(Vec<Bytes>, BasicAccount)> {
pub fn prove_account(&self, account_key: H256) -> TrieResult<(Vec<Bytes>, BasicAccount)> {
let mut recorder = Recorder::new();
let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?;
let maybe_account: Option<BasicAccount> = {
@@ -1074,7 +1074,7 @@ impl<B: Backend> State<B> {
/// Requires a secure trie to be used for correctness.
/// `account_key` == keccak(address)
/// `storage_key` == keccak(key)
pub fn prove_storage(&self, account_key: H256, storage_key: H256) -> trie::Result<(Vec<Bytes>, H256)> {
pub fn prove_storage(&self, account_key: H256, storage_key: H256) -> TrieResult<(Vec<Bytes>, H256)> {
// TODO: probably could look into cache somehow but it's keyed by
// address, not keccak(address).
let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?;

View File

@@ -16,22 +16,23 @@
//! State database abstraction. For more info, see the doc for `StateDB`
use std::collections::{VecDeque, HashSet};
use std::sync::Arc;
use lru_cache::LruCache;
use memory_cache::MemoryLruCache;
use bloom_journal::{Bloom, BloomJournal};
use byteorder::{LittleEndian, ByteOrder};
use db::COL_ACCOUNT_BLOOM;
use ethereum_types::{H256, Address};
use hash::keccak;
use hashdb::HashDB;
use keccak_hasher::KeccakHasher;
use header::BlockNumber;
use journaldb::JournalDB;
use kvdb::{KeyValueDB, DBTransaction};
use ethereum_types::{H256, Address};
use hashdb::HashDB;
use state::{self, Account};
use header::BlockNumber;
use hash::keccak;
use lru_cache::LruCache;
use memory_cache::MemoryLruCache;
use parking_lot::Mutex;
use state::{self, Account};
use std::collections::{VecDeque, HashSet};
use std::sync::Arc;
use util_error::UtilError;
use bloom_journal::{Bloom, BloomJournal};
use db::COL_ACCOUNT_BLOOM;
use byteorder::{LittleEndian, ByteOrder};
/// Value used to initialize bloom bitmap size.
///
@@ -310,12 +311,12 @@ impl StateDB {
}
/// Conversion method to interpret self as `HashDB` reference
pub fn as_hashdb(&self) -> &HashDB {
pub fn as_hashdb(&self) -> &HashDB<KeccakHasher> {
self.db.as_hashdb()
}
/// Conversion method to interpret self as mutable `HashDB` reference
pub fn as_hashdb_mut(&mut self) -> &mut HashDB {
pub fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> {
self.db.as_hashdb_mut()
}
@@ -410,11 +411,9 @@ impl StateDB {
}
impl state::Backend for StateDB {
fn as_hashdb(&self) -> &HashDB {
self.db.as_hashdb()
}
fn as_hashdb(&self) -> &HashDB<KeccakHasher> { self.db.as_hashdb() }
fn as_hashdb_mut(&mut self) -> &mut HashDB {
fn as_hashdb_mut(&mut self) -> &mut HashDB<KeccakHasher> {
self.db.as_hashdb_mut()
}