From 1fba73c15e0e52d4204c4e37d315562c177e4a03 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 21 Feb 2017 12:35:21 +0100 Subject: [PATCH] minimal state backend trait make state module public --- ethcore/src/block.rs | 12 ++-- ethcore/src/client/client.rs | 6 +- ethcore/src/executive.rs | 14 ++-- ethcore/src/externalities.rs | 22 +++--- ethcore/src/lib.rs | 2 +- ethcore/src/miner/miner.rs | 2 +- ethcore/src/spec/spec.rs | 2 +- ethcore/src/state/backend.rs | 41 ++++++++++- ethcore/src/state/mod.rs | 51 ++++++++------ ethcore/src/state_db.rs | 128 +++++++++++++++++------------------ ethcore/src/tests/helpers.rs | 4 +- 11 files changed, 167 insertions(+), 117 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 9e3e86f62..f2eff0d04 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -91,7 +91,7 @@ pub struct ExecutedBlock { uncles: Vec
, receipts: Vec, transactions_set: HashSet, - state: State, + state: State, traces: Option>>, } @@ -106,7 +106,7 @@ pub struct BlockRefMut<'a> { /// Transaction receipts. pub receipts: &'a [Receipt], /// State. - pub state: &'a mut State, + pub state: &'a mut State, /// Traces. pub traces: &'a Option>>, } @@ -122,14 +122,14 @@ pub struct BlockRef<'a> { /// Transaction receipts. pub receipts: &'a [Receipt], /// State. - pub state: &'a State, + pub state: &'a State, /// Traces. pub traces: &'a Option>>, } impl ExecutedBlock { /// Create a new block from the given `state`. - fn new(state: State, tracing: bool) -> ExecutedBlock { + fn new(state: State, tracing: bool) -> ExecutedBlock { ExecutedBlock { header: Default::default(), transactions: Default::default(), @@ -184,7 +184,7 @@ pub trait IsBlock { fn header(&self) -> &Header { &self.block().header } /// Get the final state associated with this object's block. - fn state(&self) -> &State { &self.block().state } + fn state(&self) -> &State { &self.block().state } /// Get all information on transactions in this block. fn transactions(&self) -> &[SignedTransaction] { &self.block().transactions } @@ -228,7 +228,7 @@ pub struct ClosedBlock { block: ExecutedBlock, uncle_bytes: Bytes, last_hashes: Arc, - unclosed_state: State, + unclosed_state: State, } /// Just like `ClosedBlock` except that we can't reopen it and it's faster. diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 8545db76b..96b25b351 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -656,7 +656,7 @@ impl Client { /// This will not fail if given BlockId::Latest. /// Otherwise, this can fail (but may not) if the DB prunes state or the block /// is unknown. - pub fn state_at(&self, id: BlockId) -> Option { + pub fn state_at(&self, id: BlockId) -> Option> { // fast path for latest state. match id.clone() { BlockId::Pending => return self.miner.pending_state().or_else(|| Some(self.state())), @@ -686,7 +686,7 @@ impl Client { /// /// This will not fail if given BlockId::Latest. /// Otherwise, this can fail (but may not) if the DB prunes state. - pub fn state_at_beginning(&self, id: BlockId) -> Option { + pub fn state_at_beginning(&self, id: BlockId) -> Option> { // fast path for latest state. match id { BlockId::Pending => self.state_at(BlockId::Latest), @@ -698,7 +698,7 @@ impl Client { } /// Get a copy of the best block's state. - pub fn state(&self) -> State { + pub fn state(&self) -> State { let header = self.best_block_header(); State::from_existing( self.state_db.lock().boxed_clone_canon(&header.hash()), diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 3dffc66fa..37b53202a 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -17,7 +17,7 @@ //! Transaction Execution environment. use util::*; use action_params::{ActionParams, ActionValue}; -use state::{State, Substate, CleanupMode}; +use state::{Backend as StateBackend, State, Substate, CleanupMode}; use engines::Engine; use types::executed::CallType; use env_info::EnvInfo; @@ -56,17 +56,17 @@ pub struct TransactOptions { } /// Transaction executor. -pub struct Executive<'a> { - state: &'a mut State, +pub struct Executive<'a, B: 'a + StateBackend> { + state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory, depth: usize, } -impl<'a> Executive<'a> { +impl<'a, B: 'a + StateBackend> Executive<'a, B> { /// Basic constructor. - pub fn new(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory) -> Self { + pub fn new(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory) -> Self { Executive { state: state, info: info, @@ -77,7 +77,7 @@ impl<'a> Executive<'a> { } /// Populates executive from parent properties. Increments executive depth. - pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory, parent_depth: usize) -> Self { + pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory, parent_depth: usize) -> Self { Executive { state: state, info: info, @@ -95,7 +95,7 @@ impl<'a> Executive<'a> { output: OutputPolicy<'any, 'any>, tracer: &'any mut T, vm_tracer: &'any mut V - ) -> Externalities<'any, T, V> where T: Tracer, V: VMTracer { + ) -> Externalities<'any, T, V, B> where T: Tracer, V: VMTracer { Externalities::new(self.state, self.info, self.engine, self.vm_factory, self.depth, origin_info, substate, output, tracer, vm_tracer) } diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index faac16821..49ed2261e 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -17,7 +17,7 @@ //! Transaction Execution environment. use util::*; use action_params::{ActionParams, ActionValue}; -use state::{State, Substate}; +use state::{Backend as StateBackend, State, Substate}; use engines::Engine; use env_info::EnvInfo; use executive::*; @@ -57,8 +57,10 @@ impl OriginInfo { } /// Implementation of evm Externalities. -pub struct Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer { - state: &'a mut State, +pub struct Externalities<'a, T: 'a, V: 'a, B: 'a> + where T: Tracer, V: VMTracer, B: StateBackend +{ + state: &'a mut State, env_info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory, @@ -71,10 +73,12 @@ pub struct Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer { vm_tracer: &'a mut V, } -impl<'a, T, V> Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer { - #[cfg_attr(feature="dev", allow(too_many_arguments))] +impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B> + where T: Tracer, V: VMTracer, B: StateBackend +{ /// Basic `Externalities` constructor. - pub fn new(state: &'a mut State, + #[cfg_attr(feature="dev", allow(too_many_arguments))] + pub fn new(state: &'a mut State, env_info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory, @@ -101,7 +105,9 @@ impl<'a, T, V> Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer { } } -impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer { +impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> + where T: Tracer, V: VMTracer, B: StateBackend +{ fn storage_at(&self, key: &H256) -> H256 { self.state.storage_at(&self.origin_info.address, key) } @@ -346,7 +352,7 @@ mod tests { } struct TestSetup { - state: GuardedTempResult, + state: GuardedTempResult>, engine: Arc, sub_state: Substate, env_info: EnvInfo diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index be5247340..15c5834cd 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -139,6 +139,7 @@ pub mod snapshot; pub mod action_params; pub mod db; pub mod verification; +pub mod state; #[macro_use] pub mod evm; mod cache_manager; @@ -146,7 +147,6 @@ mod blooms; mod basic_types; mod env_info; mod pod_account; -mod state; mod state_db; mod account_db; mod builtin; diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 410123c9a..9cfd4a4a0 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -307,7 +307,7 @@ impl Miner { } /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. - pub fn pending_state(&self) -> Option { + pub fn pending_state(&self) -> Option> { self.sealing_work.lock().queue.peek_last_ref().map(|b| b.block().fields().state.clone()) } diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 0cc32106a..85996d24b 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -24,7 +24,7 @@ use executive::Executive; use trace::{NoopTracer, NoopVMTracer}; use action_params::{ActionValue, ActionParams}; use types::executed::CallType; -use state::{State, Substate}; +use state::{Backend, State, Substate}; use env_info::EnvInfo; use pod_state::*; use account_db::*; diff --git a/ethcore/src/state/backend.rs b/ethcore/src/state/backend.rs index 83adc2e84..81a770fe7 100644 --- a/ethcore/src/state/backend.rs +++ b/ethcore/src/state/backend.rs @@ -24,10 +24,10 @@ use std::sync::Arc; use state::Account; -use util::{Address, HashDB, H256}; +use util::{Address, AsHashDB, HashDB, H256}; /// State backend. See module docs for more details. -pub trait Backend { +pub trait Backend: Send { /// Treat the backend as a read-only hashdb. fn as_hashdb(&self) -> &HashDB; @@ -42,7 +42,7 @@ pub trait Backend { /// hash collisions. fn cache_code(&self, hash: H256, code: Arc>); - /// Get basic copy of the cached account. Does not include storage. + /// Get basic copy of the cached account. Not required to include storage. /// Returns 'None' if cache is disabled or if the account is not cached. fn get_cached_account(&self, addr: &Address) -> Option>; @@ -55,4 +55,39 @@ pub trait Backend { /// Get cached code based on hash. fn get_cached_code(&self, hash: &H256) -> Option>>; + + /// Note that an account with the given address is non-null. + fn note_non_null_account(&self, address: &Address); + + /// Check whether an account is known to be empty. Returns true if known to be + /// empty, false otherwise. + fn is_known_null(&self, address: &Address) -> bool; +} + +/// A raw backend which simply wraps a hashdb and does no caching. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct NoCache(T); + +impl NoCache { + /// Create a new `NoCache` backend. + pub fn new(inner: T) -> Self { NoCache(inner) } + + /// Consume the backend, yielding the inner database. + pub fn into_inner(self) -> T { self.0 } +} + +impl Backend for NoCache { + fn as_hashdb(&self) -> &HashDB { self.0.as_hashdb() } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self.0.as_hashdb_mut() } + fn add_to_account_cache(&mut self, _addr: Address, _data: Option, _modified: bool) {} + fn cache_code(&self, _hash: H256, _code: Arc>) {} + fn get_cached_account(&self, _addr: &Address) -> Option> { None } + fn get_cached(&self, _a: &Address, _f: F) -> Option + where F: FnOnce(Option<&mut Account>) -> U + { + None + } + fn get_cached_code(&self, _hash: &H256) -> Option>> { None } + fn note_non_null_account(&self, _address: &Address) {} + fn is_known_null(&self, _address: &Address) -> bool { false } } diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 45cca6b3c..1d26ea30f 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -14,6 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! A mutable state representation suitable to execute transactions. +//! Generic over a `Backend`. Deals with `Account`s. +//! Unconfirmed sub-states are managed with `checkpoint`s which may be canonicalized +//! or rolled back. + use std::cell::{RefCell, RefMut}; use std::collections::hash_map::Entry; @@ -40,6 +45,7 @@ mod substate; pub mod backend; pub use self::account::Account; +pub use self::backend::Backend; pub use self::substate::Substate; /// Used to return information about an `State::apply` operation. @@ -188,8 +194,8 @@ impl AccountEntry { /// checkpoint can be discateded with `discard_checkpoint`. All of the orignal /// backed-up values are moved into a parent checkpoint (if any). /// -pub struct State { - db: StateDB, +pub struct State { + db: B, root: H256, cache: RefCell>, // The original account is preserved in @@ -205,20 +211,24 @@ enum RequireCache { Code, } +/// Mode of dealing with null accounts. #[derive(PartialEq)] pub enum CleanupMode<'a> { + /// Create accounts which would be null. ForceCreate, + /// Don't delete null accounts upon touching, but also don't create them. NoEmpty, + /// Add encountered null accounts to the provided kill-set, to be deleted later. KillEmpty(&'a mut HashSet
), } 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. \ Therefore creating a SecTrieDB with this state's root will not fail."; -impl State { +impl State { /// Creates new state with empty state root #[cfg(test)] - pub fn new(mut db: StateDB, account_start_nonce: U256, factories: Factories) -> State { + pub fn new(mut db: B, account_start_nonce: U256, factories: Factories) -> State { let mut root = H256::new(); { // init trie and reset root too null @@ -236,7 +246,7 @@ impl State { } /// Creates new state with existing state root - pub fn from_existing(db: StateDB, root: H256, account_start_nonce: U256, factories: Factories) -> Result { + pub fn from_existing(db: B, root: H256, account_start_nonce: U256, factories: Factories) -> Result, TrieError> { if !db.as_hashdb().contains(&root) { return Err(TrieError::InvalidStateRoot(root)); } @@ -330,7 +340,7 @@ impl State { } /// Destroy the current object and return root and database. - pub fn drop(mut self) -> (H256, StateDB) { + pub fn drop(mut self) -> (H256, B) { self.propagate_to_global_cache(); (self.root, self.db) } @@ -422,8 +432,8 @@ impl State { } } - // check bloom before any requests to trie - if !self.db.check_non_null_bloom(address) { return H256::zero() } + // check if the account could exist before any requests to trie + if self.db.is_known_null(address) { return H256::zero() } // account is not found in the global cache, get from the DB and insert into local let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); @@ -445,6 +455,7 @@ impl State { |a| a.as_ref().map_or(None, |a| a.code().clone())) } + /// Get an account's code hash. pub fn code_hash(&self, a: &Address) -> H256 { self.ensure_cached(a, RequireCache::None, true, |a| a.as_ref().map_or(SHA3_EMPTY, |a| a.code_hash())) @@ -538,7 +549,7 @@ impl State { #[cfg_attr(feature="dev", allow(needless_borrow))] fn commit_into( factories: &Factories, - db: &mut StateDB, + db: &mut B, root: &mut H256, accounts: &mut HashMap ) -> Result<(), Error> { @@ -632,7 +643,7 @@ impl State { /// Returns a `StateDiff` describing the difference from `orig` to `self`. /// Consumes self. - pub fn diff_from(&self, orig: State) -> StateDiff { + pub fn diff_from(&self, orig: State) -> StateDiff { let pod_state_post = self.to_pod(); let mut state_pre = orig; state_pre.query_pod(&pod_state_post); @@ -640,7 +651,7 @@ impl State { } // load required account data from the databases. - fn update_account_cache(require: RequireCache, account: &mut Account, state_db: &StateDB, db: &HashDB) { + fn update_account_cache(require: RequireCache, account: &mut Account, state_db: &B, db: &HashDB) { match (account.is_cached(), require) { (true, _) | (false, RequireCache::None) => {} (false, require) => { @@ -670,7 +681,7 @@ impl State { /// 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(&self, a: &Address, require: RequireCache, check_bloom: bool, f: F) -> U + fn ensure_cached(&self, a: &Address, require: RequireCache, check_null: bool, f: F) -> 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) { @@ -692,8 +703,8 @@ impl State { match result { Some(r) => r, None => { - // first check bloom if it is not in database for sure - if check_bloom && !self.db.check_non_null_bloom(a) { return f(None); } + // first check if it is not in database for sure + if check_null && self.db.is_known_null(a) { return f(None); } // not found in the global cache, get from the DB and insert into local let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); @@ -727,7 +738,7 @@ impl State { match self.db.get_cached_account(a) { Some(acc) => self.insert_cache(a, AccountEntry::new_clean_cached(acc)), None => { - let maybe_acc = if self.db.check_non_null_bloom(a) { + let maybe_acc = if !self.db.is_known_null(a) { let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); match db.get_with(a, Account::from_rlp) { Ok(acc) => AccountEntry::new_clean(acc), @@ -769,7 +780,7 @@ impl State { } // LES state proof implementations. -impl State { +impl State { /// Prove an account's existence or nonexistence in the state trie. /// Returns a merkle proof of the account's trie node with all nodes before `from_level` /// omitted or an encountered trie error. @@ -815,14 +826,16 @@ impl State { } } -impl fmt::Debug for State { +impl fmt::Debug for State { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self.cache.borrow()) } } -impl Clone for State { - fn clone(&self) -> State { +// TODO: cloning for `State` shouldn't be possible in general; Remove this and use +// checkpoints where possible. +impl Clone for State { + fn clone(&self) -> State { let cache = { let mut cache: HashMap = HashMap::new(); for (key, val) in self.cache.borrow().iter() { diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs index 38fe26005..85d401099 100644 --- a/ethcore/src/state_db.rs +++ b/ethcore/src/state_db.rs @@ -21,7 +21,7 @@ use util::journaldb::JournalDB; use util::kvdb::KeyValueDB; use util::hash::{H256}; use util::hashdb::HashDB; -use state::Account; +use state::{self, Account}; use header::BlockNumber; use util::{Arc, Address, DBTransaction, UtilError, Mutex, Hashable}; use bloom_journal::{Bloom, BloomJournal}; @@ -166,18 +166,6 @@ impl StateDB { bloom } - pub fn check_non_null_bloom(&self, address: &Address) -> bool { - trace!(target: "account_bloom", "Check account bloom: {:?}", address); - let bloom = self.account_bloom.lock(); - bloom.check(&*address.sha3()) - } - - pub fn note_non_null_account(&self, address: &Address) { - trace!(target: "account_bloom", "Note account bloom: {:?}", address); - let mut bloom = self.account_bloom.lock(); - bloom.set(&*address.sha3()); - } - pub fn commit_bloom(batch: &mut DBTransaction, journal: BloomJournal) -> Result<(), UtilError> { assert!(journal.hash_functions <= 255); batch.put(COL_ACCOUNT_BLOOM, ACCOUNT_BLOOM_HASHCOUNT_KEY, &[journal.hash_functions as u8]); @@ -306,12 +294,10 @@ impl StateDB { } } - /// Returns an interface to HashDB. pub fn as_hashdb(&self) -> &HashDB { self.db.as_hashdb() } - /// Returns an interface to mutable HashDB. pub fn as_hashdb_mut(&mut self) -> &mut HashDB { self.db.as_hashdb_mut() } @@ -366,56 +352,6 @@ impl StateDB { &*self.db } - /// Add a local cache entry. - /// The entry will be propagated to the global cache in `sync_cache`. - /// `modified` indicates that the entry was changed since being read from disk or global cache. - /// `data` can be set to an existing (`Some`), or non-existing account (`None`). - pub fn add_to_account_cache(&mut self, addr: Address, data: Option, modified: bool) { - self.local_cache.push(CacheQueueItem { - address: addr, - account: data, - modified: modified, - }) - } - - /// Add a global code cache entry. This doesn't need to worry about canonicality because - /// it simply maps hashes to raw code and will always be correct in the absence of - /// hash collisions. - pub fn cache_code(&self, hash: H256, code: Arc>) { - let mut cache = self.code_cache.lock(); - - cache.insert(hash, code); - } - - /// Get basic copy of the cached account. Does not include storage. - /// Returns 'None' if cache is disabled or if the account is not cached. - pub fn get_cached_account(&self, addr: &Address) -> Option> { - let mut cache = self.account_cache.lock(); - if !Self::is_allowed(addr, &self.parent_hash, &cache.modifications) { - return None; - } - cache.accounts.get_mut(addr).map(|a| a.as_ref().map(|a| a.clone_basic())) - } - - /// Get cached code based on hash. - #[cfg_attr(feature="dev", allow(map_clone))] - pub fn get_cached_code(&self, hash: &H256) -> Option>> { - let mut cache = self.code_cache.lock(); - - cache.get_mut(hash).map(|code| code.clone()) - } - - /// Get value from a cached account. - /// Returns 'None' if cache is disabled or if the account is not cached. - pub fn get_cached(&self, a: &Address, f: F) -> Option - where F: FnOnce(Option<&mut Account>) -> U { - let mut cache = self.account_cache.lock(); - if !Self::is_allowed(a, &self.parent_hash, &cache.modifications) { - return None; - } - cache.accounts.get_mut(a).map(|c| f(c.as_mut())) - } - /// Query how much memory is set aside for the accounts cache (in bytes). pub fn cache_size(&self) -> usize { self.cache_size @@ -456,11 +392,71 @@ impl StateDB { } } +impl state::Backend for StateDB { + fn as_hashdb(&self) -> &HashDB { + self.db.as_hashdb() + } + + fn as_hashdb_mut(&mut self) -> &mut HashDB { + self.db.as_hashdb_mut() + } + + fn add_to_account_cache(&mut self, addr: Address, data: Option, modified: bool) { + self.local_cache.push(CacheQueueItem { + address: addr, + account: data, + modified: modified, + }) + } + + fn cache_code(&self, hash: H256, code: Arc>) { + let mut cache = self.code_cache.lock(); + + cache.insert(hash, code); + } + + fn get_cached_account(&self, addr: &Address) -> Option> { + let mut cache = self.account_cache.lock(); + if !Self::is_allowed(addr, &self.parent_hash, &cache.modifications) { + return None; + } + cache.accounts.get_mut(addr).map(|a| a.as_ref().map(|a| a.clone_basic())) + } + + #[cfg_attr(feature="dev", allow(map_clone))] + fn get_cached_code(&self, hash: &H256) -> Option>> { + let mut cache = self.code_cache.lock(); + + cache.get_mut(hash).map(|code| code.clone()) + } + + fn get_cached(&self, a: &Address, f: F) -> Option + where F: FnOnce(Option<&mut Account>) -> U { + let mut cache = self.account_cache.lock(); + if !Self::is_allowed(a, &self.parent_hash, &cache.modifications) { + return None; + } + cache.accounts.get_mut(a).map(|c| f(c.as_mut())) + } + + fn note_non_null_account(&self, address: &Address) { + trace!(target: "account_bloom", "Note account bloom: {:?}", address); + let mut bloom = self.account_bloom.lock(); + bloom.set(&*address.sha3()); + } + + fn is_known_null(&self, address: &Address) -> bool { + trace!(target: "account_bloom", "Check account bloom: {:?}", address); + let bloom = self.account_bloom.lock(); + !bloom.check(&*address.sha3()) + } +} + #[cfg(test)] mod tests { use util::{U256, H256, FixedHash, Address, DBTransaction}; use tests::helpers::*; - use state::Account; + use state::{Account, Backend}; use util::log::init_log; #[test] diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index a937f4cf9..8a246e0be 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -349,7 +349,7 @@ pub fn get_temp_state_db() -> GuardedTempResult { } } -pub fn get_temp_state() -> GuardedTempResult { +pub fn get_temp_state() -> GuardedTempResult> { let temp = RandomTempPath::new(); let journal_db = get_temp_state_db_in(temp.as_path()); @@ -365,7 +365,7 @@ pub fn get_temp_state_db_in(path: &Path) -> StateDB { StateDB::new(journal_db, 5 * 1024 * 1024) } -pub fn get_temp_state_in(path: &Path) -> State { +pub fn get_temp_state_in(path: &Path) -> State<::state_db::StateDB> { let journal_db = get_temp_state_db_in(path); State::new(journal_db, U256::from(0), Default::default()) }