Code redundancy between ext implementation and testing. (#3830)

* fix child_storage_hash

* extract common implementation for ext and testing

* cleaning impl.

* replace ExtBasisMut by actual Ext

* remove extbasis.

* Update tests to use Ext from test externalities.

* use Ext constructor for getting ext from TestExternalities.

* Add missing extensions from ext.

* fix wasmi test

* Fix merge error.
This commit is contained in:
cheme
2019-10-18 09:52:25 +02:00
committed by Bastian Köcher
parent fddfcbacea
commit d9cffa0bb5
8 changed files with 148 additions and 228 deletions
+19 -157
View File
@@ -21,22 +21,20 @@ use hash_db::Hasher;
use crate::{
backend::{InMemory, Backend}, OverlayedChanges,
changes_trie::{
build_changes_trie, InMemoryStorage as ChangesTrieInMemoryStorage,
InMemoryStorage as ChangesTrieInMemoryStorage,
BlockNumber as ChangesTrieBlockNumber,
},
ext::Ext,
};
use primitives::{
storage::{
ChildStorageKey,
well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES, is_child_storage_key}
},
traits::Externalities, hash::H256, Blake2Hasher,
hash::H256, Blake2Hasher,
};
use codec::Encode;
use externalities::{Extensions, Extension};
const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime";
type StorageTuple = (HashMap<Vec<u8>, Vec<u8>>, HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>);
/// Simple HashMap-based Externalities impl.
@@ -48,6 +46,17 @@ pub struct TestExternalities<H: Hasher<Out=H256>=Blake2Hasher, N: ChangesTrieBlo
}
impl<H: Hasher<Out=H256>, N: ChangesTrieBlockNumber> TestExternalities<H, N> {
/// Get externalities implementation.
pub fn ext(&mut self) -> Ext<H, N, InMemory<H>, ChangesTrieInMemoryStorage<H, N>> {
Ext::new(
&mut self.overlay,
&self.backend,
Some(&self.changes_trie_storage),
Some(&mut self.extensions),
)
}
/// Create a new instance of `TestExternalities` with storage.
pub fn new(storage: StorageTuple) -> Self {
Self::new_with_code(&[], storage)
@@ -118,7 +127,8 @@ impl<H: Hasher<Out=H256>, N: ChangesTrieBlockNumber> TestExternalities<H, N> {
///
/// Returns the result of the given closure.
pub fn execute_with<R>(&mut self, execute: impl FnOnce() -> R) -> R {
externalities::set_and_run_with_externalities(self, execute)
let mut ext = self.ext();
externalities::set_and_run_with_externalities(&mut ext, execute)
}
}
@@ -146,156 +156,6 @@ impl<H: Hasher<Out=H256>, N: ChangesTrieBlockNumber> From<StorageTuple> for Test
}
}
impl<H, N> Externalities for TestExternalities<H, N> where
H: Hasher<Out=H256>,
N: ChangesTrieBlockNumber,
{
fn storage(&self, key: &[u8]) -> Option<Vec<u8>> {
self.overlay.storage(key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(||
self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL))
}
fn storage_hash(&self, key: &[u8]) -> Option<H256> {
self.storage(key).map(|v| H::hash(&v))
}
fn original_storage(&self, key: &[u8]) -> Option<Vec<u8>> {
self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL)
}
fn original_storage_hash(&self, key: &[u8]) -> Option<H256> {
self.storage_hash(key)
}
fn child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>> {
self.overlay
.child_storage(storage_key.as_ref(), key)
.map(|x| x.map(|x| x.to_vec()))
.unwrap_or_else(|| self.backend
.child_storage(storage_key.as_ref(), key)
.expect(EXT_NOT_ALLOWED_TO_FAIL)
)
}
fn child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H256> {
self.child_storage(storage_key, key).map(|v| H::hash(&v))
}
fn original_child_storage(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>> {
self.backend
.child_storage(storage_key.as_ref(), key)
.map(|x| x.map(|x| x.to_vec()))
.expect(EXT_NOT_ALLOWED_TO_FAIL)
}
fn original_child_storage_hash(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<H256> {
self.child_storage_hash(storage_key, key)
}
fn place_storage(&mut self, key: Vec<u8>, maybe_value: Option<Vec<u8>>) {
if is_child_storage_key(&key) {
panic!("Refuse to directly set child storage key");
}
self.overlay.set_storage(key, maybe_value);
}
fn place_child_storage(
&mut self,
storage_key: ChildStorageKey,
key: Vec<u8>,
value: Option<Vec<u8>>,
) {
self.overlay.set_child_storage(storage_key.into_owned(), key, value);
}
fn kill_child_storage(&mut self, storage_key: ChildStorageKey) {
let backend = &self.backend;
let overlay = &mut self.overlay;
overlay.clear_child_storage(storage_key.as_ref());
backend.for_keys_in_child_storage(storage_key.as_ref(), |key| {
overlay.set_child_storage(storage_key.as_ref().to_vec(), key.to_vec(), None);
});
}
fn clear_prefix(&mut self, prefix: &[u8]) {
if is_child_storage_key(prefix) {
panic!("Refuse to directly clear prefix that is part of child storage key");
}
self.overlay.clear_prefix(prefix);
let backend = &self.backend;
let overlay = &mut self.overlay;
backend.for_keys_with_prefix(prefix, |key| {
overlay.set_storage(key.to_vec(), None);
});
}
fn clear_child_prefix(&mut self, storage_key: ChildStorageKey, prefix: &[u8]) {
self.overlay.clear_child_prefix(storage_key.as_ref(), prefix);
let backend = &self.backend;
let overlay = &mut self.overlay;
backend.for_child_keys_with_prefix(storage_key.as_ref(), prefix, |key| {
overlay.set_child_storage(storage_key.as_ref().to_vec(), key.to_vec(), None);
});
}
fn chain_id(&self) -> u64 { 42 }
fn storage_root(&mut self) -> H256 {
let child_storage_keys =
self.overlay.prospective.children.keys()
.chain(self.overlay.committed.children.keys());
let child_delta_iter = child_storage_keys.map(|storage_key|
(storage_key.clone(), self.overlay.committed.children.get(storage_key)
.into_iter()
.flat_map(|map| map.iter().map(|(k, v)| (k.clone(), v.value.clone())))
.chain(self.overlay.prospective.children.get(storage_key)
.into_iter()
.flat_map(|map| map.iter().map(|(k, v)| (k.clone(), v.value.clone()))))));
// compute and memoize
let delta = self.overlay.committed.top.iter().map(|(k, v)| (k.clone(), v.value.clone()))
.chain(self.overlay.prospective.top.iter().map(|(k, v)| (k.clone(), v.value.clone())));
self.backend.full_storage_root(delta, child_delta_iter).0
}
fn child_storage_root(&mut self, storage_key: ChildStorageKey) -> Vec<u8> {
let storage_key = storage_key.as_ref();
let (root, is_empty, _) = {
let delta = self.overlay.committed.children.get(storage_key)
.into_iter()
.flat_map(|map| map.clone().into_iter().map(|(k, v)| (k, v.value)))
.chain(self.overlay.prospective.children.get(storage_key)
.into_iter()
.flat_map(|map| map.clone().into_iter().map(|(k, v)| (k, v.value))));
self.backend.child_storage_root(storage_key, delta)
};
if is_empty {
self.overlay.set_storage(storage_key.into(), None);
} else {
self.overlay.set_storage(storage_key.into(), Some(root.clone()));
}
root
}
fn storage_changes_root(&mut self, parent: H256) -> Result<Option<H256>, ()> {
Ok(build_changes_trie::<_, _, H, N>(
&self.backend,
Some(&self.changes_trie_storage),
&self.overlay,
parent,
)?.map(|(_, root, _)| root))
}
}
impl<H, N> externalities::ExtensionStore for TestExternalities<H, N> where
H: Hasher<Out=H256>,
N: ChangesTrieBlockNumber,
@@ -308,12 +168,13 @@ impl<H, N> externalities::ExtensionStore for TestExternalities<H, N> where
#[cfg(test)]
mod tests {
use super::*;
use primitives::{Blake2Hasher, H256};
use primitives::traits::Externalities;
use hex_literal::hex;
#[test]
fn commit_should_work() {
let mut ext = TestExternalities::<Blake2Hasher, u64>::default();
let mut ext = ext.ext();
ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec());
ext.set_storage(b"dog".to_vec(), b"puppy".to_vec());
ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec());
@@ -324,6 +185,7 @@ mod tests {
#[test]
fn set_and_retrieve_code() {
let mut ext = TestExternalities::<Blake2Hasher, u64>::default();
let mut ext = ext.ext();
let code = vec![1, 2, 3];
ext.set_storage(CODE.to_vec(), code.clone());