Don't add empty accounts to bloom (#2753)
This commit is contained in:
parent
68efbe32bf
commit
ae853a7557
@ -29,7 +29,7 @@ use engines::Engine;
|
|||||||
use ids::BlockID;
|
use ids::BlockID;
|
||||||
use views::BlockView;
|
use views::BlockView;
|
||||||
|
|
||||||
use util::{Bytes, Hashable, HashDB, snappy};
|
use util::{Bytes, Hashable, HashDB, snappy, U256, Uint};
|
||||||
use util::memorydb::MemoryDB;
|
use util::memorydb::MemoryDB;
|
||||||
use util::Mutex;
|
use util::Mutex;
|
||||||
use util::hash::{FixedHash, H256};
|
use util::hash::{FixedHash, H256};
|
||||||
@ -44,6 +44,7 @@ use self::block::AbridgedBlock;
|
|||||||
use self::io::SnapshotWriter;
|
use self::io::SnapshotWriter;
|
||||||
|
|
||||||
use super::state_db::StateDB;
|
use super::state_db::StateDB;
|
||||||
|
use super::state::Account as StateAccount;
|
||||||
|
|
||||||
use crossbeam::{scope, ScopedJoinHandle};
|
use crossbeam::{scope, ScopedJoinHandle};
|
||||||
use rand::{Rng, OsRng};
|
use rand::{Rng, OsRng};
|
||||||
@ -409,6 +410,7 @@ impl StateRebuilder {
|
|||||||
/// Feed an uncompressed state chunk into the rebuilder.
|
/// Feed an uncompressed state chunk into the rebuilder.
|
||||||
pub fn feed(&mut self, chunk: &[u8]) -> Result<(), ::error::Error> {
|
pub fn feed(&mut self, chunk: &[u8]) -> Result<(), ::error::Error> {
|
||||||
let rlp = UntrustedRlp::new(chunk);
|
let rlp = UntrustedRlp::new(chunk);
|
||||||
|
let empty_rlp = StateAccount::new_basic(U256::zero(), U256::zero()).rlp();
|
||||||
let account_fat_rlps: Vec<_> = rlp.iter().map(|r| r.as_raw()).collect();
|
let account_fat_rlps: Vec<_> = rlp.iter().map(|r| r.as_raw()).collect();
|
||||||
let mut pairs = Vec::with_capacity(rlp.item_count());
|
let mut pairs = Vec::with_capacity(rlp.item_count());
|
||||||
|
|
||||||
@ -476,7 +478,9 @@ impl StateRebuilder {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (hash, thin_rlp) in pairs {
|
for (hash, thin_rlp) in pairs {
|
||||||
bloom.set(&*hash);
|
if &thin_rlp[..] != &empty_rlp[..] {
|
||||||
|
bloom.set(&*hash);
|
||||||
|
}
|
||||||
try!(account_trie.insert(&hash, &thin_rlp));
|
try!(account_trie.insert(&hash, &thin_rlp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,6 +288,15 @@ impl Account {
|
|||||||
/// Determine whether there are any un-`commit()`-ed storage-setting operations.
|
/// Determine whether there are any un-`commit()`-ed storage-setting operations.
|
||||||
pub fn storage_is_clean(&self) -> bool { self.storage_changes.is_empty() }
|
pub fn storage_is_clean(&self) -> bool { self.storage_changes.is_empty() }
|
||||||
|
|
||||||
|
/// Check if account has zero nonce, balance, no code and no storage.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.storage_changes.is_empty() &&
|
||||||
|
self.balance.is_zero() &&
|
||||||
|
self.nonce.is_zero() &&
|
||||||
|
self.storage_root == SHA3_NULL_RLP &&
|
||||||
|
self.code_hash == SHA3_EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
/// return the storage root associated with this account or None if it has been altered via the overlay.
|
/// return the storage root associated with this account or None if it has been altered via the overlay.
|
||||||
pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} }
|
pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} }
|
||||||
|
@ -340,18 +340,20 @@ impl State {
|
|||||||
|
|
||||||
/// Determine whether an account exists.
|
/// Determine whether an account exists.
|
||||||
pub fn exists(&self, a: &Address) -> bool {
|
pub fn exists(&self, a: &Address) -> bool {
|
||||||
self.ensure_cached(a, RequireCache::None, |a| a.is_some())
|
// Bloom filter does not contain empty accounts, so it is important here to
|
||||||
|
// check if account exists in the database directly before EIP-158 is in effect.
|
||||||
|
self.ensure_cached(a, RequireCache::None, false, |a| a.is_some())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the balance of account `a`.
|
/// Get the balance of account `a`.
|
||||||
pub fn balance(&self, a: &Address) -> U256 {
|
pub fn balance(&self, a: &Address) -> U256 {
|
||||||
self.ensure_cached(a, RequireCache::None,
|
self.ensure_cached(a, RequireCache::None, true,
|
||||||
|a| a.as_ref().map_or(U256::zero(), |account| *account.balance()))
|
|a| a.as_ref().map_or(U256::zero(), |account| *account.balance()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the nonce of account `a`.
|
/// Get the nonce of account `a`.
|
||||||
pub fn nonce(&self, a: &Address) -> U256 {
|
pub fn nonce(&self, a: &Address) -> U256 {
|
||||||
self.ensure_cached(a, RequireCache::None,
|
self.ensure_cached(a, RequireCache::None, true,
|
||||||
|a| a.as_ref().map_or(self.account_start_nonce, |account| *account.nonce()))
|
|a| a.as_ref().map_or(self.account_start_nonce, |account| *account.nonce()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,18 +417,18 @@ impl State {
|
|||||||
|
|
||||||
/// Get accounts' code.
|
/// Get accounts' code.
|
||||||
pub fn code(&self, a: &Address) -> Option<Arc<Bytes>> {
|
pub fn code(&self, a: &Address) -> Option<Arc<Bytes>> {
|
||||||
self.ensure_cached(a, RequireCache::Code,
|
self.ensure_cached(a, RequireCache::Code, true,
|
||||||
|a| a.as_ref().map_or(None, |a| a.code().clone()))
|
|a| a.as_ref().map_or(None, |a| a.code().clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn code_hash(&self, a: &Address) -> H256 {
|
pub fn code_hash(&self, a: &Address) -> H256 {
|
||||||
self.ensure_cached(a, RequireCache::None,
|
self.ensure_cached(a, RequireCache::None, true,
|
||||||
|a| a.as_ref().map_or(SHA3_EMPTY, |a| a.code_hash()))
|
|a| a.as_ref().map_or(SHA3_EMPTY, |a| a.code_hash()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get accounts' code size.
|
/// Get accounts' code size.
|
||||||
pub fn code_size(&self, a: &Address) -> Option<usize> {
|
pub fn code_size(&self, a: &Address) -> Option<usize> {
|
||||||
self.ensure_cached(a, RequireCache::CodeSize,
|
self.ensure_cached(a, RequireCache::CodeSize, true,
|
||||||
|a| a.as_ref().and_then(|a| a.code_size()))
|
|a| a.as_ref().and_then(|a| a.code_size()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,7 +507,9 @@ impl State {
|
|||||||
for (address, ref mut a) in accounts.iter_mut().filter(|&(_, ref a)| a.is_dirty()) {
|
for (address, ref mut a) in accounts.iter_mut().filter(|&(_, ref a)| a.is_dirty()) {
|
||||||
match a.account {
|
match a.account {
|
||||||
Some(ref mut account) => {
|
Some(ref mut account) => {
|
||||||
db.note_account_bloom(&address);
|
if !account.is_empty() {
|
||||||
|
db.note_account_bloom(&address);
|
||||||
|
}
|
||||||
let addr_hash = account.address_hash(address);
|
let addr_hash = account.address_hash(address);
|
||||||
let mut account_db = factories.accountdb.create(db.as_hashdb_mut(), addr_hash);
|
let mut account_db = factories.accountdb.create(db.as_hashdb_mut(), addr_hash);
|
||||||
account.commit_storage(&factories.trie, account_db.as_hashdb_mut());
|
account.commit_storage(&factories.trie, account_db.as_hashdb_mut());
|
||||||
@ -559,7 +563,6 @@ impl State {
|
|||||||
pub fn populate_from(&mut self, accounts: PodState) {
|
pub fn populate_from(&mut self, accounts: PodState) {
|
||||||
assert!(self.snapshots.borrow().is_empty());
|
assert!(self.snapshots.borrow().is_empty());
|
||||||
for (add, acc) in accounts.drain().into_iter() {
|
for (add, acc) in accounts.drain().into_iter() {
|
||||||
self.db.note_account_bloom(&add);
|
|
||||||
self.cache.borrow_mut().insert(add, AccountEntry::new_dirty(Some(Account::from_pod(acc))));
|
self.cache.borrow_mut().insert(add, AccountEntry::new_dirty(Some(Account::from_pod(acc))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -579,7 +582,7 @@ impl State {
|
|||||||
|
|
||||||
fn query_pod(&mut self, query: &PodState) {
|
fn query_pod(&mut self, query: &PodState) {
|
||||||
for (address, pod_account) in query.get().into_iter()
|
for (address, pod_account) in query.get().into_iter()
|
||||||
.filter(|&(ref a, _)| self.ensure_cached(a, RequireCache::Code, |a| a.is_some()))
|
.filter(|&(ref a, _)| self.ensure_cached(a, RequireCache::Code, true, |a| a.is_some()))
|
||||||
{
|
{
|
||||||
// needs to be split into two parts for the refcell code here
|
// needs to be split into two parts for the refcell code here
|
||||||
// to work.
|
// to work.
|
||||||
@ -613,7 +616,7 @@ impl State {
|
|||||||
/// Check caches for required data
|
/// Check caches for required data
|
||||||
/// First searches for account in the local, then the shared cache.
|
/// First searches for account in the local, then the shared cache.
|
||||||
/// Populates local cache if nothing found.
|
/// Populates local cache if nothing found.
|
||||||
fn ensure_cached<F, U>(&self, a: &Address, require: RequireCache, f: F) -> U
|
fn ensure_cached<F, U>(&self, a: &Address, require: RequireCache, check_bloom: bool, f: F) -> U
|
||||||
where F: Fn(Option<&Account>) -> U {
|
where F: Fn(Option<&Account>) -> U {
|
||||||
// check local cache first
|
// check local cache first
|
||||||
if let Some(ref mut maybe_acc) = self.cache.borrow_mut().get_mut(a) {
|
if let Some(ref mut maybe_acc) = self.cache.borrow_mut().get_mut(a) {
|
||||||
@ -636,7 +639,7 @@ impl State {
|
|||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
None => {
|
None => {
|
||||||
// first check bloom if it is not in database for sure
|
// first check bloom if it is not in database for sure
|
||||||
if !self.db.check_account_bloom(a) { return f(None); }
|
if check_bloom && !self.db.check_account_bloom(a) { return f(None); }
|
||||||
|
|
||||||
// not found in the global cache, get from the DB and insert into local
|
// 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);
|
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||||
|
Loading…
Reference in New Issue
Block a user