From b9b08af518e6e8a4a6a36b3a89695cf7c6208c28 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 18 Jan 2016 13:54:46 +0100 Subject: [PATCH] Use JournalDB instead of OverlayDB. --- src/account.rs | 10 +++++----- src/block.rs | 16 ++++++++-------- src/blockchain.rs | 2 +- src/client.rs | 14 +++++++++----- src/ethereum/ethash.rs | 4 ++-- src/ethereum/mod.rs | 2 +- src/spec.rs | 5 +++-- src/state.rs | 12 ++++++------ util/src/journaldb.rs | 4 ++-- util/src/lib.rs | 1 + util/src/overlaydb.rs | 13 +++++++++---- 11 files changed, 47 insertions(+), 36 deletions(-) diff --git a/src/account.rs b/src/account.rs index 8c36c7cbd..c64e80ed8 100644 --- a/src/account.rs +++ b/src/account.rs @@ -236,7 +236,7 @@ mod tests { #[test] fn storage_at() { - let mut db = OverlayDB::new_temp(); + let mut db = MemoryDB::new_temp(); let rlp = { let mut a = Account::new_contract(U256::from(69u8)); a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64))); @@ -254,7 +254,7 @@ mod tests { #[test] fn note_code() { - let mut db = OverlayDB::new_temp(); + let mut db = MemoryDB::new_temp(); let rlp = { let mut a = Account::new_contract(U256::from(69u8)); @@ -273,7 +273,7 @@ mod tests { #[test] fn commit_storage() { let mut a = Account::new_contract(U256::from(69u8)); - let mut db = OverlayDB::new_temp(); + let mut db = MemoryDB::new_temp(); a.set_storage(x!(0), x!(0x1234)); assert_eq!(a.storage_root(), None); a.commit_storage(&mut db); @@ -283,7 +283,7 @@ mod tests { #[test] fn commit_remove_commit_storage() { let mut a = Account::new_contract(U256::from(69u8)); - let mut db = OverlayDB::new_temp(); + let mut db = MemoryDB::new_temp(); a.set_storage(x!(0), x!(0x1234)); a.commit_storage(&mut db); a.set_storage(x!(1), x!(0x1234)); @@ -296,7 +296,7 @@ mod tests { #[test] fn commit_code() { let mut a = Account::new_contract(U256::from(69u8)); - let mut db = OverlayDB::new_temp(); + let mut db = MemoryDB::new_temp(); a.init_code(vec![0x55, 0x44, 0xffu8]); assert_eq!(a.code_hash(), SHA3_EMPTY); a.commit_code(&mut db); diff --git a/src/block.rs b/src/block.rs index d149d6132..d47fccc26 100644 --- a/src/block.rs +++ b/src/block.rs @@ -103,7 +103,7 @@ pub struct SealedBlock { impl<'x, 'y> OpenBlock<'x, 'y> { /// Create a new OpenBlock ready for transaction pushing. - pub fn new<'a, 'b>(engine: &'a Engine, db: OverlayDB, parent: &Header, last_hashes: &'b LastHashes, author: Address, extra_data: Bytes) -> OpenBlock<'a, 'b> { + pub fn new<'a, 'b>(engine: &'a Engine, db: JournalDB, parent: &Header, last_hashes: &'b LastHashes, author: Address, extra_data: Bytes) -> OpenBlock<'a, 'b> { let mut r = OpenBlock { block: Block::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())), engine: engine, @@ -241,7 +241,7 @@ impl<'x, 'y> ClosedBlock<'x, 'y> { pub fn reopen(self) -> OpenBlock<'x, 'y> { self.open_block } /// Drop this object and return the underlieing database. - pub fn drain(self) -> OverlayDB { self.open_block.block.state.drop().1 } + pub fn drain(self) -> JournalDB { self.open_block.block.state.drop().1 } } impl SealedBlock { @@ -256,7 +256,7 @@ impl SealedBlock { } /// Drop this object and return the underlieing database. - pub fn drain(self) -> OverlayDB { self.block.state.drop().1 } + pub fn drain(self) -> JournalDB { self.block.state.drop().1 } } impl IsBlock for SealedBlock { @@ -264,7 +264,7 @@ impl IsBlock for SealedBlock { } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact<'x, 'y>(block_bytes: &[u8], engine: &'x Engine, db: OverlayDB, parent: &Header, last_hashes: &'y LastHashes) -> Result, Error> { +pub fn enact<'x, 'y>(block_bytes: &[u8], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes) -> Result, Error> { { let header = BlockView::new(block_bytes).header_view(); let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce()); @@ -284,7 +284,7 @@ pub fn enact<'x, 'y>(block_bytes: &[u8], engine: &'x Engine, db: OverlayDB, pare } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards -pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: OverlayDB, parent: &Header, last_hashes: &LastHashes) -> Result { +pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: &LastHashes) -> Result { let header = BlockView::new(block_bytes).header_view(); Ok(try!(try!(enact(block_bytes, engine, db, parent, last_hashes)).seal(header.seal()))) } @@ -294,7 +294,7 @@ fn open_block() { use spec::*; let engine = Spec::new_test().to_engine().unwrap(); let genesis_header = engine.spec().genesis_header(); - let mut db = OverlayDB::new_temp(); + let mut db = JournalDB::new_temp(); engine.spec().ensure_db_good(&mut db); let last_hashes = vec![genesis_header.hash()]; let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); @@ -308,13 +308,13 @@ fn enact_block() { let engine = Spec::new_test().to_engine().unwrap(); let genesis_header = engine.spec().genesis_header(); - let mut db = OverlayDB::new_temp(); + let mut db = JournalDB::new_temp(); engine.spec().ensure_db_good(&mut db); let b = OpenBlock::new(engine.deref(), db, &genesis_header, &vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); - let mut db = OverlayDB::new_temp(); + let mut db = JournalDB::new_temp(); engine.spec().ensure_db_good(&mut db); let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, &vec![genesis_header.hash()]).unwrap(); diff --git a/src/blockchain.rs b/src/blockchain.rs index f08d15057..f19b958c5 100644 --- a/src/blockchain.rs +++ b/src/blockchain.rs @@ -251,7 +251,7 @@ impl BlockChain { /// Ensure that the best block does indeed have a state_root in the state DB. /// If it doesn't, then rewind down until we find one that does and delete data to ensure that /// later blocks will be reimported. - pub fn ensure_good(&mut self, _state: &OverlayDB) { + pub fn ensure_good(&mut self, _state: &JournalDB) { unimplemented!(); } diff --git a/src/client.rs b/src/client.rs index 3ee84ccd7..fe3eee242 100644 --- a/src/client.rs +++ b/src/client.rs @@ -104,10 +104,12 @@ pub trait BlockChainClient : Sync + Send { pub struct Client { chain: Arc>, engine: Arc>, - state_db: OverlayDB, + state_db: JournalDB, queue: BlockQueue, } +const HISTORY: u64 = 1000; + impl Client { /// Create a new client with given spec and DB path. pub fn new(spec: Spec, path: &Path, message_channel: IoChannel ) -> Result { @@ -135,11 +137,12 @@ impl Client { let mut state_path = path.to_path_buf(); state_path.push("state"); let db = DB::open(&opts, state_path.to_str().unwrap()).unwrap(); - let mut state_db = OverlayDB::new(db); + let mut state_db = JournalDB::new(db); let engine = Arc::new(try!(spec.to_engine())); - engine.spec().ensure_db_good(&mut state_db); - state_db.commit().expect("Error commiting genesis state to state DB"); + if engine.spec().ensure_db_good(&mut state_db) { + state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); + } // chain.write().unwrap().ensure_good(&state_db); @@ -196,7 +199,8 @@ impl Client { } self.chain.write().unwrap().insert_block(&bytes); //TODO: err here? - match result.drain().commit() { + let ancient = if header.number() >= HISTORY { Some(header.number() - HISTORY) } else { None }; + match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.read().unwrap().block_hash(n).unwrap()))) { Ok(_) => (), Err(e) => { warn!(target: "client", "State DB commit failed: {:?}", e); diff --git a/src/ethereum/ethash.rs b/src/ethereum/ethash.rs index 99ffc3186..a5a1175fe 100644 --- a/src/ethereum/ethash.rs +++ b/src/ethereum/ethash.rs @@ -211,7 +211,7 @@ fn on_close_block() { use super::*; let engine = new_morden().to_engine().unwrap(); let genesis_header = engine.spec().genesis_header(); - let mut db = OverlayDB::new_temp(); + let mut db = JournalDB::new_temp(); engine.spec().ensure_db_good(&mut db); let last_hashes = vec![genesis_header.hash()]; let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); @@ -224,7 +224,7 @@ fn on_close_block_with_uncle() { use super::*; let engine = new_morden().to_engine().unwrap(); let genesis_header = engine.spec().genesis_header(); - let mut db = OverlayDB::new_temp(); + let mut db = JournalDB::new_temp(); engine.spec().ensure_db_good(&mut db); let last_hashes = vec![genesis_header.hash()]; let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); diff --git a/src/ethereum/mod.rs b/src/ethereum/mod.rs index 603a64e7d..25a804db3 100644 --- a/src/ethereum/mod.rs +++ b/src/ethereum/mod.rs @@ -40,7 +40,7 @@ mod tests { fn ensure_db_good() { let engine = new_morden().to_engine().unwrap(); let genesis_header = engine.spec().genesis_header(); - let mut db = OverlayDB::new_temp(); + let mut db = MemoryDB::new_temp(); engine.spec().ensure_db_good(&mut db); let s = State::from_existing(db.clone(), genesis_header.state_root.clone(), engine.account_start_nonce()); assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64)); diff --git a/src/spec.rs b/src/spec.rs index b174b0e9f..e93b460c8 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -220,7 +220,7 @@ impl FromJson for Spec { impl Spec { /// Ensure that the given state DB has the trie nodes in for the genesis state. - pub fn ensure_db_good(&self, db: &mut HashDB) { + pub fn ensure_db_good(&self, db: &mut HashDB) -> bool { if !db.contains(&self.state_root()) { info!("Populating genesis state..."); let mut root = H256::new(); @@ -232,7 +232,8 @@ impl Spec { } assert!(db.contains(&self.state_root())); info!("Genesis state is ready"); - } + true + } else { false } } /// Create a new Spec from a JSON UTF-8 data resource `data`. diff --git a/src/state.rs b/src/state.rs index a186d6cd6..e325b8d34 100644 --- a/src/state.rs +++ b/src/state.rs @@ -10,7 +10,7 @@ pub type ApplyResult = Result; /// Representation of the entire state of all accounts in the system. #[derive(Clone)] pub struct State { - db: OverlayDB, + db: JournalDB, root: H256, cache: RefCell>>, @@ -19,7 +19,7 @@ pub struct State { impl State { /// Creates new state with empty state root - pub fn new(mut db: OverlayDB, account_start_nonce: U256) -> State { + pub fn new(mut db: JournalDB, account_start_nonce: U256) -> State { let mut root = H256::new(); { // init trie and reset root too null @@ -35,7 +35,7 @@ impl State { } /// Creates new state with existing state root - pub fn from_existing(db: OverlayDB, root: H256, account_start_nonce: U256) -> State { + pub fn from_existing(db: JournalDB, root: H256, account_start_nonce: U256) -> State { { // trie should panic! if root does not exist let _ = SecTrieDB::new(&db, &root); @@ -51,11 +51,11 @@ impl State { /// Create temporary state object pub fn new_temp() -> State { - Self::new(OverlayDB::new_temp(), U256::from(0u8)) + Self::new(JournalDB::new_temp(), U256::from(0u8)) } /// Destroy the current object and return root and database. - pub fn drop(self) -> (H256, OverlayDB) { + pub fn drop(self) -> (H256, JournalDB) { (self.root, self.db) } @@ -65,7 +65,7 @@ impl State { } /// Expose the underlying database; good to use for calling `state.db().commit()`. - pub fn db(&mut self) -> &mut OverlayDB { + pub fn db(&mut self) -> &mut JournalDB { &mut self.db } diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 011d46663..8dd49cda1 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -46,7 +46,7 @@ impl JournalDB { /// Commit all recent insert operations and historical removals from the old era /// to the backing database. - pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, &H256)>) -> Result { + pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { // journal format: // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] @@ -95,7 +95,7 @@ impl JournalDB { &last })) { let rlp = Rlp::new(&rlp_data); - let to_remove: Vec = rlp.val_at(if *canon_id == rlp.val_at(0) {2} else {1}); + let to_remove: Vec = rlp.val_at(if canon_id == rlp.val_at(0) {2} else {1}); for i in to_remove.iter() { self.forward.remove(i); } diff --git a/util/src/lib.rs b/util/src/lib.rs index 34961f1de..204266c54 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -89,6 +89,7 @@ pub use rlp::*; pub use hashdb::*; pub use memorydb::*; pub use overlaydb::*; +pub use journaldb::*; pub use math::*; pub use chainfilter::*; pub use crypto::*; diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index 6330f1e25..3c2286657 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -131,10 +131,15 @@ impl OverlayDB { /// Get the refs and value of the given key. fn put_payload(&self, key: &H256, payload: (Bytes, u32)) { - let mut s = RlpStream::new_list(2); - s.append(&payload.1); - s.append(&payload.0); - self.backing.put(&key.bytes(), &s.out()).expect("Low-level database error. Some issue with your hard disk?"); + if payload.1 > 0 { + let mut s = RlpStream::new_list(2); + s.append(&payload.1); + s.append(&payload.0); + self.backing.put(&key.bytes(), &s.out()).expect("Low-level database error. Some issue with your hard disk?"); + } else { + self.backing.delete(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?"); + } + } }