journaldb changes (#10929)
* inject_batch && commit_batch are no longer a part of journaldb * get rid of redundant KeyedHashDB trait * journaldb edition 2018 * journaldb trait moved to the lib.rs file * making journaldb more idiomatic * fix parity_bytes reexport * rename parity-util-mem package in Cargo.toml file
This commit is contained in:
parent
72279856cd
commit
46954527e7
@ -21,7 +21,7 @@
|
||||
//! should become general over time to the point where not even a
|
||||
//! merkle trie is strictly necessary.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ethereum_types::{Address, H256};
|
||||
@ -29,7 +29,6 @@ use hash_db::{AsHashDB, EMPTY_PREFIX, HashDB, Prefix};
|
||||
use kvdb::DBValue;
|
||||
use memory_db::{HashKey, MemoryDB};
|
||||
use parking_lot::Mutex;
|
||||
use journaldb::AsKeyedHashDB;
|
||||
use keccak_hasher::KeccakHasher;
|
||||
|
||||
use crate::account::Account;
|
||||
@ -90,10 +89,6 @@ impl ProofCheck {
|
||||
}
|
||||
}
|
||||
|
||||
impl journaldb::KeyedHashDB for ProofCheck {
|
||||
fn keys(&self) -> HashMap<H256, i32> { self.0.keys() }
|
||||
}
|
||||
|
||||
impl HashDB<KeccakHasher, DBValue> for ProofCheck {
|
||||
fn get(&self, key: &H256, prefix: Prefix) -> Option<DBValue> {
|
||||
self.0.get(key, prefix)
|
||||
@ -146,23 +141,11 @@ pub struct Proving<H> {
|
||||
proof: Mutex<HashSet<DBValue>>,
|
||||
}
|
||||
|
||||
impl<AH: AsKeyedHashDB + Send + Sync> AsKeyedHashDB for Proving<AH> {
|
||||
fn as_keyed_hash_db(&self) -> &dyn journaldb::KeyedHashDB { self }
|
||||
}
|
||||
|
||||
impl<AH: AsHashDB<KeccakHasher, DBValue> + Send + Sync> AsHashDB<KeccakHasher, DBValue> for Proving<AH> {
|
||||
fn as_hash_db(&self) -> &dyn HashDB<KeccakHasher, DBValue> { self }
|
||||
fn as_hash_db_mut(&mut self) -> &mut dyn HashDB<KeccakHasher, DBValue> { self }
|
||||
}
|
||||
|
||||
impl<H: AsKeyedHashDB + Send + Sync> journaldb::KeyedHashDB for Proving<H> {
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
let mut keys = self.base.as_keyed_hash_db().keys();
|
||||
keys.extend(self.changed.keys());
|
||||
keys
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: AsHashDB<KeccakHasher, DBValue> + Send + Sync> HashDB<KeccakHasher, DBValue> for Proving<H> {
|
||||
fn get(&self, key: &H256, prefix: Prefix) -> Option<DBValue> {
|
||||
match self.base.as_hash_db().get(key, prefix) {
|
||||
|
@ -4,12 +4,13 @@ version = "0.2.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "A `HashDB` which can manage a short-term journal potentially containing many forks of mutually exclusive actions"
|
||||
license = "GPL3"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
parity-bytes = "0.1"
|
||||
ethereum-types = "0.6.0"
|
||||
hash-db = "0.12.4"
|
||||
parity-util-mem = "0.1"
|
||||
malloc_size_of = { version = "0.1", package = "parity-util-mem" }
|
||||
keccak-hasher = { path = "../keccak-hasher" }
|
||||
kvdb = "0.1"
|
||||
log = "0.4"
|
||||
|
@ -16,20 +16,24 @@
|
||||
|
||||
//! Disk-backed `HashDB` implementation.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
collections::{HashMap, hash_map::Entry},
|
||||
io,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
use ethereum_types::H256;
|
||||
use parity_util_mem::MallocSizeOfExt;
|
||||
use hash_db::{HashDB, Prefix};
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use kvdb::{KeyValueDB, DBTransaction, DBValue};
|
||||
use malloc_size_of::MallocSizeOfExt;
|
||||
use parity_bytes::Bytes;
|
||||
use rlp::{encode, decode};
|
||||
use super::{DB_PREFIX_LEN, LATEST_ERA_KEY, error_key_already_exists, error_negatively_reference_hash};
|
||||
use traits::JournalDB;
|
||||
|
||||
use crate::{
|
||||
DB_PREFIX_LEN, LATEST_ERA_KEY, error_key_already_exists, error_negatively_reference_hash,
|
||||
JournalDB, new_memory_db
|
||||
};
|
||||
|
||||
/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay
|
||||
/// and latent-removal semantics.
|
||||
@ -52,7 +56,7 @@ impl ArchiveDB {
|
||||
.expect("Low-level database error.")
|
||||
.map(|val| decode::<u64>(&val).expect("decoding db value failed"));
|
||||
ArchiveDB {
|
||||
overlay: ::new_memory_db(),
|
||||
overlay: new_memory_db(),
|
||||
backing,
|
||||
latest_era,
|
||||
column,
|
||||
@ -92,28 +96,7 @@ impl HashDB<KeccakHasher, DBValue> for ArchiveDB {
|
||||
}
|
||||
}
|
||||
|
||||
impl ::traits::KeyedHashDB for ArchiveDB {
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
|
||||
.map(|(key, _)| (H256::from_slice(&*key), 1))
|
||||
.collect();
|
||||
|
||||
for (key, refs) in self.overlay.keys() {
|
||||
match ret.entry(key) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() += refs;
|
||||
},
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(refs);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl JournalDB for ArchiveDB {
|
||||
|
||||
fn boxed_clone(&self) -> Box<dyn JournalDB> {
|
||||
Box::new(ArchiveDB {
|
||||
overlay: self.overlay.clone(),
|
||||
@ -200,15 +183,33 @@ impl JournalDB for ArchiveDB {
|
||||
fn consolidate(&mut self, with: super::MemoryDB) {
|
||||
self.overlay.consolidate(with);
|
||||
}
|
||||
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
|
||||
.map(|(key, _)| (H256::from_slice(&*key), 1))
|
||||
.collect();
|
||||
|
||||
for (key, refs) in self.overlay.keys() {
|
||||
match ret.entry(key) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() += refs;
|
||||
},
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(refs);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use keccak::keccak;
|
||||
use keccak_hash::keccak;
|
||||
use hash_db::{HashDB, EMPTY_PREFIX};
|
||||
use super::*;
|
||||
use {kvdb_memorydb, JournalDB};
|
||||
use kvdb_memorydb;
|
||||
use crate::{JournalDB, inject_batch, commit_batch};
|
||||
|
||||
#[test]
|
||||
fn insert_same_in_fork() {
|
||||
@ -216,18 +217,18 @@ mod tests {
|
||||
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
|
||||
|
||||
let x = jdb.insert(EMPTY_PREFIX, b"X");
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
jdb.commit_batch(3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
|
||||
jdb.commit_batch(4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
|
||||
|
||||
jdb.remove(&x, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
|
||||
let x = jdb.insert(EMPTY_PREFIX, b"X");
|
||||
jdb.commit_batch(4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
|
||||
|
||||
jdb.commit_batch(5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
|
||||
jdb.commit_batch(6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
|
||||
commit_batch(&mut jdb, 6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
|
||||
|
||||
assert!(jdb.contains(&x, EMPTY_PREFIX));
|
||||
}
|
||||
@ -237,16 +238,16 @@ mod tests {
|
||||
// history is 3
|
||||
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
|
||||
let h = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.remove(&h, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
}
|
||||
|
||||
@ -255,13 +256,13 @@ mod tests {
|
||||
fn multiple_owed_removal_not_allowed() {
|
||||
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
|
||||
let h = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.remove(&h, EMPTY_PREFIX);
|
||||
jdb.remove(&h, EMPTY_PREFIX);
|
||||
// commit_batch would call journal_under(),
|
||||
// and we don't allow multiple owned removals.
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -271,29 +272,29 @@ mod tests {
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.remove(&baz, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -303,22 +304,22 @@ mod tests {
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
|
||||
@ -328,16 +329,16 @@ mod tests {
|
||||
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
jdb.commit_batch(3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
|
||||
@ -345,16 +346,16 @@ mod tests {
|
||||
fn fork_same_key() {
|
||||
// history is 1
|
||||
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
|
||||
@ -368,21 +369,21 @@ mod tests {
|
||||
// history is 1
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.emplace(bar.clone(), EMPTY_PREFIX, DBValue::from_slice(b"bar"));
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
foo
|
||||
};
|
||||
|
||||
{
|
||||
let mut jdb = ArchiveDB::new(shared_db.clone(), None);
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
let mut jdb = ArchiveDB::new(shared_db, None);
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,24 +395,24 @@ mod tests {
|
||||
let mut jdb = ArchiveDB::new(shared_db.clone(), None);
|
||||
// history is 1
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
|
||||
// foo is ancient history.
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
foo
|
||||
};
|
||||
|
||||
{
|
||||
let mut jdb = ArchiveDB::new(shared_db, None);
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
jdb.commit_batch(5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -423,19 +424,19 @@ mod tests {
|
||||
// history is 1
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
(foo, bar, baz)
|
||||
};
|
||||
|
||||
{
|
||||
let mut jdb = ArchiveDB::new(shared_db, None);
|
||||
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
}
|
||||
@ -447,7 +448,7 @@ mod tests {
|
||||
let key = {
|
||||
let mut jdb = ArchiveDB::new(shared_db.clone(), None);
|
||||
let key = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
key
|
||||
};
|
||||
|
||||
@ -462,11 +463,11 @@ mod tests {
|
||||
fn inject() {
|
||||
let mut jdb = ArchiveDB::new(Arc::new(kvdb_memorydb::create(0)), None);
|
||||
let key = jdb.insert(EMPTY_PREFIX, b"dog");
|
||||
jdb.inject_batch().unwrap();
|
||||
inject_batch(&mut jdb).unwrap();
|
||||
|
||||
assert_eq!(jdb.get(&key, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"dog"));
|
||||
jdb.remove(&key, EMPTY_PREFIX);
|
||||
jdb.inject_batch().unwrap();
|
||||
inject_batch(&mut jdb).unwrap();
|
||||
|
||||
assert!(jdb.get(&key, EMPTY_PREFIX).is_none());
|
||||
}
|
||||
|
@ -17,13 +17,16 @@
|
||||
//! Impls of the `AsHashDB` upcast trait for all different variants of DB
|
||||
use hash_db::{HashDB, AsHashDB};
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use archivedb::ArchiveDB;
|
||||
use earlymergedb::EarlyMergeDB;
|
||||
use overlayrecentdb::OverlayRecentDB;
|
||||
use refcounteddb::RefCountedDB;
|
||||
use overlaydb::OverlayDB;
|
||||
|
||||
use kvdb::DBValue;
|
||||
use crate::{KeyedHashDB, AsKeyedHashDB};
|
||||
|
||||
use crate::{
|
||||
archivedb::ArchiveDB,
|
||||
earlymergedb::EarlyMergeDB,
|
||||
overlayrecentdb::OverlayRecentDB,
|
||||
refcounteddb::RefCountedDB,
|
||||
overlaydb::OverlayDB,
|
||||
};
|
||||
|
||||
impl AsHashDB<KeccakHasher, DBValue> for ArchiveDB {
|
||||
fn as_hash_db(&self) -> &dyn HashDB<KeccakHasher, DBValue> { self }
|
||||
@ -49,23 +52,3 @@ impl AsHashDB<KeccakHasher, DBValue> for OverlayDB {
|
||||
fn as_hash_db(&self) -> &dyn HashDB<KeccakHasher, DBValue> { self }
|
||||
fn as_hash_db_mut(&mut self) -> &mut dyn HashDB<KeccakHasher, DBValue> { self }
|
||||
}
|
||||
|
||||
impl AsKeyedHashDB for ArchiveDB {
|
||||
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB { self }
|
||||
}
|
||||
|
||||
impl AsKeyedHashDB for EarlyMergeDB {
|
||||
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB { self }
|
||||
}
|
||||
|
||||
impl AsKeyedHashDB for OverlayRecentDB {
|
||||
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB { self }
|
||||
}
|
||||
|
||||
impl AsKeyedHashDB for RefCountedDB {
|
||||
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB { self }
|
||||
}
|
||||
|
||||
impl AsKeyedHashDB for OverlayDB {
|
||||
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB { self }
|
||||
}
|
||||
|
@ -16,22 +16,27 @@
|
||||
|
||||
//! Disk-backed `HashDB` implementation.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
collections::{HashMap, hash_map::Entry},
|
||||
io,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
use ethereum_types::H256;
|
||||
use hash_db::{HashDB, Prefix};
|
||||
use parity_util_mem::{MallocSizeOf, allocators::new_malloc_size_ops};
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use kvdb::{KeyValueDB, DBTransaction, DBValue};
|
||||
use log::{trace, warn};
|
||||
use malloc_size_of::{MallocSizeOf, allocators::new_malloc_size_ops};
|
||||
use parity_bytes::Bytes;
|
||||
use parking_lot::RwLock;
|
||||
use rlp::{encode, decode};
|
||||
use super::{DB_PREFIX_LEN, LATEST_ERA_KEY, error_negatively_reference_hash, error_key_already_exists};
|
||||
use super::traits::JournalDB;
|
||||
use util::{DatabaseKey, DatabaseValueView, DatabaseValueRef};
|
||||
|
||||
use crate::{
|
||||
DB_PREFIX_LEN, LATEST_ERA_KEY, error_negatively_reference_hash, error_key_already_exists,
|
||||
JournalDB, new_memory_db,
|
||||
util::{DatabaseKey, DatabaseValueView, DatabaseValueRef},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, MallocSizeOf)]
|
||||
struct RefInfo {
|
||||
@ -115,7 +120,7 @@ impl EarlyMergeDB {
|
||||
let (latest_era, refs) = EarlyMergeDB::read_refs(&*backing, col);
|
||||
let refs = Some(Arc::new(RwLock::new(refs)));
|
||||
EarlyMergeDB {
|
||||
overlay: ::new_memory_db(),
|
||||
overlay: new_memory_db(),
|
||||
backing: backing,
|
||||
refs: refs,
|
||||
latest_era: latest_era,
|
||||
@ -311,26 +316,6 @@ impl HashDB<KeccakHasher, DBValue> for EarlyMergeDB {
|
||||
}
|
||||
}
|
||||
|
||||
impl ::traits::KeyedHashDB for EarlyMergeDB {
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
|
||||
.map(|(key, _)| (H256::from_slice(&*key), 1))
|
||||
.collect();
|
||||
|
||||
for (key, refs) in self.overlay.keys() {
|
||||
match ret.entry(key) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() += refs;
|
||||
},
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(refs);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl JournalDB for EarlyMergeDB {
|
||||
fn boxed_clone(&self) -> Box<dyn JournalDB> {
|
||||
Box::new(EarlyMergeDB {
|
||||
@ -519,16 +504,33 @@ impl JournalDB for EarlyMergeDB {
|
||||
fn consolidate(&mut self, with: super::MemoryDB) {
|
||||
self.overlay.consolidate(with);
|
||||
}
|
||||
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
|
||||
.map(|(key, _)| (H256::from_slice(&*key), 1))
|
||||
.collect();
|
||||
|
||||
for (key, refs) in self.overlay.keys() {
|
||||
match ret.entry(key) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() += refs;
|
||||
},
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(refs);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use keccak::keccak;
|
||||
use keccak_hash::keccak;
|
||||
use hash_db::{HashDB, EMPTY_PREFIX};
|
||||
use super::*;
|
||||
use super::super::traits::JournalDB;
|
||||
use kvdb_memorydb;
|
||||
use crate::{inject_batch, commit_batch};
|
||||
|
||||
#[test]
|
||||
fn insert_same_in_fork() {
|
||||
@ -536,25 +538,25 @@ mod tests {
|
||||
let mut jdb = new_db();
|
||||
|
||||
let x = jdb.insert(EMPTY_PREFIX, b"X");
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&x, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
let x = jdb.insert(EMPTY_PREFIX, b"X");
|
||||
jdb.commit_batch(4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.commit_batch(5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
|
||||
commit_batch(&mut jdb, 6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
assert!(jdb.contains(&x, EMPTY_PREFIX));
|
||||
@ -564,17 +566,17 @@ mod tests {
|
||||
fn insert_older_era() {
|
||||
let mut jdb = new_db();
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0a"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0a"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0a")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
jdb.commit_batch(0, &keccak(b"0b"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0b"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
@ -585,20 +587,20 @@ mod tests {
|
||||
// history is 3
|
||||
let mut jdb = new_db();
|
||||
let h = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.remove(&h, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(!jdb.contains(&h, EMPTY_PREFIX));
|
||||
}
|
||||
@ -610,7 +612,7 @@ mod tests {
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
@ -618,7 +620,7 @@ mod tests {
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
@ -626,20 +628,20 @@ mod tests {
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.remove(&baz, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
|
||||
@ -653,25 +655,25 @@ mod tests {
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
|
||||
@ -684,19 +686,19 @@ mod tests {
|
||||
let mut jdb = new_db();
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
jdb.commit_batch(3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -705,24 +707,24 @@ mod tests {
|
||||
fn fork_same_key_one() {
|
||||
|
||||
let mut jdb = new_db();
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -730,24 +732,24 @@ mod tests {
|
||||
#[test]
|
||||
fn fork_same_key_other() {
|
||||
let mut jdb = new_db();
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -755,33 +757,33 @@ mod tests {
|
||||
#[test]
|
||||
fn fork_ins_del_ins() {
|
||||
let mut jdb = new_db();
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(3, &keccak(b"3a"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3a"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(3, &keccak(b"3b"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3b"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.commit_batch(4, &keccak(b"4a"), Some((2, keccak(b"2a")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4a"), Some((2, keccak(b"2a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.commit_batch(5, &keccak(b"5a"), Some((3, keccak(b"3a")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5a"), Some((3, keccak(b"3a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
}
|
||||
|
||||
@ -800,7 +802,7 @@ mod tests {
|
||||
// history is 1
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.emplace(bar.clone(), EMPTY_PREFIX, DBValue::from_slice(b"bar"));
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
foo
|
||||
};
|
||||
@ -808,7 +810,7 @@ mod tests {
|
||||
{
|
||||
let mut jdb = EarlyMergeDB::new(shared_db.clone(), None);
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
}
|
||||
|
||||
@ -816,7 +818,7 @@ mod tests {
|
||||
let mut jdb = EarlyMergeDB::new(shared_db, None);
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -830,22 +832,22 @@ mod tests {
|
||||
|
||||
// history is 4
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"3"), None).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
// expunge foo
|
||||
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
}
|
||||
|
||||
@ -856,43 +858,43 @@ mod tests {
|
||||
|
||||
// history is 4
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1a"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1b"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(2, &keccak(b"2a"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2a"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(2, &keccak(b"2b"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"3a"), None).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3a"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"3b"), None).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3b"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(4, &keccak(b"4a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(4, &keccak(b"4b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
// expunge foo
|
||||
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1a")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
}
|
||||
|
||||
@ -902,25 +904,25 @@ mod tests {
|
||||
|
||||
// history is 1
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
// foo is ancient history.
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap(); // BROKEN
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap(); // BROKEN
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.commit_batch(5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -931,30 +933,30 @@ mod tests {
|
||||
|
||||
// history is 4
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(3, &keccak(b"3"), None).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
// foo is ancient history.
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
jdb.commit_batch(6, &keccak(b"6"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 6, &keccak(b"6"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(7, &keccak(b"7"), Some((3, keccak(b"3")))).unwrap();
|
||||
commit_batch(&mut jdb, 7, &keccak(b"7"), Some((3, keccak(b"3")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
}
|
||||
|
||||
@ -969,20 +971,20 @@ mod tests {
|
||||
let mut jdb = EarlyMergeDB::new(shared_db.clone(), None);
|
||||
// history is 1
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
// foo is ancient history.
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
@ -991,7 +993,7 @@ mod tests {
|
||||
let mut jdb = EarlyMergeDB::new(shared_db.clone(), None);
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
@ -999,7 +1001,7 @@ mod tests {
|
||||
}; {
|
||||
let mut jdb = EarlyMergeDB::new(shared_db.clone(), None);
|
||||
|
||||
jdb.commit_batch(5, &keccak(b"5"), Some((3, keccak(b"3")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((3, keccak(b"3")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
@ -1007,7 +1009,7 @@ mod tests {
|
||||
}; {
|
||||
let mut jdb = EarlyMergeDB::new(shared_db, None);
|
||||
|
||||
jdb.commit_batch(6, &keccak(b"6"), Some((4, keccak(b"4")))).unwrap();
|
||||
commit_batch(&mut jdb, 6, &keccak(b"6"), Some((4, keccak(b"4")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -1022,22 +1024,22 @@ mod tests {
|
||||
// history is 1
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
(foo, bar, baz)
|
||||
};
|
||||
|
||||
{
|
||||
let mut jdb = EarlyMergeDB::new(shared_db, None);
|
||||
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
|
||||
@ -1049,11 +1051,11 @@ mod tests {
|
||||
fn inject() {
|
||||
let mut jdb = new_db();
|
||||
let key = jdb.insert(EMPTY_PREFIX, b"dog");
|
||||
jdb.inject_batch().unwrap();
|
||||
inject_batch(&mut jdb).unwrap();
|
||||
|
||||
assert_eq!(jdb.get(&key, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"dog"));
|
||||
jdb.remove(&key, EMPTY_PREFIX);
|
||||
jdb.inject_batch().unwrap();
|
||||
inject_batch(&mut jdb).unwrap();
|
||||
|
||||
assert!(jdb.get(&key, EMPTY_PREFIX).is_none());
|
||||
}
|
||||
|
@ -16,51 +16,84 @@
|
||||
|
||||
//! `JournalDB` interface and implementation.
|
||||
|
||||
extern crate parity_util_mem;
|
||||
extern crate parity_util_mem as mem;
|
||||
extern crate parity_util_mem as malloc_size_of;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
use std::{
|
||||
fmt, str, io,
|
||||
sync::Arc,
|
||||
collections::HashMap,
|
||||
};
|
||||
|
||||
extern crate ethereum_types;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate hash_db;
|
||||
extern crate keccak_hasher;
|
||||
extern crate kvdb;
|
||||
extern crate memory_db;
|
||||
extern crate parking_lot;
|
||||
extern crate fastmap;
|
||||
extern crate rlp;
|
||||
use ethereum_types::H256;
|
||||
use hash_db::HashDB;
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use kvdb::{self, DBTransaction, DBValue};
|
||||
use parity_bytes::Bytes;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate env_logger;
|
||||
#[cfg(test)]
|
||||
extern crate keccak_hash as keccak;
|
||||
#[cfg(test)]
|
||||
extern crate kvdb_memorydb;
|
||||
|
||||
use std::{fmt, str, io};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Export the journaldb module.
|
||||
mod traits;
|
||||
mod archivedb;
|
||||
mod earlymergedb;
|
||||
mod overlayrecentdb;
|
||||
mod refcounteddb;
|
||||
mod util;
|
||||
mod as_hash_db_impls;
|
||||
mod overlaydb;
|
||||
|
||||
pub mod overlaydb;
|
||||
/// A `HashDB` which can manage a short-term journal potentially containing many forks of mutually
|
||||
/// exclusive actions.
|
||||
pub trait JournalDB: HashDB<KeccakHasher, DBValue> {
|
||||
/// Return a copy of ourself, in a box.
|
||||
fn boxed_clone(&self) -> Box<dyn JournalDB>;
|
||||
|
||||
/// Export the `JournalDB` trait.
|
||||
pub use self::traits::JournalDB;
|
||||
/// Returns heap memory size used
|
||||
fn mem_used(&self) -> usize;
|
||||
|
||||
/// Export keyed hash trait
|
||||
pub use self::traits::KeyedHashDB;
|
||||
/// Export as keyed hash trait
|
||||
pub use self::traits::AsKeyedHashDB;
|
||||
/// Returns the size of journalled state in memory.
|
||||
/// This function has a considerable speed requirement --
|
||||
/// it must be fast enough to call several times per block imported.
|
||||
fn journal_size(&self) -> usize { 0 }
|
||||
|
||||
/// Check if this database has any commits
|
||||
fn is_empty(&self) -> bool;
|
||||
|
||||
/// Get the earliest era in the DB. None if there isn't yet any data in there.
|
||||
fn earliest_era(&self) -> Option<u64> { None }
|
||||
|
||||
/// Get the latest era in the DB. None if there isn't yet any data in there.
|
||||
fn latest_era(&self) -> Option<u64>;
|
||||
|
||||
/// Journal recent database operations as being associated with a given era and id.
|
||||
// TODO: give the overlay to this function so journaldbs don't manage the overlays themselves.
|
||||
fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> io::Result<u32>;
|
||||
|
||||
/// Mark a given block as canonical, indicating that competing blocks' states may be pruned out.
|
||||
fn mark_canonical(&mut self, batch: &mut DBTransaction, era: u64, id: &H256) -> io::Result<u32>;
|
||||
|
||||
/// Commit all queued insert and delete operations without affecting any journalling -- this requires that all insertions
|
||||
/// and deletions are indeed canonical and will likely lead to an invalid database if that assumption is violated.
|
||||
///
|
||||
/// Any keys or values inserted or deleted must be completely independent of those affected
|
||||
/// by any previous `commit` operations. Essentially, this means that `inject` can be used
|
||||
/// either to restore a state to a fresh database, or to insert data which may only be journalled
|
||||
/// from this point onwards.
|
||||
fn inject(&mut self, batch: &mut DBTransaction) -> io::Result<u32>;
|
||||
|
||||
/// State data query
|
||||
fn state(&self, _id: &H256) -> Option<Bytes>;
|
||||
|
||||
/// Whether this database is pruned.
|
||||
fn is_prunable(&self) -> bool { true }
|
||||
|
||||
/// Get backing database.
|
||||
fn backing(&self) -> &Arc<dyn kvdb::KeyValueDB>;
|
||||
|
||||
/// Clear internal strucutres. This should called after changes have been written
|
||||
/// to the backing strage
|
||||
fn flush(&self) {}
|
||||
|
||||
/// Consolidate all the insertions and deletions in the given memory overlay.
|
||||
fn consolidate(&mut self, overlay: MemoryDB);
|
||||
|
||||
/// Primarily use for tests, highly inefficient.
|
||||
fn keys(&self) -> HashMap<H256, i32>;
|
||||
}
|
||||
|
||||
/// Alias to ethereum MemoryDB
|
||||
type MemoryDB = memory_db::MemoryDB<
|
||||
@ -177,6 +210,29 @@ pub fn new_memory_db() -> MemoryDB {
|
||||
MemoryDB::from_null_node(&rlp::NULL_RLP, rlp::NULL_RLP.as_ref().into())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// Inject all changes in a single batch.
|
||||
pub fn inject_batch(jdb: &mut dyn JournalDB) -> io::Result<u32> {
|
||||
let mut batch = jdb.backing().transaction();
|
||||
let res = jdb.inject(&mut batch)?;
|
||||
jdb.backing().write(batch).map(|_| res).map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Commit all changes in a single batch
|
||||
#[cfg(test)]
|
||||
fn commit_batch(jdb: &mut dyn JournalDB, now: u64, id: &H256, end: Option<(u64, H256)>) -> io::Result<u32> {
|
||||
let mut batch = jdb.backing().transaction();
|
||||
let mut ops = jdb.journal_under(&mut batch, now, id)?;
|
||||
|
||||
if let Some((end_era, canon_id)) = end {
|
||||
ops += jdb.mark_canonical(&mut batch, end_era, &canon_id)?;
|
||||
}
|
||||
|
||||
let result = jdb.backing().write(batch).map(|_| ops).map_err(Into::into);
|
||||
jdb.flush();
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Algorithm;
|
||||
|
@ -16,17 +16,20 @@
|
||||
|
||||
//! Disk-backed `HashDB` implementation.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
collections::{HashMap, hash_map::Entry},
|
||||
io,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use ethereum_types::H256;
|
||||
use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable, encode, decode};
|
||||
use hash_db::{HashDB, Prefix, EMPTY_PREFIX};
|
||||
use hash_db::{HashDB, Prefix};
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use kvdb::{KeyValueDB, DBTransaction, DBValue};
|
||||
use super::{error_negatively_reference_hash};
|
||||
use log::trace;
|
||||
use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable, encode, decode};
|
||||
|
||||
use crate::{error_negatively_reference_hash, new_memory_db};
|
||||
|
||||
/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay.
|
||||
///
|
||||
@ -78,8 +81,12 @@ impl Decodable for Payload {
|
||||
|
||||
impl OverlayDB {
|
||||
/// Create a new instance of OverlayDB given a `backing` database.
|
||||
pub fn new(backing: Arc<dyn KeyValueDB>, col: Option<u32>) -> OverlayDB {
|
||||
OverlayDB{ overlay: ::new_memory_db(), backing: backing, column: col }
|
||||
pub fn new(backing: Arc<dyn KeyValueDB>, column: Option<u32>) -> OverlayDB {
|
||||
OverlayDB {
|
||||
overlay: new_memory_db(),
|
||||
backing,
|
||||
column,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new instance of OverlayDB with an anonymous temporary database.
|
||||
@ -128,13 +135,6 @@ impl OverlayDB {
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Revert all operations on this object (i.e. `insert()`s and `remove()`s) since the
|
||||
/// last `commit()`.
|
||||
pub fn revert(&mut self) { self.overlay.clear(); }
|
||||
|
||||
/// Get the number of references that would be committed.
|
||||
pub fn commit_refs(&self, key: &H256) -> i32 { self.overlay.raw(key, EMPTY_PREFIX).map_or(0, |(_, refs)| refs) }
|
||||
|
||||
/// Get the refs and value of the given key.
|
||||
fn payload(&self, key: &H256) -> Option<Payload> {
|
||||
self.backing.get(self.column, key.as_bytes())
|
||||
@ -153,10 +153,7 @@ impl OverlayDB {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl crate::KeyedHashDB for OverlayDB {
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
pub fn keys(&self) -> HashMap<H256, i32> {
|
||||
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
|
||||
.map(|(key, _)| {
|
||||
let h = H256::from_slice(&*key);
|
||||
@ -177,7 +174,6 @@ impl crate::KeyedHashDB for OverlayDB {
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl HashDB<KeccakHasher, DBValue> for OverlayDB {
|
||||
@ -233,106 +229,103 @@ impl HashDB<KeccakHasher, DBValue> for OverlayDB {
|
||||
fn remove(&mut self, key: &H256, prefix: Prefix) { self.overlay.remove(key, prefix); }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlaydb_revert() {
|
||||
let mut m = OverlayDB::new_temp();
|
||||
let foo = m.insert(EMPTY_PREFIX, b"foo"); // insert foo.
|
||||
let mut batch = m.backing.transaction();
|
||||
m.commit_to_batch(&mut batch).unwrap(); // commit - new operations begin here...
|
||||
m.backing.write(batch).unwrap();
|
||||
let bar = m.insert(EMPTY_PREFIX, b"bar"); // insert bar.
|
||||
m.remove(&foo, EMPTY_PREFIX); // remove foo.
|
||||
assert!(!m.contains(&foo, EMPTY_PREFIX)); // foo is gone.
|
||||
assert!(m.contains(&bar, EMPTY_PREFIX)); // bar is here.
|
||||
m.revert(); // revert the last two operations.
|
||||
assert!(m.contains(&foo, EMPTY_PREFIX)); // foo is here.
|
||||
assert!(!m.contains(&bar, EMPTY_PREFIX)); // bar is gone.
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hash_db::EMPTY_PREFIX;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn overlaydb_overlay_insert_and_remove() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let h = trie.insert(EMPTY_PREFIX, b"hello world");
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
|
||||
trie.remove(&h, EMPTY_PREFIX);
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
|
||||
}
|
||||
#[test]
|
||||
fn overlaydb_revert() {
|
||||
let mut m = OverlayDB::new_temp();
|
||||
let foo = m.insert(EMPTY_PREFIX, b"foo"); // insert foo.
|
||||
let mut batch = m.backing.transaction();
|
||||
m.commit_to_batch(&mut batch).unwrap(); // commit - new operations begin here...
|
||||
m.backing.write(batch).unwrap();
|
||||
let bar = m.insert(EMPTY_PREFIX, b"bar"); // insert bar.
|
||||
m.remove(&foo, EMPTY_PREFIX); // remove foo.
|
||||
assert!(!m.contains(&foo, EMPTY_PREFIX)); // foo is gone.
|
||||
assert!(m.contains(&bar, EMPTY_PREFIX)); // bar is here.
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlaydb_backing_insert_revert() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let h = trie.insert(EMPTY_PREFIX, b"hello world");
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
|
||||
trie.revert();
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
|
||||
}
|
||||
#[test]
|
||||
fn overlaydb_overlay_insert_and_remove() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let h = trie.insert(EMPTY_PREFIX, b"hello world");
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
|
||||
trie.remove(&h, EMPTY_PREFIX);
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlaydb_backing_remove() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let h = trie.insert(EMPTY_PREFIX, b"hello world");
|
||||
trie.commit().unwrap();
|
||||
trie.remove(&h, EMPTY_PREFIX);
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
|
||||
trie.revert();
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
|
||||
}
|
||||
#[test]
|
||||
fn overlaydb_backing_insert_revert() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let h = trie.insert(EMPTY_PREFIX, b"hello world");
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlaydb_backing_remove_revert() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let h = trie.insert(EMPTY_PREFIX, b"hello world");
|
||||
trie.commit().unwrap();
|
||||
trie.remove(&h, EMPTY_PREFIX);
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
|
||||
trie.revert();
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"hello world"));
|
||||
}
|
||||
#[test]
|
||||
fn overlaydb_backing_remove() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let h = trie.insert(EMPTY_PREFIX, b"hello world");
|
||||
trie.commit().unwrap();
|
||||
trie.remove(&h, EMPTY_PREFIX);
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlaydb_negative() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let h = trie.insert(EMPTY_PREFIX, b"hello world");
|
||||
trie.commit().unwrap();
|
||||
trie.remove(&h, EMPTY_PREFIX);
|
||||
trie.remove(&h, EMPTY_PREFIX); //bad - sends us into negative refs.
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
|
||||
assert!(trie.commit().is_err());
|
||||
}
|
||||
#[test]
|
||||
fn overlaydb_backing_remove_revert() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let h = trie.insert(EMPTY_PREFIX, b"hello world");
|
||||
trie.commit().unwrap();
|
||||
trie.remove(&h, EMPTY_PREFIX);
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlaydb_complex() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let hfoo = trie.insert(EMPTY_PREFIX, b"foo");
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
let hbar = trie.insert(EMPTY_PREFIX, b"bar");
|
||||
assert_eq!(trie.get(&hbar, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"bar"));
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
assert_eq!(trie.get(&hbar, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"bar"));
|
||||
trie.insert(EMPTY_PREFIX, b"foo"); // two refs
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
assert_eq!(trie.get(&hbar, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"bar"));
|
||||
trie.remove(&hbar, EMPTY_PREFIX); // zero refs - delete
|
||||
assert_eq!(trie.get(&hbar, EMPTY_PREFIX), None);
|
||||
trie.remove(&hfoo, EMPTY_PREFIX); // one ref - keep
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
trie.remove(&hfoo, EMPTY_PREFIX); // zero ref - would delete, but...
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX), None);
|
||||
trie.insert(EMPTY_PREFIX, b"foo"); // one ref - keep after all.
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
trie.remove(&hfoo, EMPTY_PREFIX); // zero ref - delete
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX), None);
|
||||
trie.commit().unwrap(); //
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX), None);
|
||||
#[test]
|
||||
fn overlaydb_negative() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let h = trie.insert(EMPTY_PREFIX, b"hello world");
|
||||
trie.commit().unwrap();
|
||||
trie.remove(&h, EMPTY_PREFIX);
|
||||
trie.remove(&h, EMPTY_PREFIX); //bad - sends us into negative refs.
|
||||
assert_eq!(trie.get(&h, EMPTY_PREFIX), None);
|
||||
assert!(trie.commit().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlaydb_complex() {
|
||||
let mut trie = OverlayDB::new_temp();
|
||||
let hfoo = trie.insert(EMPTY_PREFIX, b"foo");
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
let hbar = trie.insert(EMPTY_PREFIX, b"bar");
|
||||
assert_eq!(trie.get(&hbar, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"bar"));
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
assert_eq!(trie.get(&hbar, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"bar"));
|
||||
trie.insert(EMPTY_PREFIX, b"foo"); // two refs
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
assert_eq!(trie.get(&hbar, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"bar"));
|
||||
trie.remove(&hbar, EMPTY_PREFIX); // zero refs - delete
|
||||
assert_eq!(trie.get(&hbar, EMPTY_PREFIX), None);
|
||||
trie.remove(&hfoo, EMPTY_PREFIX); // one ref - keep
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
trie.remove(&hfoo, EMPTY_PREFIX); // zero ref - would delete, but...
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX), None);
|
||||
trie.insert(EMPTY_PREFIX, b"foo"); // one ref - keep after all.
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
trie.commit().unwrap();
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"foo"));
|
||||
trie.remove(&hfoo, EMPTY_PREFIX); // zero ref - delete
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX), None);
|
||||
trie.commit().unwrap(); //
|
||||
assert_eq!(trie.get(&hfoo, EMPTY_PREFIX), None);
|
||||
}
|
||||
}
|
||||
|
@ -16,22 +16,28 @@
|
||||
|
||||
//! `JournalDB` over in-memory overlay
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
collections::{HashMap, hash_map::Entry},
|
||||
io,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
use ethereum_types::H256;
|
||||
use fastmap::H256FastMap;
|
||||
use hash_db::{HashDB, Prefix, EMPTY_PREFIX};
|
||||
use parity_util_mem::{MallocSizeOf, allocators::new_malloc_size_ops};
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use kvdb::{KeyValueDB, DBTransaction, DBValue};
|
||||
use log::trace;
|
||||
use malloc_size_of::{MallocSizeOf, allocators::new_malloc_size_ops};
|
||||
use parity_bytes::Bytes;
|
||||
use parking_lot::RwLock;
|
||||
use fastmap::H256FastMap;
|
||||
use rlp::{Rlp, RlpStream, encode, decode, DecoderError, Decodable, Encodable};
|
||||
use super::{DB_PREFIX_LEN, LATEST_ERA_KEY, JournalDB, error_negatively_reference_hash};
|
||||
use util::DatabaseKey;
|
||||
|
||||
use crate::{
|
||||
DB_PREFIX_LEN, LATEST_ERA_KEY, JournalDB, error_negatively_reference_hash,
|
||||
new_memory_db,
|
||||
util::DatabaseKey
|
||||
};
|
||||
|
||||
/// Implementation of the `JournalDB` trait for a disk-backed database with a memory overlay
|
||||
/// and, possibly, latent-removal semantics.
|
||||
@ -150,7 +156,7 @@ impl OverlayRecentDB {
|
||||
pub fn new(backing: Arc<dyn KeyValueDB>, col: Option<u32>) -> OverlayRecentDB {
|
||||
let journal_overlay = Arc::new(RwLock::new(OverlayRecentDB::read_overlay(&*backing, col)));
|
||||
OverlayRecentDB {
|
||||
transaction_overlay: ::new_memory_db(),
|
||||
transaction_overlay: new_memory_db(),
|
||||
backing: backing,
|
||||
journal_overlay: journal_overlay,
|
||||
column: col,
|
||||
@ -176,7 +182,7 @@ impl OverlayRecentDB {
|
||||
|
||||
fn read_overlay(db: &dyn KeyValueDB, col: Option<u32>) -> JournalOverlay {
|
||||
let mut journal = HashMap::new();
|
||||
let mut overlay = ::new_memory_db();
|
||||
let mut overlay = new_memory_db();
|
||||
let mut count = 0;
|
||||
let mut latest_era = None;
|
||||
let mut earliest_era = None;
|
||||
@ -238,26 +244,6 @@ fn to_short_key(key: &H256) -> H256 {
|
||||
k
|
||||
}
|
||||
|
||||
impl ::traits::KeyedHashDB for OverlayRecentDB {
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
|
||||
.map(|(key, _)| (H256::from_slice(&*key), 1))
|
||||
.collect();
|
||||
|
||||
for (key, refs) in self.transaction_overlay.keys() {
|
||||
match ret.entry(key) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() += refs;
|
||||
},
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(refs);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl JournalDB for OverlayRecentDB {
|
||||
|
||||
fn boxed_clone(&self) -> Box<dyn JournalDB> {
|
||||
@ -455,6 +441,24 @@ impl JournalDB for OverlayRecentDB {
|
||||
fn consolidate(&mut self, with: super::MemoryDB) {
|
||||
self.transaction_overlay.consolidate(with);
|
||||
}
|
||||
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
let mut ret: HashMap<H256, i32> = self.backing.iter(self.column)
|
||||
.map(|(key, _)| (H256::from_slice(&*key), 1))
|
||||
.collect();
|
||||
|
||||
for (key, refs) in self.transaction_overlay.keys() {
|
||||
match ret.entry(key) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() += refs;
|
||||
},
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(refs);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl HashDB<KeccakHasher, DBValue> for OverlayRecentDB {
|
||||
@ -490,11 +494,11 @@ impl HashDB<KeccakHasher, DBValue> for OverlayRecentDB {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use keccak::keccak;
|
||||
use keccak_hash::keccak;
|
||||
use super::*;
|
||||
use hash_db::{HashDB, EMPTY_PREFIX};
|
||||
use {kvdb_memorydb, JournalDB};
|
||||
use kvdb_memorydb;
|
||||
use crate::{JournalDB, inject_batch, commit_batch};
|
||||
|
||||
fn new_db() -> OverlayRecentDB {
|
||||
let backing = Arc::new(kvdb_memorydb::create(0));
|
||||
@ -507,25 +511,25 @@ mod tests {
|
||||
let mut jdb = new_db();
|
||||
|
||||
let x = jdb.insert(EMPTY_PREFIX, b"X");
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"1002a"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"1003a"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&x, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"1002b"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
let x = jdb.insert(EMPTY_PREFIX, b"X");
|
||||
jdb.commit_batch(4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"1003b"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.commit_batch(5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"1004a"), Some((3, keccak(b"1002a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
|
||||
commit_batch(&mut jdb, 6, &keccak(b"1005a"), Some((4, keccak(b"1003a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
assert!(jdb.contains(&x, EMPTY_PREFIX));
|
||||
@ -536,20 +540,20 @@ mod tests {
|
||||
// history is 3
|
||||
let mut jdb = new_db();
|
||||
let h = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.remove(&h, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(!jdb.contains(&h, EMPTY_PREFIX));
|
||||
}
|
||||
@ -561,7 +565,7 @@ mod tests {
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
@ -569,7 +573,7 @@ mod tests {
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
@ -577,20 +581,20 @@ mod tests {
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.remove(&baz, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
|
||||
@ -604,25 +608,25 @@ mod tests {
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
|
||||
@ -635,19 +639,19 @@ mod tests {
|
||||
let mut jdb = new_db();
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
jdb.commit_batch(3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"2"), Some((0, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -655,24 +659,24 @@ mod tests {
|
||||
#[test]
|
||||
fn fork_same_key_one() {
|
||||
let mut jdb = new_db();
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2a"), Some((1, keccak(b"1a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -681,24 +685,24 @@ mod tests {
|
||||
fn fork_same_key_other() {
|
||||
let mut jdb = new_db();
|
||||
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1c"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -707,33 +711,33 @@ mod tests {
|
||||
fn fork_ins_del_ins() {
|
||||
let mut jdb = new_db();
|
||||
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(3, &keccak(b"3a"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3a"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(3, &keccak(b"3b"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3b"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.commit_batch(4, &keccak(b"4a"), Some((2, keccak(b"2a")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4a"), Some((2, keccak(b"2a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.commit_batch(5, &keccak(b"5a"), Some((3, keccak(b"3a")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5a"), Some((3, keccak(b"3a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
}
|
||||
|
||||
@ -747,7 +751,7 @@ mod tests {
|
||||
// history is 1
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.emplace(bar.clone(), EMPTY_PREFIX, DBValue::from_slice(b"bar"));
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
foo
|
||||
};
|
||||
@ -755,7 +759,7 @@ mod tests {
|
||||
{
|
||||
let mut jdb = OverlayRecentDB::new(shared_db.clone(), None);
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
}
|
||||
|
||||
@ -763,7 +767,7 @@ mod tests {
|
||||
let mut jdb = OverlayRecentDB::new(shared_db.clone(), None);
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -776,22 +780,22 @@ mod tests {
|
||||
|
||||
// history is 4
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"3"), None).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
// expunge foo
|
||||
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
}
|
||||
|
||||
@ -802,43 +806,43 @@ mod tests {
|
||||
|
||||
// history is 4
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1a"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1b"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(2, &keccak(b"2a"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2a"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(2, &keccak(b"2b"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"3a"), None).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3a"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"3b"), None).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3b"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(4, &keccak(b"4a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(4, &keccak(b"4b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
// expunge foo
|
||||
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1a")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
}
|
||||
|
||||
@ -847,25 +851,25 @@ mod tests {
|
||||
let mut jdb = new_db();
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
// foo is ancient history.
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap(); // BROKEN
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap(); // BROKEN
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.commit_batch(5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((4, keccak(b"4")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -875,30 +879,30 @@ mod tests {
|
||||
let mut jdb = new_db();
|
||||
// history is 4
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(3, &keccak(b"3"), None).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
// foo is ancient history.
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
jdb.commit_batch(6, &keccak(b"6"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 6, &keccak(b"6"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(7, &keccak(b"7"), Some((3, keccak(b"3")))).unwrap();
|
||||
commit_batch(&mut jdb, 7, &keccak(b"7"), Some((3, keccak(b"3")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
}
|
||||
|
||||
@ -913,20 +917,20 @@ mod tests {
|
||||
let mut jdb = OverlayRecentDB::new(shared_db.clone(), None);
|
||||
// history is 1
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
// foo is ancient history.
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
@ -935,7 +939,7 @@ mod tests {
|
||||
let mut jdb = OverlayRecentDB::new(shared_db.clone(), None);
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
@ -943,7 +947,7 @@ mod tests {
|
||||
}; {
|
||||
let mut jdb = OverlayRecentDB::new(shared_db.clone(), None);
|
||||
|
||||
jdb.commit_batch(5, &keccak(b"5"), Some((3, keccak(b"3")))).unwrap();
|
||||
commit_batch(&mut jdb, 5, &keccak(b"5"), Some((3, keccak(b"3")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
|
||||
@ -951,7 +955,7 @@ mod tests {
|
||||
}; {
|
||||
let mut jdb = OverlayRecentDB::new(shared_db, None);
|
||||
|
||||
jdb.commit_batch(6, &keccak(b"6"), Some((4, keccak(b"4")))).unwrap();
|
||||
commit_batch(&mut jdb, 6, &keccak(b"6"), Some((4, keccak(b"4")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
|
||||
}
|
||||
@ -966,22 +970,22 @@ mod tests {
|
||||
// history is 1
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
(foo, bar, baz)
|
||||
};
|
||||
|
||||
{
|
||||
let mut jdb = OverlayRecentDB::new(shared_db, None);
|
||||
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
|
||||
@ -993,17 +997,17 @@ mod tests {
|
||||
fn insert_older_era() {
|
||||
let mut jdb = new_db();
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0a"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0a"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0a")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0a")))).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
jdb.commit_batch(0, &keccak(b"0b"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0b"), None).unwrap();
|
||||
assert!(jdb.can_reconstruct_refs());
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
@ -1013,11 +1017,11 @@ mod tests {
|
||||
fn inject() {
|
||||
let mut jdb = new_db();
|
||||
let key = jdb.insert(EMPTY_PREFIX, b"dog");
|
||||
jdb.inject_batch().unwrap();
|
||||
inject_batch(&mut jdb).unwrap();
|
||||
|
||||
assert_eq!(jdb.get(&key, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"dog"));
|
||||
jdb.remove(&key, EMPTY_PREFIX);
|
||||
jdb.inject_batch().unwrap();
|
||||
inject_batch(&mut jdb).unwrap();
|
||||
|
||||
assert!(jdb.get(&key, EMPTY_PREFIX).is_none());
|
||||
}
|
||||
|
@ -16,21 +16,26 @@
|
||||
|
||||
//! Disk-backed, ref-counted `JournalDB` implementation.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
io,
|
||||
sync::Arc,
|
||||
collections::HashMap,
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
use ethereum_types::H256;
|
||||
use hash_db::{HashDB, Prefix, EMPTY_PREFIX};
|
||||
use parity_util_mem::{MallocSizeOf, allocators::new_malloc_size_ops};
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use kvdb::{KeyValueDB, DBTransaction, DBValue};
|
||||
use overlaydb::OverlayDB;
|
||||
use log::trace;
|
||||
use malloc_size_of::{MallocSizeOf, allocators::new_malloc_size_ops};
|
||||
use parity_bytes::Bytes;
|
||||
use rlp::{encode, decode};
|
||||
use super::{DB_PREFIX_LEN, LATEST_ERA_KEY};
|
||||
use super::traits::JournalDB;
|
||||
use util::{DatabaseKey, DatabaseValueView, DatabaseValueRef};
|
||||
|
||||
use crate::{
|
||||
overlaydb::OverlayDB,
|
||||
JournalDB, DB_PREFIX_LEN, LATEST_ERA_KEY,
|
||||
util::{DatabaseKey, DatabaseValueView, DatabaseValueRef},
|
||||
};
|
||||
|
||||
/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay
|
||||
/// and latent-removal semantics.
|
||||
@ -87,10 +92,6 @@ impl HashDB<KeccakHasher, DBValue> for RefCountedDB {
|
||||
fn remove(&mut self, key: &H256, _prefix: Prefix) { self.removes.push(key.clone()); }
|
||||
}
|
||||
|
||||
impl ::traits::KeyedHashDB for RefCountedDB {
|
||||
fn keys(&self) -> HashMap<H256, i32> { self.forward.keys() }
|
||||
}
|
||||
|
||||
impl JournalDB for RefCountedDB {
|
||||
fn boxed_clone(&self) -> Box<dyn JournalDB> {
|
||||
Box::new(RefCountedDB {
|
||||
@ -213,15 +214,19 @@ impl JournalDB for RefCountedDB {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn keys(&self) -> HashMap<H256, i32> {
|
||||
self.forward.keys()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use keccak::keccak;
|
||||
use keccak_hash::keccak;
|
||||
use hash_db::{HashDB, EMPTY_PREFIX};
|
||||
use super::*;
|
||||
use {JournalDB, kvdb_memorydb};
|
||||
use kvdb_memorydb;
|
||||
use crate::{JournalDB, inject_batch, commit_batch};
|
||||
|
||||
fn new_db() -> RefCountedDB {
|
||||
let backing = Arc::new(kvdb_memorydb::create(0));
|
||||
@ -233,16 +238,16 @@ mod tests {
|
||||
// history is 3
|
||||
let mut jdb = new_db();
|
||||
let h = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.remove(&h, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.contains(&h, EMPTY_PREFIX));
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(!jdb.contains(&h, EMPTY_PREFIX));
|
||||
}
|
||||
|
||||
@ -252,16 +257,16 @@ mod tests {
|
||||
let mut jdb = new_db();
|
||||
assert_eq!(jdb.latest_era(), None);
|
||||
let h = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert_eq!(jdb.latest_era(), Some(0));
|
||||
jdb.remove(&h, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1"), None).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), None).unwrap();
|
||||
assert_eq!(jdb.latest_era(), Some(1));
|
||||
jdb.commit_batch(2, &keccak(b"2"), None).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), None).unwrap();
|
||||
assert_eq!(jdb.latest_era(), Some(2));
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert_eq!(jdb.latest_era(), Some(3));
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert_eq!(jdb.latest_era(), Some(4));
|
||||
}
|
||||
|
||||
@ -272,32 +277,32 @@ mod tests {
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
|
||||
jdb.commit_batch(1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1"), Some((0, keccak(b"0")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
jdb.remove(&baz, EMPTY_PREFIX);
|
||||
jdb.commit_batch(2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2"), Some((1, keccak(b"1")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
jdb.commit_batch(3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
|
||||
commit_batch(&mut jdb, 3, &keccak(b"3"), Some((2, keccak(b"2")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
commit_batch(&mut jdb, 4, &keccak(b"4"), Some((3, keccak(b"3")))).unwrap();
|
||||
assert!(!jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
|
||||
@ -310,22 +315,22 @@ mod tests {
|
||||
|
||||
let foo = jdb.insert(EMPTY_PREFIX, b"foo");
|
||||
let bar = jdb.insert(EMPTY_PREFIX, b"bar");
|
||||
jdb.commit_batch(0, &keccak(b"0"), None).unwrap();
|
||||
commit_batch(&mut jdb, 0, &keccak(b"0"), None).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
|
||||
jdb.remove(&foo, EMPTY_PREFIX);
|
||||
let baz = jdb.insert(EMPTY_PREFIX, b"baz");
|
||||
jdb.commit_batch(1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1a"), Some((0, keccak(b"0")))).unwrap();
|
||||
|
||||
jdb.remove(&bar, EMPTY_PREFIX);
|
||||
jdb.commit_batch(1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
commit_batch(&mut jdb, 1, &keccak(b"1b"), Some((0, keccak(b"0")))).unwrap();
|
||||
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&bar, EMPTY_PREFIX));
|
||||
assert!(jdb.contains(&baz, EMPTY_PREFIX));
|
||||
|
||||
jdb.commit_batch(2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
commit_batch(&mut jdb, 2, &keccak(b"2b"), Some((1, keccak(b"1b")))).unwrap();
|
||||
assert!(jdb.contains(&foo, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&baz, EMPTY_PREFIX));
|
||||
assert!(!jdb.contains(&bar, EMPTY_PREFIX));
|
||||
@ -335,11 +340,11 @@ mod tests {
|
||||
fn inject() {
|
||||
let mut jdb = new_db();
|
||||
let key = jdb.insert(EMPTY_PREFIX, b"dog");
|
||||
jdb.inject_batch().unwrap();
|
||||
inject_batch(&mut jdb).unwrap();
|
||||
|
||||
assert_eq!(jdb.get(&key, EMPTY_PREFIX).unwrap(), DBValue::from_slice(b"dog"));
|
||||
jdb.remove(&key, EMPTY_PREFIX);
|
||||
jdb.inject_batch().unwrap();
|
||||
inject_batch(&mut jdb).unwrap();
|
||||
|
||||
assert!(jdb.get(&key, EMPTY_PREFIX).is_none());
|
||||
}
|
||||
|
@ -1,120 +0,0 @@
|
||||
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Ethereum.
|
||||
|
||||
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Disk-backed `HashDB` implementation.
|
||||
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bytes::Bytes;
|
||||
use ethereum_types::H256;
|
||||
use hash_db::{HashDB, AsHashDB};
|
||||
use keccak_hasher::KeccakHasher;
|
||||
use kvdb::{self, DBTransaction, DBValue};
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
||||
/// expose keys of a hashDB for debugging or tests (slow).
|
||||
pub trait KeyedHashDB: HashDB<KeccakHasher, DBValue> {
|
||||
/// Primarily use for tests, highly inefficient.
|
||||
fn keys(&self) -> HashMap<H256, i32>;
|
||||
}
|
||||
|
||||
/// Upcast to `KeyedHashDB`
|
||||
pub trait AsKeyedHashDB: AsHashDB<KeccakHasher, DBValue> {
|
||||
/// Perform upcast to KeyedHashDB.
|
||||
fn as_keyed_hash_db(&self) -> &dyn KeyedHashDB;
|
||||
}
|
||||
|
||||
/// A `HashDB` which can manage a short-term journal potentially containing many forks of mutually
|
||||
/// exclusive actions.
|
||||
pub trait JournalDB: KeyedHashDB {
|
||||
|
||||
/// Return a copy of ourself, in a box.
|
||||
fn boxed_clone(&self) -> Box<dyn JournalDB>;
|
||||
|
||||
/// Returns heap memory size used
|
||||
fn mem_used(&self) -> usize;
|
||||
|
||||
/// Returns the size of journalled state in memory.
|
||||
/// This function has a considerable speed requirement --
|
||||
/// it must be fast enough to call several times per block imported.
|
||||
fn journal_size(&self) -> usize { 0 }
|
||||
|
||||
/// Check if this database has any commits
|
||||
fn is_empty(&self) -> bool;
|
||||
|
||||
/// Get the earliest era in the DB. None if there isn't yet any data in there.
|
||||
fn earliest_era(&self) -> Option<u64> { None }
|
||||
|
||||
/// Get the latest era in the DB. None if there isn't yet any data in there.
|
||||
fn latest_era(&self) -> Option<u64>;
|
||||
|
||||
/// Journal recent database operations as being associated with a given era and id.
|
||||
// TODO: give the overlay to this function so journaldbs don't manage the overlays themselves.
|
||||
fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> io::Result<u32>;
|
||||
|
||||
/// Mark a given block as canonical, indicating that competing blocks' states may be pruned out.
|
||||
fn mark_canonical(&mut self, batch: &mut DBTransaction, era: u64, id: &H256) -> io::Result<u32>;
|
||||
|
||||
/// Commit all queued insert and delete operations without affecting any journalling -- this requires that all insertions
|
||||
/// and deletions are indeed canonical and will likely lead to an invalid database if that assumption is violated.
|
||||
///
|
||||
/// Any keys or values inserted or deleted must be completely independent of those affected
|
||||
/// by any previous `commit` operations. Essentially, this means that `inject` can be used
|
||||
/// either to restore a state to a fresh database, or to insert data which may only be journalled
|
||||
/// from this point onwards.
|
||||
fn inject(&mut self, batch: &mut DBTransaction) -> io::Result<u32>;
|
||||
|
||||
/// State data query
|
||||
fn state(&self, _id: &H256) -> Option<Bytes>;
|
||||
|
||||
/// Whether this database is pruned.
|
||||
fn is_prunable(&self) -> bool { true }
|
||||
|
||||
/// Get backing database.
|
||||
fn backing(&self) -> &Arc<dyn kvdb::KeyValueDB>;
|
||||
|
||||
/// Clear internal strucutres. This should called after changes have been written
|
||||
/// to the backing strage
|
||||
fn flush(&self) {}
|
||||
|
||||
/// Consolidate all the insertions and deletions in the given memory overlay.
|
||||
fn consolidate(&mut self, overlay: super::MemoryDB);
|
||||
|
||||
/// Commit all changes in a single batch
|
||||
#[cfg(test)]
|
||||
fn commit_batch(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> io::Result<u32> {
|
||||
let mut batch = self.backing().transaction();
|
||||
let mut ops = self.journal_under(&mut batch, now, id)?;
|
||||
|
||||
if let Some((end_era, canon_id)) = end {
|
||||
ops += self.mark_canonical(&mut batch, end_era, &canon_id)?;
|
||||
}
|
||||
|
||||
let result = self.backing().write(batch).map(|_| ops).map_err(Into::into);
|
||||
self.flush();
|
||||
result
|
||||
}
|
||||
|
||||
/// Inject all changes in a single batch.
|
||||
#[cfg(test)]
|
||||
fn inject_batch(&mut self) -> io::Result<u32> {
|
||||
let mut batch = self.backing().transaction();
|
||||
let res = self.inject(&mut batch)?;
|
||||
self.backing().write(batch).map(|_| res).map_err(Into::into)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user