mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-22 02:05:41 +00:00
Introduce prefixed storage with enumeration (#4185)
* Introduce storage_next allowing iteration. (without childtries) * Implement prefixed storage * impl cache in client_storage_cache (needs test) * switch overlay change to btreemap * Revert "impl cache in client_storage_cache" This reverts commit c91a4848916eba87184b3dc4722cea81aec9339d. the storage cache cannot be used this way * Revert "Implement prefixed storage" This reverts commit 4931088126a427082d7310ed7e83b8eea966bc20. * Impl StoragePrefixedMap for all map storages * remove comment * Move all overlays to BTreeMap * btreemap iteration improvment * impl for child tries * impl tests for childs * fix * remove cache comment * Fix grumble
This commit is contained in:
committed by
Bastian Köcher
parent
fb1eb9d9e4
commit
e5b6935c2a
@@ -151,6 +151,14 @@ impl<B: BlockT> StateBackend<Blake2Hasher> for RefTrackingState<B> {
|
|||||||
self.state.exists_child_storage(storage_key, key)
|
self.state.exists_child_storage(storage_key, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
self.state.next_storage_key(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_child_storage_key(&self, storage_key: &[u8], key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
self.state.next_child_storage_key(storage_key, key)
|
||||||
|
}
|
||||||
|
|
||||||
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
|
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
|
||||||
self.state.for_keys_with_prefix(prefix, f)
|
self.state.for_keys_with_prefix(prefix, f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -544,6 +544,14 @@ impl<H: Hasher, S: StateBackend<H>, B: BlockT> StateBackend<H> for CachingState<
|
|||||||
self.state.exists_child_storage(storage_key, key)
|
self.state.exists_child_storage(storage_key, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
self.state.next_storage_key(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_child_storage_key(&self, storage_key: &[u8], key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
self.state.next_child_storage_key(storage_key, key)
|
||||||
|
}
|
||||||
|
|
||||||
fn for_keys_in_child_storage<F: FnMut(&[u8])>(&self, storage_key: &[u8], f: F) {
|
fn for_keys_in_child_storage<F: FnMut(&[u8])>(&self, storage_key: &[u8], f: F) {
|
||||||
self.state.for_keys_in_child_storage(storage_key, f)
|
self.state.for_keys_in_child_storage(storage_key, f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,6 +365,22 @@ impl<H: Hasher> StateBackend<H> for GenesisOrUnavailableState<H>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
match *self {
|
||||||
|
GenesisOrUnavailableState::Genesis(ref state) =>
|
||||||
|
Ok(state.next_storage_key(key).expect(IN_MEMORY_EXPECT_PROOF)),
|
||||||
|
GenesisOrUnavailableState::Unavailable => Err(ClientError::NotAvailableOnLightClient),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_child_storage_key(&self, storage_key: &[u8], key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
match *self {
|
||||||
|
GenesisOrUnavailableState::Genesis(ref state) =>
|
||||||
|
Ok(state.next_child_storage_key(storage_key, key).expect(IN_MEMORY_EXPECT_PROOF)),
|
||||||
|
GenesisOrUnavailableState::Unavailable => Err(ClientError::NotAvailableOnLightClient),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn for_keys_with_prefix<A: FnMut(&[u8])>(&self, prefix: &[u8], action: A) {
|
fn for_keys_with_prefix<A: FnMut(&[u8])>(&self, prefix: &[u8], action: A) {
|
||||||
match *self {
|
match *self {
|
||||||
GenesisOrUnavailableState::Genesis(ref state) => state.for_keys_with_prefix(prefix, action),
|
GenesisOrUnavailableState::Genesis(ref state) => state.for_keys_with_prefix(prefix, action),
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ use proc_macro::TokenStream;
|
|||||||
/// * Map: `Foo: map hasher($hash) type => type`: Implements the
|
/// * Map: `Foo: map hasher($hash) type => type`: Implements the
|
||||||
/// [`StorageMap`](../frame_support/storage/trait.StorageMap.html) trait using the
|
/// [`StorageMap`](../frame_support/storage/trait.StorageMap.html) trait using the
|
||||||
/// [`StorageMap generator`](../frame_support/storage/generator/trait.StorageMap.html).
|
/// [`StorageMap generator`](../frame_support/storage/generator/trait.StorageMap.html).
|
||||||
|
/// And [`StoragePrefixedMap`](../frame_support/storage/trait.StoragePrefixedMap.html).
|
||||||
///
|
///
|
||||||
/// `$hash` representing a choice of hashing algorithms available in the
|
/// `$hash` representing a choice of hashing algorithms available in the
|
||||||
/// [`Hashable`](../frame_support/trait.Hashable.html) trait.
|
/// [`Hashable`](../frame_support/trait.Hashable.html) trait.
|
||||||
@@ -89,6 +90,7 @@ use proc_macro::TokenStream;
|
|||||||
/// * Linked map: `Foo: linked_map hasher($hash) type => type`: Implements the
|
/// * Linked map: `Foo: linked_map hasher($hash) type => type`: Implements the
|
||||||
/// [`StorageLinkedMap`](../frame_support/storage/trait.StorageLinkedMap.html) trait using the
|
/// [`StorageLinkedMap`](../frame_support/storage/trait.StorageLinkedMap.html) trait using the
|
||||||
/// [`StorageLinkedMap generator`](../frame_support/storage/generator/trait.StorageLinkedMap.html).
|
/// [`StorageLinkedMap generator`](../frame_support/storage/generator/trait.StorageLinkedMap.html).
|
||||||
|
/// And [`StoragePrefixedMap`](../frame_support/storage/trait.StoragePrefixedMap.html).
|
||||||
///
|
///
|
||||||
/// `$hash` representing a choice of hashing algorithms available in the
|
/// `$hash` representing a choice of hashing algorithms available in the
|
||||||
/// [`Hashable`](../frame_support/trait.Hashable.html) trait.
|
/// [`Hashable`](../frame_support/trait.Hashable.html) trait.
|
||||||
@@ -118,6 +120,7 @@ use proc_macro::TokenStream;
|
|||||||
/// * Double map: `Foo: double_map hasher($hash1) u32, $hash2(u32) => u32`: Implements the
|
/// * Double map: `Foo: double_map hasher($hash1) u32, $hash2(u32) => u32`: Implements the
|
||||||
/// [`StorageDoubleMap`](../frame_support/storage/trait.StorageDoubleMap.html) trait using the
|
/// [`StorageDoubleMap`](../frame_support/storage/trait.StorageDoubleMap.html) trait using the
|
||||||
/// [`StorageDoubleMap generator`](../frame_support/storage/generator/trait.StorageDoubleMap.html).
|
/// [`StorageDoubleMap generator`](../frame_support/storage/generator/trait.StorageDoubleMap.html).
|
||||||
|
/// And [`StoragePrefixedMap`](../frame_support/storage/trait.StoragePrefixedMap.html).
|
||||||
///
|
///
|
||||||
/// `$hash1` and `$hash2` representing choices of hashing algorithms available in the
|
/// `$hash1` and `$hash2` representing choices of hashing algorithms available in the
|
||||||
/// [`Hashable`](../frame_support/trait.Hashable.html) trait. They must be choosen with care, see
|
/// [`Hashable`](../frame_support/trait.Hashable.html) trait. They must be choosen with care, see
|
||||||
|
|||||||
@@ -418,7 +418,8 @@ pub fn decl_storage_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStr
|
|||||||
StorageValue as _,
|
StorageValue as _,
|
||||||
StorageMap as _,
|
StorageMap as _,
|
||||||
StorageLinkedMap as _,
|
StorageLinkedMap as _,
|
||||||
StorageDoubleMap as _
|
StorageDoubleMap as _,
|
||||||
|
StoragePrefixedMap as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
#scrate_decl
|
#scrate_decl
|
||||||
|
|||||||
@@ -122,6 +122,18 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre
|
|||||||
StorageLineTypeDef::Map(map) => {
|
StorageLineTypeDef::Map(map) => {
|
||||||
let hasher = map.hasher.to_storage_hasher_struct();
|
let hasher = map.hasher.to_storage_hasher_struct();
|
||||||
quote!(
|
quote!(
|
||||||
|
impl<#impl_trait> #scrate::storage::StoragePrefixedMap<#value_type>
|
||||||
|
for #storage_struct #optional_storage_where_clause
|
||||||
|
{
|
||||||
|
fn module_prefix() -> &'static [u8] {
|
||||||
|
#instance_or_inherent::PREFIX.as_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storage_prefix() -> &'static [u8] {
|
||||||
|
#storage_name_str.as_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct
|
impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct
|
||||||
#optional_storage_where_clause
|
#optional_storage_where_clause
|
||||||
{
|
{
|
||||||
@@ -155,6 +167,18 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre
|
|||||||
);
|
);
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
|
impl<#impl_trait> #scrate::storage::StoragePrefixedMap<#value_type>
|
||||||
|
for #storage_struct #optional_storage_where_clause
|
||||||
|
{
|
||||||
|
fn module_prefix() -> &'static [u8] {
|
||||||
|
#instance_or_inherent::PREFIX.as_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storage_prefix() -> &'static [u8] {
|
||||||
|
#storage_name_str.as_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct
|
impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct
|
||||||
#optional_storage_where_clause
|
#optional_storage_where_clause
|
||||||
{
|
{
|
||||||
@@ -191,6 +215,18 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre
|
|||||||
let hasher1 = map.hasher1.to_storage_hasher_struct();
|
let hasher1 = map.hasher1.to_storage_hasher_struct();
|
||||||
let hasher2 = map.hasher2.to_storage_hasher_struct();
|
let hasher2 = map.hasher2.to_storage_hasher_struct();
|
||||||
quote!(
|
quote!(
|
||||||
|
impl<#impl_trait> #scrate::storage::StoragePrefixedMap<#value_type>
|
||||||
|
for #storage_struct #optional_storage_where_clause
|
||||||
|
{
|
||||||
|
fn module_prefix() -> &'static [u8] {
|
||||||
|
#instance_or_inherent::PREFIX.as_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storage_prefix() -> &'static [u8] {
|
||||||
|
#storage_name_str.as_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct
|
impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct
|
||||||
#optional_storage_where_clause
|
#optional_storage_where_clause
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ pub mod traits;
|
|||||||
pub mod weights;
|
pub mod weights;
|
||||||
|
|
||||||
pub use self::hash::{Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat, Hashable};
|
pub use self::hash::{Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat, Hashable};
|
||||||
pub use self::storage::{StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap};
|
pub use self::storage::{
|
||||||
|
StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap, StoragePrefixedMap
|
||||||
|
};
|
||||||
pub use self::dispatch::{Parameter, Callable, IsSubType};
|
pub use self::dispatch::{Parameter, Callable, IsSubType};
|
||||||
pub use sp_runtime::{self, ConsensusEngineId, print, traits::Printable};
|
pub use sp_runtime::{self, ConsensusEngineId, print, traits::Printable};
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
//! Stuff to do with the runtime's storage.
|
//! Stuff to do with the runtime's storage.
|
||||||
|
|
||||||
use rstd::prelude::*;
|
use rstd::{prelude::*, marker::PhantomData};
|
||||||
use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike, Decode};
|
use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike, Decode};
|
||||||
use crate::traits::Len;
|
use crate::{traits::Len, hash::{Twox128, StorageHasher}};
|
||||||
|
|
||||||
pub mod unhashed;
|
pub mod unhashed;
|
||||||
pub mod hashed;
|
pub mod hashed;
|
||||||
@@ -352,3 +352,126 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
|
|||||||
KArg2: EncodeLike<K2>,
|
KArg2: EncodeLike<K2>,
|
||||||
V: codec::DecodeLength + Len;
|
V: codec::DecodeLength + Len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterator for prefixed map.
|
||||||
|
pub struct PrefixIterator<Value> {
|
||||||
|
prefix: Vec<u8>,
|
||||||
|
previous_key: Vec<u8>,
|
||||||
|
phantom_data: PhantomData<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Value: Decode> Iterator for PrefixIterator<Value> {
|
||||||
|
type Item = Value;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match runtime_io::storage::next_key(&self.previous_key) {
|
||||||
|
Some(next_key) if next_key.starts_with(&self.prefix[..]) => {
|
||||||
|
let value = unhashed::get(&next_key);
|
||||||
|
|
||||||
|
if value.is_none() {
|
||||||
|
runtime_print!(
|
||||||
|
"ERROR: returned next_key has no value:\nkey is {:?}\nnext_key is {:?}",
|
||||||
|
&self.previous_key, &next_key,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.previous_key = next_key;
|
||||||
|
|
||||||
|
value
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for maps that store all its value after a unique prefix.
|
||||||
|
///
|
||||||
|
/// By default the final prefix is:
|
||||||
|
/// ```nocompile
|
||||||
|
/// Twox128(module_prefix) ++ Twox128(storage_prefix)
|
||||||
|
/// ```
|
||||||
|
pub trait StoragePrefixedMap<Value: FullCodec> {
|
||||||
|
|
||||||
|
/// Module prefix. Used for generating final key.
|
||||||
|
fn module_prefix() -> &'static [u8];
|
||||||
|
|
||||||
|
/// Storage prefix. Used for generating final key.
|
||||||
|
fn storage_prefix() -> &'static [u8];
|
||||||
|
|
||||||
|
fn final_prefix() -> [u8; 32] {
|
||||||
|
let mut final_key = [0u8; 32];
|
||||||
|
final_key[0..16].copy_from_slice(&Twox128::hash(Self::module_prefix()));
|
||||||
|
final_key[16..32].copy_from_slice(&Twox128::hash(Self::storage_prefix()));
|
||||||
|
final_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_all() {
|
||||||
|
runtime_io::storage::clear_prefix(&Self::final_prefix())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter() -> PrefixIterator<Value> {
|
||||||
|
let prefix = Self::final_prefix();
|
||||||
|
PrefixIterator {
|
||||||
|
prefix: prefix.to_vec(),
|
||||||
|
previous_key: prefix.to_vec(),
|
||||||
|
phantom_data: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use primitives::hashing::twox_128;
|
||||||
|
use runtime_io::TestExternalities;
|
||||||
|
use crate::storage::{unhashed, StoragePrefixedMap};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn prefixed_map_works() {
|
||||||
|
TestExternalities::default().execute_with(|| {
|
||||||
|
struct MyStorage;
|
||||||
|
impl StoragePrefixedMap<u64> for MyStorage {
|
||||||
|
fn module_prefix() -> &'static [u8] {
|
||||||
|
b"MyModule"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storage_prefix() -> &'static [u8] {
|
||||||
|
b"MyStorage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let key_before = {
|
||||||
|
let mut k = MyStorage::final_prefix();
|
||||||
|
let last = k.iter_mut().last().unwrap();
|
||||||
|
*last = last.checked_sub(1).unwrap();
|
||||||
|
k
|
||||||
|
};
|
||||||
|
let key_after = {
|
||||||
|
let mut k = MyStorage::final_prefix();
|
||||||
|
let last = k.iter_mut().last().unwrap();
|
||||||
|
*last = last.checked_add(1).unwrap();
|
||||||
|
k
|
||||||
|
};
|
||||||
|
|
||||||
|
unhashed::put(&key_before[..], &32u64);
|
||||||
|
unhashed::put(&key_after[..], &33u64);
|
||||||
|
|
||||||
|
let k = [twox_128(b"MyModule"), twox_128(b"MyStorage")].concat();
|
||||||
|
assert_eq!(MyStorage::final_prefix().to_vec(), k);
|
||||||
|
|
||||||
|
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![]);
|
||||||
|
|
||||||
|
unhashed::put(&[&k[..], &vec![1][..]].concat(), &1u64);
|
||||||
|
unhashed::put(&[&k[..], &vec![1, 1][..]].concat(), &2u64);
|
||||||
|
unhashed::put(&[&k[..], &vec![8][..]].concat(), &3u64);
|
||||||
|
unhashed::put(&[&k[..], &vec![10][..]].concat(), &4u64);
|
||||||
|
|
||||||
|
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![1, 2, 3, 4]);
|
||||||
|
|
||||||
|
MyStorage::remove_all();
|
||||||
|
|
||||||
|
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![]);
|
||||||
|
assert_eq!(unhashed::get(&key_before[..]), Some(32u64));
|
||||||
|
assert_eq!(unhashed::get(&key_after[..]), Some(33u64));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use support::storage::unhashed;
|
use support::storage::unhashed;
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use support::{StorageDoubleMap, StorageLinkedMap, StorageMap, StorageValue};
|
use support::{StorageDoubleMap, StorageLinkedMap, StorageMap, StorageValue, StoragePrefixedMap};
|
||||||
use runtime_io::{TestExternalities, hashing::{twox_128, blake2_128, blake2_256}};
|
use runtime_io::{TestExternalities, hashing::{twox_128, blake2_128, blake2_256}};
|
||||||
|
|
||||||
mod no_instance {
|
mod no_instance {
|
||||||
@@ -96,11 +96,13 @@ fn final_keys_no_instance() {
|
|||||||
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"Map")].concat();
|
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"Map")].concat();
|
||||||
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
|
assert_eq!(&k[..32], &<no_instance::Map>::final_prefix());
|
||||||
|
|
||||||
no_instance::Map2::insert(1, 2);
|
no_instance::Map2::insert(1, 2);
|
||||||
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"Map2")].concat();
|
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"Map2")].concat();
|
||||||
k.extend(1u32.using_encoded(twox_128).to_vec());
|
k.extend(1u32.using_encoded(twox_128).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
|
assert_eq!(&k[..32], &<no_instance::Map2>::final_prefix());
|
||||||
|
|
||||||
let head = [twox_128(b"FinalKeysNone"), twox_128(b"HeadOfLinkedMap")].concat();
|
let head = [twox_128(b"FinalKeysNone"), twox_128(b"HeadOfLinkedMap")].concat();
|
||||||
assert_eq!(unhashed::get::<u32>(&head), None);
|
assert_eq!(unhashed::get::<u32>(&head), None);
|
||||||
@@ -110,23 +112,27 @@ fn final_keys_no_instance() {
|
|||||||
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
assert_eq!(unhashed::get::<u32>(&head), Some(1u32));
|
assert_eq!(unhashed::get::<u32>(&head), Some(1u32));
|
||||||
|
assert_eq!(&k[..32], &<no_instance::LinkedMap>::final_prefix());
|
||||||
|
|
||||||
no_instance::LinkedMap2::insert(1, 2);
|
no_instance::LinkedMap2::insert(1, 2);
|
||||||
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"LinkedMap2")].concat();
|
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"LinkedMap2")].concat();
|
||||||
k.extend(1u32.using_encoded(twox_128).to_vec());
|
k.extend(1u32.using_encoded(twox_128).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
|
assert_eq!(&k[..32], &<no_instance::LinkedMap2>::final_prefix());
|
||||||
|
|
||||||
no_instance::DoubleMap::insert(&1, &2, &3);
|
no_instance::DoubleMap::insert(&1, &2, &3);
|
||||||
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"DoubleMap")].concat();
|
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"DoubleMap")].concat();
|
||||||
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
||||||
k.extend(2u32.using_encoded(blake2_256).to_vec());
|
k.extend(2u32.using_encoded(blake2_256).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
||||||
|
assert_eq!(&k[..32], &<no_instance::DoubleMap>::final_prefix());
|
||||||
|
|
||||||
no_instance::DoubleMap2::insert(&1, &2, &3);
|
no_instance::DoubleMap2::insert(&1, &2, &3);
|
||||||
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"DoubleMap2")].concat();
|
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"DoubleMap2")].concat();
|
||||||
k.extend(1u32.using_encoded(twox_128).to_vec());
|
k.extend(1u32.using_encoded(twox_128).to_vec());
|
||||||
k.extend(2u32.using_encoded(blake2_128).to_vec());
|
k.extend(2u32.using_encoded(blake2_128).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
||||||
|
assert_eq!(&k[..32], &<no_instance::DoubleMap2>::final_prefix());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,11 +147,13 @@ fn final_keys_default_instance() {
|
|||||||
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"Map")].concat();
|
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"Map")].concat();
|
||||||
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::Map<instance::DefaultInstance>>::final_prefix());
|
||||||
|
|
||||||
<instance::Map2<instance::DefaultInstance>>::insert(1, 2);
|
<instance::Map2<instance::DefaultInstance>>::insert(1, 2);
|
||||||
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"Map2")].concat();
|
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"Map2")].concat();
|
||||||
k.extend(1u32.using_encoded(twox_128).to_vec());
|
k.extend(1u32.using_encoded(twox_128).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::Map2<instance::DefaultInstance>>::final_prefix());
|
||||||
|
|
||||||
let head = [twox_128(b"FinalKeysSome"), twox_128(b"HeadOfLinkedMap")].concat();
|
let head = [twox_128(b"FinalKeysSome"), twox_128(b"HeadOfLinkedMap")].concat();
|
||||||
assert_eq!(unhashed::get::<u32>(&head), None);
|
assert_eq!(unhashed::get::<u32>(&head), None);
|
||||||
@@ -155,23 +163,27 @@ fn final_keys_default_instance() {
|
|||||||
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
assert_eq!(unhashed::get::<u32>(&head), Some(1u32));
|
assert_eq!(unhashed::get::<u32>(&head), Some(1u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::LinkedMap<instance::DefaultInstance>>::final_prefix());
|
||||||
|
|
||||||
<instance::LinkedMap2<instance::DefaultInstance>>::insert(1, 2);
|
<instance::LinkedMap2<instance::DefaultInstance>>::insert(1, 2);
|
||||||
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"LinkedMap2")].concat();
|
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"LinkedMap2")].concat();
|
||||||
k.extend(1u32.using_encoded(twox_128).to_vec());
|
k.extend(1u32.using_encoded(twox_128).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::LinkedMap2<instance::DefaultInstance>>::final_prefix());
|
||||||
|
|
||||||
<instance::DoubleMap<instance::DefaultInstance>>::insert(&1, &2, &3);
|
<instance::DoubleMap<instance::DefaultInstance>>::insert(&1, &2, &3);
|
||||||
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"DoubleMap")].concat();
|
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"DoubleMap")].concat();
|
||||||
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
||||||
k.extend(2u32.using_encoded(blake2_256).to_vec());
|
k.extend(2u32.using_encoded(blake2_256).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::DoubleMap<instance::DefaultInstance>>::final_prefix());
|
||||||
|
|
||||||
<instance::DoubleMap2<instance::DefaultInstance>>::insert(&1, &2, &3);
|
<instance::DoubleMap2<instance::DefaultInstance>>::insert(&1, &2, &3);
|
||||||
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"DoubleMap2")].concat();
|
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"DoubleMap2")].concat();
|
||||||
k.extend(1u32.using_encoded(twox_128).to_vec());
|
k.extend(1u32.using_encoded(twox_128).to_vec());
|
||||||
k.extend(2u32.using_encoded(blake2_128).to_vec());
|
k.extend(2u32.using_encoded(blake2_128).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::DoubleMap2<instance::DefaultInstance>>::final_prefix());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,11 +198,13 @@ fn final_keys_instance_2() {
|
|||||||
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"Map")].concat();
|
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"Map")].concat();
|
||||||
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::Map<instance::Instance2>>::final_prefix());
|
||||||
|
|
||||||
<instance::Map2<instance::Instance2>>::insert(1, 2);
|
<instance::Map2<instance::Instance2>>::insert(1, 2);
|
||||||
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"Map2")].concat();
|
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"Map2")].concat();
|
||||||
k.extend(1u32.using_encoded(twox_128).to_vec());
|
k.extend(1u32.using_encoded(twox_128).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::Map2<instance::Instance2>>::final_prefix());
|
||||||
|
|
||||||
let head = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"HeadOfLinkedMap")].concat();
|
let head = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"HeadOfLinkedMap")].concat();
|
||||||
assert_eq!(unhashed::get::<u32>(&head), None);
|
assert_eq!(unhashed::get::<u32>(&head), None);
|
||||||
@@ -200,22 +214,26 @@ fn final_keys_instance_2() {
|
|||||||
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
assert_eq!(unhashed::get::<u32>(&head), Some(1u32));
|
assert_eq!(unhashed::get::<u32>(&head), Some(1u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::LinkedMap<instance::Instance2>>::final_prefix());
|
||||||
|
|
||||||
<instance::LinkedMap2<instance::Instance2>>::insert(1, 2);
|
<instance::LinkedMap2<instance::Instance2>>::insert(1, 2);
|
||||||
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"LinkedMap2")].concat();
|
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"LinkedMap2")].concat();
|
||||||
k.extend(1u32.using_encoded(twox_128).to_vec());
|
k.extend(1u32.using_encoded(twox_128).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::LinkedMap2<instance::Instance2>>::final_prefix());
|
||||||
|
|
||||||
<instance::DoubleMap<instance::Instance2>>::insert(&1, &2, &3);
|
<instance::DoubleMap<instance::Instance2>>::insert(&1, &2, &3);
|
||||||
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"DoubleMap")].concat();
|
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"DoubleMap")].concat();
|
||||||
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
k.extend(1u32.using_encoded(blake2_256).to_vec());
|
||||||
k.extend(2u32.using_encoded(blake2_256).to_vec());
|
k.extend(2u32.using_encoded(blake2_256).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::DoubleMap<instance::Instance2>>::final_prefix());
|
||||||
|
|
||||||
<instance::DoubleMap2<instance::Instance2>>::insert(&1, &2, &3);
|
<instance::DoubleMap2<instance::Instance2>>::insert(&1, &2, &3);
|
||||||
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"DoubleMap2")].concat();
|
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"DoubleMap2")].concat();
|
||||||
k.extend(1u32.using_encoded(twox_128).to_vec());
|
k.extend(1u32.using_encoded(twox_128).to_vec());
|
||||||
k.extend(2u32.using_encoded(blake2_128).to_vec());
|
k.extend(2u32.using_encoded(blake2_128).to_vec());
|
||||||
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
|
||||||
|
assert_eq!(&k[..32], &<instance::DoubleMap2<instance::Instance2>>::final_prefix());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -300,7 +300,7 @@ fn new_test_ext() -> runtime_io::TestExternalities {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn storage_instance_independance() {
|
fn storage_instance_independance() {
|
||||||
let mut storage = (std::collections::HashMap::new(), std::collections::HashMap::new());
|
let mut storage = Default::default();
|
||||||
state_machine::BasicExternalities::execute_with_storage(&mut storage, || {
|
state_machine::BasicExternalities::execute_with_storage(&mut storage, || {
|
||||||
module2::Value::<Runtime>::put(0);
|
module2::Value::<Runtime>::put(0);
|
||||||
module2::Value::<Runtime, module2::Instance1>::put(0);
|
module2::Value::<Runtime, module2::Instance1>::put(0);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ pub struct StorageData(
|
|||||||
|
|
||||||
/// A set of key value pairs for storage.
|
/// A set of key value pairs for storage.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub type StorageOverlay = std::collections::HashMap<Vec<u8>, Vec<u8>>;
|
pub type StorageOverlay = std::collections::BTreeMap<Vec<u8>, Vec<u8>>;
|
||||||
|
|
||||||
/// A set of key value pairs for children storage;
|
/// A set of key value pairs for children storage;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
|||||||
@@ -106,6 +106,12 @@ pub trait Externalities: ExtensionStore {
|
|||||||
self.child_storage(storage_key, key).is_some()
|
self.child_storage(storage_key, key).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the key immediately following the given key, if it exists.
|
||||||
|
fn next_storage_key(&self, key: &[u8]) -> Option<Vec<u8>>;
|
||||||
|
|
||||||
|
/// Returns the key immediately following the given key, if it exists, in child storage.
|
||||||
|
fn next_child_storage_key(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>>;
|
||||||
|
|
||||||
/// Clear an entire child storage.
|
/// Clear an entire child storage.
|
||||||
fn kill_child_storage(&mut self, storage_key: ChildStorageKey);
|
fn kill_child_storage(&mut self, storage_key: ChildStorageKey);
|
||||||
|
|
||||||
|
|||||||
@@ -213,6 +213,17 @@ pub trait Storage {
|
|||||||
fn changes_root(&mut self, parent_hash: &[u8]) -> Option<Vec<u8>> {
|
fn changes_root(&mut self, parent_hash: &[u8]) -> Option<Vec<u8>> {
|
||||||
self.storage_changes_root(parent_hash).ok().and_then(|h| h)
|
self.storage_changes_root(parent_hash).ok().and_then(|h| h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the next key in storage after the given one in lexicographic order.
|
||||||
|
fn next_key(&mut self, key: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
self.next_storage_key(&key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next key in storage after the given one in lexicographic order in child storage.
|
||||||
|
fn child_next_key(&mut self, child_storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
let storage_key = child_storage_key_or_panic(child_storage_key);
|
||||||
|
self.next_child_storage_key(storage_key, key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interface that provides trie related functionality.
|
/// Interface that provides trie related functionality.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
//! State machine backends. These manage the code and storage of contracts.
|
//! State machine backends. These manage the code and storage of contracts.
|
||||||
|
|
||||||
use std::{error, fmt, cmp::Ord, collections::HashMap, marker::PhantomData};
|
use std::{error, fmt, cmp::Ord, collections::{HashMap, BTreeMap}, marker::PhantomData, ops};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
use crate::trie_backend::TrieBackend;
|
use crate::trie_backend::TrieBackend;
|
||||||
@@ -67,6 +67,16 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
|
|||||||
Ok(self.child_storage(storage_key, key)?.is_some())
|
Ok(self.child_storage(storage_key, key)?.is_some())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the next key in storage in lexicographic order or `None` if there is no value.
|
||||||
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
|
||||||
|
|
||||||
|
/// Return the next key in child storage in lexicographic order or `None` if there is no value.
|
||||||
|
fn next_child_storage_key(
|
||||||
|
&self,
|
||||||
|
storage_key: &[u8],
|
||||||
|
key: &[u8]
|
||||||
|
) -> Result<Option<Vec<u8>>, Self::Error>;
|
||||||
|
|
||||||
/// Retrieve all entries keys of child storage and call `f` for each of those keys.
|
/// Retrieve all entries keys of child storage and call `f` for each of those keys.
|
||||||
fn for_keys_in_child_storage<F: FnMut(&[u8])>(&self, storage_key: &[u8], f: F);
|
fn for_keys_in_child_storage<F: FnMut(&[u8])>(&self, storage_key: &[u8], f: F);
|
||||||
|
|
||||||
@@ -171,6 +181,14 @@ impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T {
|
|||||||
(*self).child_storage(storage_key, key)
|
(*self).child_storage(storage_key, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
(*self).next_storage_key(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_child_storage_key(&self, storage_key: &[u8], key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
(*self).next_child_storage_key(storage_key, key)
|
||||||
|
}
|
||||||
|
|
||||||
fn for_keys_in_child_storage<F: FnMut(&[u8])>(&self, storage_key: &[u8], f: F) {
|
fn for_keys_in_child_storage<F: FnMut(&[u8])>(&self, storage_key: &[u8], f: F) {
|
||||||
(*self).for_keys_in_child_storage(storage_key, f)
|
(*self).for_keys_in_child_storage(storage_key, f)
|
||||||
}
|
}
|
||||||
@@ -250,7 +268,7 @@ impl error::Error for Void {
|
|||||||
/// In-memory backend. Fully recomputes tries each time `as_trie_backend` is called but useful for
|
/// In-memory backend. Fully recomputes tries each time `as_trie_backend` is called but useful for
|
||||||
/// tests and proof checking.
|
/// tests and proof checking.
|
||||||
pub struct InMemory<H: Hasher> {
|
pub struct InMemory<H: Hasher> {
|
||||||
inner: HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>,
|
inner: HashMap<Option<Vec<u8>>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||||
// This field is only needed for returning reference in `as_trie_backend`.
|
// This field is only needed for returning reference in `as_trie_backend`.
|
||||||
trie: Option<TrieBackend<MemoryDB<H>, H>>,
|
trie: Option<TrieBackend<MemoryDB<H>, H>>,
|
||||||
_hasher: PhantomData<H>,
|
_hasher: PhantomData<H>,
|
||||||
@@ -291,7 +309,7 @@ impl<H: Hasher> PartialEq for InMemory<H> {
|
|||||||
impl<H: Hasher> InMemory<H> where H::Out: Codec {
|
impl<H: Hasher> InMemory<H> where H::Out: Codec {
|
||||||
/// Copy the state, with applied updates
|
/// Copy the state, with applied updates
|
||||||
pub fn update(&self, changes: <Self as Backend<H>>::Transaction) -> Self {
|
pub fn update(&self, changes: <Self as Backend<H>>::Transaction) -> Self {
|
||||||
let mut inner: HashMap<_, _> = self.inner.clone();
|
let mut inner = self.inner.clone();
|
||||||
for (storage_key, key, val) in changes {
|
for (storage_key, key, val) in changes {
|
||||||
match val {
|
match val {
|
||||||
Some(v) => { inner.entry(storage_key).or_default().insert(key, v); },
|
Some(v) => { inner.entry(storage_key).or_default().insert(key, v); },
|
||||||
@@ -303,8 +321,8 @@ impl<H: Hasher> InMemory<H> where H::Out: Codec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: Hasher> From<HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>> for InMemory<H> {
|
impl<H: Hasher> From<HashMap<Option<Vec<u8>>, BTreeMap<Vec<u8>, Vec<u8>>>> for InMemory<H> {
|
||||||
fn from(inner: HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>) -> Self {
|
fn from(inner: HashMap<Option<Vec<u8>>, BTreeMap<Vec<u8>, Vec<u8>>>) -> Self {
|
||||||
InMemory {
|
InMemory {
|
||||||
inner: inner,
|
inner: inner,
|
||||||
trie: None,
|
trie: None,
|
||||||
@@ -314,14 +332,14 @@ impl<H: Hasher> From<HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>> for In
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<H: Hasher> From<(
|
impl<H: Hasher> From<(
|
||||||
HashMap<Vec<u8>, Vec<u8>>,
|
BTreeMap<Vec<u8>, Vec<u8>>,
|
||||||
HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>,
|
HashMap<Vec<u8>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||||
)> for InMemory<H> {
|
)> for InMemory<H> {
|
||||||
fn from(inners: (
|
fn from(inners: (
|
||||||
HashMap<Vec<u8>, Vec<u8>>,
|
BTreeMap<Vec<u8>, Vec<u8>>,
|
||||||
HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>,
|
HashMap<Vec<u8>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||||
)) -> Self {
|
)) -> Self {
|
||||||
let mut inner: HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>
|
let mut inner: HashMap<Option<Vec<u8>>, BTreeMap<Vec<u8>, Vec<u8>>>
|
||||||
= inners.1.into_iter().map(|(k, v)| (Some(k), v)).collect();
|
= inners.1.into_iter().map(|(k, v)| (Some(k), v)).collect();
|
||||||
inner.insert(None, inners.0);
|
inner.insert(None, inners.0);
|
||||||
InMemory {
|
InMemory {
|
||||||
@@ -332,8 +350,8 @@ impl<H: Hasher> From<(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: Hasher> From<HashMap<Vec<u8>, Vec<u8>>> for InMemory<H> {
|
impl<H: Hasher> From<BTreeMap<Vec<u8>, Vec<u8>>> for InMemory<H> {
|
||||||
fn from(inner: HashMap<Vec<u8>, Vec<u8>>) -> Self {
|
fn from(inner: BTreeMap<Vec<u8>, Vec<u8>>) -> Self {
|
||||||
let mut expanded = HashMap::new();
|
let mut expanded = HashMap::new();
|
||||||
expanded.insert(None, inner);
|
expanded.insert(None, inner);
|
||||||
InMemory {
|
InMemory {
|
||||||
@@ -346,7 +364,7 @@ impl<H: Hasher> From<HashMap<Vec<u8>, Vec<u8>>> for InMemory<H> {
|
|||||||
|
|
||||||
impl<H: Hasher> From<Vec<(Option<Vec<u8>>, Vec<u8>, Option<Vec<u8>>)>> for InMemory<H> {
|
impl<H: Hasher> From<Vec<(Option<Vec<u8>>, Vec<u8>, Option<Vec<u8>>)>> for InMemory<H> {
|
||||||
fn from(inner: Vec<(Option<Vec<u8>>, Vec<u8>, Option<Vec<u8>>)>) -> Self {
|
fn from(inner: Vec<(Option<Vec<u8>>, Vec<u8>, Option<Vec<u8>>)>) -> Self {
|
||||||
let mut expanded: HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>> = HashMap::new();
|
let mut expanded: HashMap<Option<Vec<u8>>, BTreeMap<Vec<u8>, Vec<u8>>> = HashMap::new();
|
||||||
for (child_key, key, value) in inner {
|
for (child_key, key, value) in inner {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
expanded.entry(child_key).or_default().insert(key, value);
|
expanded.entry(child_key).or_default().insert(key, value);
|
||||||
@@ -380,6 +398,22 @@ impl<H: Hasher> Backend<H> for InMemory<H> where H::Out: Codec {
|
|||||||
Ok(self.inner.get(&None).map(|map| map.get(key).is_some()).unwrap_or(false))
|
Ok(self.inner.get(&None).map(|map| map.get(key).is_some()).unwrap_or(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded);
|
||||||
|
let next_key = self.inner.get(&None)
|
||||||
|
.and_then(|map| map.range::<[u8], _>(range).next().map(|(k, _)| k).cloned());
|
||||||
|
|
||||||
|
Ok(next_key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_child_storage_key(&self, storage_key: &[u8], key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded);
|
||||||
|
let next_key = self.inner.get(&Some(storage_key.to_vec()))
|
||||||
|
.and_then(|map| map.range::<[u8], _>(range).next().map(|(k, _)| k).cloned());
|
||||||
|
|
||||||
|
Ok(next_key)
|
||||||
|
}
|
||||||
|
|
||||||
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
|
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
|
||||||
self.inner.get(&None).map(|map| map.keys().filter(|key| key.starts_with(prefix)).map(|k| &**k).for_each(f));
|
self.inner.get(&None).map(|map| map.keys().filter(|key| key.starts_with(prefix)).map(|k| &**k).for_each(f));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
//! Basic implementation for Externalities.
|
//! Basic implementation for Externalities.
|
||||||
|
|
||||||
use std::{collections::HashMap, any::{TypeId, Any}, iter::FromIterator};
|
use std::{
|
||||||
|
collections::{HashMap, BTreeMap}, any::{TypeId, Any}, iter::FromIterator, mem, ops::Bound
|
||||||
|
};
|
||||||
use crate::backend::{Backend, InMemory};
|
use crate::backend::{Backend, InMemory};
|
||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
use trie::{TrieConfiguration, default_child_trie_root};
|
use trie::{TrieConfiguration, default_child_trie_root};
|
||||||
@@ -54,8 +56,8 @@ impl BasicExternalities {
|
|||||||
|
|
||||||
/// Consume self and returns inner storages
|
/// Consume self and returns inner storages
|
||||||
pub fn into_storages(self) -> (
|
pub fn into_storages(self) -> (
|
||||||
HashMap<Vec<u8>, Vec<u8>>,
|
BTreeMap<Vec<u8>, Vec<u8>>,
|
||||||
HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>,
|
HashMap<Vec<u8>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||||
) {
|
) {
|
||||||
(self.top, self.children)
|
(self.top, self.children)
|
||||||
}
|
}
|
||||||
@@ -68,8 +70,8 @@ impl BasicExternalities {
|
|||||||
f: impl FnOnce() -> R,
|
f: impl FnOnce() -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
let mut ext = Self {
|
let mut ext = Self {
|
||||||
top: storage.0.drain().collect(),
|
top: mem::replace(&mut storage.0, BTreeMap::default()),
|
||||||
children: storage.1.drain().collect(),
|
children: mem::replace(&mut storage.1, HashMap::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let r = ext.execute_with(f);
|
let r = ext.execute_with(f);
|
||||||
@@ -105,8 +107,8 @@ impl Default for BasicExternalities {
|
|||||||
fn default() -> Self { Self::new(Default::default(), Default::default()) }
|
fn default() -> Self { Self::new(Default::default(), Default::default()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<HashMap<Vec<u8>, Vec<u8>>> for BasicExternalities {
|
impl From<BTreeMap<Vec<u8>, Vec<u8>>> for BasicExternalities {
|
||||||
fn from(hashmap: HashMap<Vec<u8>, Vec<u8>>) -> Self {
|
fn from(hashmap: BTreeMap<Vec<u8>, Vec<u8>>) -> Self {
|
||||||
BasicExternalities {
|
BasicExternalities {
|
||||||
top: hashmap,
|
top: hashmap,
|
||||||
children: Default::default(),
|
children: Default::default(),
|
||||||
@@ -151,6 +153,17 @@ impl Externalities for BasicExternalities {
|
|||||||
Externalities::child_storage(self, storage_key, key)
|
Externalities::child_storage(self, storage_key, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_storage_key(&self, key: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
let range = (Bound::Excluded(key), Bound::Unbounded);
|
||||||
|
self.top.range::<[u8], _>(range).next().map(|(k, _)| k).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_child_storage_key(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
let range = (Bound::Excluded(key), Bound::Unbounded);
|
||||||
|
self.children.get(storage_key.as_ref())
|
||||||
|
.and_then(|child| child.range::<[u8], _>(range).next().map(|(k, _)| k).cloned())
|
||||||
|
}
|
||||||
|
|
||||||
fn place_storage(&mut self, key: Vec<u8>, maybe_value: Option<Vec<u8>>) {
|
fn place_storage(&mut self, key: Vec<u8>, maybe_value: Option<Vec<u8>>) {
|
||||||
if is_child_storage_key(&key) {
|
if is_child_storage_key(&key) {
|
||||||
warn!(target: "trie", "Refuse to set child storage key via main storage");
|
warn!(target: "trie", "Refuse to set child storage key via main storage");
|
||||||
@@ -190,12 +203,28 @@ impl Externalities for BasicExternalities {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.top.retain(|key, _| !key.starts_with(prefix));
|
let to_remove = self.top.range::<[u8], _>((Bound::Included(prefix), Bound::Unbounded))
|
||||||
|
.map(|(k, _)| k)
|
||||||
|
.take_while(|k| k.starts_with(prefix))
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for key in to_remove {
|
||||||
|
self.top.remove(&key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_child_prefix(&mut self, storage_key: ChildStorageKey, prefix: &[u8]) {
|
fn clear_child_prefix(&mut self, storage_key: ChildStorageKey, prefix: &[u8]) {
|
||||||
if let Some(child) = self.children.get_mut(storage_key.as_ref()) {
|
if let Some(child) = self.children.get_mut(storage_key.as_ref()) {
|
||||||
child.retain(|key, _| !key.starts_with(prefix));
|
let to_remove = child.range::<[u8], _>((Bound::Included(prefix), Bound::Unbounded))
|
||||||
|
.map(|(k, _)| k)
|
||||||
|
.take_while(|k| k.starts_with(prefix))
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for key in to_remove {
|
||||||
|
child.remove(&key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ mod test {
|
|||||||
(vec![103], vec![255]),
|
(vec![103], vec![255]),
|
||||||
(vec![104], vec![255]),
|
(vec![104], vec![255]),
|
||||||
(vec![105], vec![255]),
|
(vec![105], vec![255]),
|
||||||
].into_iter().collect::<::std::collections::HashMap<_, _>>().into();
|
].into_iter().collect::<::std::collections::BTreeMap<_, _>>().into();
|
||||||
let child_trie_key1 = b"1".to_vec();
|
let child_trie_key1 = b"1".to_vec();
|
||||||
let child_trie_key2 = b"2".to_vec();
|
let child_trie_key2 = b"2".to_vec();
|
||||||
let storage = InMemoryStorage::with_inputs(vec![
|
let storage = InMemoryStorage::with_inputs(vec![
|
||||||
|
|||||||
@@ -336,6 +336,40 @@ where
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_storage_key(&self, key: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
let next_backend_key = self.backend.next_storage_key(key).expect(EXT_NOT_ALLOWED_TO_FAIL);
|
||||||
|
let next_overlay_key_change = self.overlay.next_storage_key_change(key);
|
||||||
|
|
||||||
|
match (next_backend_key, next_overlay_key_change) {
|
||||||
|
(Some(backend_key), Some(overlay_key)) if &backend_key[..] < overlay_key.0 => Some(backend_key),
|
||||||
|
(backend_key, None) => backend_key,
|
||||||
|
(_, Some(overlay_key)) => if overlay_key.1.value.is_some() {
|
||||||
|
Some(overlay_key.0.to_vec())
|
||||||
|
} else {
|
||||||
|
self.next_storage_key(&overlay_key.0[..])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_child_storage_key(&self, storage_key: ChildStorageKey, key: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
let next_backend_key = self.backend.next_child_storage_key(storage_key.as_ref(), key)
|
||||||
|
.expect(EXT_NOT_ALLOWED_TO_FAIL);
|
||||||
|
let next_overlay_key_change = self.overlay.next_child_storage_key_change(
|
||||||
|
storage_key.as_ref(),
|
||||||
|
key
|
||||||
|
);
|
||||||
|
|
||||||
|
match (next_backend_key, next_overlay_key_change) {
|
||||||
|
(Some(backend_key), Some(overlay_key)) if &backend_key[..] < overlay_key.0 => Some(backend_key),
|
||||||
|
(backend_key, None) => backend_key,
|
||||||
|
(_, Some(overlay_key)) => if overlay_key.1.value.is_some() {
|
||||||
|
Some(overlay_key.0.to_vec())
|
||||||
|
} else {
|
||||||
|
self.next_child_storage_key(storage_key, &overlay_key.0[..])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn place_storage(&mut self, key: Vec<u8>, value: Option<Vec<u8>>) {
|
fn place_storage(&mut self, key: Vec<u8>, value: Option<Vec<u8>>) {
|
||||||
trace!(target: "state-trace", "{:04x}: Put {}={:?}",
|
trace!(target: "state-trace", "{:04x}: Put {}={:?}",
|
||||||
self.id,
|
self.id,
|
||||||
@@ -619,4 +653,71 @@ mod tests {
|
|||||||
Some(hex!("96f5aae4690e7302737b6f9b7f8567d5bbb9eac1c315f80101235a92d9ec27f4").to_vec()),
|
Some(hex!("96f5aae4690e7302737b6f9b7f8567d5bbb9eac1c315f80101235a92d9ec27f4").to_vec()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn next_storage_key_works() {
|
||||||
|
let mut overlay = OverlayedChanges::default();
|
||||||
|
overlay.set_storage(vec![20], None);
|
||||||
|
overlay.set_storage(vec![30], Some(vec![31]));
|
||||||
|
let backend = vec![
|
||||||
|
(None, vec![10], Some(vec![10])),
|
||||||
|
(None, vec![20], Some(vec![20])),
|
||||||
|
(None, vec![40], Some(vec![40])),
|
||||||
|
].into();
|
||||||
|
|
||||||
|
let ext = TestExt::new(&mut overlay, &backend, None, None);
|
||||||
|
|
||||||
|
// next_backend < next_overlay
|
||||||
|
assert_eq!(ext.next_storage_key(&[5]), Some(vec![10]));
|
||||||
|
|
||||||
|
// next_backend == next_overlay but next_overlay is a delete
|
||||||
|
assert_eq!(ext.next_storage_key(&[10]), Some(vec![30]));
|
||||||
|
|
||||||
|
// next_overlay < next_backend
|
||||||
|
assert_eq!(ext.next_storage_key(&[20]), Some(vec![30]));
|
||||||
|
|
||||||
|
// next_backend exist but next_overlay doesn't exist
|
||||||
|
assert_eq!(ext.next_storage_key(&[30]), Some(vec![40]));
|
||||||
|
|
||||||
|
drop(ext);
|
||||||
|
overlay.set_storage(vec![50], Some(vec![50]));
|
||||||
|
let ext = TestExt::new(&mut overlay, &backend, None, None);
|
||||||
|
|
||||||
|
// next_overlay exist but next_backend doesn't exist
|
||||||
|
assert_eq!(ext.next_storage_key(&[40]), Some(vec![50]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn next_child_storage_key_works() {
|
||||||
|
let child = || ChildStorageKey::from_slice(b":child_storage:default:Child1").unwrap();
|
||||||
|
let mut overlay = OverlayedChanges::default();
|
||||||
|
overlay.set_child_storage(child().as_ref().to_vec(), vec![20], None);
|
||||||
|
overlay.set_child_storage(child().as_ref().to_vec(), vec![30], Some(vec![31]));
|
||||||
|
let backend = vec![
|
||||||
|
(Some(child().as_ref().to_vec()), vec![10], Some(vec![10])),
|
||||||
|
(Some(child().as_ref().to_vec()), vec![20], Some(vec![20])),
|
||||||
|
(Some(child().as_ref().to_vec()), vec![40], Some(vec![40])),
|
||||||
|
].into();
|
||||||
|
|
||||||
|
let ext = TestExt::new(&mut overlay, &backend, None, None);
|
||||||
|
|
||||||
|
// next_backend < next_overlay
|
||||||
|
assert_eq!(ext.next_child_storage_key(child(), &[5]), Some(vec![10]));
|
||||||
|
|
||||||
|
// next_backend == next_overlay but next_overlay is a delete
|
||||||
|
assert_eq!(ext.next_child_storage_key(child(), &[10]), Some(vec![30]));
|
||||||
|
|
||||||
|
// next_overlay < next_backend
|
||||||
|
assert_eq!(ext.next_child_storage_key(child(), &[20]), Some(vec![30]));
|
||||||
|
|
||||||
|
// next_backend exist but next_overlay doesn't exist
|
||||||
|
assert_eq!(ext.next_child_storage_key(child(), &[30]), Some(vec![40]));
|
||||||
|
|
||||||
|
drop(ext);
|
||||||
|
overlay.set_child_storage(child().as_ref().to_vec(), vec![50], Some(vec![50]));
|
||||||
|
let ext = TestExt::new(&mut overlay, &backend, None, None);
|
||||||
|
|
||||||
|
// next_overlay exist but next_backend doesn't exist
|
||||||
|
assert_eq!(ext.next_child_storage_key(child(), &[40]), Some(vec![50]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -731,7 +731,7 @@ fn try_read_overlay_value<H, B>(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::HashMap;
|
use std::collections::BTreeMap;
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use overlayed_changes::OverlayedValue;
|
use overlayed_changes::OverlayedValue;
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -921,7 +921,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn clear_prefix_in_ext_works() {
|
fn clear_prefix_in_ext_works() {
|
||||||
let initial: HashMap<_, _> = map![
|
let initial: BTreeMap<_, _> = map![
|
||||||
b"aaa".to_vec() => b"0".to_vec(),
|
b"aaa".to_vec() => b"0".to_vec(),
|
||||||
b"abb".to_vec() => b"1".to_vec(),
|
b"abb".to_vec() => b"1".to_vec(),
|
||||||
b"abc".to_vec() => b"2".to_vec(),
|
b"abc".to_vec() => b"2".to_vec(),
|
||||||
|
|||||||
@@ -18,10 +18,11 @@
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::collections::{HashMap, BTreeSet};
|
use std::collections::{HashMap, BTreeMap, BTreeSet};
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use crate::changes_trie::{NO_EXTRINSIC_INDEX, Configuration as ChangesTrieConfig};
|
use crate::changes_trie::{NO_EXTRINSIC_INDEX, Configuration as ChangesTrieConfig};
|
||||||
use primitives::storage::well_known_keys::EXTRINSIC_INDEX;
|
use primitives::storage::well_known_keys::EXTRINSIC_INDEX;
|
||||||
|
use std::{mem, ops};
|
||||||
|
|
||||||
/// The overlayed changes to state to be queried on top of the backend.
|
/// The overlayed changes to state to be queried on top of the backend.
|
||||||
///
|
///
|
||||||
@@ -54,9 +55,9 @@ pub struct OverlayedValue {
|
|||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
pub struct OverlayedChangeSet {
|
pub struct OverlayedChangeSet {
|
||||||
/// Top level storage changes.
|
/// Top level storage changes.
|
||||||
pub top: HashMap<Vec<u8>, OverlayedValue>,
|
pub top: BTreeMap<Vec<u8>, OverlayedValue>,
|
||||||
/// Child storage changes.
|
/// Child storage changes.
|
||||||
pub children: HashMap<Vec<u8>, HashMap<Vec<u8>, OverlayedValue>>,
|
pub children: HashMap<Vec<u8>, BTreeMap<Vec<u8>, OverlayedValue>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -274,9 +275,10 @@ impl OverlayedChanges {
|
|||||||
/// Commit prospective changes to state.
|
/// Commit prospective changes to state.
|
||||||
pub fn commit_prospective(&mut self) {
|
pub fn commit_prospective(&mut self) {
|
||||||
if self.committed.is_empty() {
|
if self.committed.is_empty() {
|
||||||
::std::mem::swap(&mut self.prospective, &mut self.committed);
|
mem::swap(&mut self.prospective, &mut self.committed);
|
||||||
} else {
|
} else {
|
||||||
for (key, val) in self.prospective.top.drain() {
|
let top_to_commit = mem::replace(&mut self.prospective.top, BTreeMap::new());
|
||||||
|
for (key, val) in top_to_commit.into_iter() {
|
||||||
let entry = self.committed.top.entry(key).or_default();
|
let entry = self.committed.top.entry(key).or_default();
|
||||||
entry.value = val.value;
|
entry.value = val.value;
|
||||||
|
|
||||||
@@ -285,9 +287,9 @@ impl OverlayedChanges {
|
|||||||
.extend(prospective_extrinsics);
|
.extend(prospective_extrinsics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (storage_key, mut map) in self.prospective.children.drain() {
|
for (storage_key, map) in self.prospective.children.drain() {
|
||||||
let map_dest = self.committed.children.entry(storage_key).or_default();
|
let map_dest = self.committed.children.entry(storage_key).or_default();
|
||||||
for (key, val) in map.drain() {
|
for (key, val) in map.into_iter() {
|
||||||
let entry = map_dest.entry(key).or_default();
|
let entry = map_dest.entry(key).or_default();
|
||||||
entry.value = val.value;
|
entry.value = val.value;
|
||||||
|
|
||||||
@@ -339,6 +341,56 @@ impl OverlayedChanges {
|
|||||||
false => None,
|
false => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the next (in lexicographic order) storage key in the overlayed alongside its value.
|
||||||
|
/// If no value is next then `None` is returned.
|
||||||
|
pub fn next_storage_key_change(&self, key: &[u8]) -> Option<(&[u8], &OverlayedValue)> {
|
||||||
|
let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded);
|
||||||
|
|
||||||
|
let next_prospective_key = self.prospective.top
|
||||||
|
.range::<[u8], _>(range)
|
||||||
|
.next()
|
||||||
|
.map(|(k, v)| (&k[..], v));
|
||||||
|
|
||||||
|
let next_committed_key = self.committed.top
|
||||||
|
.range::<[u8], _>(range)
|
||||||
|
.next()
|
||||||
|
.map(|(k, v)| (&k[..], v));
|
||||||
|
|
||||||
|
match (next_committed_key, next_prospective_key) {
|
||||||
|
// Committed is strictly less than prospective
|
||||||
|
(Some(committed_key), Some(prospective_key)) if committed_key.0 < prospective_key.0 =>
|
||||||
|
Some(committed_key),
|
||||||
|
(committed_key, None) => committed_key,
|
||||||
|
// Prospective key is less or equal to committed or committed doesn't exist
|
||||||
|
(_, prospective_key) => prospective_key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the next (in lexicographic order) child storage key in the overlayed alongside its
|
||||||
|
/// value. If no value is next then `None` is returned.
|
||||||
|
pub fn next_child_storage_key_change(
|
||||||
|
&self,
|
||||||
|
storage_key: &[u8],
|
||||||
|
key: &[u8]
|
||||||
|
) -> Option<(&[u8], &OverlayedValue)> {
|
||||||
|
let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded);
|
||||||
|
|
||||||
|
let next_prospective_key = self.prospective.children.get(storage_key)
|
||||||
|
.and_then(|map| map.range::<[u8], _>(range).next().map(|(k, v)| (&k[..], v)));
|
||||||
|
|
||||||
|
let next_committed_key = self.committed.children.get(storage_key)
|
||||||
|
.and_then(|map| map.range::<[u8], _>(range).next().map(|(k, v)| (&k[..], v)));
|
||||||
|
|
||||||
|
match (next_committed_key, next_prospective_key) {
|
||||||
|
// Committed is strictly less than prospective
|
||||||
|
(Some(committed_key), Some(prospective_key)) if committed_key.0 < prospective_key.0 =>
|
||||||
|
Some(committed_key),
|
||||||
|
(committed_key, None) => committed_key,
|
||||||
|
// Prospective key is less or equal to committed or committed doesn't exist
|
||||||
|
(_, prospective_key) => prospective_key,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -359,8 +411,8 @@ mod tests {
|
|||||||
use crate::ext::Ext;
|
use crate::ext::Ext;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn strip_extrinsic_index(map: &HashMap<Vec<u8>, OverlayedValue>)
|
fn strip_extrinsic_index(map: &BTreeMap<Vec<u8>, OverlayedValue>)
|
||||||
-> HashMap<Vec<u8>, OverlayedValue>
|
-> BTreeMap<Vec<u8>, OverlayedValue>
|
||||||
{
|
{
|
||||||
let mut clone = map.clone();
|
let mut clone = map.clone();
|
||||||
clone.remove(&EXTRINSIC_INDEX.to_vec());
|
clone.remove(&EXTRINSIC_INDEX.to_vec());
|
||||||
@@ -397,7 +449,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn overlayed_storage_root_works() {
|
fn overlayed_storage_root_works() {
|
||||||
let initial: HashMap<_, _> = vec![
|
let initial: BTreeMap<_, _> = vec![
|
||||||
(b"doe".to_vec(), b"reindeer".to_vec()),
|
(b"doe".to_vec(), b"reindeer".to_vec()),
|
||||||
(b"dog".to_vec(), b"puppyXXX".to_vec()),
|
(b"dog".to_vec(), b"puppyXXX".to_vec()),
|
||||||
(b"dogglesworth".to_vec(), b"catXXX".to_vec()),
|
(b"dogglesworth".to_vec(), b"catXXX".to_vec()),
|
||||||
@@ -543,4 +595,79 @@ mod tests {
|
|||||||
assert_eq!(overlay.prospective,
|
assert_eq!(overlay.prospective,
|
||||||
Default::default());
|
Default::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn next_storage_key_change_works() {
|
||||||
|
let mut overlay = OverlayedChanges::default();
|
||||||
|
overlay.set_storage(vec![20], Some(vec![20]));
|
||||||
|
overlay.set_storage(vec![30], Some(vec![30]));
|
||||||
|
overlay.set_storage(vec![40], Some(vec![40]));
|
||||||
|
overlay.commit_prospective();
|
||||||
|
overlay.set_storage(vec![10], Some(vec![10]));
|
||||||
|
overlay.set_storage(vec![30], None);
|
||||||
|
|
||||||
|
// next_prospective < next_committed
|
||||||
|
let next_to_5 = overlay.next_storage_key_change(&[5]).unwrap();
|
||||||
|
assert_eq!(next_to_5.0.to_vec(), vec![10]);
|
||||||
|
assert_eq!(next_to_5.1.value, Some(vec![10]));
|
||||||
|
|
||||||
|
// next_committed < next_prospective
|
||||||
|
let next_to_10 = overlay.next_storage_key_change(&[10]).unwrap();
|
||||||
|
assert_eq!(next_to_10.0.to_vec(), vec![20]);
|
||||||
|
assert_eq!(next_to_10.1.value, Some(vec![20]));
|
||||||
|
|
||||||
|
// next_committed == next_prospective
|
||||||
|
let next_to_20 = overlay.next_storage_key_change(&[20]).unwrap();
|
||||||
|
assert_eq!(next_to_20.0.to_vec(), vec![30]);
|
||||||
|
assert_eq!(next_to_20.1.value, None);
|
||||||
|
|
||||||
|
// next_committed, no next_prospective
|
||||||
|
let next_to_30 = overlay.next_storage_key_change(&[30]).unwrap();
|
||||||
|
assert_eq!(next_to_30.0.to_vec(), vec![40]);
|
||||||
|
assert_eq!(next_to_30.1.value, Some(vec![40]));
|
||||||
|
|
||||||
|
overlay.set_storage(vec![50], Some(vec![50]));
|
||||||
|
// next_prospective, no next_committed
|
||||||
|
let next_to_40 = overlay.next_storage_key_change(&[40]).unwrap();
|
||||||
|
assert_eq!(next_to_40.0.to_vec(), vec![50]);
|
||||||
|
assert_eq!(next_to_40.1.value, Some(vec![50]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn next_child_storage_key_change_works() {
|
||||||
|
let child = b"Child1".to_vec();
|
||||||
|
let mut overlay = OverlayedChanges::default();
|
||||||
|
overlay.set_child_storage(child.clone(), vec![20], Some(vec![20]));
|
||||||
|
overlay.set_child_storage(child.clone(), vec![30], Some(vec![30]));
|
||||||
|
overlay.set_child_storage(child.clone(), vec![40], Some(vec![40]));
|
||||||
|
overlay.commit_prospective();
|
||||||
|
overlay.set_child_storage(child.clone(), vec![10], Some(vec![10]));
|
||||||
|
overlay.set_child_storage(child.clone(), vec![30], None);
|
||||||
|
|
||||||
|
// next_prospective < next_committed
|
||||||
|
let next_to_5 = overlay.next_child_storage_key_change(&child, &[5]).unwrap();
|
||||||
|
assert_eq!(next_to_5.0.to_vec(), vec![10]);
|
||||||
|
assert_eq!(next_to_5.1.value, Some(vec![10]));
|
||||||
|
|
||||||
|
// next_committed < next_prospective
|
||||||
|
let next_to_10 = overlay.next_child_storage_key_change(&child, &[10]).unwrap();
|
||||||
|
assert_eq!(next_to_10.0.to_vec(), vec![20]);
|
||||||
|
assert_eq!(next_to_10.1.value, Some(vec![20]));
|
||||||
|
|
||||||
|
// next_committed == next_prospective
|
||||||
|
let next_to_20 = overlay.next_child_storage_key_change(&child, &[20]).unwrap();
|
||||||
|
assert_eq!(next_to_20.0.to_vec(), vec![30]);
|
||||||
|
assert_eq!(next_to_20.1.value, None);
|
||||||
|
|
||||||
|
// next_committed, no next_prospective
|
||||||
|
let next_to_30 = overlay.next_child_storage_key_change(&child, &[30]).unwrap();
|
||||||
|
assert_eq!(next_to_30.0.to_vec(), vec![40]);
|
||||||
|
assert_eq!(next_to_30.1.value, Some(vec![40]));
|
||||||
|
|
||||||
|
overlay.set_child_storage(child.clone(), vec![50], Some(vec![50]));
|
||||||
|
// next_prospective, no next_committed
|
||||||
|
let next_to_40 = overlay.next_child_storage_key_change(&child, &[40]).unwrap();
|
||||||
|
assert_eq!(next_to_40.0.to_vec(), vec![50]);
|
||||||
|
assert_eq!(next_to_40.1.value, Some(vec![50]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,6 +272,14 @@ impl<'a, S, H> Backend<H> for ProvingBackend<'a, S, H>
|
|||||||
self.0.child_storage(storage_key, key)
|
self.0.child_storage(storage_key, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
self.0.next_storage_key(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_child_storage_key(&self, storage_key: &[u8], key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
self.0.next_child_storage_key(storage_key, key)
|
||||||
|
}
|
||||||
|
|
||||||
fn for_keys_in_child_storage<F: FnMut(&[u8])>(&self, storage_key: &[u8], f: F) {
|
fn for_keys_in_child_storage<F: FnMut(&[u8])>(&self, storage_key: &[u8], f: F) {
|
||||||
self.0.for_keys_in_child_storage(storage_key, f)
|
self.0.for_keys_in_child_storage(storage_key, f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
//! Test implementation for Externalities.
|
//! Test implementation for Externalities.
|
||||||
|
|
||||||
use std::{collections::HashMap, any::{Any, TypeId}};
|
use std::{collections::{HashMap, BTreeMap}, any::{Any, TypeId}};
|
||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{InMemory, Backend}, OverlayedChanges,
|
backend::{InMemory, Backend}, OverlayedChanges,
|
||||||
@@ -35,7 +35,7 @@ use primitives::{
|
|||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use externalities::{Extensions, Extension};
|
use externalities::{Extensions, Extension};
|
||||||
|
|
||||||
type StorageTuple = (HashMap<Vec<u8>, Vec<u8>>, HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>);
|
type StorageTuple = (BTreeMap<Vec<u8>, Vec<u8>>, HashMap<Vec<u8>, BTreeMap<Vec<u8>, Vec<u8>>>);
|
||||||
|
|
||||||
/// Simple HashMap-based Externalities impl.
|
/// Simple HashMap-based Externalities impl.
|
||||||
pub struct TestExternalities<H: Hasher<Out=H256>=Blake2Hasher, N: ChangesTrieBlockNumber=u64> {
|
pub struct TestExternalities<H: Hasher<Out=H256>=Blake2Hasher, N: ChangesTrieBlockNumber=u64> {
|
||||||
|
|||||||
@@ -79,6 +79,14 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
|
|||||||
self.essence.child_storage(storage_key, key)
|
self.essence.child_storage(storage_key, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
self.essence.next_storage_key(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_child_storage_key(&self, storage_key: &[u8], key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||||
|
self.essence.next_child_storage_key(storage_key, key)
|
||||||
|
}
|
||||||
|
|
||||||
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
|
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
|
||||||
self.essence.for_keys_with_prefix(prefix, f)
|
self.essence.for_keys_with_prefix(prefix, f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,76 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
|
|||||||
self.storage
|
self.storage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the next key in the trie i.e. the minimum key that is strictly superior to `key` in
|
||||||
|
/// lexicographic order.
|
||||||
|
pub fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, String> {
|
||||||
|
self.next_storage_key_from_root(&self.root, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the next key in the child trie i.e. the minimum key that is strictly superior to
|
||||||
|
/// `key` in lexicographic order.
|
||||||
|
pub fn next_child_storage_key(
|
||||||
|
&self,
|
||||||
|
storage_key: &[u8],
|
||||||
|
key: &[u8],
|
||||||
|
) -> Result<Option<Vec<u8>>, String> {
|
||||||
|
let child_root = match self.storage(storage_key)? {
|
||||||
|
Some(child_root) => child_root,
|
||||||
|
None => return Ok(None),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut hash = H::Out::default();
|
||||||
|
|
||||||
|
if child_root.len() != hash.as_ref().len() {
|
||||||
|
return Err(format!("Invalid child storage hash at {:?}", storage_key));
|
||||||
|
}
|
||||||
|
// note: child_root and hash must be same size, panics otherwise.
|
||||||
|
hash.as_mut().copy_from_slice(&child_root[..]);
|
||||||
|
|
||||||
|
self.next_storage_key_from_root(&hash, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return next key from main trie or child trie by providing corresponding root.
|
||||||
|
fn next_storage_key_from_root(
|
||||||
|
&self,
|
||||||
|
root: &H::Out,
|
||||||
|
key: &[u8],
|
||||||
|
) -> Result<Option<Vec<u8>>, String> {
|
||||||
|
let mut read_overlay = S::Overlay::default();
|
||||||
|
let eph = Ephemeral {
|
||||||
|
storage: &self.storage,
|
||||||
|
overlay: &mut read_overlay,
|
||||||
|
};
|
||||||
|
|
||||||
|
let trie = TrieDB::<H>::new(&eph, root)
|
||||||
|
.map_err(|e| format!("TrieDB creation error: {}", e))?;
|
||||||
|
let mut iter = trie.iter()
|
||||||
|
.map_err(|e| format!("TrieDB iteration error: {}", e))?;
|
||||||
|
|
||||||
|
// The key just after the one given in input, basically `key++0`.
|
||||||
|
// Note: We are sure this is the next key if:
|
||||||
|
// * size of key has no limit (i.e. we can always add 0 to the path),
|
||||||
|
// * and no keys can be inserted between `key` and `key++0` (this is ensured by sr-io).
|
||||||
|
let mut potential_next_key = Vec::with_capacity(key.len() + 1);
|
||||||
|
potential_next_key.extend_from_slice(key);
|
||||||
|
potential_next_key.push(0);
|
||||||
|
|
||||||
|
iter.seek(&potential_next_key)
|
||||||
|
.map_err(|e| format!("TrieDB iterator seek error: {}", e))?;
|
||||||
|
|
||||||
|
let next_element = iter.next();
|
||||||
|
|
||||||
|
let next_key = if let Some(next_element) = next_element {
|
||||||
|
let (next_key, _) = next_element
|
||||||
|
.map_err(|e| format!("TrieDB iterator next error: {}", e))?;
|
||||||
|
Some(next_key)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(next_key)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the value of storage at given key.
|
/// Get the value of storage at given key.
|
||||||
pub fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, String> {
|
pub fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, String> {
|
||||||
let mut read_overlay = S::Overlay::default();
|
let mut read_overlay = S::Overlay::default();
|
||||||
@@ -345,3 +415,47 @@ impl<H: Hasher> TrieBackendStorage<H> for MemoryDB<H> {
|
|||||||
Ok(hash_db::HashDB::get(self, key, prefix))
|
Ok(hash_db::HashDB::get(self, key, prefix))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use primitives::{Blake2Hasher, H256};
|
||||||
|
use trie::{TrieMut, PrefixedMemoryDB, trie_types::TrieDBMut};
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn next_storage_key_and_next_child_storage_key_work() {
|
||||||
|
// Contains values
|
||||||
|
let mut root_1 = H256::default();
|
||||||
|
// Contains child trie
|
||||||
|
let mut root_2 = H256::default();
|
||||||
|
|
||||||
|
let mut mdb = PrefixedMemoryDB::<Blake2Hasher>::default();
|
||||||
|
{
|
||||||
|
let mut trie = TrieDBMut::new(&mut mdb, &mut root_1);
|
||||||
|
trie.insert(b"3", &[1]).expect("insert failed");
|
||||||
|
trie.insert(b"4", &[1]).expect("insert failed");
|
||||||
|
trie.insert(b"6", &[1]).expect("insert failed");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut trie = TrieDBMut::new(&mut mdb, &mut root_2);
|
||||||
|
trie.insert(b"MyChild", root_1.as_ref()).expect("insert failed");
|
||||||
|
};
|
||||||
|
|
||||||
|
let essence_1 = TrieBackendEssence::new(mdb, root_1);
|
||||||
|
|
||||||
|
assert_eq!(essence_1.next_storage_key(b"2"), Ok(Some(b"3".to_vec())));
|
||||||
|
assert_eq!(essence_1.next_storage_key(b"3"), Ok(Some(b"4".to_vec())));
|
||||||
|
assert_eq!(essence_1.next_storage_key(b"4"), Ok(Some(b"6".to_vec())));
|
||||||
|
assert_eq!(essence_1.next_storage_key(b"5"), Ok(Some(b"6".to_vec())));
|
||||||
|
assert_eq!(essence_1.next_storage_key(b"6"), Ok(None));
|
||||||
|
|
||||||
|
let mdb = essence_1.into_storage();
|
||||||
|
let essence_2 = TrieBackendEssence::new(mdb, root_2);
|
||||||
|
|
||||||
|
assert_eq!(essence_2.next_child_storage_key(b"MyChild", b"2"), Ok(Some(b"3".to_vec())));
|
||||||
|
assert_eq!(essence_2.next_child_storage_key(b"MyChild", b"3"), Ok(Some(b"4".to_vec())));
|
||||||
|
assert_eq!(essence_2.next_child_storage_key(b"MyChild", b"4"), Ok(Some(b"6".to_vec())));
|
||||||
|
assert_eq!(essence_2.next_child_storage_key(b"MyChild", b"5"), Ok(Some(b"6".to_vec())));
|
||||||
|
assert_eq!(essence_2.next_child_storage_key(b"MyChild", b"6"), Ok(None));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub mod trait_tests;
|
|||||||
mod block_builder_ext;
|
mod block_builder_ext;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, BTreeMap};
|
||||||
pub use block_builder_ext::BlockBuilderExt;
|
pub use block_builder_ext::BlockBuilderExt;
|
||||||
pub use generic_test_client::*;
|
pub use generic_test_client::*;
|
||||||
pub use runtime;
|
pub use runtime;
|
||||||
@@ -97,8 +97,8 @@ pub type LightExecutor = client::light::call_executor::GenesisCallExecutor<
|
|||||||
pub struct GenesisParameters {
|
pub struct GenesisParameters {
|
||||||
support_changes_trie: bool,
|
support_changes_trie: bool,
|
||||||
heap_pages_override: Option<u64>,
|
heap_pages_override: Option<u64>,
|
||||||
extra_storage: HashMap<Vec<u8>, Vec<u8>>,
|
extra_storage: BTreeMap<Vec<u8>, Vec<u8>>,
|
||||||
child_extra_storage: HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>,
|
child_extra_storage: HashMap<Vec<u8>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenesisParameters {
|
impl GenesisParameters {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
//! Tool for creating the genesis block.
|
//! Tool for creating the genesis block.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use runtime_io::hashing::{blake2_256, twox_128};
|
use runtime_io::hashing::{blake2_256, twox_128};
|
||||||
use super::{AuthorityId, AccountId, WASM_BINARY, system};
|
use super::{AuthorityId, AccountId, WASM_BINARY, system};
|
||||||
use codec::{Encode, KeyedVec, Joiner};
|
use codec::{Encode, KeyedVec, Joiner};
|
||||||
@@ -30,8 +30,8 @@ pub struct GenesisConfig {
|
|||||||
balances: Vec<(AccountId, u64)>,
|
balances: Vec<(AccountId, u64)>,
|
||||||
heap_pages_override: Option<u64>,
|
heap_pages_override: Option<u64>,
|
||||||
/// Additional storage key pairs that will be added to the genesis map.
|
/// Additional storage key pairs that will be added to the genesis map.
|
||||||
extra_storage: HashMap<Vec<u8>, Vec<u8>>,
|
extra_storage: BTreeMap<Vec<u8>, Vec<u8>>,
|
||||||
child_extra_storage: HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>,
|
child_extra_storage: HashMap<Vec<u8>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenesisConfig {
|
impl GenesisConfig {
|
||||||
@@ -41,8 +41,8 @@ impl GenesisConfig {
|
|||||||
endowed_accounts: Vec<AccountId>,
|
endowed_accounts: Vec<AccountId>,
|
||||||
balance: u64,
|
balance: u64,
|
||||||
heap_pages_override: Option<u64>,
|
heap_pages_override: Option<u64>,
|
||||||
extra_storage: HashMap<Vec<u8>, Vec<u8>>,
|
extra_storage: BTreeMap<Vec<u8>, Vec<u8>>,
|
||||||
child_extra_storage: HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>,
|
child_extra_storage: HashMap<Vec<u8>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
GenesisConfig {
|
GenesisConfig {
|
||||||
changes_trie_config: match support_changes_trie {
|
changes_trie_config: match support_changes_trie {
|
||||||
@@ -58,11 +58,11 @@ impl GenesisConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn genesis_map(&self) -> (
|
pub fn genesis_map(&self) -> (
|
||||||
HashMap<Vec<u8>, Vec<u8>>,
|
BTreeMap<Vec<u8>, Vec<u8>>,
|
||||||
HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>,
|
HashMap<Vec<u8>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||||
) {
|
) {
|
||||||
let wasm_runtime = WASM_BINARY.to_vec();
|
let wasm_runtime = WASM_BINARY.to_vec();
|
||||||
let mut map: HashMap<Vec<u8>, Vec<u8>> = self.balances.iter()
|
let mut map: BTreeMap<Vec<u8>, Vec<u8>> = self.balances.iter()
|
||||||
.map(|&(ref account, balance)| (account.to_keyed_vec(b"balance:"), vec![].and(&balance)))
|
.map(|&(ref account, balance)| (account.to_keyed_vec(b"balance:"), vec![].and(&balance)))
|
||||||
.map(|(k, v)| (blake2_256(&k[..])[..].to_vec(), v.to_vec()))
|
.map(|(k, v)| (blake2_256(&k[..])[..].to_vec(), v.to_vec()))
|
||||||
.chain(vec![
|
.chain(vec![
|
||||||
@@ -92,8 +92,8 @@ impl GenesisConfig {
|
|||||||
|
|
||||||
pub fn insert_genesis_block(
|
pub fn insert_genesis_block(
|
||||||
storage: &mut (
|
storage: &mut (
|
||||||
HashMap<Vec<u8>, Vec<u8>>,
|
BTreeMap<Vec<u8>, Vec<u8>>,
|
||||||
HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>,
|
HashMap<Vec<u8>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||||
)
|
)
|
||||||
) -> primitives::hash::H256 {
|
) -> primitives::hash::H256 {
|
||||||
let child_roots = storage.1.iter().map(|(sk, child_map)| {
|
let child_roots = storage.1.iter().map(|(sk, child_map)| {
|
||||||
@@ -111,7 +111,7 @@ pub fn insert_genesis_block(
|
|||||||
genesis_hash
|
genesis_hash
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn additional_storage_with_genesis(genesis_block: &crate::Block) -> HashMap<Vec<u8>, Vec<u8>> {
|
pub fn additional_storage_with_genesis(genesis_block: &crate::Block) -> BTreeMap<Vec<u8>, Vec<u8>> {
|
||||||
map![
|
map![
|
||||||
twox_128(&b"latest"[..]).to_vec() => genesis_block.hash().as_fixed_bytes().to_vec()
|
twox_128(&b"latest"[..]).to_vec() => genesis_block.hash().as_fixed_bytes().to_vec()
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user