Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
State cache
Browse files Browse the repository at this point in the history
  • Loading branch information
arkpar committed Sep 25, 2016
1 parent c374164 commit 9d34f8a
Show file tree
Hide file tree
Showing 22 changed files with 360 additions and 96 deletions.
14 changes: 14 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ethcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ ethcore-ipc = { path = "../ipc/rpc" }
ethstore = { path = "../ethstore" }
ethcore-ipc-nano = { path = "../ipc/nano" }
rand = "0.3"
lru-cache = "0.0.7"

[dependencies.hyper]
git = "https://github.com/ethcore/hyper"
Expand Down
51 changes: 47 additions & 4 deletions ethcore/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ pub struct Account {
storage_overlay: RefCell<HashMap<H256, (Filth, H256)>>,
// Code hash of the account. If None, means that it's a contract whose code has not yet been set.
code_hash: Option<H256>,
// Size of the accoun code.
code_size: Option<u64>,
// Code cache of the account.
code_cache: Bytes,
// Account is new or has been modified
Expand All @@ -54,6 +56,7 @@ impl Account {
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()),
code_hash: Some(code.sha3()),
code_size: Some(code.len() as u64),
code_cache: code,
filth: Filth::Dirty,
address_hash: Cell::new(None),
Expand All @@ -68,7 +71,8 @@ impl Account {
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(pod.storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()),
code_hash: pod.code.as_ref().map(|c| c.sha3()),
code_cache: pod.code.as_ref().map_or_else(|| { warn!("POD account with unknown code is being created! Assuming no code."); vec![] }, |c| c.clone()),
code_size: Some(pod.code.as_ref().map_or(0, |c| c.len() as u64)),
code_cache: pod.code.map_or_else(|| { warn!("POD account with unknown code is being created! Assuming no code."); vec![] }, |c| c),
filth: Filth::Dirty,
address_hash: Cell::new(None),
}
Expand All @@ -83,6 +87,7 @@ impl Account {
storage_overlay: RefCell::new(HashMap::new()),
code_hash: Some(SHA3_EMPTY),
code_cache: vec![],
code_size: Some(0),
filth: Filth::Dirty,
address_hash: Cell::new(None),
}
Expand All @@ -98,6 +103,7 @@ impl Account {
storage_overlay: RefCell::new(HashMap::new()),
code_hash: Some(r.val_at(3)),
code_cache: vec![],
code_size: None,
filth: Filth::Clean,
address_hash: Cell::new(None),
}
Expand All @@ -113,6 +119,7 @@ impl Account {
storage_overlay: RefCell::new(HashMap::new()),
code_hash: None,
code_cache: vec![],
code_size: None,
filth: Filth::Dirty,
address_hash: Cell::new(None),
}
Expand All @@ -123,12 +130,14 @@ impl Account {
pub fn init_code(&mut self, code: Bytes) {
assert!(self.code_hash.is_none());
self.code_cache = code;
self.code_size = Some(self.code_cache.len() as u64);
self.filth = Filth::Dirty;
}

/// Reset this account's code to the given code.
pub fn reset_code(&mut self, code: Bytes) {
self.code_hash = None;
self.code_size = Some(0);
self.init_code(code);
}

Expand Down Expand Up @@ -196,13 +205,20 @@ impl Account {
}
}

/// returns the account's code size. If `None` then the code cache or code size cache isn't available -
/// get someone who knows to call `note_code`.
pub fn code_size(&self) -> Option<u64> {
self.code_size.clone()
}

#[cfg(test)]
/// Provide a byte array which hashes to the `code_hash`. returns the hash as a result.
pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> {
let h = code.sha3();
match self.code_hash {
Some(ref i) if h == *i => {
self.code_cache = code;
self.code_size = Some(self.code_cache.len() as u64);
Ok(())
},
_ => Err(h)
Expand Down Expand Up @@ -231,7 +247,29 @@ impl Account {
self.is_cached() ||
match self.code_hash {
Some(ref h) => match db.get(h) {
Some(x) => { self.code_cache = x.to_vec(); true },
Some(x) => {
self.code_cache = x.to_vec();
self.code_size = Some(x.len() as u64);
true },
_ => {
warn!("Failed reverse get of {}", h);
false
},
},
_ => false,
}
}

/// 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: &AccountDB) -> 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() ||
match self.code_hash {
Some(ref h) if h != &SHA3_EMPTY => match db.get(h) {
Some(x) => {
self.code_size = Some(x.len() as u64);
true },
_ => {
warn!("Failed reverse get of {}", h);
false
Expand Down Expand Up @@ -303,9 +341,13 @@ impl Account {
pub fn commit_code(&mut self, db: &mut AccountDBMut) {
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_hash.is_none(), self.code_cache.is_empty());
match (self.code_hash.is_none(), self.code_cache.is_empty()) {
(true, true) => self.code_hash = Some(SHA3_EMPTY),
(true, true) => {
self.code_hash = Some(SHA3_EMPTY);
self.code_size = Some(0);
}
(true, false) => {
self.code_hash = Some(db.insert(&self.code_cache));
self.code_size = Some(self.code_cache.len() as u64);
},
(false, _) => {},
}
Expand All @@ -317,7 +359,7 @@ impl Account {
stream.append(&self.nonce);
stream.append(&self.balance);
stream.append(&self.storage_root);
stream.append(self.code_hash.as_ref().expect("Cannot form RLP of contract account without code."));
stream.append(self.code_hash.as_ref().unwrap_or(&SHA3_EMPTY));
stream.out()
}
}
Expand Down Expand Up @@ -415,6 +457,7 @@ mod tests {
let mut db = AccountDBMut::new(&mut db, &Address::new());
a.init_code(vec![0x55, 0x44, 0xffu8]);
assert_eq!(a.code_hash(), SHA3_EMPTY);
assert_eq!(a.code_size(), Some(3));
a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
}
Expand Down
51 changes: 29 additions & 22 deletions ethcore/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use common::*;
use engines::Engine;
use state::*;
use state_db::StateDB;
use verification::PreverifiedBlock;
use trace::FlatTrace;
use evm::Factory as EvmFactory;
Expand Down Expand Up @@ -178,7 +179,7 @@ pub trait IsBlock {
/// Trait for a object that has a state database.
pub trait Drain {
/// Drop this object and return the underlieing database.
fn drain(self) -> Box<JournalDB>;
fn drain(self) -> StateDB;
}

impl IsBlock for ExecutedBlock {
Expand Down Expand Up @@ -233,7 +234,7 @@ impl<'x> OpenBlock<'x> {
vm_factory: &'x EvmFactory,
trie_factory: TrieFactory,
tracing: bool,
db: Box<JournalDB>,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
author: Address,
Expand Down Expand Up @@ -465,7 +466,10 @@ impl LockedBlock {

impl Drain for LockedBlock {
/// Drop this object and return the underlieing database.
fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
fn drain(mut self) -> StateDB {
self.block.state.commit_cache();
self.block.state.drop().1
}
}

impl SealedBlock {
Expand All @@ -481,7 +485,10 @@ impl SealedBlock {

impl Drain for SealedBlock {
/// Drop this object and return the underlieing database.
fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
fn drain(mut self) -> StateDB {
self.block.state.commit_cache();
self.block.state.drop().1
}
}

impl IsBlock for SealedBlock {
Expand All @@ -496,7 +503,7 @@ pub fn enact(
uncles: &[Header],
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
Expand Down Expand Up @@ -529,7 +536,7 @@ pub fn enact_bytes(
block_bytes: &[u8],
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
Expand All @@ -546,7 +553,7 @@ pub fn enact_verified(
block: &PreverifiedBlock,
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
Expand All @@ -562,7 +569,7 @@ pub fn enact_and_seal(
block_bytes: &[u8],
engine: &Engine,
tracing: bool,
db: Box<JournalDB>,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
Expand All @@ -583,9 +590,9 @@ mod tests {
use spec::*;
let spec = Spec::new_test();
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(&*spec.engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
Expand All @@ -600,26 +607,26 @@ mod tests {
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();

let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let vm_factory = Default::default();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine, vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();

let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();

assert_eq!(e.rlp_bytes(), orig_bytes);

let db = e.drain();
assert_eq!(orig_db.keys(), db.keys());
assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None);
assert_eq!(orig_db.journal_db().keys(), db.journal_db().keys());
assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None);
}

#[test]
Expand All @@ -629,9 +636,9 @@ mod tests {
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();

let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let vm_factory = Default::default();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let mut open_block = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
Expand All @@ -646,9 +653,9 @@ mod tests {
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();

let mut db_result = get_temp_journal_db();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
spec.ensure_db_good(&mut db).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();

let bytes = e.rlp_bytes();
Expand All @@ -657,7 +664,7 @@ mod tests {
assert_eq!(uncles[1].extra_data, b"uncle2");

let db = e.drain();
assert_eq!(orig_db.keys(), db.keys());
assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None);
assert_eq!(orig_db.journal_db().keys(), db.journal_db().keys());
assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None);
}
}
Loading

0 comments on commit 9d34f8a

Please sign in to comment.