diff --git a/substrate/srml/contract/src/account_db.rs b/substrate/srml/contract/src/account_db.rs index d7ff094003..af71b6bbd9 100644 --- a/substrate/srml/contract/src/account_db.rs +++ b/substrate/srml/contract/src/account_db.rs @@ -17,11 +17,10 @@ //! Auxilliaries to help with managing partial changes to accounts state. use super::{CodeOf, StorageOf, Trait}; -use double_map::StorageDoubleMap; use rstd::cell::RefCell; use rstd::collections::btree_map::{BTreeMap, Entry}; use rstd::prelude::*; -use runtime_support::StorageMap; +use runtime_support::{StorageMap, StorageDoubleMap}; use {balances, system}; pub struct ChangeEntry { diff --git a/substrate/srml/contract/src/lib.rs b/substrate/srml/contract/src/lib.rs index cf1d2ac1db..199f005881 100644 --- a/substrate/srml/contract/src/lib.rs +++ b/substrate/srml/contract/src/lib.rs @@ -84,7 +84,6 @@ extern crate assert_matches; extern crate wabt; mod account_db; -mod double_map; mod exec; mod vm; mod gas; @@ -94,15 +93,15 @@ mod tests; use exec::ExecutionContext; use account_db::{AccountDb, OverlayAccountDb}; -use double_map::StorageDoubleMap; use rstd::prelude::*; use rstd::marker::PhantomData; use codec::{Codec, HasCompact}; use runtime_primitives::traits::{Hash, As, SimpleArithmetic}; use runtime_support::dispatch::Result; -use runtime_support::{Parameter, StorageMap, StorageValue}; +use runtime_support::{Parameter, StorageMap, StorageValue, StorageDoubleMap}; use system::ensure_signed; +use runtime_io::{blake2_256, twox_128}; pub trait Trait: balances::Trait { /// Function type to get the contract address given the creator. @@ -302,11 +301,22 @@ decl_storage! { /// /// TODO: keys should also be able to take AsRef to ensure Vecs can be passed as &[u8] pub(crate) struct StorageOf(::rstd::marker::PhantomData); -impl double_map::StorageDoubleMap for StorageOf { +impl StorageDoubleMap for StorageOf { const PREFIX: &'static [u8] = b"con:sto:"; type Key1 = T::AccountId; type Key2 = Vec; type Value = Vec; + + /// Hashed by XX + fn derive_key1(key1_data: Vec) -> Vec { + twox_128(&key1_data).to_vec() + } + + /// Blake2 is used for `Key2` is because it will be used as a key for contract's storage and + /// thus will be susceptible for a untrusted input. + fn derive_key2(key2_data: Vec) -> Vec { + blake2_256(&key2_data).to_vec() + } } impl balances::OnFreeBalanceZero for Module { diff --git a/substrate/srml/contract/src/tests.rs b/substrate/srml/contract/src/tests.rs index 330f11a3b2..b28bfcb82d 100644 --- a/substrate/srml/contract/src/tests.rs +++ b/substrate/srml/contract/src/tests.rs @@ -14,12 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use double_map::StorageDoubleMap; use runtime_io::with_externalities; use runtime_primitives::testing::{Digest, DigestItem, H256, Header}; use runtime_primitives::traits::{BlakeTwo256}; use runtime_primitives::BuildStorage; -use runtime_support::StorageMap; +use runtime_support::{StorageMap, StorageDoubleMap}; use substrate_primitives::{Blake2Hasher}; use system::{Phase, EventRecord}; use wabt; diff --git a/substrate/srml/contract/src/double_map.rs b/substrate/srml/support/src/double_map.rs similarity index 56% rename from substrate/srml/contract/src/double_map.rs rename to substrate/srml/support/src/double_map.rs index bd154e100e..afc707b4f1 100644 --- a/substrate/srml/contract/src/double_map.rs +++ b/substrate/srml/support/src/double_map.rs @@ -15,36 +15,10 @@ // along with Substrate. If not, see . //! An implementation of double map backed by storage. -//! -//! This implementation is somewhat specialized to the tracking of the storage of accounts. use rstd::prelude::*; use codec::{Codec, Encode}; -use runtime_support::storage::unhashed; -use runtime_io::{blake2_256, twox_128}; - -/// Returns only a first part of the storage key. -/// -/// Hashed by XX. -fn first_part_of_key(k1: M::Key1) -> [u8; 16] { - let mut raw_prefix = Vec::new(); - raw_prefix.extend(M::PREFIX); - raw_prefix.extend(Encode::encode(&k1)); - twox_128(&raw_prefix) -} - -/// Returns a compound key that consist of the two parts: (prefix, `k1`) and `k2`. -/// -/// The first part is hased by XX and then concatenated with a blake2 hash of `k2`. -fn full_key(k1: M::Key1, k2: M::Key2) -> Vec { - let first_part = first_part_of_key::(k1); - let second_part = blake2_256(&Encode::encode(&k2)); - - let mut k = Vec::new(); - k.extend(&first_part); - k.extend(&second_part); - k -} +use storage::unhashed; /// An implementation of a map with a two keys. /// @@ -54,11 +28,8 @@ fn full_key(k1: M::Key1, k2: M::Key2) -> Vec { /// # Mapping of keys to a storage path /// /// The storage key (i.e. the key under which the `Value` will be stored) is created from two parts. -/// The first part is a XX hash of a concatenation of the `PREFIX` and `Key1`. And the second part -/// is a blake2 hash of a `Key2`. -/// -/// Blake2 is used for `Key2` is because it will be used as a key for contract's storage and -/// thus will be susceptible for a untrusted input. +/// The first part is a hash of a concatenation of the `PREFIX` and `Key1`. And the second part +/// is a hash of a `Key2`. pub trait StorageDoubleMap { type Key1: Codec; type Key2: Codec; @@ -68,28 +39,57 @@ pub trait StorageDoubleMap { /// Insert an entry into this map. fn insert(k1: Self::Key1, k2: Self::Key2, val: Self::Value) { - unhashed::put(&full_key::(k1, k2)[..], &val); + unhashed::put(&Self::full_key(k1, k2)[..], &val); } /// Remove an entry from this map. fn remove(k1: Self::Key1, k2: Self::Key2) { - unhashed::kill(&full_key::(k1, k2)[..]); + unhashed::kill(&Self::full_key(k1, k2)[..]); } /// Get an entry from this map. /// /// If there is entry stored under the given keys, returns `None`. fn get(k1: Self::Key1, k2: Self::Key2) -> Option { - unhashed::get(&full_key::(k1, k2)[..]) + unhashed::get(&Self::full_key(k1, k2)[..]) } /// Returns `true` if value under the specified keys exists. fn exists(k1: Self::Key1, k2: Self::Key2) -> bool { - unhashed::exists(&full_key::(k1, k2)[..]) + unhashed::exists(&Self::full_key(k1, k2)[..]) } /// Removes all entries that shares the `k1` as the first key. fn remove_prefix(k1: Self::Key1) { - unhashed::kill_prefix(&first_part_of_key::(k1)) + unhashed::kill_prefix(&Self::derive_key1(Self::encode_key1(k1))) + } + + /// Encode key1 into Vec and prepend a prefix + fn encode_key1(key: Self::Key1) -> Vec { + let mut raw_prefix = Vec::new(); + raw_prefix.extend(Self::PREFIX); + raw_prefix.extend(Encode::encode(&key)); + raw_prefix + } + + /// Encode key2 into Vec + fn encode_key2(key: Self::Key2) -> Vec { + Encode::encode(&key) + } + + /// Derive the first part of the key + fn derive_key1(key1_data: Vec) -> Vec; + + /// Derive the remaining part of the key + fn derive_key2(key2_data: Vec) -> Vec; + + /// Returns a compound key that consist of the two parts: (prefix, `k1`) and `k2`. + /// The first part is hased and then concatenated with a hash of `k2`. + fn full_key(k1: Self::Key1, k2: Self::Key2) -> Vec { + let key1_data = Self::encode_key1(k1); + let key2_data = Self::encode_key2(k2); + let mut key = Self::derive_key1(key1_data); + key.extend(Self::derive_key2(key2_data)); + key } } diff --git a/substrate/srml/support/src/lib.rs b/substrate/srml/support/src/lib.rs index 6ab77d9b58..3a988426e2 100644 --- a/substrate/srml/support/src/lib.rs +++ b/substrate/srml/support/src/lib.rs @@ -67,12 +67,14 @@ pub mod metadata; mod runtime; #[macro_use] pub mod inherent; +mod double_map; pub use self::storage::{StorageVec, StorageList, StorageValue, StorageMap}; pub use self::hashable::Hashable; pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType}; pub use self::metadata::RuntimeMetadata; pub use runtime_io::print; +pub use double_map::StorageDoubleMap; #[doc(inline)] pub use srml_support_procedural::decl_storage;