Support multi-hash in multi-trie via PlainDB (#1106)

* Temporarily pin trie to #2

* Use generic and delay trait object casting

Rust does not support super-trait upcasting

* Add PlainDB impl for Ephemeral

* Add PlainDB trait alias for completeness

* Use PlainDB for test TrieBackendStorage fetch

We always check overlay first for a storage fetch, which already checked null data. Using PlainDB here makes it work
nicer with other PlainDB overlays.

* Update trie reference

* Use HashDBRef in places when approriate

* Use PlainDBRef in places when approriate

* Update trie crate reference

* Remove unused HashDB::keys

* Patch dependencies

* Fix cargolock

* Update cargo lock again
This commit is contained in:
Wei Tang
2019-02-06 11:16:40 +01:00
committed by Arkadiy Paronyan
parent fa2e323478
commit 1ba7e35c18
11 changed files with 322 additions and 105 deletions
@@ -48,7 +48,7 @@ impl<'a, S, H> ProvingBackendEssence<'a, S, H>
let map_e = |e| format!("Trie lookup error: {}", e);
read_trie_value_with(&eph, self.backend.root(), key, &mut *self.proof_recorder).map_err(map_e)
read_trie_value_with::<H, _, Ephemeral<S, H>>(&eph, self.backend.root(), key, &mut *self.proof_recorder).map_err(map_e)
}
pub fn child_storage(&mut self, storage_key: &[u8], key: &[u8]) -> Result<Option<Vec<u8>>, String> {
@@ -74,7 +74,7 @@ impl<'a, S, H> ProvingBackendEssence<'a, S, H>
let mut iter = move || -> Result<(), Box<TrieError<H::Out>>> {
let root = self.backend.root();
record_all_keys::<H>(&eph, root, &mut *self.proof_recorder)
record_all_keys::<H, _>(&eph, root, &mut *self.proof_recorder)
};
if let Err(e) = iter() {
@@ -138,7 +138,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
&mut write_overlay,
);
match delta_trie_root::<H, _, _, _>(&mut eph, root, delta) {
match delta_trie_root::<H, _, _, _, _>(&mut eph, root, delta) {
Ok(ret) => root = ret,
Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e),
}
@@ -169,7 +169,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
&mut write_overlay,
);
match child_delta_trie_root::<H, _, _, _>(storage_key, &mut eph, root.clone(), delta) {
match child_delta_trie_root::<H, _, _, _, _>(storage_key, &mut eph, root.clone(), delta) {
Ok(ret) => root = ret,
Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e),
}
@@ -17,7 +17,6 @@
//! Trie-based state machine backend essence used to read values
//! from storage.
use std::collections::HashMap;
use std::ops::Deref;
use std::sync::Arc;
use log::{debug, warn};
@@ -106,7 +105,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
overlay: &mut read_overlay,
};
if let Err(e) = for_keys_in_child_trie::<H, _>(storage_key, &eph, &root, f) {
if let Err(e) = for_keys_in_child_trie::<H, _, Ephemeral<S, H>>(storage_key, &eph, &root, f) {
debug!(target: "trie", "Error while iterating child storage: {}", e);
}
}
@@ -149,6 +148,17 @@ pub(crate) struct Ephemeral<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> {
overlay: &'a mut MemoryDB<H>,
}
impl<'a,
S: 'a + TrieBackendStorage<H>,
H: 'a + Hasher
> hash_db::AsPlainDB<H::Out, DBValue>
for Ephemeral<'a, S, H>
where H::Out: HeapSizeOf
{
fn as_plain_db<'b>(&'b self) -> &'b (hash_db::PlainDB<H::Out, DBValue> + 'b) { self }
fn as_plain_db_mut<'b>(&'b mut self) -> &'b mut (hash_db::PlainDB<H::Out, DBValue> + 'b) { self }
}
impl<'a,
S: 'a + TrieBackendStorage<H>,
H: 'a + Hasher
@@ -172,50 +182,97 @@ impl<'a, S: TrieBackendStorage<H>, H: Hasher> Ephemeral<'a, S, H> {
impl<'a,
S: 'a + TrieBackendStorage<H>,
H: Hasher
> hash_db::HashDB<H, DBValue>
> hash_db::PlainDB<H::Out, DBValue>
for Ephemeral<'a, S, H>
where H::Out: HeapSizeOf
{
fn keys(&self) -> HashMap<H::Out, i32> {
self.overlay.keys()
}
fn get(&self, key: &H::Out) -> Option<DBValue> {
match self.overlay.raw(key) {
Some((val, i)) => {
if i <= 0 {
None
} else {
Some(val.clone())
}
}
None => match self.storage.get(&key) {
if let Some(val) = hash_db::PlainDB::get(self.overlay, key) {
Some(val)
} else {
match self.storage.get(&key) {
Ok(x) => x,
Err(e) => {
warn!(target: "trie", "Failed to read from DB: {}", e);
None
},
},
}
}
}
fn contains(&self, key: &H::Out) -> bool {
self.get(key).is_some()
}
fn insert(&mut self, value: &[u8]) -> H::Out {
self.overlay.insert(value)
hash_db::PlainDB::get(self, key).is_some()
}
fn emplace(&mut self, key: H::Out, value: DBValue) {
self.overlay.emplace(key, value)
hash_db::PlainDB::emplace(self.overlay, key, value)
}
fn remove(&mut self, key: &H::Out) {
self.overlay.remove(key)
hash_db::PlainDB::remove(self.overlay, key)
}
}
impl<'a,
S: 'a + TrieBackendStorage<H>,
H: Hasher
> hash_db::PlainDBRef<H::Out, DBValue>
for Ephemeral<'a, S, H>
where H::Out: HeapSizeOf
{
fn get(&self, key: &H::Out) -> Option<DBValue> { hash_db::PlainDB::get(self, key) }
fn contains(&self, key: &H::Out) -> bool { hash_db::PlainDB::contains(self, key) }
}
impl<'a,
S: 'a + TrieBackendStorage<H>,
H: Hasher
> hash_db::HashDB<H, DBValue>
for Ephemeral<'a, S, H>
where H::Out: HeapSizeOf
{
fn get(&self, key: &H::Out) -> Option<DBValue> {
if let Some(val) = hash_db::HashDB::get(self.overlay, key) {
Some(val)
} else {
match self.storage.get(&key) {
Ok(x) => x,
Err(e) => {
warn!(target: "trie", "Failed to read from DB: {}", e);
None
},
}
}
}
fn contains(&self, key: &H::Out) -> bool {
hash_db::HashDB::get(self, key).is_some()
}
fn insert(&mut self, value: &[u8]) -> H::Out {
hash_db::HashDB::insert(self.overlay, value)
}
fn emplace(&mut self, key: H::Out, value: DBValue) {
hash_db::HashDB::emplace(self.overlay, key, value)
}
fn remove(&mut self, key: &H::Out) {
hash_db::HashDB::remove(self.overlay, key)
}
}
impl<'a,
S: 'a + TrieBackendStorage<H>,
H: Hasher
> hash_db::HashDBRef<H, DBValue>
for Ephemeral<'a, S, H>
where H::Out: HeapSizeOf
{
fn get(&self, key: &H::Out) -> Option<DBValue> { hash_db::HashDB::get(self, key) }
fn contains(&self, key: &H::Out) -> bool { hash_db::HashDB::contains(self, key) }
}
/// Key-value pairs storage that is used by trie backend essence.
pub trait TrieBackendStorage<H: Hasher>: Send + Sync {
/// Get the value stored at key.
@@ -232,7 +289,7 @@ impl<H: Hasher> TrieBackendStorage<H> for Arc<Storage<H>> {
// This implementation is used by test storage trie clients.
impl<H: Hasher> TrieBackendStorage<H> for MemoryDB<H> {
fn get(&self, key: &H::Out) -> Result<Option<DBValue>, String> {
Ok(<Self as hash_db::HashDB<H, DBValue>>::get(self, key))
Ok(hash_db::PlainDB::get(self, key))
}
}