mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-19 15:51:04 +00:00
Add typedefs for storage types (#4654)
* Add typedefs for storage types * Fix after merge
This commit is contained in:
committed by
Bastian Köcher
parent
20ce6c120c
commit
482ca522cc
@@ -22,7 +22,10 @@ use sp_core::ChangesTrieConfigurationRange;
|
|||||||
use sp_core::offchain::OffchainStorage;
|
use sp_core::offchain::OffchainStorage;
|
||||||
use sp_runtime::{generic::BlockId, Justification, Storage};
|
use sp_runtime::{generic::BlockId, Justification, Storage};
|
||||||
use sp_runtime::traits::{Block as BlockT, NumberFor, HasherFor};
|
use sp_runtime::traits::{Block as BlockT, NumberFor, HasherFor};
|
||||||
use sp_state_machine::{ChangesTrieState, ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction};
|
use sp_state_machine::{
|
||||||
|
ChangesTrieState, ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction,
|
||||||
|
StorageCollection, ChildStorageCollection,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
blockchain::{
|
blockchain::{
|
||||||
Backend as BlockchainBackend, well_known_cache_keys
|
Backend as BlockchainBackend, well_known_cache_keys
|
||||||
@@ -45,12 +48,6 @@ pub type TransactionForSB<B, Block> = <B as StateBackend<HasherFor<Block>>>::Tra
|
|||||||
/// Extracts the transaction for the given backend.
|
/// Extracts the transaction for the given backend.
|
||||||
pub type TransactionFor<B, Block> = TransactionForSB<StateBackendFor<B, Block>, Block>;
|
pub type TransactionFor<B, Block> = TransactionForSB<StateBackendFor<B, Block>, Block>;
|
||||||
|
|
||||||
/// In memory array of storage values.
|
|
||||||
pub type StorageCollection = Vec<(Vec<u8>, Option<Vec<u8>>)>;
|
|
||||||
|
|
||||||
/// In memory arrays of storage values for multiple child tries.
|
|
||||||
pub type ChildStorageCollection = Vec<(Vec<u8>, StorageCollection)>;
|
|
||||||
|
|
||||||
/// Import operation summary.
|
/// Import operation summary.
|
||||||
///
|
///
|
||||||
/// Contains information about the block that just got imported,
|
/// Contains information about the block that just got imported,
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use sc_client_api::{execution_extensions::ExecutionExtensions, ForkBlocks, UsageInfo, MemoryInfo, BadBlocks, IoInfo};
|
use sc_client_api::{execution_extensions::ExecutionExtensions, ForkBlocks, UsageInfo, MemoryInfo, BadBlocks, IoInfo};
|
||||||
use sc_client_api::backend::NewBlockState;
|
use sc_client_api::backend::NewBlockState;
|
||||||
use sc_client_api::backend::{PrunableStateChangesTrieStorage, StorageCollection, ChildStorageCollection};
|
use sc_client_api::backend::PrunableStateChangesTrieStorage;
|
||||||
use sp_blockchain::{
|
use sp_blockchain::{
|
||||||
Result as ClientResult, Error as ClientError,
|
Result as ClientResult, Error as ClientError,
|
||||||
well_known_cache_keys, HeaderBackend,
|
well_known_cache_keys, HeaderBackend,
|
||||||
@@ -66,8 +66,9 @@ use sp_runtime::traits::{
|
|||||||
};
|
};
|
||||||
use sc_executor::RuntimeInfo;
|
use sc_executor::RuntimeInfo;
|
||||||
use sp_state_machine::{
|
use sp_state_machine::{
|
||||||
DBValue, ChangesTrieTransaction, ChangesTrieCacheAction,
|
DBValue, ChangesTrieTransaction, ChangesTrieCacheAction, UsageInfo as StateUsageInfo,
|
||||||
backend::Backend as StateBackend, UsageInfo as StateUsageInfo,
|
StorageCollection, ChildStorageCollection,
|
||||||
|
backend::Backend as StateBackend,
|
||||||
};
|
};
|
||||||
use crate::utils::{DatabaseType, Meta, db_err, meta_keys, read_db, read_meta};
|
use crate::utils::{DatabaseType, Meta, db_err, meta_keys, read_db, read_meta};
|
||||||
use crate::changes_tries_storage::{DbChangesTrieStorage, DbChangesTrieStorageTransaction};
|
use crate::changes_tries_storage::{DbChangesTrieStorage, DbChangesTrieStorageTransaction};
|
||||||
|
|||||||
@@ -24,17 +24,17 @@ use hash_db::Hasher;
|
|||||||
use sp_runtime::traits::{Block as BlockT, Header, HasherFor, NumberFor};
|
use sp_runtime::traits::{Block as BlockT, Header, HasherFor, NumberFor};
|
||||||
use sp_core::hexdisplay::HexDisplay;
|
use sp_core::hexdisplay::HexDisplay;
|
||||||
use sp_core::storage::ChildInfo;
|
use sp_core::storage::ChildInfo;
|
||||||
use sp_state_machine::{backend::Backend as StateBackend, TrieBackend};
|
use sp_state_machine::{
|
||||||
|
backend::Backend as StateBackend, TrieBackend, StorageKey, StorageValue,
|
||||||
|
StorageCollection, ChildStorageCollection,
|
||||||
|
};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use sc_client_api::backend::{StorageCollection, ChildStorageCollection};
|
|
||||||
use std::hash::Hash as StdHash;
|
use std::hash::Hash as StdHash;
|
||||||
use crate::stats::StateUsageStats;
|
use crate::stats::StateUsageStats;
|
||||||
|
|
||||||
const STATE_CACHE_BLOCKS: usize = 12;
|
const STATE_CACHE_BLOCKS: usize = 12;
|
||||||
|
|
||||||
type StorageKey = Vec<u8>;
|
|
||||||
type ChildStorageKey = (Vec<u8>, Vec<u8>);
|
type ChildStorageKey = (Vec<u8>, Vec<u8>);
|
||||||
type StorageValue = Vec<u8>;
|
|
||||||
|
|
||||||
/// Shared canonical state cache.
|
/// Shared canonical state cache.
|
||||||
pub struct Cache<B: BlockT> {
|
pub struct Cache<B: BlockT> {
|
||||||
|
|||||||
@@ -26,11 +26,14 @@ use sp_core::offchain::storage::{
|
|||||||
use sp_runtime::generic::BlockId;
|
use sp_runtime::generic::BlockId;
|
||||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Zero, NumberFor, HasherFor};
|
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Zero, NumberFor, HasherFor};
|
||||||
use sp_runtime::{Justification, Storage};
|
use sp_runtime::{Justification, Storage};
|
||||||
use sp_state_machine::{ChangesTrieTransaction, InMemoryBackend, Backend as StateBackend};
|
use sp_state_machine::{
|
||||||
|
ChangesTrieTransaction, InMemoryBackend, Backend as StateBackend, StorageCollection,
|
||||||
|
ChildStorageCollection,
|
||||||
|
};
|
||||||
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata};
|
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata};
|
||||||
|
|
||||||
use sc_client_api::{
|
use sc_client_api::{
|
||||||
backend::{self, NewBlockState, StorageCollection, ChildStorageCollection},
|
backend::{self, NewBlockState},
|
||||||
blockchain::{
|
blockchain::{
|
||||||
self, BlockStatus, HeaderBackend, well_known_cache_keys::Id as CacheKeyId
|
self, BlockStatus, HeaderBackend, well_known_cache_keys::Id as CacheKeyId
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ use sp_core::ChangesTrieConfiguration;
|
|||||||
use sp_core::storage::{well_known_keys, ChildInfo, OwnedChildInfo};
|
use sp_core::storage::{well_known_keys, ChildInfo, OwnedChildInfo};
|
||||||
use sp_core::offchain::storage::InMemOffchainStorage;
|
use sp_core::offchain::storage::InMemOffchainStorage;
|
||||||
use sp_state_machine::{
|
use sp_state_machine::{
|
||||||
Backend as StateBackend, TrieBackend, InMemoryBackend, ChangesTrieTransaction
|
Backend as StateBackend, TrieBackend, InMemoryBackend, ChangesTrieTransaction,
|
||||||
|
StorageCollection, ChildStorageCollection,
|
||||||
};
|
};
|
||||||
use sp_runtime::{generic::BlockId, Justification, Storage};
|
use sp_runtime::{generic::BlockId, Justification, Storage};
|
||||||
use sp_runtime::traits::{Block as BlockT, NumberFor, Zero, Header, HasherFor};
|
use sp_runtime::traits::{Block as BlockT, NumberFor, Zero, Header, HasherFor};
|
||||||
@@ -36,7 +37,7 @@ use sp_blockchain::{Error as ClientError, Result as ClientResult};
|
|||||||
use sc_client_api::{
|
use sc_client_api::{
|
||||||
backend::{
|
backend::{
|
||||||
AuxStore, Backend as ClientBackend, BlockImportOperation, RemoteBackend, NewBlockState,
|
AuxStore, Backend as ClientBackend, BlockImportOperation, RemoteBackend, NewBlockState,
|
||||||
StorageCollection, ChildStorageCollection, PrunableStateChangesTrieStorage,
|
PrunableStateChangesTrieStorage,
|
||||||
},
|
},
|
||||||
blockchain::{
|
blockchain::{
|
||||||
HeaderBackend as BlockchainHeaderBackend, well_known_cache_keys,
|
HeaderBackend as BlockchainHeaderBackend, well_known_cache_keys,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use sp_trie::{TrieMut, MemoryDB, trie_types::TrieDBMut};
|
|||||||
use crate::{
|
use crate::{
|
||||||
trie_backend::TrieBackend,
|
trie_backend::TrieBackend,
|
||||||
trie_backend_essence::TrieBackendStorage,
|
trie_backend_essence::TrieBackendStorage,
|
||||||
UsageInfo,
|
UsageInfo, StorageKey, StorageValue, StorageCollection,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A state backend is used to read state data and can have changes committed
|
/// A state backend is used to read state data and can have changes committed
|
||||||
@@ -44,7 +44,7 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
|
|||||||
type TrieBackendStorage: TrieBackendStorage<H>;
|
type TrieBackendStorage: TrieBackendStorage<H>;
|
||||||
|
|
||||||
/// Get keyed storage or None if there is nothing associated.
|
/// Get keyed storage or None if there is nothing associated.
|
||||||
fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
|
fn storage(&self, key: &[u8]) -> Result<Option<StorageValue>, Self::Error>;
|
||||||
|
|
||||||
/// Get keyed storage value hash or None if there is nothing associated.
|
/// Get keyed storage value hash or None if there is nothing associated.
|
||||||
fn storage_hash(&self, key: &[u8]) -> Result<Option<H::Out>, Self::Error> {
|
fn storage_hash(&self, key: &[u8]) -> Result<Option<H::Out>, Self::Error> {
|
||||||
@@ -57,7 +57,7 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<Vec<u8>>, Self::Error>;
|
) -> Result<Option<StorageValue>, Self::Error>;
|
||||||
|
|
||||||
/// Get child keyed storage value hash or None if there is nothing associated.
|
/// Get child keyed storage value hash or None if there is nothing associated.
|
||||||
fn child_storage_hash(
|
fn child_storage_hash(
|
||||||
@@ -85,7 +85,7 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the next key in storage in lexicographic order or `None` if there is no value.
|
/// 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>;
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<StorageKey>, Self::Error>;
|
||||||
|
|
||||||
/// Return the next key in child storage in lexicographic order or `None` if there is no value.
|
/// Return the next key in child storage in lexicographic order or `None` if there is no value.
|
||||||
fn next_child_storage_key(
|
fn next_child_storage_key(
|
||||||
@@ -93,7 +93,7 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8]
|
key: &[u8]
|
||||||
) -> Result<Option<Vec<u8>>, Self::Error>;
|
) -> Result<Option<StorageKey>, 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])>(
|
fn for_keys_in_child_storage<F: FnMut(&[u8])>(
|
||||||
@@ -129,7 +129,7 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
|
|||||||
/// Does not include child storage updates.
|
/// Does not include child storage updates.
|
||||||
fn storage_root<I>(&self, delta: I) -> (H::Out, Self::Transaction)
|
fn storage_root<I>(&self, delta: I) -> (H::Out, Self::Transaction)
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
I: IntoIterator<Item=(StorageKey, Option<StorageValue>)>,
|
||||||
H::Out: Ord;
|
H::Out: Ord;
|
||||||
|
|
||||||
/// Calculate the child storage root, with given delta over what is already stored in
|
/// Calculate the child storage root, with given delta over what is already stored in
|
||||||
@@ -142,14 +142,14 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
|
|||||||
delta: I,
|
delta: I,
|
||||||
) -> (H::Out, bool, Self::Transaction)
|
) -> (H::Out, bool, Self::Transaction)
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
I: IntoIterator<Item=(StorageKey, Option<StorageValue>)>,
|
||||||
H::Out: Ord;
|
H::Out: Ord;
|
||||||
|
|
||||||
/// Get all key/value pairs into a Vec.
|
/// Get all key/value pairs into a Vec.
|
||||||
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)>;
|
fn pairs(&self) -> Vec<(StorageKey, StorageValue)>;
|
||||||
|
|
||||||
/// Get all keys with given prefix
|
/// Get all keys with given prefix
|
||||||
fn keys(&self, prefix: &[u8]) -> Vec<Vec<u8>> {
|
fn keys(&self, prefix: &[u8]) -> Vec<StorageKey> {
|
||||||
let mut all = Vec::new();
|
let mut all = Vec::new();
|
||||||
self.for_keys_with_prefix(prefix, |k| all.push(k.to_vec()));
|
self.for_keys_with_prefix(prefix, |k| all.push(k.to_vec()));
|
||||||
all
|
all
|
||||||
@@ -161,7 +161,7 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
prefix: &[u8],
|
prefix: &[u8],
|
||||||
) -> Vec<Vec<u8>> {
|
) -> Vec<StorageKey> {
|
||||||
let mut all = Vec::new();
|
let mut all = Vec::new();
|
||||||
self.for_child_keys_with_prefix(storage_key, child_info, prefix, |k| all.push(k.to_vec()));
|
self.for_child_keys_with_prefix(storage_key, child_info, prefix, |k| all.push(k.to_vec()));
|
||||||
all
|
all
|
||||||
@@ -181,9 +181,9 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
|
|||||||
child_deltas: I2)
|
child_deltas: I2)
|
||||||
-> (H::Out, Self::Transaction)
|
-> (H::Out, Self::Transaction)
|
||||||
where
|
where
|
||||||
I1: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
I1: IntoIterator<Item=(StorageKey, Option<StorageValue>)>,
|
||||||
I2i: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
I2i: IntoIterator<Item=(StorageKey, Option<StorageValue>)>,
|
||||||
I2: IntoIterator<Item=(Vec<u8>, I2i, OwnedChildInfo)>,
|
I2: IntoIterator<Item=(StorageKey, I2i, OwnedChildInfo)>,
|
||||||
H::Out: Ord + Encode,
|
H::Out: Ord + Encode,
|
||||||
{
|
{
|
||||||
let mut txs: Self::Transaction = Default::default();
|
let mut txs: Self::Transaction = Default::default();
|
||||||
@@ -220,7 +220,7 @@ impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T {
|
|||||||
type Transaction = T::Transaction;
|
type Transaction = T::Transaction;
|
||||||
type TrieBackendStorage = T::TrieBackendStorage;
|
type TrieBackendStorage = T::TrieBackendStorage;
|
||||||
|
|
||||||
fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
fn storage(&self, key: &[u8]) -> Result<Option<StorageKey>, Self::Error> {
|
||||||
(*self).storage(key)
|
(*self).storage(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T {
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
) -> Result<Option<StorageKey>, Self::Error> {
|
||||||
(*self).child_storage(storage_key, child_info, key)
|
(*self).child_storage(storage_key, child_info, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +242,7 @@ impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T {
|
|||||||
(*self).for_keys_in_child_storage(storage_key, child_info, f)
|
(*self).for_keys_in_child_storage(storage_key, child_info, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<StorageKey>, Self::Error> {
|
||||||
(*self).next_storage_key(key)
|
(*self).next_storage_key(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T {
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
) -> Result<Option<StorageKey>, Self::Error> {
|
||||||
(*self).next_child_storage_key(storage_key, child_info, key)
|
(*self).next_child_storage_key(storage_key, child_info, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +271,7 @@ impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T {
|
|||||||
|
|
||||||
fn storage_root<I>(&self, delta: I) -> (H::Out, Self::Transaction)
|
fn storage_root<I>(&self, delta: I) -> (H::Out, Self::Transaction)
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
I: IntoIterator<Item=(StorageKey, Option<StorageValue>)>,
|
||||||
H::Out: Ord,
|
H::Out: Ord,
|
||||||
{
|
{
|
||||||
(*self).storage_root(delta)
|
(*self).storage_root(delta)
|
||||||
@@ -284,13 +284,13 @@ impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T {
|
|||||||
delta: I,
|
delta: I,
|
||||||
) -> (H::Out, bool, Self::Transaction)
|
) -> (H::Out, bool, Self::Transaction)
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
I: IntoIterator<Item=(StorageKey, Option<StorageValue>)>,
|
||||||
H::Out: Ord,
|
H::Out: Ord,
|
||||||
{
|
{
|
||||||
(*self).child_storage_root(storage_key, child_info, delta)
|
(*self).child_storage_root(storage_key, child_info, delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
|
fn pairs(&self) -> Vec<(StorageKey, StorageValue)> {
|
||||||
(*self).pairs()
|
(*self).pairs()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,8 +316,8 @@ impl Consolidate for () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Consolidate for Vec<(
|
impl Consolidate for Vec<(
|
||||||
Option<(Vec<u8>, OwnedChildInfo)>,
|
Option<(StorageKey, OwnedChildInfo)>,
|
||||||
Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
StorageCollection,
|
||||||
)> {
|
)> {
|
||||||
fn consolidate(&mut self, mut other: Self) {
|
fn consolidate(&mut self, mut other: Self) {
|
||||||
self.append(&mut other);
|
self.append(&mut other);
|
||||||
@@ -334,7 +334,7 @@ impl<H: Hasher, KF: sp_trie::KeyFunction<H>> Consolidate for sp_trie::GenericMem
|
|||||||
pub(crate) fn insert_into_memory_db<H, I>(mdb: &mut MemoryDB<H>, input: I) -> Option<H::Out>
|
pub(crate) fn insert_into_memory_db<H, I>(mdb: &mut MemoryDB<H>, input: I) -> Option<H::Out>
|
||||||
where
|
where
|
||||||
H: Hasher,
|
H: Hasher,
|
||||||
I: IntoIterator<Item=(Vec<u8>, Vec<u8>)>,
|
I: IntoIterator<Item=(StorageKey, StorageValue)>,
|
||||||
{
|
{
|
||||||
let mut root = <H as Hasher>::Out::default();
|
let mut root = <H as Hasher>::Out::default();
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap, any::{TypeId, Any}, iter::FromIterator, ops::Bound
|
collections::BTreeMap, any::{TypeId, Any}, iter::FromIterator, ops::Bound
|
||||||
};
|
};
|
||||||
use crate::{Backend, InMemoryBackend};
|
use crate::{Backend, InMemoryBackend, StorageKey, StorageValue};
|
||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
use sp_trie::{TrieConfiguration, default_child_trie_root};
|
use sp_trie::{TrieConfiguration, default_child_trie_root};
|
||||||
use sp_trie::trie_types::Layout;
|
use sp_trie::trie_types::Layout;
|
||||||
@@ -46,7 +46,7 @@ impl BasicExternalities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Insert key/value
|
/// Insert key/value
|
||||||
pub fn insert(&mut self, k: Vec<u8>, v: Vec<u8>) -> Option<Vec<u8>> {
|
pub fn insert(&mut self, k: StorageKey, v: StorageValue) -> Option<StorageValue> {
|
||||||
self.inner.top.insert(k, v)
|
self.inner.top.insert(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,8 +89,8 @@ impl PartialEq for BasicExternalities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator<(Vec<u8>, Vec<u8>)> for BasicExternalities {
|
impl FromIterator<(StorageKey, StorageValue)> for BasicExternalities {
|
||||||
fn from_iter<I: IntoIterator<Item=(Vec<u8>, Vec<u8>)>>(iter: I) -> Self {
|
fn from_iter<I: IntoIterator<Item=(StorageKey, StorageValue)>>(iter: I) -> Self {
|
||||||
let mut t = Self::default();
|
let mut t = Self::default();
|
||||||
t.inner.top.extend(iter);
|
t.inner.top.extend(iter);
|
||||||
t
|
t
|
||||||
@@ -101,8 +101,8 @@ impl Default for BasicExternalities {
|
|||||||
fn default() -> Self { Self::new(Default::default()) }
|
fn default() -> Self { Self::new(Default::default()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BTreeMap<Vec<u8>, Vec<u8>>> for BasicExternalities {
|
impl From<BTreeMap<StorageKey, StorageValue>> for BasicExternalities {
|
||||||
fn from(hashmap: BTreeMap<Vec<u8>, Vec<u8>>) -> Self {
|
fn from(hashmap: BTreeMap<StorageKey, StorageValue>) -> Self {
|
||||||
BasicExternalities { inner: Storage {
|
BasicExternalities { inner: Storage {
|
||||||
top: hashmap,
|
top: hashmap,
|
||||||
children: Default::default(),
|
children: Default::default(),
|
||||||
@@ -111,7 +111,7 @@ impl From<BTreeMap<Vec<u8>, Vec<u8>>> for BasicExternalities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Externalities for BasicExternalities {
|
impl Externalities for BasicExternalities {
|
||||||
fn storage(&self, key: &[u8]) -> Option<Vec<u8>> {
|
fn storage(&self, key: &[u8]) -> Option<StorageValue> {
|
||||||
self.inner.top.get(key).cloned()
|
self.inner.top.get(key).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ impl Externalities for BasicExternalities {
|
|||||||
self.storage(key).map(|v| Blake2Hasher::hash(&v).encode())
|
self.storage(key).map(|v| Blake2Hasher::hash(&v).encode())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn original_storage(&self, key: &[u8]) -> Option<Vec<u8>> {
|
fn original_storage(&self, key: &[u8]) -> Option<StorageValue> {
|
||||||
self.storage(key)
|
self.storage(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ impl Externalities for BasicExternalities {
|
|||||||
storage_key: ChildStorageKey,
|
storage_key: ChildStorageKey,
|
||||||
_child_info: ChildInfo,
|
_child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Option<Vec<u8>> {
|
) -> Option<StorageValue> {
|
||||||
self.inner.children.get(storage_key.as_ref()).and_then(|child| child.data.get(key)).cloned()
|
self.inner.children.get(storage_key.as_ref()).and_then(|child| child.data.get(key)).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,11 +159,11 @@ impl Externalities for BasicExternalities {
|
|||||||
storage_key: ChildStorageKey,
|
storage_key: ChildStorageKey,
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Option<Vec<u8>> {
|
) -> Option<StorageValue> {
|
||||||
Externalities::child_storage(self, storage_key, child_info, key)
|
Externalities::child_storage(self, storage_key, child_info, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_storage_key(&self, key: &[u8]) -> Option<Vec<u8>> {
|
fn next_storage_key(&self, key: &[u8]) -> Option<StorageKey> {
|
||||||
let range = (Bound::Excluded(key), Bound::Unbounded);
|
let range = (Bound::Excluded(key), Bound::Unbounded);
|
||||||
self.inner.top.range::<[u8], _>(range).next().map(|(k, _)| k).cloned()
|
self.inner.top.range::<[u8], _>(range).next().map(|(k, _)| k).cloned()
|
||||||
}
|
}
|
||||||
@@ -173,13 +173,13 @@ impl Externalities for BasicExternalities {
|
|||||||
storage_key: ChildStorageKey,
|
storage_key: ChildStorageKey,
|
||||||
_child_info: ChildInfo,
|
_child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Option<Vec<u8>> {
|
) -> Option<StorageKey> {
|
||||||
let range = (Bound::Excluded(key), Bound::Unbounded);
|
let range = (Bound::Excluded(key), Bound::Unbounded);
|
||||||
self.inner.children.get(storage_key.as_ref())
|
self.inner.children.get(storage_key.as_ref())
|
||||||
.and_then(|child| child.data.range::<[u8], _>(range).next().map(|(k, _)| k).cloned())
|
.and_then(|child| child.data.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: StorageKey, maybe_value: Option<StorageValue>) {
|
||||||
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");
|
||||||
return;
|
return;
|
||||||
@@ -195,8 +195,8 @@ impl Externalities for BasicExternalities {
|
|||||||
&mut self,
|
&mut self,
|
||||||
storage_key: ChildStorageKey,
|
storage_key: ChildStorageKey,
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: Vec<u8>,
|
key: StorageKey,
|
||||||
value: Option<Vec<u8>>,
|
value: Option<StorageValue>,
|
||||||
) {
|
) {
|
||||||
let child_map = self.inner.children.entry(storage_key.into_owned())
|
let child_map = self.inner.children.entry(storage_key.into_owned())
|
||||||
.or_insert_with(|| StorageChild {
|
.or_insert_with(|| StorageChild {
|
||||||
|
|||||||
@@ -21,13 +21,17 @@ use std::collections::btree_map::Entry;
|
|||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
use num_traits::One;
|
use num_traits::One;
|
||||||
use crate::backend::Backend;
|
use crate::{
|
||||||
use crate::overlayed_changes::OverlayedChanges;
|
StorageKey,
|
||||||
use crate::trie_backend_essence::TrieBackendEssence;
|
backend::Backend,
|
||||||
use crate::changes_trie::build_iterator::digest_build_iterator;
|
overlayed_changes::OverlayedChanges,
|
||||||
use crate::changes_trie::input::{InputKey, InputPair, DigestIndex, ExtrinsicIndex};
|
trie_backend_essence::TrieBackendEssence,
|
||||||
use crate::changes_trie::{AnchorBlockId, ConfigurationRange, Storage, BlockNumber};
|
changes_trie::{
|
||||||
use crate::changes_trie::input::ChildIndex;
|
AnchorBlockId, ConfigurationRange, Storage, BlockNumber,
|
||||||
|
build_iterator::digest_build_iterator,
|
||||||
|
input::{InputKey, InputPair, DigestIndex, ExtrinsicIndex, ChildIndex},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/// Prepare input pairs for building a changes trie of given block.
|
/// Prepare input pairs for building a changes trie of given block.
|
||||||
///
|
///
|
||||||
@@ -101,7 +105,7 @@ fn prepare_extrinsics_input<'a, B, H, Number>(
|
|||||||
Number: BlockNumber,
|
Number: BlockNumber,
|
||||||
{
|
{
|
||||||
|
|
||||||
let mut children_keys = BTreeSet::<Vec<u8>>::new();
|
let mut children_keys = BTreeSet::<StorageKey>::new();
|
||||||
let mut children_result = BTreeMap::new();
|
let mut children_result = BTreeMap::new();
|
||||||
for (storage_key, _) in changes.prospective.children.iter()
|
for (storage_key, _) in changes.prospective.children.iter()
|
||||||
.chain(changes.committed.children.iter()) {
|
.chain(changes.committed.children.iter()) {
|
||||||
@@ -126,7 +130,7 @@ fn prepare_extrinsics_input_inner<'a, B, H, Number>(
|
|||||||
backend: &'a B,
|
backend: &'a B,
|
||||||
block: &Number,
|
block: &Number,
|
||||||
changes: &'a OverlayedChanges,
|
changes: &'a OverlayedChanges,
|
||||||
storage_key: Option<Vec<u8>>,
|
storage_key: Option<StorageKey>,
|
||||||
) -> Result<impl Iterator<Item=InputPair<Number>> + 'a, String>
|
) -> Result<impl Iterator<Item=InputPair<Number>> + 'a, String>
|
||||||
where
|
where
|
||||||
B: Backend<H>,
|
B: Backend<H>,
|
||||||
@@ -231,7 +235,7 @@ fn prepare_digest_input<'a, H, Number>(
|
|||||||
let trie_root = storage.root(parent, digest_build_block.clone())?;
|
let trie_root = storage.root(parent, digest_build_block.clone())?;
|
||||||
let trie_root = trie_root.ok_or_else(|| format!("No changes trie root for block {}", digest_build_block.clone()))?;
|
let trie_root = trie_root.ok_or_else(|| format!("No changes trie root for block {}", digest_build_block.clone()))?;
|
||||||
|
|
||||||
let insert_to_map = |map: &mut BTreeMap<_,_>, key: Vec<u8>| {
|
let insert_to_map = |map: &mut BTreeMap<_,_>, key: StorageKey| {
|
||||||
match map.entry(key.clone()) {
|
match map.entry(key.clone()) {
|
||||||
Entry::Vacant(entry) => {
|
Entry::Vacant(entry) => {
|
||||||
entry.insert((DigestIndex {
|
entry.insert((DigestIndex {
|
||||||
@@ -277,7 +281,7 @@ fn prepare_digest_input<'a, H, Number>(
|
|||||||
return Ok((map, child_map));
|
return Ok((map, child_map));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut children_roots = BTreeMap::<Vec<u8>, _>::new();
|
let mut children_roots = BTreeMap::<StorageKey, _>::new();
|
||||||
{
|
{
|
||||||
let trie_storage = TrieBackendEssence::<_, H>::new(
|
let trie_storage = TrieBackendEssence::<_, H>::new(
|
||||||
crate::changes_trie::TrieBackendStorageAdapter(storage),
|
crate::changes_trie::TrieBackendStorageAdapter(storage),
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use crate::StorageKey;
|
||||||
|
|
||||||
/// Changes trie build cache.
|
/// Changes trie build cache.
|
||||||
///
|
///
|
||||||
/// Helps to avoid read of changes tries from the database when digest trie
|
/// Helps to avoid read of changes tries from the database when digest trie
|
||||||
@@ -36,7 +38,7 @@ pub struct BuildCache<H, N> {
|
|||||||
/// The `Option<Vec<u8>>` in inner `HashMap` stands for the child storage key.
|
/// The `Option<Vec<u8>>` in inner `HashMap` stands for the child storage key.
|
||||||
/// If it is `None`, then the `HashSet` contains keys changed in top-level storage.
|
/// If it is `None`, then the `HashSet` contains keys changed in top-level storage.
|
||||||
/// If it is `Some`, then the `HashSet` contains keys changed in child storage, identified by the key.
|
/// If it is `Some`, then the `HashSet` contains keys changed in child storage, identified by the key.
|
||||||
changed_keys: HashMap<H, HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>>,
|
changed_keys: HashMap<H, HashMap<Option<StorageKey>, HashSet<StorageKey>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The action to perform when block-with-changes-trie is imported.
|
/// The action to perform when block-with-changes-trie is imported.
|
||||||
@@ -54,7 +56,7 @@ pub struct CachedBuildData<H, N> {
|
|||||||
block: N,
|
block: N,
|
||||||
trie_root: H,
|
trie_root: H,
|
||||||
digest_input_blocks: Vec<N>,
|
digest_input_blocks: Vec<N>,
|
||||||
changed_keys: HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>,
|
changed_keys: HashMap<Option<StorageKey>, HashSet<StorageKey>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The action to perform when block-with-changes-trie is imported.
|
/// The action to perform when block-with-changes-trie is imported.
|
||||||
@@ -70,7 +72,7 @@ pub(crate) enum IncompleteCacheAction<N> {
|
|||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub(crate) struct IncompleteCachedBuildData<N> {
|
pub(crate) struct IncompleteCachedBuildData<N> {
|
||||||
digest_input_blocks: Vec<N>,
|
digest_input_blocks: Vec<N>,
|
||||||
changed_keys: HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>,
|
changed_keys: HashMap<Option<StorageKey>, HashSet<StorageKey>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, N> BuildCache<H, N>
|
impl<H, N> BuildCache<H, N>
|
||||||
@@ -87,7 +89,7 @@ impl<H, N> BuildCache<H, N>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get cached changed keys for changes trie with given root.
|
/// Get cached changed keys for changes trie with given root.
|
||||||
pub fn get(&self, root: &H) -> Option<&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>> {
|
pub fn get(&self, root: &H) -> Option<&HashMap<Option<StorageKey>, HashSet<StorageKey>>> {
|
||||||
self.changed_keys.get(&root)
|
self.changed_keys.get(&root)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +98,7 @@ impl<H, N> BuildCache<H, N>
|
|||||||
pub fn with_changed_keys(
|
pub fn with_changed_keys(
|
||||||
&self,
|
&self,
|
||||||
root: &H,
|
root: &H,
|
||||||
functor: &mut dyn FnMut(&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>),
|
functor: &mut dyn FnMut(&HashMap<Option<StorageKey>, HashSet<StorageKey>>),
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match self.changed_keys.get(&root) {
|
match self.changed_keys.get(&root) {
|
||||||
Some(changed_keys) => {
|
Some(changed_keys) => {
|
||||||
@@ -162,8 +164,8 @@ impl<N> IncompleteCacheAction<N> {
|
|||||||
/// Insert changed keys of given storage into cached data.
|
/// Insert changed keys of given storage into cached data.
|
||||||
pub(crate) fn insert(
|
pub(crate) fn insert(
|
||||||
self,
|
self,
|
||||||
storage_key: Option<Vec<u8>>,
|
storage_key: Option<StorageKey>,
|
||||||
changed_keys: HashSet<Vec<u8>>,
|
changed_keys: HashSet<StorageKey>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match self {
|
match self {
|
||||||
IncompleteCacheAction::CacheBuildData(build_data) =>
|
IncompleteCacheAction::CacheBuildData(build_data) =>
|
||||||
@@ -198,8 +200,8 @@ impl<N> IncompleteCachedBuildData<N> {
|
|||||||
|
|
||||||
fn insert(
|
fn insert(
|
||||||
mut self,
|
mut self,
|
||||||
storage_key: Option<Vec<u8>>,
|
storage_key: Option<StorageKey>,
|
||||||
changed_keys: HashSet<Vec<u8>>,
|
changed_keys: HashSet<StorageKey>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.changed_keys.insert(storage_key, changed_keys);
|
self.changed_keys.insert(storage_key, changed_keys);
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -17,7 +17,10 @@
|
|||||||
//! Different types of changes trie input pairs.
|
//! Different types of changes trie input pairs.
|
||||||
|
|
||||||
use codec::{Decode, Encode, Input, Output, Error};
|
use codec::{Decode, Encode, Input, Output, Error};
|
||||||
use crate::changes_trie::BlockNumber;
|
use crate::{
|
||||||
|
StorageKey, StorageValue,
|
||||||
|
changes_trie::BlockNumber
|
||||||
|
};
|
||||||
|
|
||||||
/// Key of { changed key => set of extrinsic indices } mapping.
|
/// Key of { changed key => set of extrinsic indices } mapping.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
@@ -25,7 +28,7 @@ pub struct ExtrinsicIndex<Number: BlockNumber> {
|
|||||||
/// Block at which this key has been inserted in the trie.
|
/// Block at which this key has been inserted in the trie.
|
||||||
pub block: Number,
|
pub block: Number,
|
||||||
/// Storage key this node is responsible for.
|
/// Storage key this node is responsible for.
|
||||||
pub key: Vec<u8>,
|
pub key: StorageKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Value of { changed key => set of extrinsic indices } mapping.
|
/// Value of { changed key => set of extrinsic indices } mapping.
|
||||||
@@ -37,7 +40,7 @@ pub struct DigestIndex<Number: BlockNumber> {
|
|||||||
/// Block at which this key has been inserted in the trie.
|
/// Block at which this key has been inserted in the trie.
|
||||||
pub block: Number,
|
pub block: Number,
|
||||||
/// Storage key this node is responsible for.
|
/// Storage key this node is responsible for.
|
||||||
pub key: Vec<u8>,
|
pub key: StorageKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Key of { childtrie key => Childchange trie } mapping.
|
/// Key of { childtrie key => Childchange trie } mapping.
|
||||||
@@ -46,7 +49,7 @@ pub struct ChildIndex<Number: BlockNumber> {
|
|||||||
/// Block at which this key has been inserted in the trie.
|
/// Block at which this key has been inserted in the trie.
|
||||||
pub block: Number,
|
pub block: Number,
|
||||||
/// Storage key this node is responsible for.
|
/// Storage key this node is responsible for.
|
||||||
pub storage_key: Vec<u8>,
|
pub storage_key: StorageKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Value of { changed key => block/digest block numbers } mapping.
|
/// Value of { changed key => block/digest block numbers } mapping.
|
||||||
@@ -89,8 +92,8 @@ impl<Number: BlockNumber> InputPair<Number> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Number: BlockNumber> Into<(Vec<u8>, Vec<u8>)> for InputPair<Number> {
|
impl<Number: BlockNumber> Into<(StorageKey, StorageValue)> for InputPair<Number> {
|
||||||
fn into(self) -> (Vec<u8>, Vec<u8>) {
|
fn into(self) -> (StorageKey, StorageValue) {
|
||||||
match self {
|
match self {
|
||||||
InputPair::ExtrinsicIndex(key, value) => (key.encode(), value.encode()),
|
InputPair::ExtrinsicIndex(key, value) => (key.encode(), value.encode()),
|
||||||
InputPair::DigestIndex(key, value) => (key.encode(), value.encode()),
|
InputPair::DigestIndex(key, value) => (key.encode(), value.encode()),
|
||||||
|
|||||||
@@ -68,15 +68,20 @@ pub use self::prune::prune;
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use hash_db::{Hasher, Prefix};
|
use hash_db::{Hasher, Prefix};
|
||||||
use crate::backend::Backend;
|
|
||||||
use num_traits::{One, Zero};
|
use num_traits::{One, Zero};
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use sp_core;
|
use sp_core;
|
||||||
use crate::changes_trie::build::prepare_input;
|
|
||||||
use crate::changes_trie::build_cache::{IncompleteCachedBuildData, IncompleteCacheAction};
|
|
||||||
use crate::overlayed_changes::OverlayedChanges;
|
|
||||||
use sp_trie::{MemoryDB, DBValue, TrieMut};
|
use sp_trie::{MemoryDB, DBValue, TrieMut};
|
||||||
use sp_trie::trie_types::TrieDBMut;
|
use sp_trie::trie_types::TrieDBMut;
|
||||||
|
use crate::{
|
||||||
|
StorageKey,
|
||||||
|
backend::Backend,
|
||||||
|
overlayed_changes::OverlayedChanges,
|
||||||
|
changes_trie::{
|
||||||
|
build::prepare_input,
|
||||||
|
build_cache::{IncompleteCachedBuildData, IncompleteCacheAction},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/// Changes that are made outside of extrinsics are marked with this index;
|
/// Changes that are made outside of extrinsics are marked with this index;
|
||||||
pub const NO_EXTRINSIC_INDEX: u32 = 0xffffffff;
|
pub const NO_EXTRINSIC_INDEX: u32 = 0xffffffff;
|
||||||
@@ -151,7 +156,7 @@ pub trait Storage<H: Hasher, Number: BlockNumber>: RootsStorage<H, Number> {
|
|||||||
fn with_cached_changed_keys(
|
fn with_cached_changed_keys(
|
||||||
&self,
|
&self,
|
||||||
root: &H::Out,
|
root: &H::Out,
|
||||||
functor: &mut dyn FnMut(&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>),
|
functor: &mut dyn FnMut(&HashMap<Option<StorageKey>, HashSet<StorageKey>>),
|
||||||
) -> bool;
|
) -> bool;
|
||||||
/// Get a trie node.
|
/// Get a trie node.
|
||||||
fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>, String>;
|
fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>, String>;
|
||||||
|
|||||||
@@ -21,8 +21,11 @@ use hash_db::{Hasher, Prefix, EMPTY_PREFIX};
|
|||||||
use sp_trie::DBValue;
|
use sp_trie::DBValue;
|
||||||
use sp_trie::MemoryDB;
|
use sp_trie::MemoryDB;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use crate::changes_trie::{BuildCache, RootsStorage, Storage, AnchorBlockId, BlockNumber};
|
use crate::{
|
||||||
use crate::trie_backend_essence::TrieBackendStorage;
|
StorageKey,
|
||||||
|
trie_backend_essence::TrieBackendStorage,
|
||||||
|
changes_trie::{BuildCache, RootsStorage, Storage, AnchorBlockId, BlockNumber},
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::backend::insert_into_memory_db;
|
use crate::backend::insert_into_memory_db;
|
||||||
@@ -93,7 +96,7 @@ impl<H: Hasher, Number: BlockNumber> InMemoryStorage<H, Number> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn with_inputs(
|
pub fn with_inputs(
|
||||||
mut top_inputs: Vec<(Number, Vec<InputPair<Number>>)>,
|
mut top_inputs: Vec<(Number, Vec<InputPair<Number>>)>,
|
||||||
children_inputs: Vec<(Vec<u8>, Vec<(Number, Vec<InputPair<Number>>)>)>,
|
children_inputs: Vec<(StorageKey, Vec<(Number, Vec<InputPair<Number>>)>)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut mdb = MemoryDB::default();
|
let mut mdb = MemoryDB::default();
|
||||||
let mut roots = BTreeMap::new();
|
let mut roots = BTreeMap::new();
|
||||||
@@ -179,7 +182,7 @@ impl<H: Hasher, Number: BlockNumber> Storage<H, Number> for InMemoryStorage<H, N
|
|||||||
fn with_cached_changed_keys(
|
fn with_cached_changed_keys(
|
||||||
&self,
|
&self,
|
||||||
root: &H::Out,
|
root: &H::Out,
|
||||||
functor: &mut dyn FnMut(&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>),
|
functor: &mut dyn FnMut(&HashMap<Option<StorageKey>, HashSet<StorageKey>>),
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.cache.with_changed_keys(root, functor)
|
self.cache.with_changed_keys(root, functor)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
//! Concrete externalities implementation.
|
//! Concrete externalities implementation.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::Backend, OverlayedChanges, StorageTransactionCache,
|
StorageKey, StorageValue, OverlayedChanges, StorageTransactionCache,
|
||||||
|
backend::Backend,
|
||||||
changes_trie::State as ChangesTrieState,
|
changes_trie::State as ChangesTrieState,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -130,7 +131,7 @@ where
|
|||||||
B: 'a + Backend<H>,
|
B: 'a + Backend<H>,
|
||||||
N: crate::changes_trie::BlockNumber,
|
N: crate::changes_trie::BlockNumber,
|
||||||
{
|
{
|
||||||
pub fn storage_pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
|
pub fn storage_pairs(&self) -> Vec<(StorageKey, StorageValue)> {
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
self.backend.pairs().iter()
|
self.backend.pairs().iter()
|
||||||
@@ -151,7 +152,7 @@ where
|
|||||||
B: 'a + Backend<H>,
|
B: 'a + Backend<H>,
|
||||||
N: crate::changes_trie::BlockNumber,
|
N: crate::changes_trie::BlockNumber,
|
||||||
{
|
{
|
||||||
fn storage(&self, key: &[u8]) -> Option<Vec<u8>> {
|
fn storage(&self, key: &[u8]) -> Option<StorageValue> {
|
||||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||||
let result = self.overlay.storage(key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(||
|
let result = self.overlay.storage(key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(||
|
||||||
self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL));
|
self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL));
|
||||||
@@ -178,7 +179,7 @@ where
|
|||||||
result.map(|r| r.encode())
|
result.map(|r| r.encode())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn original_storage(&self, key: &[u8]) -> Option<Vec<u8>> {
|
fn original_storage(&self, key: &[u8]) -> Option<StorageValue> {
|
||||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||||
let result = self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL);
|
let result = self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL);
|
||||||
|
|
||||||
@@ -207,7 +208,7 @@ where
|
|||||||
storage_key: ChildStorageKey,
|
storage_key: ChildStorageKey,
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Option<Vec<u8>> {
|
) -> Option<StorageValue> {
|
||||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||||
let result = self.overlay
|
let result = self.overlay
|
||||||
.child_storage(storage_key.as_ref(), key)
|
.child_storage(storage_key.as_ref(), key)
|
||||||
@@ -256,7 +257,7 @@ where
|
|||||||
storage_key: ChildStorageKey,
|
storage_key: ChildStorageKey,
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Option<Vec<u8>> {
|
) -> Option<StorageValue> {
|
||||||
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
let _guard = sp_panic_handler::AbortGuard::force_abort();
|
||||||
let result = self.backend
|
let result = self.backend
|
||||||
.child_storage(storage_key.as_ref(), child_info, key)
|
.child_storage(storage_key.as_ref(), child_info, key)
|
||||||
@@ -332,7 +333,7 @@ where
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_storage_key(&self, key: &[u8]) -> Option<Vec<u8>> {
|
fn next_storage_key(&self, key: &[u8]) -> Option<StorageKey> {
|
||||||
let next_backend_key = self.backend.next_storage_key(key).expect(EXT_NOT_ALLOWED_TO_FAIL);
|
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);
|
let next_overlay_key_change = self.overlay.next_storage_key_change(key);
|
||||||
|
|
||||||
@@ -352,7 +353,7 @@ where
|
|||||||
storage_key: ChildStorageKey,
|
storage_key: ChildStorageKey,
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Option<Vec<u8>> {
|
) -> Option<StorageKey> {
|
||||||
let next_backend_key = self.backend
|
let next_backend_key = self.backend
|
||||||
.next_child_storage_key(storage_key.as_ref(), child_info, key)
|
.next_child_storage_key(storage_key.as_ref(), child_info, key)
|
||||||
.expect(EXT_NOT_ALLOWED_TO_FAIL);
|
.expect(EXT_NOT_ALLOWED_TO_FAIL);
|
||||||
@@ -376,7 +377,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn place_storage(&mut self, key: Vec<u8>, value: Option<Vec<u8>>) {
|
fn place_storage(&mut self, key: StorageKey, value: Option<StorageValue>) {
|
||||||
trace!(target: "state-trace", "{:04x}: Put {}={:?}",
|
trace!(target: "state-trace", "{:04x}: Put {}={:?}",
|
||||||
self.id,
|
self.id,
|
||||||
HexDisplay::from(&key),
|
HexDisplay::from(&key),
|
||||||
@@ -396,8 +397,8 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
storage_key: ChildStorageKey,
|
storage_key: ChildStorageKey,
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: Vec<u8>,
|
key: StorageKey,
|
||||||
value: Option<Vec<u8>>,
|
value: Option<StorageValue>,
|
||||||
) {
|
) {
|
||||||
trace!(target: "state-trace", "{:04x}: PutChild({}) {}={:?}",
|
trace!(target: "state-trace", "{:04x}: PutChild({}) {}={:?}",
|
||||||
self.id,
|
self.id,
|
||||||
|
|||||||
@@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
//! State machine in memory backend.
|
//! State machine in memory backend.
|
||||||
|
|
||||||
use crate::{trie_backend::TrieBackend, backend::{Backend, insert_into_memory_db}};
|
use crate::{
|
||||||
|
StorageKey, StorageValue, StorageCollection,
|
||||||
|
trie_backend::TrieBackend,
|
||||||
|
backend::{Backend, insert_into_memory_db},
|
||||||
|
};
|
||||||
use std::{error, fmt, collections::{BTreeMap, HashMap}, marker::PhantomData, ops};
|
use std::{error, fmt, collections::{BTreeMap, HashMap}, marker::PhantomData, ops};
|
||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
use sp_trie::{
|
use sp_trie::{
|
||||||
@@ -43,7 +47,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>, OwnedChildInfo)>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
inner: HashMap<Option<(StorageKey, OwnedChildInfo)>, BTreeMap<StorageKey, StorageValue>>,
|
||||||
// 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>,
|
||||||
@@ -84,7 +88,7 @@ impl<H: Hasher> PartialEq for InMemory<H> {
|
|||||||
impl<H: Hasher> InMemory<H> {
|
impl<H: Hasher> InMemory<H> {
|
||||||
/// Copy the state, with applied updates
|
/// Copy the state, with applied updates
|
||||||
pub fn update<
|
pub fn update<
|
||||||
T: IntoIterator<Item = (Option<(Vec<u8>, OwnedChildInfo)>, Vec<(Vec<u8>, Option<Vec<u8>>)>)>
|
T: IntoIterator<Item = (Option<(StorageKey, OwnedChildInfo)>, StorageCollection)>
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
changes: T,
|
changes: T,
|
||||||
@@ -103,10 +107,10 @@ impl<H: Hasher> InMemory<H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: Hasher> From<HashMap<Option<(Vec<u8>, OwnedChildInfo)>, BTreeMap<Vec<u8>, Vec<u8>>>>
|
impl<H: Hasher> From<HashMap<Option<(StorageKey, OwnedChildInfo)>, BTreeMap<StorageKey, StorageValue>>>
|
||||||
for InMemory<H>
|
for InMemory<H>
|
||||||
{
|
{
|
||||||
fn from(inner: HashMap<Option<(Vec<u8>, OwnedChildInfo)>, BTreeMap<Vec<u8>, Vec<u8>>>) -> Self {
|
fn from(inner: HashMap<Option<(StorageKey, OwnedChildInfo)>, BTreeMap<StorageKey, StorageValue>>) -> Self {
|
||||||
InMemory {
|
InMemory {
|
||||||
inner,
|
inner,
|
||||||
trie: None,
|
trie: None,
|
||||||
@@ -117,7 +121,7 @@ impl<H: Hasher> From<HashMap<Option<(Vec<u8>, OwnedChildInfo)>, BTreeMap<Vec<u8>
|
|||||||
|
|
||||||
impl<H: Hasher> From<Storage> for InMemory<H> {
|
impl<H: Hasher> From<Storage> for InMemory<H> {
|
||||||
fn from(inners: Storage) -> Self {
|
fn from(inners: Storage) -> Self {
|
||||||
let mut inner: HashMap<Option<(Vec<u8>, OwnedChildInfo)>, BTreeMap<Vec<u8>, Vec<u8>>>
|
let mut inner: HashMap<Option<(StorageKey, OwnedChildInfo)>, BTreeMap<StorageKey, StorageValue>>
|
||||||
= inners.children.into_iter().map(|(k, c)| (Some((k, c.child_info)), c.data)).collect();
|
= inners.children.into_iter().map(|(k, c)| (Some((k, c.child_info)), c.data)).collect();
|
||||||
inner.insert(None, inners.top);
|
inner.insert(None, inners.top);
|
||||||
InMemory {
|
InMemory {
|
||||||
@@ -128,8 +132,8 @@ impl<H: Hasher> From<Storage> for InMemory<H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: Hasher> From<BTreeMap<Vec<u8>, Vec<u8>>> for InMemory<H> {
|
impl<H: Hasher> From<BTreeMap<StorageKey, StorageValue>> for InMemory<H> {
|
||||||
fn from(inner: BTreeMap<Vec<u8>, Vec<u8>>) -> Self {
|
fn from(inner: BTreeMap<StorageKey, StorageValue>) -> Self {
|
||||||
let mut expanded = HashMap::new();
|
let mut expanded = HashMap::new();
|
||||||
expanded.insert(None, inner);
|
expanded.insert(None, inner);
|
||||||
InMemory {
|
InMemory {
|
||||||
@@ -140,12 +144,12 @@ impl<H: Hasher> From<BTreeMap<Vec<u8>, Vec<u8>>> for InMemory<H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: Hasher> From<Vec<(Option<(Vec<u8>, OwnedChildInfo)>, Vec<(Vec<u8>, Option<Vec<u8>>)>)>>
|
impl<H: Hasher> From<Vec<(Option<(StorageKey, OwnedChildInfo)>, StorageCollection)>>
|
||||||
for InMemory<H> {
|
for InMemory<H> {
|
||||||
fn from(
|
fn from(
|
||||||
inner: Vec<(Option<(Vec<u8>, OwnedChildInfo)>, Vec<(Vec<u8>, Option<Vec<u8>>)>)>,
|
inner: Vec<(Option<(StorageKey, OwnedChildInfo)>, StorageCollection)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut expanded: HashMap<Option<(Vec<u8>, OwnedChildInfo)>, BTreeMap<Vec<u8>, Vec<u8>>>
|
let mut expanded: HashMap<Option<(StorageKey, OwnedChildInfo)>, BTreeMap<StorageKey, StorageValue>>
|
||||||
= HashMap::new();
|
= HashMap::new();
|
||||||
for (child_info, key_values) in inner {
|
for (child_info, key_values) in inner {
|
||||||
let entry = expanded.entry(child_info).or_default();
|
let entry = expanded.entry(child_info).or_default();
|
||||||
@@ -171,12 +175,12 @@ impl<H: Hasher> InMemory<H> {
|
|||||||
impl<H: Hasher> Backend<H> for InMemory<H> where H::Out: Codec {
|
impl<H: Hasher> Backend<H> for InMemory<H> where H::Out: Codec {
|
||||||
type Error = Void;
|
type Error = Void;
|
||||||
type Transaction = Vec<(
|
type Transaction = Vec<(
|
||||||
Option<(Vec<u8>, OwnedChildInfo)>,
|
Option<(StorageKey, OwnedChildInfo)>,
|
||||||
Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
StorageCollection,
|
||||||
)>;
|
)>;
|
||||||
type TrieBackendStorage = MemoryDB<H>;
|
type TrieBackendStorage = MemoryDB<H>;
|
||||||
|
|
||||||
fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
fn storage(&self, key: &[u8]) -> Result<Option<StorageValue>, Self::Error> {
|
||||||
Ok(self.inner.get(&None).and_then(|map| map.get(key).map(Clone::clone)))
|
Ok(self.inner.get(&None).and_then(|map| map.get(key).map(Clone::clone)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +189,7 @@ impl<H: Hasher> Backend<H> for InMemory<H> where H::Out: Codec {
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
) -> Result<Option<StorageValue>, Self::Error> {
|
||||||
Ok(self.inner.get(&Some((storage_key.to_vec(), child_info.to_owned())))
|
Ok(self.inner.get(&Some((storage_key.to_vec(), child_info.to_owned())))
|
||||||
.and_then(|map| map.get(key).map(Clone::clone)))
|
.and_then(|map| map.get(key).map(Clone::clone)))
|
||||||
}
|
}
|
||||||
@@ -279,7 +283,7 @@ impl<H: Hasher> Backend<H> for InMemory<H> where H::Out: Codec {
|
|||||||
(root, is_default, vec![(child_info, full_transaction)])
|
(root, is_default, vec![(child_info, full_transaction)])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<StorageKey>, Self::Error> {
|
||||||
let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded);
|
let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded);
|
||||||
let next_key = self.inner.get(&None)
|
let next_key = self.inner.get(&None)
|
||||||
.and_then(|map| map.range::<[u8], _>(range).next().map(|(k, _)| k).cloned());
|
.and_then(|map| map.range::<[u8], _>(range).next().map(|(k, _)| k).cloned());
|
||||||
@@ -292,7 +296,7 @@ impl<H: Hasher> Backend<H> for InMemory<H> where H::Out: Codec {
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
) -> Result<Option<StorageKey>, Self::Error> {
|
||||||
let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded);
|
let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded);
|
||||||
let next_key = self.inner.get(&Some((storage_key.to_vec(), child_info.to_owned())))
|
let next_key = self.inner.get(&Some((storage_key.to_vec(), child_info.to_owned())))
|
||||||
.and_then(|map| map.range::<[u8], _>(range).next().map(|(k, _)| k).cloned());
|
.and_then(|map| map.range::<[u8], _>(range).next().map(|(k, _)| k).cloned());
|
||||||
@@ -300,14 +304,14 @@ impl<H: Hasher> Backend<H> for InMemory<H> where H::Out: Codec {
|
|||||||
Ok(next_key)
|
Ok(next_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
|
fn pairs(&self) -> Vec<(StorageKey, StorageValue)> {
|
||||||
self.inner.get(&None)
|
self.inner.get(&None)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|map| map.iter().map(|(k, v)| (k.clone(), v.clone())))
|
.flat_map(|map| map.iter().map(|(k, v)| (k.clone(), v.clone())))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keys(&self, prefix: &[u8]) -> Vec<Vec<u8>> {
|
fn keys(&self, prefix: &[u8]) -> Vec<StorageKey> {
|
||||||
self.inner.get(&None)
|
self.inner.get(&None)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|map| map.keys().filter(|k| k.starts_with(prefix)).cloned())
|
.flat_map(|map| map.keys().filter(|k| k.starts_with(prefix)).cloned())
|
||||||
@@ -319,7 +323,7 @@ impl<H: Hasher> Backend<H> for InMemory<H> where H::Out: Codec {
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
prefix: &[u8],
|
prefix: &[u8],
|
||||||
) -> Vec<Vec<u8>> {
|
) -> Vec<StorageKey> {
|
||||||
self.inner.get(&Some((storage_key.to_vec(), child_info.to_owned())))
|
self.inner.get(&Some((storage_key.to_vec(), child_info.to_owned())))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|map| map.keys().filter(|k| k.starts_with(prefix)).cloned())
|
.flat_map(|map| map.keys().filter(|k| k.starts_with(prefix)).cloned())
|
||||||
|
|||||||
@@ -62,7 +62,10 @@ pub use changes_trie::{
|
|||||||
disabled_state as disabled_changes_trie_state,
|
disabled_state as disabled_changes_trie_state,
|
||||||
BlockNumber as ChangesTrieBlockNumber,
|
BlockNumber as ChangesTrieBlockNumber,
|
||||||
};
|
};
|
||||||
pub use overlayed_changes::{OverlayedChanges, StorageChanges, StorageTransactionCache};
|
pub use overlayed_changes::{
|
||||||
|
OverlayedChanges, StorageChanges, StorageTransactionCache, StorageKey, StorageValue,
|
||||||
|
StorageCollection, ChildStorageCollection,
|
||||||
|
};
|
||||||
pub use proving_backend::{
|
pub use proving_backend::{
|
||||||
create_proof_check_backend, create_proof_check_backend_storage, merge_storage_proofs,
|
create_proof_check_backend, create_proof_check_backend_storage, merge_storage_proofs,
|
||||||
ProofRecorder, ProvingBackend, ProvingBackendRecorder, StorageProof,
|
ProofRecorder, ProvingBackend, ProvingBackendRecorder, StorageProof,
|
||||||
|
|||||||
@@ -33,6 +33,18 @@ use std::{mem, ops};
|
|||||||
|
|
||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
|
|
||||||
|
/// Storage key.
|
||||||
|
pub type StorageKey = Vec<u8>;
|
||||||
|
|
||||||
|
/// Storage value.
|
||||||
|
pub type StorageValue = Vec<u8>;
|
||||||
|
|
||||||
|
/// In memory array of storage values.
|
||||||
|
pub type StorageCollection = Vec<(StorageKey, Option<StorageValue>)>;
|
||||||
|
|
||||||
|
/// In memory arrays of storage values for multiple child tries.
|
||||||
|
pub type ChildStorageCollection = Vec<(StorageKey, StorageCollection)>;
|
||||||
|
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
/// A transaction shares all prospective changes within an inner overlay
|
/// A transaction shares all prospective changes within an inner overlay
|
||||||
@@ -52,7 +64,7 @@ pub struct OverlayedChanges {
|
|||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
pub struct OverlayedValue {
|
pub struct OverlayedValue {
|
||||||
/// Current value. None if value has been deleted.
|
/// Current value. None if value has been deleted.
|
||||||
pub value: Option<Vec<u8>>,
|
pub value: Option<StorageValue>,
|
||||||
/// The set of extinsic indices where the values has been changed.
|
/// The set of extinsic indices where the values has been changed.
|
||||||
/// Is filled only if runtime has announced changes trie support.
|
/// Is filled only if runtime has announced changes trie support.
|
||||||
pub extrinsics: Option<BTreeSet<u32>>,
|
pub extrinsics: Option<BTreeSet<u32>>,
|
||||||
@@ -63,9 +75,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: BTreeMap<Vec<u8>, OverlayedValue>,
|
pub top: BTreeMap<StorageKey, OverlayedValue>,
|
||||||
/// Child storage changes.
|
/// Child storage changes.
|
||||||
pub children: HashMap<Vec<u8>, (BTreeMap<Vec<u8>, OverlayedValue>, OwnedChildInfo)>,
|
pub children: HashMap<StorageKey, (BTreeMap<StorageKey, OverlayedValue>, OwnedChildInfo)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A storage changes structure that can be generated by the data collected in [`OverlayedChanges`].
|
/// A storage changes structure that can be generated by the data collected in [`OverlayedChanges`].
|
||||||
@@ -76,9 +88,9 @@ pub struct StorageChanges<Transaction, H: Hasher, N: BlockNumber> {
|
|||||||
/// All changes to the main storage.
|
/// All changes to the main storage.
|
||||||
///
|
///
|
||||||
/// A value of `None` means that it was deleted.
|
/// A value of `None` means that it was deleted.
|
||||||
pub main_storage_changes: Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
pub main_storage_changes: StorageCollection,
|
||||||
/// All changes to the child storages.
|
/// All changes to the child storages.
|
||||||
pub child_storage_changes: Vec<(Vec<u8>, Vec<(Vec<u8>, Option<Vec<u8>>)>)>,
|
pub child_storage_changes: ChildStorageCollection,
|
||||||
/// A transaction for the backend that contains all changes from
|
/// A transaction for the backend that contains all changes from
|
||||||
/// [`main_storage_changes`](Self::main_storage_changes) and from
|
/// [`main_storage_changes`](Self::main_storage_changes) and from
|
||||||
/// [`child_storage_changes`](Self::child_storage_changes).
|
/// [`child_storage_changes`](Self::child_storage_changes).
|
||||||
@@ -94,8 +106,8 @@ pub struct StorageChanges<Transaction, H: Hasher, N: BlockNumber> {
|
|||||||
impl<Transaction, H: Hasher, N: BlockNumber> StorageChanges<Transaction, H, N> {
|
impl<Transaction, H: Hasher, N: BlockNumber> StorageChanges<Transaction, H, N> {
|
||||||
/// Deconstruct into the inner values
|
/// Deconstruct into the inner values
|
||||||
pub fn into_inner(self) -> (
|
pub fn into_inner(self) -> (
|
||||||
Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
StorageCollection,
|
||||||
Vec<(Vec<u8>, Vec<(Vec<u8>, Option<Vec<u8>>)>)>,
|
ChildStorageCollection,
|
||||||
Transaction,
|
Transaction,
|
||||||
H::Out,
|
H::Out,
|
||||||
Option<ChangesTrieTransaction<H, N>>,
|
Option<ChangesTrieTransaction<H, N>>,
|
||||||
@@ -155,8 +167,8 @@ impl<Transaction: Default, H: Hasher, N: BlockNumber> Default for StorageChanges
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl FromIterator<(Vec<u8>, OverlayedValue)> for OverlayedChangeSet {
|
impl FromIterator<(StorageKey, OverlayedValue)> for OverlayedChangeSet {
|
||||||
fn from_iter<T: IntoIterator<Item = (Vec<u8>, OverlayedValue)>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = (StorageKey, OverlayedValue)>>(iter: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
top: iter.into_iter().collect(),
|
top: iter.into_iter().collect(),
|
||||||
children: Default::default(),
|
children: Default::default(),
|
||||||
@@ -219,7 +231,7 @@ impl OverlayedChanges {
|
|||||||
/// Inserts the given key-value pair into the prospective change set.
|
/// Inserts the given key-value pair into the prospective change set.
|
||||||
///
|
///
|
||||||
/// `None` can be used to delete a value specified by the given key.
|
/// `None` can be used to delete a value specified by the given key.
|
||||||
pub(crate) fn set_storage(&mut self, key: Vec<u8>, val: Option<Vec<u8>>) {
|
pub(crate) fn set_storage(&mut self, key: StorageKey, val: Option<StorageValue>) {
|
||||||
let extrinsic_index = self.extrinsic_index();
|
let extrinsic_index = self.extrinsic_index();
|
||||||
let entry = self.prospective.top.entry(key).or_default();
|
let entry = self.prospective.top.entry(key).or_default();
|
||||||
entry.value = val;
|
entry.value = val;
|
||||||
@@ -235,10 +247,10 @@ impl OverlayedChanges {
|
|||||||
/// `None` can be used to delete a value specified by the given key.
|
/// `None` can be used to delete a value specified by the given key.
|
||||||
pub(crate) fn set_child_storage(
|
pub(crate) fn set_child_storage(
|
||||||
&mut self,
|
&mut self,
|
||||||
storage_key: Vec<u8>,
|
storage_key: StorageKey,
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: Vec<u8>,
|
key: StorageKey,
|
||||||
val: Option<Vec<u8>>,
|
val: Option<StorageValue>,
|
||||||
) {
|
) {
|
||||||
let extrinsic_index = self.extrinsic_index();
|
let extrinsic_index = self.extrinsic_index();
|
||||||
let map_entry = self.prospective.children.entry(storage_key)
|
let map_entry = self.prospective.children.entry(storage_key)
|
||||||
@@ -417,8 +429,8 @@ impl OverlayedChanges {
|
|||||||
/// Panics:
|
/// Panics:
|
||||||
/// Will panic if there are any uncommitted prospective changes.
|
/// Will panic if there are any uncommitted prospective changes.
|
||||||
pub fn into_committed(self) -> (
|
pub fn into_committed(self) -> (
|
||||||
impl Iterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
impl Iterator<Item=(StorageKey, Option<StorageValue>)>,
|
||||||
impl Iterator<Item=(Vec<u8>, (impl Iterator<Item=(Vec<u8>, Option<Vec<u8>>)>, OwnedChildInfo))>,
|
impl Iterator<Item=(StorageKey, (impl Iterator<Item=(StorageKey, Option<StorageValue>)>, OwnedChildInfo))>,
|
||||||
){
|
){
|
||||||
assert!(self.prospective.is_empty());
|
assert!(self.prospective.is_empty());
|
||||||
(
|
(
|
||||||
@@ -631,8 +643,8 @@ impl OverlayedChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl From<Option<Vec<u8>>> for OverlayedValue {
|
impl From<Option<StorageValue>> for OverlayedValue {
|
||||||
fn from(value: Option<Vec<u8>>) -> OverlayedValue {
|
fn from(value: Option<StorageValue>) -> OverlayedValue {
|
||||||
OverlayedValue { value, ..Default::default() }
|
OverlayedValue { value, ..Default::default() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -647,8 +659,8 @@ mod tests {
|
|||||||
use crate::ext::Ext;
|
use crate::ext::Ext;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn strip_extrinsic_index(map: &BTreeMap<Vec<u8>, OverlayedValue>)
|
fn strip_extrinsic_index(map: &BTreeMap<StorageKey, OverlayedValue>)
|
||||||
-> BTreeMap<Vec<u8>, OverlayedValue>
|
-> BTreeMap<StorageKey, OverlayedValue>
|
||||||
{
|
{
|
||||||
let mut clone = map.clone();
|
let mut clone = map.clone();
|
||||||
clone.remove(&EXTRINSIC_INDEX.to_vec());
|
clone.remove(&EXTRINSIC_INDEX.to_vec());
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ use codec::Decode;
|
|||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::Backend, OverlayedChanges, StorageTransactionCache, ext::Ext, InMemoryBackend,
|
backend::Backend, OverlayedChanges, StorageTransactionCache, ext::Ext, InMemoryBackend,
|
||||||
|
StorageKey, StorageValue,
|
||||||
changes_trie::{
|
changes_trie::{
|
||||||
Configuration as ChangesTrieConfiguration,
|
Configuration as ChangesTrieConfiguration,
|
||||||
InMemoryStorage as ChangesTrieInMemoryStorage,
|
InMemoryStorage as ChangesTrieInMemoryStorage,
|
||||||
@@ -104,7 +105,7 @@ impl<H: Hasher, N: ChangesTrieBlockNumber> TestExternalities<H, N>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Insert key/value into backend
|
/// Insert key/value into backend
|
||||||
pub fn insert(&mut self, k: Vec<u8>, v: Vec<u8>) {
|
pub fn insert(&mut self, k: StorageKey, v: StorageValue) {
|
||||||
self.backend = self.backend.update(vec![(None, vec![(k, Some(v))])]);
|
self.backend = self.backend.update(vec![(None, vec![(k, Some(v))])]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,12 @@ use log::{warn, debug};
|
|||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
use sp_trie::{Trie, delta_trie_root, default_child_trie_root, child_delta_trie_root};
|
use sp_trie::{Trie, delta_trie_root, default_child_trie_root, child_delta_trie_root};
|
||||||
use sp_trie::trie_types::{TrieDB, TrieError, Layout};
|
use sp_trie::trie_types::{TrieDB, TrieError, Layout};
|
||||||
use crate::trie_backend_essence::{TrieBackendEssence, TrieBackendStorage, Ephemeral};
|
|
||||||
use crate::Backend;
|
|
||||||
use sp_core::storage::ChildInfo;
|
use sp_core::storage::ChildInfo;
|
||||||
use codec::{Codec, Decode};
|
use codec::{Codec, Decode};
|
||||||
|
use crate::{
|
||||||
|
StorageKey, StorageValue, Backend,
|
||||||
|
trie_backend_essence::{TrieBackendEssence, TrieBackendStorage, Ephemeral},
|
||||||
|
};
|
||||||
|
|
||||||
/// Patricia trie-based backend. Transaction type is an overlay of changes to commit.
|
/// Patricia trie-based backend. Transaction type is an overlay of changes to commit.
|
||||||
pub struct TrieBackend<S: TrieBackendStorage<H>, H: Hasher> {
|
pub struct TrieBackend<S: TrieBackendStorage<H>, H: Hasher> {
|
||||||
@@ -72,7 +74,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
|
|||||||
type Transaction = S::Overlay;
|
type Transaction = S::Overlay;
|
||||||
type TrieBackendStorage = S;
|
type TrieBackendStorage = S;
|
||||||
|
|
||||||
fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
fn storage(&self, key: &[u8]) -> Result<Option<StorageValue>, Self::Error> {
|
||||||
self.essence.storage(key)
|
self.essence.storage(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,11 +83,11 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
) -> Result<Option<StorageValue>, Self::Error> {
|
||||||
self.essence.child_storage(storage_key, child_info, key)
|
self.essence.child_storage(storage_key, child_info, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
fn next_storage_key(&self, key: &[u8]) -> Result<Option<StorageKey>, Self::Error> {
|
||||||
self.essence.next_storage_key(key)
|
self.essence.next_storage_key(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +96,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
) -> Result<Option<StorageKey>, Self::Error> {
|
||||||
self.essence.next_child_storage_key(storage_key, child_info, key)
|
self.essence.next_child_storage_key(storage_key, child_info, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +127,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
|
|||||||
self.essence.for_child_keys_with_prefix(storage_key, child_info, prefix, f)
|
self.essence.for_child_keys_with_prefix(storage_key, child_info, prefix, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
|
fn pairs(&self) -> Vec<(StorageKey, StorageValue)> {
|
||||||
let mut read_overlay = S::Overlay::default();
|
let mut read_overlay = S::Overlay::default();
|
||||||
let eph = Ephemeral::new(self.essence.backend_storage(), &mut read_overlay);
|
let eph = Ephemeral::new(self.essence.backend_storage(), &mut read_overlay);
|
||||||
|
|
||||||
@@ -149,7 +151,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keys(&self, prefix: &[u8]) -> Vec<Vec<u8>> {
|
fn keys(&self, prefix: &[u8]) -> Vec<StorageKey> {
|
||||||
let mut read_overlay = S::Overlay::default();
|
let mut read_overlay = S::Overlay::default();
|
||||||
let eph = Ephemeral::new(self.essence.backend_storage(), &mut read_overlay);
|
let eph = Ephemeral::new(self.essence.backend_storage(), &mut read_overlay);
|
||||||
|
|
||||||
@@ -170,7 +172,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn storage_root<I>(&self, delta: I) -> (H::Out, S::Overlay)
|
fn storage_root<I>(&self, delta: I) -> (H::Out, S::Overlay)
|
||||||
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
|
where I: IntoIterator<Item=(StorageKey, Option<StorageValue>)>
|
||||||
{
|
{
|
||||||
let mut write_overlay = S::Overlay::default();
|
let mut write_overlay = S::Overlay::default();
|
||||||
let mut root = *self.essence.root();
|
let mut root = *self.essence.root();
|
||||||
@@ -197,7 +199,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
|
|||||||
delta: I,
|
delta: I,
|
||||||
) -> (H::Out, bool, Self::Transaction)
|
) -> (H::Out, bool, Self::Transaction)
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
I: IntoIterator<Item=(StorageKey, Option<StorageValue>)>,
|
||||||
H::Out: Ord,
|
H::Out: Ord,
|
||||||
{
|
{
|
||||||
let default_root = default_child_trie_root::<Layout<H>>(storage_key);
|
let default_root = default_child_trie_root::<Layout<H>>(storage_key);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ use sp_trie::{Trie, MemoryDB, PrefixedMemoryDB, DBValue,
|
|||||||
default_child_trie_root, read_trie_value, read_child_trie_value,
|
default_child_trie_root, read_trie_value, read_child_trie_value,
|
||||||
for_keys_in_child_trie, KeySpacedDB};
|
for_keys_in_child_trie, KeySpacedDB};
|
||||||
use sp_trie::trie_types::{TrieDB, TrieError, Layout};
|
use sp_trie::trie_types::{TrieDB, TrieError, Layout};
|
||||||
use crate::backend::Consolidate;
|
use crate::{backend::Consolidate, StorageKey, StorageValue};
|
||||||
use sp_core::storage::ChildInfo;
|
use sp_core::storage::ChildInfo;
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
|
|||||||
|
|
||||||
/// Return the next key in the trie i.e. the minimum key that is strictly superior to `key` in
|
/// Return the next key in the trie i.e. the minimum key that is strictly superior to `key` in
|
||||||
/// lexicographic order.
|
/// lexicographic order.
|
||||||
pub fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, String> {
|
pub fn next_storage_key(&self, key: &[u8]) -> Result<Option<StorageKey>, String> {
|
||||||
self.next_storage_key_from_root(&self.root, None, key)
|
self.next_storage_key_from_root(&self.root, None, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<Vec<u8>>, String> {
|
) -> Result<Option<StorageKey>, String> {
|
||||||
let child_root = match self.storage(storage_key)? {
|
let child_root = match self.storage(storage_key)? {
|
||||||
Some(child_root) => child_root,
|
Some(child_root) => child_root,
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
@@ -101,7 +101,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
|
|||||||
root: &H::Out,
|
root: &H::Out,
|
||||||
child_info: Option<ChildInfo>,
|
child_info: Option<ChildInfo>,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<Vec<u8>>, String> {
|
) -> Result<Option<StorageKey>, String> {
|
||||||
let mut read_overlay = S::Overlay::default();
|
let mut read_overlay = S::Overlay::default();
|
||||||
let eph = Ephemeral {
|
let eph = Ephemeral {
|
||||||
storage: &self.storage,
|
storage: &self.storage,
|
||||||
@@ -146,7 +146,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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<StorageValue>, String> {
|
||||||
let mut read_overlay = S::Overlay::default();
|
let mut read_overlay = S::Overlay::default();
|
||||||
let eph = Ephemeral {
|
let eph = Ephemeral {
|
||||||
storage: &self.storage,
|
storage: &self.storage,
|
||||||
@@ -164,7 +164,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
|
|||||||
storage_key: &[u8],
|
storage_key: &[u8],
|
||||||
child_info: ChildInfo,
|
child_info: ChildInfo,
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Result<Option<Vec<u8>>, String> {
|
) -> Result<Option<StorageValue>, String> {
|
||||||
let root = self.storage(storage_key)?
|
let root = self.storage(storage_key)?
|
||||||
.unwrap_or(default_child_trie_root::<Layout<H>>(storage_key).encode());
|
.unwrap_or(default_child_trie_root::<Layout<H>>(storage_key).encode());
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user