// Copyright 2017-2018 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate 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. // Substrate 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 Substrate. If not, see . //! Test implementation for Externalities. use std::collections::HashMap; use std::iter::FromIterator; use hash_db::Hasher; use heapsize::HeapSizeOf; use trie::trie_root; use backend::InMemory; use changes_trie::{compute_changes_trie_root, InMemoryStorage as ChangesTrieInMemoryStorage, AnchorBlockId}; use primitives::storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES}; use codec::Encode; use super::{Externalities, OverlayedChanges}; /// Simple HashMap-based Externalities impl. pub struct TestExternalities where H::Out: HeapSizeOf { inner: HashMap, Vec>, changes_trie_storage: ChangesTrieInMemoryStorage, changes: OverlayedChanges, code: Vec, } impl TestExternalities where H::Out: HeapSizeOf { /// Create a new instance of `TestExternalities` pub fn new(inner: HashMap, Vec>) -> Self { Self::new_with_code(&[], inner) } /// Create a new instance of `TestExternalities` pub fn new_with_code(code: &[u8], inner: HashMap, Vec>) -> Self { let mut overlay = OverlayedChanges::default(); super::set_changes_trie_config( &mut overlay, inner.get(&CHANGES_TRIE_CONFIG.to_vec()).cloned(), false, ).expect("changes trie configuration is correct in test env; qed"); TestExternalities { inner, changes_trie_storage: ChangesTrieInMemoryStorage::new(), changes: overlay, code: code.to_vec(), } } /// Insert key/value pub fn insert(&mut self, k: Vec, v: Vec) -> Option> { self.inner.insert(k, v) } } impl ::std::fmt::Debug for TestExternalities where H::Out: HeapSizeOf { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "{:?}", self.inner) } } impl PartialEq for TestExternalities where H::Out: HeapSizeOf { fn eq(&self, other: &TestExternalities) -> bool { self.inner.eq(&other.inner) } } impl FromIterator<(Vec, Vec)> for TestExternalities where H::Out: HeapSizeOf { fn from_iter, Vec)>>(iter: I) -> Self { let mut t = Self::new(Default::default()); for i in iter { t.inner.insert(i.0, i.1); } t } } impl Default for TestExternalities where H::Out: HeapSizeOf { fn default() -> Self { Self::new(Default::default()) } } impl From> for HashMap, Vec> where H::Out: HeapSizeOf { fn from(tex: TestExternalities) -> Self { tex.inner.into() } } impl From< HashMap, Vec> > for TestExternalities where H::Out: HeapSizeOf { fn from(hashmap: HashMap, Vec>) -> Self { TestExternalities { inner: hashmap, changes_trie_storage: ChangesTrieInMemoryStorage::new(), changes: Default::default(), code: Default::default(), } } } impl Externalities for TestExternalities where H::Out: Ord + HeapSizeOf { fn storage(&self, key: &[u8]) -> Option> { match key { CODE => Some(self.code.clone()), HEAP_PAGES => Some(8u64.encode()), _ => self.inner.get(key).map(|x| x.to_vec()), } } fn child_storage(&self, _storage_key: &[u8], _key: &[u8]) -> Option> { None } fn place_storage(&mut self, key: Vec, maybe_value: Option>) { self.changes.set_storage(key.clone(), maybe_value.clone()); match maybe_value { Some(value) => { self.inner.insert(key, value); } None => { self.inner.remove(&key); } } } fn place_child_storage(&mut self, _storage_key: Vec, _key: Vec, _value: Option>) -> bool { false } fn kill_child_storage(&mut self, _storage_key: &[u8]) { } fn clear_prefix(&mut self, prefix: &[u8]) { self.changes.clear_prefix(prefix); self.inner.retain(|key, _| !key.starts_with(prefix)); } fn chain_id(&self) -> u64 { 42 } fn storage_root(&mut self) -> H::Out { trie_root::(self.inner.clone()) } fn child_storage_root(&mut self, _storage_key: &[u8]) -> Option> { None } fn storage_changes_root(&mut self, parent: H::Out, parent_num: u64) -> Option { compute_changes_trie_root::<_, _, H>( &InMemory::default(), Some(&self.changes_trie_storage), &self.changes, &AnchorBlockId { hash: parent, number: parent_num }, ).map(|(root, _)| root.clone()) } } #[cfg(test)] mod tests { use super::*; use primitives::{Blake2Hasher, H256}; #[test] fn commit_should_work() { let mut ext = TestExternalities::::default(); 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()); const ROOT: [u8; 32] = hex!("0b41e488cccbd67d1f1089592c2c235f5c5399b053f7fe9152dd4b5f279914cd"); assert_eq!(ext.storage_root(), H256::from(ROOT)); } }