diff --git a/substrate/core/state-machine/src/testing.rs b/substrate/core/state-machine/src/testing.rs index 216b3ebdc2..a9ed13eb8e 100644 --- a/substrate/core/state-machine/src/testing.rs +++ b/substrate/core/state-machine/src/testing.rs @@ -107,6 +107,9 @@ impl From< HashMap, Vec> > for TestExternalities where } } +// TODO child test primitives are currently limited to `changes` (for non child the way +// things are defined seems utterly odd to (put changes in changes but never make them +// available for read through inner) impl Externalities for TestExternalities where H::Out: Ord + HeapSizeOf { fn storage(&self, key: &[u8]) -> Option> { match key { @@ -115,8 +118,8 @@ impl Externalities for TestExternalities where H::Out: Ord + He } } - fn child_storage(&self, _storage_key: &[u8], _key: &[u8]) -> Option> { - None + fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Option> { + self.changes.child_storage(storage_key, key)?.map(Vec::from) } fn place_storage(&mut self, key: Vec, maybe_value: Option>) { @@ -132,11 +135,15 @@ impl Externalities for TestExternalities where H::Out: Ord + He } } - fn place_child_storage(&mut self, _storage_key: Vec, _key: Vec, _value: Option>) -> bool { - false + fn place_child_storage(&mut self, storage_key: Vec, key: Vec, value: Option>) -> bool { + self.changes.set_child_storage(storage_key, key, value); + // TODO place_child_storage and set_child_storage should always be valid (create child on set)? + true } - fn kill_child_storage(&mut self, _storage_key: &[u8]) { } + fn kill_child_storage(&mut self, storage_key: &[u8]) { + self.changes.clear_child_storage(storage_key); + } fn clear_prefix(&mut self, prefix: &[u8]) { self.changes.clear_prefix(prefix); diff --git a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 4f75adc74d..6e4e047e40 100644 Binary files a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/substrate/node-template/runtime/src/template.rs b/substrate/node-template/runtime/src/template.rs index 10f8b1eb13..92abe980f0 100644 --- a/substrate/node-template/runtime/src/template.rs +++ b/substrate/node-template/runtime/src/template.rs @@ -95,7 +95,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index 1f52620cd4..c069bed172 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -59,7 +59,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_name: create_runtime_str!("substrate-node"), authoring_version: 10, spec_version: 38, - impl_version: 39, + impl_version: 40, apis: RUNTIME_API_VERSIONS, }; @@ -172,6 +172,7 @@ impl contract::Trait for Runtime { type Gas = u64; type DetermineContractAddress = contract::SimpleAddressDeterminator; type ComputeDispatchFee = contract::DefaultDispatchFeeComputor; + type TrieIdGenerator = contract::TrieIdFromParentCounter; type GasPayment = (); } diff --git a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index 5076de93a3..36103fef20 100644 Binary files a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm and b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm differ diff --git a/substrate/srml/assets/src/lib.rs b/substrate/srml/assets/src/lib.rs index 14dba1d198..0ed4f7a309 100644 --- a/substrate/srml/assets/src/lib.rs +++ b/substrate/srml/assets/src/lib.rs @@ -154,7 +154,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/substrate/srml/aura/src/mock.rs b/substrate/srml/aura/src/mock.rs index 6a0afb6469..1cb6413ac2 100644 --- a/substrate/srml/aura/src/mock.rs +++ b/substrate/srml/aura/src/mock.rs @@ -46,7 +46,7 @@ impl system::Trait for Test { type Hashing = ::primitives::traits::BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/substrate/srml/balances/src/mock.rs b/substrate/srml/balances/src/mock.rs index adec340bf4..db20efc475 100644 --- a/substrate/srml/balances/src/mock.rs +++ b/substrate/srml/balances/src/mock.rs @@ -40,7 +40,7 @@ impl system::Trait for Runtime { type Hashing = ::primitives::traits::BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/substrate/srml/consensus/src/mock.rs b/substrate/srml/consensus/src/mock.rs index 490c1ca078..85e6dc3654 100644 --- a/substrate/srml/consensus/src/mock.rs +++ b/substrate/srml/consensus/src/mock.rs @@ -44,7 +44,7 @@ impl system::Trait for Test { type Hashing = ::primitives::traits::BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/substrate/srml/contract/src/account_db.rs b/substrate/srml/contract/src/account_db.rs index 2fcddd5d79..e7dc144161 100644 --- a/substrate/srml/contract/src/account_db.rs +++ b/substrate/srml/contract/src/account_db.rs @@ -16,14 +16,15 @@ //! Auxilliaries to help with managing partial changes to accounts state. -use super::{CodeHash, CodeHashOf, StorageOf, Trait}; +use super::{CodeHash, CodeHashOf, Trait, AccountInfo, TrieId, AccountInfoOf}; use {balances, system}; use rstd::cell::RefCell; +use rstd::rc::Rc; use rstd::collections::btree_map::{BTreeMap, Entry}; use rstd::prelude::*; use runtime_primitives::traits::Zero; -use srml_support::{StorageMap, StorageDoubleMap, traits::{UpdateBalanceOutcome, - SignedImbalance, Currency, Imbalance}}; +use srml_support::{StorageMap, traits::{UpdateBalanceOutcome, + SignedImbalance, Currency, Imbalance}, storage::child}; pub struct ChangeEntry { balance: Option, @@ -45,8 +46,50 @@ impl Default for ChangeEntry { pub type ChangeSet = BTreeMap<::AccountId, ChangeEntry>; +#[derive(Clone, Default)] +pub struct AccountTrieIdMapping { + to_account: BTreeMap, + to_key: BTreeMap, + // this lock is related to the way overlaydb stack + // if set it must be unset at the lower level + lock: bool, +} + +impl AccountTrieIdMapping { + + pub fn new() -> Self { + AccountTrieIdMapping { + to_account: BTreeMap::new(), + to_key: BTreeMap::new(), + lock: false, + } + } + + pub fn lock(&mut self) { + self.lock = true; + } + pub fn unlock(&mut self) { + self.lock = false; + } + pub fn insert(&mut self, account: A, ks: TrieId) { + self.to_account.insert(ks.clone(), account.clone()); + self.to_key.insert(account, ks); + } + pub fn get_trieid(&self, account: &A) -> Option<&TrieId> { + if self.lock { return None } + self.to_key.get(account) + } + pub fn get_account(&self, ks: &TrieId) -> Option<&A> { + if self.lock { return None } + self.to_account.get(ks) + } + +} + pub trait AccountDb { - fn get_storage(&self, account: &T::AccountId, location: &[u8]) -> Option>; + fn get_account_info(&self, account: &T::AccountId) -> Option; + fn get_or_create_trieid(&self, account: &T::AccountId) -> TrieId; + fn get_storage(&self, trie_id: &TrieId, location: &[u8]) -> Option>; fn get_code(&self, account: &T::AccountId) -> Option>; fn get_balance(&self, account: &T::AccountId) -> T::Balance; @@ -55,8 +98,18 @@ pub trait AccountDb { pub struct DirectAccountDb; impl AccountDb for DirectAccountDb { - fn get_storage(&self, account: &T::AccountId, location: &[u8]) -> Option> { - >::get(account, &location.to_vec()) + fn get_account_info(&self, account: &T::AccountId) -> Option { + let res: Option = AccountInfoOf::::get(account); + res + } + fn get_or_create_trieid(&self, account: &T::AccountId) -> TrieId { + use super::TrieIdGenerator; + >::get_account_info(self, account) + .map(|s|s.trie_id) + .unwrap_or_else(||::TrieIdGenerator::trie_id(account)) + } + fn get_storage(&self, trie_id: &TrieId, location: &[u8]) -> Option> { + child::get_raw(trie_id, location) } fn get_code(&self, account: &T::AccountId) -> Option> { >::get(account) @@ -67,12 +120,13 @@ impl AccountDb for DirectAccountDb { fn commit(&mut self, s: ChangeSet) { let mut total_imbalance = SignedImbalance::zero(); for (address, changed) in s.into_iter() { + let trieid = >::get_or_create_trieid(&self, &address); if let Some(balance) = changed.balance { let (imbalance, outcome) = balances::Module::::ensure_free_balance_is(&address, balance); total_imbalance = total_imbalance.merge(imbalance); if let UpdateBalanceOutcome::AccountKilled = outcome { // Account killed. This will ultimately lead to calling `OnFreeBalanceZero` callback - // which will make removal of CodeHashOf and StorageOf for this account. + // which will make removal of CodeHashOf and AccountStorage for this account. // In order to avoid writing over the deleted properties we `continue` here. continue; } @@ -86,9 +140,9 @@ impl AccountDb for DirectAccountDb { } for (k, v) in changed.storage.into_iter() { if let Some(value) = v { - >::insert(&address, &k, value); + child::put_raw(&trieid[..], &k, &value[..]); } else { - >::remove(&address, &k); + child::kill(&trieid[..], &k); } } } @@ -104,19 +158,30 @@ impl AccountDb for DirectAccountDb { } } } - pub struct OverlayAccountDb<'a, T: Trait + 'a> { local: RefCell>, + trie_account: Rc::AccountId>>>, + trie_account_cache: bool, underlying: &'a AccountDb, } impl<'a, T: Trait> OverlayAccountDb<'a, T> { - pub fn new(underlying: &'a AccountDb) -> OverlayAccountDb<'a, T> { + pub fn new( + underlying: &'a AccountDb, + trie_account: Rc::AccountId>>>, + trie_account_cache: bool, + ) -> OverlayAccountDb<'a, T> { OverlayAccountDb { local: RefCell::new(ChangeSet::new()), + trie_account, + trie_account_cache, underlying, } } + pub fn reg_cache_new_rc(&self) -> Rc::AccountId>>> { + self.trie_account.clone() + } + pub fn into_change_set(self) -> ChangeSet { self.local.into_inner() } @@ -127,13 +192,13 @@ impl<'a, T: Trait> OverlayAccountDb<'a, T> { location: Vec, value: Option>, ) { - self.local - .borrow_mut() + self.local.borrow_mut() .entry(account.clone()) .or_insert(Default::default()) .storage .insert(location, value); } + pub fn set_code(&mut self, account: &T::AccountId, code: Option>) { self.local .borrow_mut() @@ -151,13 +216,39 @@ impl<'a, T: Trait> OverlayAccountDb<'a, T> { } impl<'a, T: Trait> AccountDb for OverlayAccountDb<'a, T> { - fn get_storage(&self, account: &T::AccountId, location: &[u8]) -> Option> { - self.local + fn get_account_info(&self, account: &T::AccountId) -> Option { + let v = self.underlying.get_account_info(account); + if self.trie_account_cache { + v.as_ref().map(|v|self.trie_account.as_ref().borrow_mut().insert(account.clone(), v.trie_id.clone())); + } + v + } + fn get_or_create_trieid(&self, account: &T::AccountId) -> TrieId { + if self.trie_account_cache { + let mut ka_mut = self.trie_account.as_ref().borrow_mut(); + if let Some(v) = ka_mut.get_trieid(account) { + v.clone() + } else { + ka_mut.unlock(); + let v = self.underlying.get_or_create_trieid(account); + ka_mut.insert(account.clone(), v.clone()); + v + } + } else { + let res = self.trie_account.as_ref().borrow().get_trieid(account).map(|v|v.clone()); + res.unwrap_or_else(|| { + self.trie_account.as_ref().borrow_mut().lock(); + self.underlying.get_or_create_trieid(account) + }) + } + } + fn get_storage(&self, ks: &TrieId, location: &[u8]) -> Option> { + self.trie_account.as_ref().borrow().get_account(ks).and_then(|account| self.local .borrow() - .get(account) + .get(&account) .and_then(|a| a.storage.get(location)) .cloned() - .unwrap_or_else(|| self.underlying.get_storage(account, location)) + .unwrap_or_else(|| self.underlying.get_storage(ks, location))) } fn get_code(&self, account: &T::AccountId) -> Option> { self.local diff --git a/substrate/srml/contract/src/exec.rs b/substrate/srml/contract/src/exec.rs index 8650839bf1..011f1d9e1e 100644 --- a/substrate/srml/contract/src/exec.rs +++ b/substrate/srml/contract/src/exec.rs @@ -14,11 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use super::{CodeHash, Config, ContractAddressFor, Event, RawEvent, Trait}; -use crate::account_db::{AccountDb, DirectAccountDb, OverlayAccountDb}; +use super::{CodeHash, Config, ContractAddressFor, Event, RawEvent, Trait, TrieId}; +use crate::account_db::{AccountDb, DirectAccountDb, OverlayAccountDb, AccountTrieIdMapping}; use crate::gas::{GasMeter, Token, approx_gas_for_balance}; use rstd::prelude::*; +use rstd::cell::RefCell; +use rstd::rc::Rc; use runtime_primitives::traits::{CheckedAdd, CheckedSub, Zero}; use srml_support::traits::{WithdrawReason, Currency}; use timestamp; @@ -225,6 +227,7 @@ impl Token for ExecFeeToken { pub struct ExecutionContext<'a, T: Trait + 'a, V, L> { pub self_account: T::AccountId, + pub self_trieid: TrieId, pub overlay: OverlayAccountDb<'a, T>, pub depth: usize, pub events: Vec>, @@ -244,9 +247,11 @@ where /// /// The specified `origin` address will be used as `sender` for pub fn top_level(origin: T::AccountId, cfg: &'a Config, vm: &'a V, loader: &'a L) -> Self { - let overlay = OverlayAccountDb::::new(&DirectAccountDb); + let overlay = OverlayAccountDb::::new(&DirectAccountDb, Rc::new(RefCell::new(AccountTrieIdMapping::new())), true); + let self_trieid = overlay.get_or_create_trieid(&origin); ExecutionContext { self_account: origin, + self_trieid, depth: 0, overlay, events: Vec::new(), @@ -258,9 +263,11 @@ where } fn nested(&self, overlay: OverlayAccountDb<'a, T>, dest: T::AccountId) -> Self { + let self_trieid = overlay.get_or_create_trieid(&dest); ExecutionContext { - overlay: overlay, + overlay, self_account: dest, + self_trieid, depth: self.depth + 1, events: Vec::new(), calls: Vec::new(), @@ -295,7 +302,7 @@ where let (change_set, events, calls) = { let mut nested = self.nested( - OverlayAccountDb::new(&self.overlay), + OverlayAccountDb::new(&self.overlay, self.overlay.reg_cache_new_rc(), false), dest.clone() ); @@ -370,7 +377,8 @@ where } let (change_set, events, calls) = { - let mut overlay = OverlayAccountDb::new(&self.overlay); + let mut overlay = OverlayAccountDb::new(&self.overlay, self.overlay.reg_cache_new_rc(), false); + overlay.set_code(&dest, Some(code_hash.clone())); let mut nested = self.nested(overlay, dest.clone()); @@ -554,7 +562,7 @@ where type T = T; fn get_storage(&self, key: &[u8]) -> Option> { - self.ctx.overlay.get_storage(&self.ctx.self_account, key) + self.ctx.overlay.get_storage(&self.ctx.self_trieid, key) } fn set_storage(&mut self, key: &[u8], value: Option>) { @@ -639,9 +647,9 @@ mod tests { use crate::{CodeHash, Config}; use runtime_io::with_externalities; use std::cell::RefCell; + use std::rc::Rc; use std::collections::HashMap; use std::marker::PhantomData; - use std::rc::Rc; use assert_matches::assert_matches; const ALICE: u64 = 1; diff --git a/substrate/srml/contract/src/lib.rs b/substrate/srml/contract/src/lib.rs index 1a703a5321..a3f6faf41c 100644 --- a/substrate/srml/contract/src/lib.rs +++ b/substrate/srml/contract/src/lib.rs @@ -63,7 +63,7 @@ mod wasm; mod tests; use crate::exec::ExecutionContext; -use crate::account_db::AccountDb; +use crate::account_db::{AccountDb, DirectAccountDb}; #[cfg(feature = "std")] use serde_derive::{Serialize, Deserialize}; @@ -73,16 +73,16 @@ use rstd::marker::PhantomData; use parity_codec::{Codec, Encode, Decode}; use runtime_primitives::traits::{Hash, As, SimpleArithmetic,Bounded, StaticLookup}; use srml_support::dispatch::{Result, Dispatchable}; -use srml_support::{Parameter, StorageMap, StorageValue, StorageDoubleMap, decl_module, decl_event, decl_storage}; +use srml_support::{Parameter, StorageMap, StorageValue, decl_module, decl_event, decl_storage, storage::child}; use srml_support::traits::{OnFreeBalanceZero, OnUnbalanced}; use system::{ensure_signed, RawOrigin}; -use runtime_io::{blake2_256, twox_128}; use timestamp; pub type CodeHash = ::Hash; +pub type TrieId = Vec; /// A function that generates an `AccountId` for a contract upon instantiation. -pub trait ContractAddressFor { +pub trait ContractAddressFor { fn contract_address_for(code_hash: &CodeHash, data: &[u8], origin: &AccountId) -> AccountId; } @@ -91,6 +91,48 @@ pub trait ComputeDispatchFee { fn compute_dispatch_fee(call: &Call) -> Balance; } +#[derive(Encode,Decode,Clone,Debug)] +/// Information for managing an acocunt and its sub trie abstraction. +/// This is the required info to cache for an account +pub struct AccountInfo { + /// unique ID for the subtree encoded as a byte + pub trie_id: TrieId, + /// the size of stored value in octet + pub current_mem_stored: u64, +} + +/// Get a trie id (trie id must be unique and collision resistant depending upon its context) +/// Note that it is different than encode because trie id should have collision resistance +/// property (being a proper uniqueid). +pub trait TrieIdGenerator { + /// get a trie id for an account, using reference to parent account trie id to ensure + /// uniqueness of trie id + /// The implementation must ensure every new trie id is unique: two consecutive call with the + /// same parameter needs to return different trie id values. + fn trie_id(account_id: &AccountId) -> TrieId; +} + +/// Get trie id from `account_id` +pub struct TrieIdFromParentCounter(PhantomData); + +/// This generator use inner counter for account id and apply hash over `AccountId + +/// accountid_counter` +impl TrieIdGenerator for TrieIdFromParentCounter +where + T::AccountId: AsRef<[u8]> +{ + fn trie_id(account_id: &T::AccountId) -> TrieId { + // note that skipping a value due to error is not an issue here. + // we only need uniqueness, not sequence. + let new_seed = >::mutate(|v| v.wrapping_add(1)); + + let mut buf = Vec::new(); + buf.extend_from_slice(account_id.as_ref()); + buf.extend_from_slice(&new_seed.to_le_bytes()[..]); + T::Hashing::hash(&buf[..]).as_ref().into() + } +} + pub trait Trait: balances::Trait + timestamp::Trait { /// The outer call dispatch type. type Call: Parameter + Dispatchable::Origin>; @@ -109,6 +151,8 @@ pub trait Trait: balances::Trait + timestamp::Trait { /// It is recommended (though not required) for this function to return a fee that would be taken /// by executive module for regular dispatch. type ComputeDispatchFee: ComputeDispatchFee::Balance>; + /// trieid id generator + type TrieIdGenerator: TrieIdGenerator; /// Handler for the unbalanced reduction when making a gas payment. type GasPayment: OnUnbalanced>; @@ -214,8 +258,8 @@ decl_module! { let result = ctx.call(dest, value, &mut gas_meter, &data, exec::EmptyOutputBuf::new()); if let Ok(_) = result { - // Commit all changes that made it thus far into the persistent storage. - account_db::DirectAccountDb.commit(ctx.overlay.into_change_set()); + // Commit all changes that made it thus far into the persistant storage. + DirectAccountDb.commit(ctx.overlay.into_change_set()); // Then deposit all events produced. ctx.events.into_iter().for_each(Self::deposit_event); @@ -268,7 +312,7 @@ decl_module! { if let Ok(_) = result { // Commit all changes that made it thus far into the persistant storage. - account_db::DirectAccountDb.commit(ctx.overlay.into_change_set()); + DirectAccountDb.commit(ctx.overlay.into_change_set()); // Then deposit all events produced. ctx.events.into_iter().for_each(Self::deposit_event); @@ -344,34 +388,19 @@ decl_storage! { pub PristineCode: map CodeHash => Option>; /// A mapping between an original code hash and instrumented wasm code, ready for the execution. pub CodeStorage: map CodeHash => Option; - } -} - -/// The storage items associated with an account/key. -/// -pub(crate) struct StorageOf(rstd::marker::PhantomData); -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() + /// The subtrie counter + pub AccountCounter: u64 = 0; + /// The code associated with a given account. + pub AccountInfoOf: map T::AccountId => Option; } } impl OnFreeBalanceZero for Module { fn on_free_balance_zero(who: &T::AccountId) { >::remove(who); - >::remove_prefix(who); + >::get_account_info(&DirectAccountDb, who).map(|subtrie| { + child::kill_storage(&subtrie.trie_id); + }); } } diff --git a/substrate/srml/contract/src/tests.rs b/substrate/srml/contract/src/tests.rs index a0cefa664e..2b4768a7ee 100644 --- a/substrate/srml/contract/src/tests.rs +++ b/substrate/srml/contract/src/tests.rs @@ -24,7 +24,7 @@ use runtime_primitives::testing::{Digest, DigestItem, H256, Header, UintAuthorit use runtime_primitives::traits::{BlakeTwo256, IdentityLookup}; use runtime_primitives::BuildStorage; use runtime_io; -use srml_support::{StorageMap, StorageDoubleMap, assert_ok, impl_outer_event, impl_outer_dispatch, +use srml_support::{storage::child, StorageMap, assert_ok, impl_outer_event, impl_outer_dispatch, impl_outer_origin, traits::Currency}; use substrate_primitives::Blake2Hasher; use system::{self, Phase, EventRecord}; @@ -32,9 +32,13 @@ use {wabt, balances, consensus}; use hex_literal::*; use assert_matches::assert_matches; use crate::{ - ContractAddressFor, GenesisConfig, Module, RawEvent, StorageOf, - Trait, ComputeDispatchFee + ContractAddressFor, GenesisConfig, Module, RawEvent, + Trait, ComputeDispatchFee, TrieIdGenerator, TrieId, + AccountInfo, AccountInfoOf, }; +use substrate_primitives::storage::well_known_keys; +use parity_codec::{Encode, Decode, KeyedVec}; +use std::sync::atomic::{AtomicUsize, Ordering}; mod contract { // Re-export contents of the root. This basically @@ -68,7 +72,7 @@ impl system::Trait for Test { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = MetaEvent; type Log = DigestItem; @@ -97,6 +101,7 @@ impl Trait for Test { type DetermineContractAddress = DummyContractAddressFor; type Event = MetaEvent; type ComputeDispatchFee = DummyComputeDispatchFee; + type TrieIdGenerator = DummyTrieIdGenerator; type GasPayment = (); } @@ -111,6 +116,17 @@ impl ContractAddressFor for DummyContractAddressFor { } } +static KEY_COUNTER: AtomicUsize = AtomicUsize::new(0); + +pub struct DummyTrieIdGenerator; +impl TrieIdGenerator for DummyTrieIdGenerator { + fn trie_id(account_id: &u64) -> TrieId { + let mut res = KEY_COUNTER.fetch_add(1, Ordering::Relaxed).to_le_bytes().to_vec(); + res.extend_from_slice(&account_id.to_le_bytes()); + res + } +} + pub struct DummyComputeDispatchFee; impl ComputeDispatchFee for DummyComputeDispatchFee { fn compute_dispatch_fee(call: &Call) -> u64 { @@ -217,18 +233,29 @@ fn refunds_unused_gas() { #[test] fn account_removal_removes_storage() { + let unique_id1 = b"unique_id1"; + let unique_id2 = b"unique_id2"; with_externalities( &mut ExtBuilder::default().existential_deposit(100).build(), || { // Setup two accounts with free balance above than exsistential threshold. { Balances::deposit_creating(&1, 110); - >::insert(&1, &b"foo".to_vec(), b"1".to_vec()); - >::insert(&1, &b"bar".to_vec(), b"2".to_vec()); + AccountInfoOf::::insert(1, &AccountInfo { + trie_id: unique_id1.to_vec(), + current_mem_stored: 0, + }); + child::put(&unique_id1[..], &b"foo".to_vec(), &b"1".to_vec()); + assert_eq!(child::get(&unique_id1[..], &b"foo".to_vec()), Some(b"1".to_vec())); + child::put(&unique_id1[..], &b"bar".to_vec(), &b"2".to_vec()); Balances::deposit_creating(&2, 110); - >::insert(&2, &b"hello".to_vec(), b"3".to_vec()); - >::insert(&2, &b"world".to_vec(), b"4".to_vec()); + AccountInfoOf::::insert(2, &AccountInfo { + trie_id: unique_id2.to_vec(), + current_mem_stored: 0, + }); + child::put(&unique_id2[..], &b"hello".to_vec(), &b"3".to_vec()); + child::put(&unique_id2[..], &b"world".to_vec(), &b"4".to_vec()); } // Transfer funds from account 1 of such amount that after this transfer @@ -240,15 +267,15 @@ fn account_removal_removes_storage() { // Verify that all entries from account 1 is removed, while // entries from account 2 is in place. { - assert_eq!(>::get(&1, &b"foo".to_vec()), None); - assert_eq!(>::get(&1, &b"bar".to_vec()), None); + assert_eq!(child::get_raw(&unique_id1[..], &b"foo".to_vec()), None); + assert_eq!(child::get_raw(&unique_id1[..], &b"bar".to_vec()), None); assert_eq!( - >::get(&2, &b"hello".to_vec()), + child::get(&unique_id2[..], &b"hello".to_vec()), Some(b"3".to_vec()) ); assert_eq!( - >::get(&2, &b"world".to_vec()), + child::get(&unique_id2[..], &b"world".to_vec()), Some(b"4".to_vec()) ); } diff --git a/substrate/srml/council/src/lib.rs b/substrate/srml/council/src/lib.rs index 458e6ffd38..a13eb7e280 100644 --- a/substrate/srml/council/src/lib.rs +++ b/substrate/srml/council/src/lib.rs @@ -67,7 +67,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = Event; type Log = DigestItem; diff --git a/substrate/srml/democracy/src/lib.rs b/substrate/srml/democracy/src/lib.rs index eb0502ccd9..b9538ed249 100644 --- a/substrate/srml/democracy/src/lib.rs +++ b/substrate/srml/democracy/src/lib.rs @@ -501,7 +501,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/substrate/srml/example/src/lib.rs b/substrate/srml/example/src/lib.rs index 452e75ccc3..81a4a7a4ef 100644 --- a/substrate/srml/example/src/lib.rs +++ b/substrate/srml/example/src/lib.rs @@ -271,7 +271,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/substrate/srml/grandpa/src/mock.rs b/substrate/srml/grandpa/src/mock.rs index 7c35141e17..4405604ab1 100644 --- a/substrate/srml/grandpa/src/mock.rs +++ b/substrate/srml/grandpa/src/mock.rs @@ -52,7 +52,7 @@ impl system::Trait for Test { type Hashing = ::primitives::traits::BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = TestEvent; type Log = DigestItem; diff --git a/substrate/srml/session/src/lib.rs b/substrate/srml/session/src/lib.rs index 47fb0fca41..d7d48e27f2 100644 --- a/substrate/srml/session/src/lib.rs +++ b/substrate/srml/session/src/lib.rs @@ -250,7 +250,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/substrate/srml/staking/src/mock.rs b/substrate/srml/staking/src/mock.rs index 662396e2f1..c52baa06db 100644 --- a/substrate/srml/staking/src/mock.rs +++ b/substrate/srml/staking/src/mock.rs @@ -48,7 +48,7 @@ impl system::Trait for Test { type Hashing = ::primitives::traits::BlakeTwo256; type Digest = Digest; type AccountId = AccountIdType; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/substrate/srml/support/src/storage/mod.rs b/substrate/srml/support/src/storage/mod.rs index fde0762877..ec758092f7 100644 --- a/substrate/srml/support/src/storage/mod.rs +++ b/substrate/srml/support/src/storage/mod.rs @@ -38,6 +38,22 @@ impl<'a> Input for IncrementalInput<'a> { } } +struct IncrementalChildInput<'a> { + storage_key: &'a [u8], + key: &'a [u8], + pos: usize, +} + +impl<'a> Input for IncrementalChildInput<'a> { + fn read(&mut self, into: &mut [u8]) -> usize { + let len = runtime_io::read_child_storage(self.storage_key, self.key, into, self.pos).unwrap_or(0); + let read = crate::rstd::cmp::min(len, into.len()); + self.pos += read; + read + } +} + + /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. pub fn get(key: &[u8]) -> Option { let key = twox_128(key); @@ -560,6 +576,104 @@ pub mod unhashed { } } +/// child storage NOTE could replace unhashed by having only one kind of storage (root being null storage +/// key (storage_key can become Option<&[u8]>). +/// This module is a currently only a variant of unhashed with additional `storage_key`. +/// Note that `storage_key` must be unique and strong (strong in the sense of being long enough to +/// avoid collision from a resistant hash function (which unique implies)). +pub mod child { + use super::{runtime_io, Codec, Decode, Vec, IncrementalChildInput}; + + /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. + pub fn get(storage_key: &[u8], key: &[u8]) -> Option { + runtime_io::read_child_storage(storage_key, key, &mut [0; 0][..], 0).map(|_| { + let mut input = IncrementalChildInput { + storage_key, + key, + pos: 0, + }; + Decode::decode(&mut input).expect("storage is not null, therefore must be a valid type") + }) + } + + /// Return the value of the item in storage under `key`, or the type's default if there is no + /// explicit entry. + pub fn get_or_default(storage_key: &[u8], key: &[u8]) -> T { + get(storage_key, key).unwrap_or_else(Default::default) + } + + /// Return the value of the item in storage under `key`, or `default_value` if there is no + /// explicit entry. + pub fn get_or(storage_key: &[u8], key: &[u8], default_value: T) -> T { + get(storage_key, key).unwrap_or(default_value) + } + + /// Return the value of the item in storage under `key`, or `default_value()` if there is no + /// explicit entry. + pub fn get_or_else T>(storage_key: &[u8], key: &[u8], default_value: F) -> T { + get(storage_key, key).unwrap_or_else(default_value) + } + + /// Put `value` in storage under `key`. + pub fn put(storage_key: &[u8], key: &[u8], value: &T) { + value.using_encoded(|slice| runtime_io::set_child_storage(storage_key, key, slice)); + } + + /// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise. + pub fn take(storage_key: &[u8], key: &[u8]) -> Option { + let r = get(storage_key, key); + if r.is_some() { + kill(storage_key, key); + } + r + } + + /// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage, + /// the default for its type. + pub fn take_or_default(storage_key: &[u8], key: &[u8]) -> T { + take(storage_key, key).unwrap_or_else(Default::default) + } + + /// Return the value of the item in storage under `key`, or `default_value` if there is no + /// explicit entry. Ensure there is no explicit entry on return. + pub fn take_or(storage_key: &[u8],key: &[u8], default_value: T) -> T { + take(storage_key, key).unwrap_or(default_value) + } + + /// Return the value of the item in storage under `key`, or `default_value()` if there is no + /// explicit entry. Ensure there is no explicit entry on return. + pub fn take_or_else T>(storage_key: &[u8], key: &[u8], default_value: F) -> T { + take(storage_key, key).unwrap_or_else(default_value) + } + + /// Check to see if `key` has an explicit entry in storage. + pub fn exists(storage_key: &[u8], key: &[u8]) -> bool { + runtime_io::read_child_storage(storage_key, key, &mut [0;0][..], 0).is_some() + } + + /// Remove all `storage_key` key/values + pub fn kill_storage(storage_key: &[u8]) { + runtime_io::kill_child_storage(storage_key) + } + + /// Ensure `key` has no explicit entry in storage. + pub fn kill(storage_key: &[u8], key: &[u8]) { + runtime_io::clear_child_storage(storage_key, key); + } + + /// Get a Vec of bytes from storage. + pub fn get_raw(storage_key: &[u8], key: &[u8]) -> Option> { + runtime_io::child_storage(storage_key, key) + } + + /// Put a raw byte slice into storage. + pub fn put_raw(storage_key: &[u8], key: &[u8], value: &[u8]) { + runtime_io::set_child_storage(storage_key, key, value) + } + + pub use super::unhashed::StorageVec; +} + #[cfg(test)] mod tests { use super::*; diff --git a/substrate/srml/system/src/lib.rs b/substrate/srml/system/src/lib.rs index c5397345a1..c1a5ff9d9a 100644 --- a/substrate/srml/system/src/lib.rs +++ b/substrate/srml/system/src/lib.rs @@ -481,7 +481,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = u16; type Log = DigestItem; diff --git a/substrate/srml/timestamp/src/lib.rs b/substrate/srml/timestamp/src/lib.rs index f3e0d8153e..4eff0dc539 100644 --- a/substrate/srml/timestamp/src/lib.rs +++ b/substrate/srml/timestamp/src/lib.rs @@ -326,7 +326,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem; diff --git a/substrate/srml/treasury/src/lib.rs b/substrate/srml/treasury/src/lib.rs index 8585950f7c..673f989a78 100644 --- a/substrate/srml/treasury/src/lib.rs +++ b/substrate/srml/treasury/src/lib.rs @@ -290,7 +290,7 @@ mod tests { type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; - type Lookup = IdentityLookup; + type Lookup = IdentityLookup; type Header = Header; type Event = (); type Log = DigestItem;