mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 00:01:09 +00:00
Remove requirement on Hash = H256, make Proposer return StorageChanges and Proof (#3860)
* Extend `Proposer` to optionally generate a proof of the proposal * Something * Refactor sr-api to not depend on client anymore * Fix benches * Apply suggestions from code review Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Apply suggestions from code review * Introduce new `into_storage_changes` function * Switch to runtime api for `execute_block` and don't require `H256` anywhere in the code * Put the `StorageChanges` into the `Proposal` * Move the runtime api error to its own trait * Adds `StorageTransactionCache` to the runtime api This requires that we add `type NodeBlock = ` to the `impl_runtime_apis!` macro to work around some bugs in rustc :( * Remove `type NodeBlock` and switch to a "better" hack * Start using the transaction cache from the runtime api * Make it compile * Move `InMemory` to its own file * Make all tests work again * Return block, storage_changes and proof from Blockbuilder::bake() * Make sure that we use/set `storage_changes` when possible * Add test * Fix deadlock * Remove accidentally added folders * Introduce `RecordProof` as argument type to be more explicit * Update client/src/client.rs Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Update primitives/state-machine/src/ext.rs Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Integrates review feedback * Remove `unsafe` usage * Update client/block-builder/src/lib.rs Co-Authored-By: Benjamin Kampmann <ben@gnunicorn.org> * Update client/src/call_executor.rs * Bump versions Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com> Co-authored-by: Benjamin Kampmann <ben.kampmann@googlemail.com>
This commit is contained in:
+134
-101
@@ -47,18 +47,18 @@ use sp_blockchain::{
|
||||
well_known_cache_keys, HeaderBackend,
|
||||
};
|
||||
use codec::{Decode, Encode};
|
||||
use hash_db::{Hasher, Prefix};
|
||||
use hash_db::Prefix;
|
||||
use kvdb::{KeyValueDB, DBTransaction};
|
||||
use sp_trie::{MemoryDB, PrefixedMemoryDB, prefixed_key};
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use sp_core::{H256, Blake2Hasher, ChangesTrieConfiguration, convert_hash, traits::CodeExecutor};
|
||||
use sp_core::{ChangesTrieConfiguration, convert_hash, traits::CodeExecutor};
|
||||
use sp_core::storage::{well_known_keys, ChildInfo};
|
||||
use sp_runtime::{
|
||||
generic::{BlockId, DigestItem}, Justification, Storage,
|
||||
BuildStorage,
|
||||
};
|
||||
use sp_runtime::traits::{
|
||||
Block as BlockT, Header as HeaderT, NumberFor, Zero, One, SaturatedConversion
|
||||
Block as BlockT, Header as HeaderT, NumberFor, Zero, One, SaturatedConversion, HasherFor,
|
||||
};
|
||||
use sc_executor::RuntimeInfo;
|
||||
use sp_state_machine::{
|
||||
@@ -83,7 +83,9 @@ const MIN_BLOCKS_TO_KEEP_CHANGES_TRIES_FOR: u32 = 32768;
|
||||
const DEFAULT_CHILD_RATIO: (usize, usize) = (1, 10);
|
||||
|
||||
/// DB-backed patricia trie state, transaction type is an overlay of changes to commit.
|
||||
pub type DbState = sp_state_machine::TrieBackend<Arc<dyn sp_state_machine::Storage<Blake2Hasher>>, Blake2Hasher>;
|
||||
pub type DbState<B> = sp_state_machine::TrieBackend<
|
||||
Arc<dyn sp_state_machine::Storage<HasherFor<B>>>, HasherFor<B>
|
||||
>;
|
||||
|
||||
/// Re-export the KVDB trait so that one can pass an implementation of it.
|
||||
pub use kvdb;
|
||||
@@ -93,17 +95,13 @@ pub use kvdb;
|
||||
/// It makes sure that the hash we are using stays pinned in storage
|
||||
/// until this structure is dropped.
|
||||
pub struct RefTrackingState<Block: BlockT> {
|
||||
state: DbState,
|
||||
state: DbState<Block>,
|
||||
storage: Arc<StorageDb<Block>>,
|
||||
parent_hash: Option<Block::Hash>,
|
||||
}
|
||||
|
||||
impl<B: BlockT> RefTrackingState<B> {
|
||||
fn new(
|
||||
state: DbState,
|
||||
storage: Arc<StorageDb<B>>,
|
||||
parent_hash: Option<B::Hash>,
|
||||
) -> RefTrackingState<B> {
|
||||
fn new(state: DbState<B>, storage: Arc<StorageDb<B>>, parent_hash: Option<B::Hash>) -> Self {
|
||||
RefTrackingState {
|
||||
state,
|
||||
parent_hash,
|
||||
@@ -126,16 +124,16 @@ impl<Block: BlockT> std::fmt::Debug for RefTrackingState<Block> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: BlockT> StateBackend<Blake2Hasher> for RefTrackingState<B> {
|
||||
type Error = <DbState as StateBackend<Blake2Hasher>>::Error;
|
||||
type Transaction = <DbState as StateBackend<Blake2Hasher>>::Transaction;
|
||||
type TrieBackendStorage = <DbState as StateBackend<Blake2Hasher>>::TrieBackendStorage;
|
||||
impl<B: BlockT> StateBackend<HasherFor<B>> for RefTrackingState<B> {
|
||||
type Error = <DbState<B> as StateBackend<HasherFor<B>>>::Error;
|
||||
type Transaction = <DbState<B> as StateBackend<HasherFor<B>>>::Transaction;
|
||||
type TrieBackendStorage = <DbState<B> as StateBackend<HasherFor<B>>>::TrieBackendStorage;
|
||||
|
||||
fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
self.state.storage(key)
|
||||
}
|
||||
|
||||
fn storage_hash(&self, key: &[u8]) -> Result<Option<H256>, Self::Error> {
|
||||
fn storage_hash(&self, key: &[u8]) -> Result<Option<B::Hash>, Self::Error> {
|
||||
self.state.storage_hash(key)
|
||||
}
|
||||
|
||||
@@ -201,7 +199,7 @@ impl<B: BlockT> StateBackend<Blake2Hasher> for RefTrackingState<B> {
|
||||
self.state.for_child_keys_with_prefix(storage_key, child_info, prefix, f)
|
||||
}
|
||||
|
||||
fn storage_root<I>(&self, delta: I) -> (H256, Self::Transaction)
|
||||
fn storage_root<I>(&self, delta: I) -> (B::Hash, Self::Transaction)
|
||||
where
|
||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
|
||||
{
|
||||
@@ -213,7 +211,7 @@ impl<B: BlockT> StateBackend<Blake2Hasher> for RefTrackingState<B> {
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
delta: I,
|
||||
) -> (H256, bool, Self::Transaction)
|
||||
) -> (B::Hash, bool, Self::Transaction)
|
||||
where
|
||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
||||
{
|
||||
@@ -237,9 +235,9 @@ impl<B: BlockT> StateBackend<Blake2Hasher> for RefTrackingState<B> {
|
||||
self.state.child_keys(storage_key, child_info, prefix)
|
||||
}
|
||||
|
||||
fn as_trie_backend(
|
||||
&mut self,
|
||||
) -> Option<&sp_state_machine::TrieBackend<Self::TrieBackendStorage, Blake2Hasher>> {
|
||||
fn as_trie_backend(&mut self)
|
||||
-> Option<&sp_state_machine::TrieBackend<Self::TrieBackendStorage, HasherFor<B>>>
|
||||
{
|
||||
self.state.as_trie_backend()
|
||||
}
|
||||
}
|
||||
@@ -290,7 +288,7 @@ pub fn new_client<E, S, Block, RA>(
|
||||
sp_blockchain::Error,
|
||||
>
|
||||
where
|
||||
Block: BlockT<Hash=H256>,
|
||||
Block: BlockT,
|
||||
E: CodeExecutor + RuntimeInfo,
|
||||
S: BuildStorage,
|
||||
{
|
||||
@@ -505,13 +503,13 @@ impl<Block: BlockT> HeaderMetadata<Block> for BlockchainDb<Block> {
|
||||
}
|
||||
|
||||
/// Database transaction
|
||||
pub struct BlockImportOperation<Block: BlockT, H: Hasher> {
|
||||
old_state: CachingState<Blake2Hasher, RefTrackingState<Block>, Block>,
|
||||
db_updates: PrefixedMemoryDB<H>,
|
||||
pub struct BlockImportOperation<Block: BlockT> {
|
||||
old_state: CachingState<RefTrackingState<Block>, Block>,
|
||||
db_updates: PrefixedMemoryDB<HasherFor<Block>>,
|
||||
storage_updates: StorageCollection,
|
||||
child_storage_updates: ChildStorageCollection,
|
||||
changes_trie_updates: MemoryDB<H>,
|
||||
changes_trie_cache_update: Option<ChangesTrieCacheAction<H::Out, NumberFor<Block>>>,
|
||||
changes_trie_updates: MemoryDB<HasherFor<Block>>,
|
||||
changes_trie_cache_update: Option<ChangesTrieCacheAction<Block::Hash, NumberFor<Block>>>,
|
||||
pending_block: Option<PendingBlock<Block>>,
|
||||
aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
||||
finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>,
|
||||
@@ -519,7 +517,7 @@ pub struct BlockImportOperation<Block: BlockT, H: Hasher> {
|
||||
commit_state: bool,
|
||||
}
|
||||
|
||||
impl<Block: BlockT, H: Hasher> BlockImportOperation<Block, H> {
|
||||
impl<Block: BlockT> BlockImportOperation<Block> {
|
||||
fn apply_aux(&mut self, transaction: &mut DBTransaction) {
|
||||
for (key, maybe_val) in self.aux_ops.drain(..) {
|
||||
match maybe_val {
|
||||
@@ -530,10 +528,8 @@ impl<Block: BlockT, H: Hasher> BlockImportOperation<Block, H> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block> sc_client_api::backend::BlockImportOperation<Block, Blake2Hasher>
|
||||
for BlockImportOperation<Block, Blake2Hasher> where Block: BlockT<Hash=H256>,
|
||||
{
|
||||
type State = CachingState<Blake2Hasher, RefTrackingState<Block>, Block>;
|
||||
impl<Block: BlockT> sc_client_api::backend::BlockImportOperation<Block> for BlockImportOperation<Block> {
|
||||
type State = CachingState<RefTrackingState<Block>, Block>;
|
||||
|
||||
fn state(&self) -> ClientResult<Option<&Self::State>> {
|
||||
Ok(Some(&self.old_state))
|
||||
@@ -560,7 +556,7 @@ impl<Block> sc_client_api::backend::BlockImportOperation<Block, Blake2Hasher>
|
||||
// Currently cache isn't implemented on full nodes.
|
||||
}
|
||||
|
||||
fn update_db_storage(&mut self, update: PrefixedMemoryDB<Blake2Hasher>) -> ClientResult<()> {
|
||||
fn update_db_storage(&mut self, update: PrefixedMemoryDB<HasherFor<Block>>) -> ClientResult<()> {
|
||||
self.db_updates = update;
|
||||
Ok(())
|
||||
}
|
||||
@@ -568,7 +564,7 @@ impl<Block> sc_client_api::backend::BlockImportOperation<Block, Blake2Hasher>
|
||||
fn reset_storage(
|
||||
&mut self,
|
||||
storage: Storage,
|
||||
) -> ClientResult<H256> {
|
||||
) -> ClientResult<Block::Hash> {
|
||||
|
||||
if storage.top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) {
|
||||
return Err(sp_blockchain::Error::GenesisInvalid.into());
|
||||
@@ -597,7 +593,7 @@ impl<Block> sc_client_api::backend::BlockImportOperation<Block, Blake2Hasher>
|
||||
|
||||
fn update_changes_trie(
|
||||
&mut self,
|
||||
update: ChangesTrieTransaction<Blake2Hasher, NumberFor<Block>>,
|
||||
update: ChangesTrieTransaction<HasherFor<Block>, NumberFor<Block>>,
|
||||
) -> ClientResult<()> {
|
||||
self.changes_trie_updates = update.0;
|
||||
self.changes_trie_cache_update = Some(update.1);
|
||||
@@ -621,7 +617,11 @@ impl<Block> sc_client_api::backend::BlockImportOperation<Block, Blake2Hasher>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mark_finalized(&mut self, block: BlockId<Block>, justification: Option<Justification>) -> ClientResult<()> {
|
||||
fn mark_finalized(
|
||||
&mut self,
|
||||
block: BlockId<Block>,
|
||||
justification: Option<Justification>,
|
||||
) -> ClientResult<()> {
|
||||
self.finalized_blocks.push((block, justification));
|
||||
Ok(())
|
||||
}
|
||||
@@ -638,9 +638,9 @@ struct StorageDb<Block: BlockT> {
|
||||
pub state_db: StateDb<Block::Hash, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> sp_state_machine::Storage<Blake2Hasher> for StorageDb<Block> {
|
||||
fn get(&self, key: &H256, prefix: Prefix) -> Result<Option<DBValue>, String> {
|
||||
let key = prefixed_key::<Blake2Hasher>(key, prefix);
|
||||
impl<Block: BlockT> sp_state_machine::Storage<HasherFor<Block>> for StorageDb<Block> {
|
||||
fn get(&self, key: &Block::Hash, prefix: Prefix) -> Result<Option<DBValue>, String> {
|
||||
let key = prefixed_key::<HasherFor<Block>>(key, prefix);
|
||||
self.state_db.get(&key, self)
|
||||
.map_err(|e| format!("Database backend error: {:?}", e))
|
||||
}
|
||||
@@ -655,19 +655,19 @@ impl<Block: BlockT> sc_state_db::NodeDb for StorageDb<Block> {
|
||||
}
|
||||
}
|
||||
|
||||
struct DbGenesisStorage(pub H256);
|
||||
struct DbGenesisStorage<Block: BlockT>(pub Block::Hash);
|
||||
|
||||
impl DbGenesisStorage {
|
||||
impl<Block: BlockT> DbGenesisStorage<Block> {
|
||||
pub fn new() -> Self {
|
||||
let mut root = H256::default();
|
||||
let mut mdb = MemoryDB::<Blake2Hasher>::default();
|
||||
sp_state_machine::TrieDBMut::<Blake2Hasher>::new(&mut mdb, &mut root);
|
||||
let mut root = Block::Hash::default();
|
||||
let mut mdb = MemoryDB::<HasherFor<Block>>::default();
|
||||
sp_state_machine::TrieDBMut::<HasherFor<Block>>::new(&mut mdb, &mut root);
|
||||
DbGenesisStorage(root)
|
||||
}
|
||||
}
|
||||
|
||||
impl sp_state_machine::Storage<Blake2Hasher> for DbGenesisStorage {
|
||||
fn get(&self, _key: &H256, _prefix: Prefix) -> Result<Option<DBValue>, String> {
|
||||
impl<Block: BlockT> sp_state_machine::Storage<HasherFor<Block>> for DbGenesisStorage<Block> {
|
||||
fn get(&self, _key: &Block::Hash, _prefix: Prefix) -> Result<Option<DBValue>, String> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
@@ -678,14 +678,13 @@ pub struct DbChangesTrieStorage<Block: BlockT> {
|
||||
meta: Arc<RwLock<Meta<NumberFor<Block>, Block::Hash>>>,
|
||||
min_blocks_to_keep: Option<u32>,
|
||||
cache: RwLock<ChangesTrieBuildCache<Block::Hash, NumberFor<Block>>>,
|
||||
_phantom: ::std::marker::PhantomData<Block>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT<Hash=H256>> DbChangesTrieStorage<Block> {
|
||||
impl<Block: BlockT> DbChangesTrieStorage<Block> {
|
||||
/// Commit new changes trie.
|
||||
pub fn commit(&self, tx: &mut DBTransaction, mut changes_trie: MemoryDB<Blake2Hasher>) {
|
||||
pub fn commit(&self, tx: &mut DBTransaction, mut changes_trie: MemoryDB<HasherFor<Block>>) {
|
||||
for (key, (val, _)) in changes_trie.drain() {
|
||||
tx.put(columns::CHANGES_TRIE, &key[..], &val);
|
||||
tx.put(columns::CHANGES_TRIE, key.as_ref(), &val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,10 +719,8 @@ impl<Block: BlockT<Hash=H256>> DbChangesTrieStorage<Block> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block> sc_client_api::backend::PrunableStateChangesTrieStorage<Block, Blake2Hasher>
|
||||
impl<Block: BlockT> sc_client_api::backend::PrunableStateChangesTrieStorage<Block>
|
||||
for DbChangesTrieStorage<Block>
|
||||
where
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
fn oldest_changes_trie_block(
|
||||
&self,
|
||||
@@ -741,16 +738,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block> sp_state_machine::ChangesTrieRootsStorage<Blake2Hasher, NumberFor<Block>>
|
||||
impl<Block: BlockT> sp_state_machine::ChangesTrieRootsStorage<HasherFor<Block>, NumberFor<Block>>
|
||||
for DbChangesTrieStorage<Block>
|
||||
where
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
fn build_anchor(
|
||||
&self,
|
||||
hash: H256,
|
||||
) -> Result<sp_state_machine::ChangesTrieAnchorBlockId<H256, NumberFor<Block>>, String> {
|
||||
utils::read_header::<Block>(&*self.db, columns::KEY_LOOKUP, columns::HEADER, BlockId::Hash(hash))
|
||||
hash: Block::Hash,
|
||||
) -> Result<sp_state_machine::ChangesTrieAnchorBlockId<Block::Hash, NumberFor<Block>>, String> {
|
||||
utils::read_header::<Block>(
|
||||
&*self.db,
|
||||
columns::KEY_LOOKUP,
|
||||
columns::HEADER,
|
||||
BlockId::Hash(hash),
|
||||
)
|
||||
.map_err(|e| e.to_string())
|
||||
.and_then(|maybe_header| maybe_header.map(|header|
|
||||
sp_state_machine::ChangesTrieAnchorBlockId {
|
||||
@@ -762,12 +762,14 @@ where
|
||||
|
||||
fn root(
|
||||
&self,
|
||||
anchor: &sp_state_machine::ChangesTrieAnchorBlockId<H256, NumberFor<Block>>,
|
||||
anchor: &sp_state_machine::ChangesTrieAnchorBlockId<Block::Hash, NumberFor<Block>>,
|
||||
block: NumberFor<Block>,
|
||||
) -> Result<Option<H256>, String> {
|
||||
) -> Result<Option<Block::Hash>, String> {
|
||||
// check API requirement: we can't get NEXT block(s) based on anchor
|
||||
if block > anchor.number {
|
||||
return Err(format!("Can't get changes trie root at {} using anchor at {}", block, anchor.number));
|
||||
return Err(
|
||||
format!("Can't get changes trie root at {} using anchor at {}", block, anchor.number)
|
||||
)
|
||||
}
|
||||
|
||||
// we need to get hash of the block to resolve changes trie root
|
||||
@@ -801,33 +803,40 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
Ok(utils::require_header::<Block>(&*self.db, columns::KEY_LOOKUP, columns::HEADER, block_id)
|
||||
Ok(
|
||||
utils::require_header::<Block>(
|
||||
&*self.db,
|
||||
columns::KEY_LOOKUP,
|
||||
columns::HEADER,
|
||||
block_id,
|
||||
)
|
||||
.map_err(|e| e.to_string())?
|
||||
.digest().log(DigestItem::as_changes_trie_root)
|
||||
.map(|root| H256::from_slice(root.as_ref())))
|
||||
.digest()
|
||||
.log(DigestItem::as_changes_trie_root)
|
||||
.cloned()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block> sp_state_machine::ChangesTrieStorage<Blake2Hasher, NumberFor<Block>>
|
||||
impl<Block: BlockT> sp_state_machine::ChangesTrieStorage<HasherFor<Block>, NumberFor<Block>>
|
||||
for DbChangesTrieStorage<Block>
|
||||
where
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
fn as_roots_storage(&self) -> &dyn sp_state_machine::ChangesTrieRootsStorage<Blake2Hasher, NumberFor<Block>> {
|
||||
fn as_roots_storage(&self)
|
||||
-> &dyn sp_state_machine::ChangesTrieRootsStorage<HasherFor<Block>, NumberFor<Block>>
|
||||
{
|
||||
self
|
||||
}
|
||||
|
||||
fn with_cached_changed_keys(
|
||||
&self,
|
||||
root: &H256,
|
||||
root: &Block::Hash,
|
||||
functor: &mut dyn FnMut(&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>),
|
||||
) -> bool {
|
||||
self.cache.read().with_changed_keys(root, functor)
|
||||
}
|
||||
|
||||
fn get(&self, key: &H256, _prefix: Prefix) -> Result<Option<DBValue>, String> {
|
||||
self.db.get(columns::CHANGES_TRIE, &key[..])
|
||||
.map_err(|err| format!("{}", err))
|
||||
fn get(&self, key: &Block::Hash, _prefix: Prefix) -> Result<Option<DBValue>, String> {
|
||||
self.db.get(columns::CHANGES_TRIE, key.as_ref()).map_err(|err| format!("{}", err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -883,13 +892,13 @@ pub struct Backend<Block: BlockT> {
|
||||
changes_trie_config: Mutex<Option<Option<ChangesTrieConfiguration>>>,
|
||||
blockchain: BlockchainDb<Block>,
|
||||
canonicalization_delay: u64,
|
||||
shared_cache: SharedCache<Block, Blake2Hasher>,
|
||||
shared_cache: SharedCache<Block>,
|
||||
import_lock: RwLock<()>,
|
||||
is_archive: bool,
|
||||
io_stats: FrozenForDuration<kvdb::IoStats>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT<Hash=H256>> Backend<Block> {
|
||||
impl<Block: BlockT> Backend<Block> {
|
||||
/// Create a new instance of database backend.
|
||||
///
|
||||
/// The pruning window is how old a block must be before the state is pruned.
|
||||
@@ -915,13 +924,16 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
|
||||
fn from_kvdb(
|
||||
db: Arc<dyn KeyValueDB>,
|
||||
canonicalization_delay: u64,
|
||||
config: &DatabaseSettings
|
||||
config: &DatabaseSettings,
|
||||
) -> ClientResult<Self> {
|
||||
let is_archive_pruning = config.pruning.is_archive();
|
||||
let blockchain = BlockchainDb::new(db.clone())?;
|
||||
let meta = blockchain.meta.clone();
|
||||
let map_e = |e: sc_state_db::Error<io::Error>| ::sp_blockchain::Error::from(format!("State database error: {:?}", e));
|
||||
let state_db: StateDb<_, _> = StateDb::new(config.pruning.clone(), &StateMetaDb(&*db)).map_err(map_e)?;
|
||||
let map_e = |e: sc_state_db::Error<io::Error>| sp_blockchain::Error::from(
|
||||
format!("State database error: {:?}", e)
|
||||
);
|
||||
let state_db: StateDb<_, _> = StateDb::new(config.pruning.clone(), &StateMetaDb(&*db))
|
||||
.map_err(map_e)?;
|
||||
let storage_db = StorageDb {
|
||||
db: db.clone(),
|
||||
state_db,
|
||||
@@ -930,9 +942,12 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
|
||||
let changes_tries_storage = DbChangesTrieStorage {
|
||||
db,
|
||||
meta,
|
||||
min_blocks_to_keep: if is_archive_pruning { None } else { Some(MIN_BLOCKS_TO_KEEP_CHANGES_TRIES_FOR) },
|
||||
min_blocks_to_keep: if is_archive_pruning {
|
||||
None
|
||||
} else {
|
||||
Some(MIN_BLOCKS_TO_KEEP_CHANGES_TRIES_FOR)
|
||||
},
|
||||
cache: RwLock::new(ChangesTrieBuildCache::new()),
|
||||
_phantom: Default::default(),
|
||||
};
|
||||
|
||||
Ok(Backend {
|
||||
@@ -952,13 +967,13 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns in-memory blockchain that contains the same set of blocks that the self.
|
||||
/// Returns in-memory blockchain that contains the same set of blocks as self.
|
||||
#[cfg(feature = "test-helpers")]
|
||||
pub fn as_in_memory(&self) -> InMemoryBackend<Block, Blake2Hasher> {
|
||||
pub fn as_in_memory(&self) -> InMemoryBackend<Block> {
|
||||
use sc_client_api::backend::{Backend as ClientBackend, BlockImportOperation};
|
||||
use sc_client::blockchain::Backend as BlockchainBackend;
|
||||
|
||||
let inmem = InMemoryBackend::<Block, Blake2Hasher>::new();
|
||||
let inmem = InMemoryBackend::<Block>::new();
|
||||
|
||||
// get all headers hashes && sort them by number (could be duplicate)
|
||||
let mut headers: Vec<(NumberFor<Block>, Block::Hash, Block::Header)> = Vec::new();
|
||||
@@ -1174,7 +1189,7 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_commit_operation(&self, mut operation: BlockImportOperation<Block, Blake2Hasher>)
|
||||
fn try_commit_operation(&self, mut operation: BlockImportOperation<Block>)
|
||||
-> ClientResult<()>
|
||||
{
|
||||
let mut transaction = DBTransaction::new();
|
||||
@@ -1375,9 +1390,7 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
|
||||
f_header: &Block::Header,
|
||||
f_hash: Block::Hash,
|
||||
displaced: &mut Option<FinalizationDisplaced<Block::Hash, NumberFor<Block>>>
|
||||
) -> ClientResult<()> where
|
||||
Block: BlockT<Hash=H256>,
|
||||
{
|
||||
) -> ClientResult<()> {
|
||||
let f_num = f_header.number().clone();
|
||||
|
||||
if self.storage.state_db.best_canonical().map(|c| f_num.saturated_into::<u64>() > c).unwrap_or(true) {
|
||||
@@ -1421,7 +1434,7 @@ fn apply_state_commit(transaction: &mut DBTransaction, commit: sc_state_db::Comm
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block> sc_client_api::backend::AuxStore for Backend<Block> where Block: BlockT<Hash=H256> {
|
||||
impl<Block> sc_client_api::backend::AuxStore for Backend<Block> where Block: BlockT {
|
||||
fn insert_aux<
|
||||
'a,
|
||||
'b: 'a,
|
||||
@@ -1445,10 +1458,10 @@ impl<Block> sc_client_api::backend::AuxStore for Backend<Block> where Block: Blo
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block> sc_client_api::backend::Backend<Block, Blake2Hasher> for Backend<Block> where Block: BlockT<Hash=H256> {
|
||||
type BlockImportOperation = BlockImportOperation<Block, Blake2Hasher>;
|
||||
impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
|
||||
type BlockImportOperation = BlockImportOperation<Block>;
|
||||
type Blockchain = BlockchainDb<Block>;
|
||||
type State = CachingState<Blake2Hasher, RefTrackingState<Block>, Block>;
|
||||
type State = CachingState<RefTrackingState<Block>, Block>;
|
||||
type ChangesTrieStorage = DbChangesTrieStorage<Block>;
|
||||
type OffchainStorage = offchain::LocalStorage;
|
||||
|
||||
@@ -1634,9 +1647,9 @@ impl<Block> sc_client_api::backend::Backend<Block, Blake2Hasher> for Backend<Blo
|
||||
// special case for genesis initialization
|
||||
match block {
|
||||
BlockId::Hash(h) if h == Default::default() => {
|
||||
let genesis_storage = DbGenesisStorage::new();
|
||||
let genesis_storage = DbGenesisStorage::<Block>::new();
|
||||
let root = genesis_storage.0.clone();
|
||||
let db_state = DbState::new(Arc::new(genesis_storage), root);
|
||||
let db_state = DbState::<Block>::new(Arc::new(genesis_storage), root);
|
||||
let state = RefTrackingState::new(db_state, self.storage.clone(), None);
|
||||
return Ok(CachingState::new(state, self.shared_cache.clone(), None));
|
||||
},
|
||||
@@ -1647,18 +1660,34 @@ impl<Block> sc_client_api::backend::Backend<Block, Blake2Hasher> for Backend<Blo
|
||||
Ok(Some(ref hdr)) => {
|
||||
let hash = hdr.hash();
|
||||
if !self.have_state_at(&hash, *hdr.number()) {
|
||||
return Err(sp_blockchain::Error::UnknownBlock(format!("State already discarded for {:?}", block)))
|
||||
return Err(
|
||||
sp_blockchain::Error::UnknownBlock(
|
||||
format!("State already discarded for {:?}", block)
|
||||
)
|
||||
)
|
||||
}
|
||||
if let Ok(()) = self.storage.state_db.pin(&hash) {
|
||||
let root = H256::from_slice(hdr.state_root().as_ref());
|
||||
let db_state = DbState::new(self.storage.clone(), root);
|
||||
let state = RefTrackingState::new(db_state, self.storage.clone(), Some(hash.clone()));
|
||||
let root = hdr.state_root();
|
||||
let db_state = DbState::<Block>::new(self.storage.clone(), *root);
|
||||
let state = RefTrackingState::new(
|
||||
db_state,
|
||||
self.storage.clone(),
|
||||
Some(hash.clone()),
|
||||
);
|
||||
Ok(CachingState::new(state, self.shared_cache.clone(), Some(hash)))
|
||||
} else {
|
||||
Err(sp_blockchain::Error::UnknownBlock(format!("State already discarded for {:?}", block)))
|
||||
Err(
|
||||
sp_blockchain::Error::UnknownBlock(
|
||||
format!("State already discarded for {:?}", block)
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
Ok(None) => Err(sp_blockchain::Error::UnknownBlock(format!("Unknown state for block {:?}", block))),
|
||||
Ok(None) => Err(
|
||||
sp_blockchain::Error::UnknownBlock(
|
||||
format!("Unknown state for block {:?}", block)
|
||||
)
|
||||
),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
@@ -1667,7 +1696,11 @@ impl<Block> sc_client_api::backend::Backend<Block, Blake2Hasher> for Backend<Blo
|
||||
if self.is_archive {
|
||||
match self.blockchain.header(BlockId::Hash(hash.clone())) {
|
||||
Ok(Some(header)) => {
|
||||
sp_state_machine::Storage::get(self.storage.as_ref(), &header.state_root(), (&[], None)).unwrap_or(None).is_some()
|
||||
sp_state_machine::Storage::get(
|
||||
self.storage.as_ref(),
|
||||
&header.state_root(),
|
||||
(&[], None),
|
||||
).unwrap_or(None).is_some()
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
@@ -1689,8 +1722,7 @@ impl<Block> sc_client_api::backend::Backend<Block, Blake2Hasher> for Backend<Blo
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block> sc_client_api::backend::LocalBackend<Block, Blake2Hasher> for Backend<Block>
|
||||
where Block: BlockT<Hash=H256> {}
|
||||
impl<Block: BlockT> sc_client_api::backend::LocalBackend<Block> for Backend<Block> {}
|
||||
|
||||
/// TODO: remove me in #3201
|
||||
pub fn unused_sink<Block: BlockT>(cache_tx: crate::cache::DbCacheTransaction<Block>) {
|
||||
@@ -1703,6 +1735,7 @@ mod tests {
|
||||
use hash_db::{HashDB, EMPTY_PREFIX};
|
||||
use super::*;
|
||||
use crate::columns;
|
||||
use sp_core::{Blake2Hasher, H256};
|
||||
use sc_client_api::backend::{Backend as BTrait, BlockImportOperation as Op};
|
||||
use sc_client::blockchain::Backend as BLBTrait;
|
||||
use sp_runtime::testing::{Header, Block as RawBlock, ExtrinsicWrapper};
|
||||
|
||||
@@ -35,9 +35,8 @@ use sp_blockchain::{
|
||||
};
|
||||
use sc_client::light::blockchain::Storage as LightBlockchainStorage;
|
||||
use codec::{Decode, Encode};
|
||||
use sp_core::Blake2Hasher;
|
||||
use sp_runtime::generic::{DigestItem, BlockId};
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Zero, One, NumberFor};
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Zero, One, NumberFor, HasherFor};
|
||||
use crate::cache::{DbCacheSync, DbCache, ComplexBlockId, EntryType as CacheEntryType};
|
||||
use crate::utils::{self, meta_keys, Meta, db_err, read_db, block_id_to_lookup_key, read_meta};
|
||||
use crate::{DatabaseSettings, FrozenForDuration};
|
||||
@@ -306,7 +305,7 @@ impl<Block: BlockT> LightStorage<Block> {
|
||||
Some(old_current_num)
|
||||
});
|
||||
|
||||
let new_header_cht_root = cht::compute_root::<Block::Header, Blake2Hasher, _>(
|
||||
let new_header_cht_root = cht::compute_root::<Block::Header, HasherFor<Block>, _>(
|
||||
cht::size(), new_cht_number, cht_range.map(|num| self.hash(num))
|
||||
)?;
|
||||
transaction.put(
|
||||
@@ -323,7 +322,7 @@ impl<Block: BlockT> LightStorage<Block> {
|
||||
current_num = current_num + One::one();
|
||||
Some(old_current_num)
|
||||
});
|
||||
let new_changes_trie_cht_root = cht::compute_root::<Block::Header, Blake2Hasher, _>(
|
||||
let new_changes_trie_cht_root = cht::compute_root::<Block::Header, HasherFor<Block>, _>(
|
||||
cht::size(), new_cht_number, cht_range
|
||||
.map(|num| self.changes_trie_root(BlockId::Number(num)))
|
||||
)?;
|
||||
|
||||
@@ -21,7 +21,7 @@ use std::sync::Arc;
|
||||
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
|
||||
use linked_hash_map::{LinkedHashMap, Entry};
|
||||
use hash_db::Hasher;
|
||||
use sp_runtime::traits::{Block as BlockT, Header};
|
||||
use sp_runtime::traits::{Block as BlockT, Header, HasherFor, NumberFor};
|
||||
use sp_core::hexdisplay::HexDisplay;
|
||||
use sp_core::storage::ChildInfo;
|
||||
use sp_state_machine::{backend::Backend as StateBackend, TrieBackend};
|
||||
@@ -36,11 +36,11 @@ type ChildStorageKey = (Vec<u8>, Vec<u8>);
|
||||
type StorageValue = Vec<u8>;
|
||||
|
||||
/// Shared canonical state cache.
|
||||
pub struct Cache<B: BlockT, H: Hasher> {
|
||||
pub struct Cache<B: BlockT> {
|
||||
/// Storage cache. `None` indicates that key is known to be missing.
|
||||
lru_storage: LRUMap<StorageKey, Option<StorageValue>>,
|
||||
/// Storage hashes cache. `None` indicates that key is known to be missing.
|
||||
lru_hashes: LRUMap<StorageKey, OptionHOut<H::Out>>,
|
||||
lru_hashes: LRUMap<StorageKey, OptionHOut<B::Hash>>,
|
||||
/// Storage cache for child trie. `None` indicates that key is known to be missing.
|
||||
lru_child_storage: LRUMap<ChildStorageKey, Option<StorageValue>>,
|
||||
/// Information on the modifications in recently committed blocks; specifically which keys
|
||||
@@ -147,7 +147,7 @@ impl<K: EstimateSize + Eq + StdHash, V: EstimateSize> LRUMap<K, V> {
|
||||
|
||||
}
|
||||
|
||||
impl<B: BlockT, H: Hasher> Cache<B, H> {
|
||||
impl<B: BlockT> Cache<B> {
|
||||
/// Returns the used memory size of the storage cache in bytes.
|
||||
pub fn used_storage_cache_size(&self) -> usize {
|
||||
self.lru_storage.used_size()
|
||||
@@ -215,25 +215,31 @@ impl<B: BlockT, H: Hasher> Cache<B, H> {
|
||||
}
|
||||
}
|
||||
|
||||
pub type SharedCache<B, H> = Arc<Mutex<Cache<B, H>>>;
|
||||
pub type SharedCache<B> = Arc<Mutex<Cache<B>>>;
|
||||
|
||||
/// Fix lru storage size for hash (small 64ko).
|
||||
const FIX_LRU_HASH_SIZE: usize = 65_536;
|
||||
|
||||
/// Create a new shared cache instance with given max memory usage.
|
||||
pub fn new_shared_cache<B: BlockT, H: Hasher>(
|
||||
pub fn new_shared_cache<B: BlockT>(
|
||||
shared_cache_size: usize,
|
||||
child_ratio: (usize, usize),
|
||||
) -> SharedCache<B, H> {
|
||||
) -> SharedCache<B> {
|
||||
let top = child_ratio.1.saturating_sub(child_ratio.0);
|
||||
Arc::new(Mutex::new(Cache {
|
||||
lru_storage: LRUMap(LinkedHashMap::new(), 0,
|
||||
shared_cache_size * top / child_ratio.1),
|
||||
lru_hashes: LRUMap(LinkedHashMap::new(), 0, FIX_LRU_HASH_SIZE),
|
||||
lru_child_storage: LRUMap(LinkedHashMap::new(), 0,
|
||||
shared_cache_size * child_ratio.0 / child_ratio.1),
|
||||
modifications: VecDeque::new(),
|
||||
}))
|
||||
Arc::new(
|
||||
Mutex::new(
|
||||
Cache {
|
||||
lru_storage: LRUMap(
|
||||
LinkedHashMap::new(), 0, shared_cache_size * top / child_ratio.1
|
||||
),
|
||||
lru_hashes: LRUMap(LinkedHashMap::new(), 0, FIX_LRU_HASH_SIZE),
|
||||
lru_child_storage: LRUMap(
|
||||
LinkedHashMap::new(), 0, shared_cache_size * child_ratio.0 / child_ratio.1
|
||||
),
|
||||
modifications: VecDeque::new(),
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -270,11 +276,11 @@ struct LocalCache<H: Hasher> {
|
||||
}
|
||||
|
||||
/// Cache changes.
|
||||
pub struct CacheChanges<H: Hasher, B: BlockT> {
|
||||
pub struct CacheChanges<B: BlockT> {
|
||||
/// Shared canonical state cache.
|
||||
shared_cache: SharedCache<B, H>,
|
||||
shared_cache: SharedCache<B>,
|
||||
/// Local cache of values for this state.
|
||||
local_cache: RwLock<LocalCache<H>>,
|
||||
local_cache: RwLock<LocalCache<HasherFor<B>>>,
|
||||
/// Hash of the block on top of which this instance was created or
|
||||
/// `None` if cache is disabled
|
||||
pub parent_hash: Option<B::Hash>,
|
||||
@@ -289,20 +295,20 @@ pub struct CacheChanges<H: Hasher, B: BlockT> {
|
||||
/// For canonical instances local cache is accumulated and applied
|
||||
/// in `sync_cache` along with the change overlay.
|
||||
/// For non-canonical clones local cache and changes are dropped.
|
||||
pub struct CachingState<H: Hasher, S: StateBackend<H>, B: BlockT> {
|
||||
pub struct CachingState<S: StateBackend<HasherFor<B>>, B: BlockT> {
|
||||
/// Backing state.
|
||||
state: S,
|
||||
/// Cache data.
|
||||
pub cache: CacheChanges<H, B>
|
||||
pub cache: CacheChanges<B>,
|
||||
}
|
||||
|
||||
impl<H: Hasher, S: StateBackend<H>, B: BlockT> std::fmt::Debug for CachingState<H, S, B> {
|
||||
impl<S: StateBackend<HasherFor<B>>, B: BlockT> std::fmt::Debug for CachingState<S, B> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Block {:?}", self.cache.parent_hash)
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: Hasher, B: BlockT> CacheChanges<H, B> {
|
||||
impl<B: BlockT> CacheChanges<B> {
|
||||
/// Propagate local cache into the shared cache and synchronize
|
||||
/// the shared cache with the best block state.
|
||||
///
|
||||
@@ -317,11 +323,17 @@ impl<H: Hasher, B: BlockT> CacheChanges<H, B> {
|
||||
changes: StorageCollection,
|
||||
child_changes: ChildStorageCollection,
|
||||
commit_hash: Option<B::Hash>,
|
||||
commit_number: Option<<B::Header as Header>::Number>,
|
||||
commit_number: Option<NumberFor<B>>,
|
||||
is_best: bool,
|
||||
) {
|
||||
let mut cache = self.shared_cache.lock();
|
||||
trace!("Syncing cache, id = (#{:?}, {:?}), parent={:?}, best={}", commit_number, commit_hash, self.parent_hash, is_best);
|
||||
trace!(
|
||||
"Syncing cache, id = (#{:?}, {:?}), parent={:?}, best={}",
|
||||
commit_number,
|
||||
commit_hash,
|
||||
self.parent_hash,
|
||||
is_best,
|
||||
);
|
||||
let cache = &mut *cache;
|
||||
// Filter out commiting block if any.
|
||||
let enacted: Vec<_> = enacted
|
||||
@@ -405,9 +417,9 @@ impl<H: Hasher, B: BlockT> CacheChanges<H, B> {
|
||||
|
||||
}
|
||||
|
||||
impl<H: Hasher, S: StateBackend<H>, B: BlockT> CachingState<H, S, B> {
|
||||
impl<S: StateBackend<HasherFor<B>>, B: BlockT> CachingState<S, B> {
|
||||
/// Create a new instance wrapping generic State and shared cache.
|
||||
pub fn new(state: S, shared_cache: SharedCache<B, H>, parent_hash: Option<B::Hash>) -> CachingState<H, S, B> {
|
||||
pub fn new(state: S, shared_cache: SharedCache<B>, parent_hash: Option<B::Hash>) -> Self {
|
||||
CachingState {
|
||||
state,
|
||||
cache: CacheChanges {
|
||||
@@ -468,12 +480,12 @@ impl<H: Hasher, S: StateBackend<H>, B: BlockT> CachingState<H, S, B> {
|
||||
}
|
||||
|
||||
/// Dispose state and return cache data.
|
||||
pub fn release(self) -> CacheChanges<H, B> {
|
||||
pub fn release(self) -> CacheChanges<B> {
|
||||
self.cache
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: Hasher, S: StateBackend<H>, B: BlockT> StateBackend<H> for CachingState<H, S, B> {
|
||||
impl<S: StateBackend<HasherFor<B>>, B: BlockT> StateBackend<HasherFor<B>> for CachingState<S, B> {
|
||||
type Error = S::Error;
|
||||
type Transaction = S::Transaction;
|
||||
type TrieBackendStorage = S::TrieBackendStorage;
|
||||
@@ -498,7 +510,7 @@ impl<H: Hasher, S: StateBackend<H>, B: BlockT> StateBackend<H> for CachingState<
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn storage_hash(&self, key: &[u8]) -> Result<Option<H::Out>, Self::Error> {
|
||||
fn storage_hash(&self, key: &[u8]) -> Result<Option<B::Hash>, Self::Error> {
|
||||
let local_cache = self.cache.local_cache.upgradable_read();
|
||||
if let Some(entry) = local_cache.hashes.get(key).cloned() {
|
||||
trace!("Found hash in local cache: {:?}", HexDisplay::from(&key));
|
||||
@@ -595,10 +607,9 @@ impl<H: Hasher, S: StateBackend<H>, B: BlockT> StateBackend<H> for CachingState<
|
||||
self.state.for_child_keys_with_prefix(storage_key, child_info, prefix, f)
|
||||
}
|
||||
|
||||
fn storage_root<I>(&self, delta: I) -> (H::Out, Self::Transaction)
|
||||
fn storage_root<I>(&self, delta: I) -> (B::Hash, Self::Transaction)
|
||||
where
|
||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
||||
H::Out: Ord
|
||||
{
|
||||
self.state.storage_root(delta)
|
||||
}
|
||||
@@ -608,10 +619,9 @@ impl<H: Hasher, S: StateBackend<H>, B: BlockT> StateBackend<H> for CachingState<
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
delta: I,
|
||||
) -> (H::Out, bool, Self::Transaction)
|
||||
) -> (B::Hash, bool, Self::Transaction)
|
||||
where
|
||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
||||
H::Out: Ord
|
||||
{
|
||||
self.state.child_storage_root(storage_key, child_info, delta)
|
||||
}
|
||||
@@ -633,7 +643,7 @@ impl<H: Hasher, S: StateBackend<H>, B: BlockT> StateBackend<H> for CachingState<
|
||||
self.state.child_keys(storage_key, child_info, prefix)
|
||||
}
|
||||
|
||||
fn as_trie_backend(&mut self) -> Option<&TrieBackend<Self::TrieBackendStorage, H>> {
|
||||
fn as_trie_backend(&mut self) -> Option<&TrieBackend<Self::TrieBackendStorage, HasherFor<B>>> {
|
||||
self.state.as_trie_backend()
|
||||
}
|
||||
}
|
||||
@@ -642,7 +652,7 @@ impl<H: Hasher, S: StateBackend<H>, B: BlockT> StateBackend<H> for CachingState<
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sp_runtime::testing::{H256, Block as RawBlock, ExtrinsicWrapper};
|
||||
use sp_state_machine::backend::InMemory;
|
||||
use sp_state_machine::InMemoryBackend;
|
||||
use sp_core::Blake2Hasher;
|
||||
|
||||
type Block = RawBlock<ExtrinsicWrapper<u32>>;
|
||||
@@ -660,43 +670,119 @@ mod tests {
|
||||
let h3a = H256::random();
|
||||
let h3b = H256::random();
|
||||
|
||||
let shared = new_shared_cache::<Block, Blake2Hasher>(256*1024, (0,1));
|
||||
let shared = new_shared_cache::<Block>(256 * 1024, (0, 1));
|
||||
|
||||
// blocks [ 3a(c) 2a(c) 2b 1b 1a(c) 0 ]
|
||||
// state [ 5 5 4 3 2 2 ]
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(root_parent));
|
||||
s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![2]))], vec![], Some(h0), Some(0), true);
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(root_parent),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[],
|
||||
&[],
|
||||
vec![(key.clone(), Some(vec![2]))],
|
||||
vec![],
|
||||
Some(h0),
|
||||
Some(0),
|
||||
true,
|
||||
);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h0));
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h0),
|
||||
);
|
||||
s.cache.sync_cache(&[], &[], vec![], vec![], Some(h1a), Some(1), true);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h0));
|
||||
s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![3]))], vec![], Some(h1b), Some(1), false);
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h0),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[],
|
||||
&[],
|
||||
vec![(key.clone(), Some(vec![3]))],
|
||||
vec![],
|
||||
Some(h1b),
|
||||
Some(1),
|
||||
false,
|
||||
);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h1b.clone()));
|
||||
s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![4]))], vec![], Some(h2b), Some(2), false);
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h1b),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[],
|
||||
&[],
|
||||
vec![(key.clone(), Some(vec![4]))],
|
||||
vec![],
|
||||
Some(h2b),
|
||||
Some(2),
|
||||
false,
|
||||
);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h1a.clone()));
|
||||
s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![5]))], vec![], Some(h2a), Some(2), true);
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h1a),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[],
|
||||
&[],
|
||||
vec![(key.clone(), Some(vec![5]))],
|
||||
vec![],
|
||||
Some(h2a),
|
||||
Some(2),
|
||||
true,
|
||||
);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h2a));
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h2a),
|
||||
);
|
||||
s.cache.sync_cache(&[], &[], vec![], vec![], Some(h3a), Some(3), true);
|
||||
|
||||
let s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h3a));
|
||||
let s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h3a),
|
||||
);
|
||||
assert_eq!(s.storage(&key).unwrap().unwrap(), vec![5]);
|
||||
|
||||
let s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h1a));
|
||||
let s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h1a),
|
||||
);
|
||||
assert!(s.storage(&key).unwrap().is_none());
|
||||
|
||||
let s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h2b));
|
||||
let s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h2b),
|
||||
);
|
||||
assert!(s.storage(&key).unwrap().is_none());
|
||||
|
||||
let s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h1b));
|
||||
let s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h1b),
|
||||
);
|
||||
assert!(s.storage(&key).unwrap().is_none());
|
||||
|
||||
// reorg to 3b
|
||||
// blocks [ 3b(c) 3a 2a 2b(c) 1b 1a 0 ]
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h2b));
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h2b),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[h1b, h2b, h3b],
|
||||
&[h1a, h2a, h3a],
|
||||
@@ -706,7 +792,11 @@ mod tests {
|
||||
Some(3),
|
||||
true,
|
||||
);
|
||||
let s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h3a));
|
||||
let s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h3a),
|
||||
);
|
||||
assert!(s.storage(&key).unwrap().is_none());
|
||||
}
|
||||
|
||||
@@ -721,21 +811,65 @@ mod tests {
|
||||
let h2b = H256::random();
|
||||
let h3b = H256::random();
|
||||
|
||||
let shared = new_shared_cache::<Block, Blake2Hasher>(256*1024, (0,1));
|
||||
let shared = new_shared_cache::<Block>(256*1024, (0,1));
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(root_parent));
|
||||
s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![2]))], vec![], Some(h1), Some(1), true);
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(root_parent),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[],
|
||||
&[],
|
||||
vec![(key.clone(), Some(vec![2]))],
|
||||
vec![],
|
||||
Some(h1),
|
||||
Some(1),
|
||||
true,
|
||||
);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h1));
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h1),
|
||||
);
|
||||
s.cache.sync_cache(&[], &[], vec![], vec![], Some(h2a), Some(2), true);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h1));
|
||||
s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![3]))], vec![], Some(h2b), Some(2), false);
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h1),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[],
|
||||
&[],
|
||||
vec![(key.clone(), Some(vec![3]))],
|
||||
vec![],
|
||||
Some(h2b),
|
||||
Some(2),
|
||||
false,
|
||||
);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h2b));
|
||||
s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![3]))], vec![], Some(h3b), Some(2), false);
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h2b),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[],
|
||||
&[],
|
||||
vec![(key.clone(), Some(vec![3]))],
|
||||
vec![],
|
||||
Some(h3b),
|
||||
Some(2),
|
||||
false,
|
||||
);
|
||||
|
||||
let s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h2a));
|
||||
let s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h2a),
|
||||
);
|
||||
assert_eq!(s.storage(&key).unwrap().unwrap(), vec![2]);
|
||||
}
|
||||
|
||||
@@ -749,34 +883,76 @@ mod tests {
|
||||
let h3a = H256::random();
|
||||
let h3b = H256::random();
|
||||
|
||||
let shared = new_shared_cache::<Block, Blake2Hasher>(256*1024, (0,1));
|
||||
let shared = new_shared_cache::<Block>(256*1024, (0,1));
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(root_parent));
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(root_parent),
|
||||
);
|
||||
s.cache.sync_cache(&[], &[], vec![], vec![], Some(h1), Some(1), true);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h1));
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h1),
|
||||
);
|
||||
s.cache.sync_cache(&[], &[], vec![], vec![], Some(h2a), Some(2), true);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h2a));
|
||||
s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![2]))], vec![], Some(h3a), Some(3), true);
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h2a),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[],
|
||||
&[],
|
||||
vec![(key.clone(), Some(vec![2]))],
|
||||
vec![],
|
||||
Some(h3a),
|
||||
Some(3),
|
||||
true,
|
||||
);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h1));
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h1),
|
||||
);
|
||||
s.cache.sync_cache(&[], &[], vec![], vec![], Some(h2b), Some(2), false);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h2b));
|
||||
s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![3]))], vec![], Some(h3b), Some(3), false);
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h2b),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[],
|
||||
&[],
|
||||
vec![(key.clone(), Some(vec![3]))],
|
||||
vec![],
|
||||
Some(h3b),
|
||||
Some(3),
|
||||
false,
|
||||
);
|
||||
|
||||
let s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h3a));
|
||||
let s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h3a),
|
||||
);
|
||||
assert_eq!(s.storage(&key).unwrap().unwrap(), vec![2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_track_used_size_correctly() {
|
||||
let root_parent = H256::random();
|
||||
let shared = new_shared_cache::<Block, Blake2Hasher>(109, ((109-36), 109));
|
||||
let shared = new_shared_cache::<Block>(109, ((109-36), 109));
|
||||
let h0 = H256::random();
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(root_parent));
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(), shared.clone(), Some(root_parent.clone()),
|
||||
);
|
||||
|
||||
let key = H256::random()[..].to_vec();
|
||||
let s_key = H256::random()[..].to_vec();
|
||||
@@ -809,10 +985,14 @@ mod tests {
|
||||
#[test]
|
||||
fn should_remove_lru_items_based_on_tracking_used_size() {
|
||||
let root_parent = H256::random();
|
||||
let shared = new_shared_cache::<Block, Blake2Hasher>(36*3, (2,3));
|
||||
let shared = new_shared_cache::<Block>(36*3, (2,3));
|
||||
let h0 = H256::random();
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(root_parent));
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(root_parent),
|
||||
);
|
||||
|
||||
let key = H256::random()[..].to_vec();
|
||||
s.cache.sync_cache(
|
||||
@@ -851,14 +1031,42 @@ mod tests {
|
||||
let h0 = H256::random();
|
||||
let h1 = H256::random();
|
||||
|
||||
let shared = new_shared_cache::<Block, Blake2Hasher>(256*1024, (0, 1));
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(root_parent));
|
||||
s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![2]))], vec![], Some(h0), Some(0), true);
|
||||
let shared = new_shared_cache::<Block>(256 * 1024, (0, 1));
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(root_parent.clone()),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[],
|
||||
&[],
|
||||
vec![(key.clone(), Some(vec![2]))],
|
||||
vec![],
|
||||
Some(h0.clone()),
|
||||
Some(0),
|
||||
true,
|
||||
);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h0));
|
||||
s.cache.sync_cache(&[], &[], vec![(key.clone(), Some(vec![3]))], vec![], Some(h1), Some(1), true);
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h0),
|
||||
);
|
||||
s.cache.sync_cache(
|
||||
&[],
|
||||
&[],
|
||||
vec![(key.clone(), Some(vec![3]))],
|
||||
vec![],
|
||||
Some(h1),
|
||||
Some(1),
|
||||
true,
|
||||
);
|
||||
|
||||
let mut s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h1));
|
||||
let mut s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h1),
|
||||
);
|
||||
assert_eq!(s.storage(&key).unwrap(), Some(vec![3]));
|
||||
|
||||
// Restart (or unknown block?), clear caches.
|
||||
@@ -877,7 +1085,11 @@ mod tests {
|
||||
// New value is propagated.
|
||||
s.cache.sync_cache(&[], &[], vec![], vec![], None, None, true);
|
||||
|
||||
let s = CachingState::new(InMemory::<Blake2Hasher>::default(), shared.clone(), Some(h1));
|
||||
let s = CachingState::new(
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
shared.clone(),
|
||||
Some(h1),
|
||||
);
|
||||
assert_eq!(s.storage(&key).unwrap(), None);
|
||||
}
|
||||
}
|
||||
@@ -890,7 +1102,7 @@ mod qc {
|
||||
|
||||
use super::*;
|
||||
use sp_runtime::testing::{H256, Block as RawBlock, ExtrinsicWrapper};
|
||||
use sp_state_machine::backend::InMemory;
|
||||
use sp_state_machine::InMemoryBackend;
|
||||
use sp_core::Blake2Hasher;
|
||||
|
||||
type Block = RawBlock<ExtrinsicWrapper<u32>>;
|
||||
@@ -1002,14 +1214,14 @@ mod qc {
|
||||
}
|
||||
|
||||
struct Mutator {
|
||||
shared: SharedCache<Block, Blake2Hasher>,
|
||||
shared: SharedCache<Block>,
|
||||
canon: Vec<Node>,
|
||||
forks: HashMap<H256, Vec<Node>>,
|
||||
}
|
||||
|
||||
impl Mutator {
|
||||
fn new_empty() -> Self {
|
||||
let shared = new_shared_cache::<Block, Blake2Hasher>(256*1024, (0,1));
|
||||
let shared = new_shared_cache::<Block>(256*1024, (0,1));
|
||||
|
||||
Self {
|
||||
shared,
|
||||
@@ -1018,19 +1230,22 @@ mod qc {
|
||||
}
|
||||
}
|
||||
|
||||
fn head_state(&self, hash: H256) -> CachingState<Blake2Hasher, InMemory<Blake2Hasher>, Block> {
|
||||
fn head_state(&self, hash: H256) -> CachingState<InMemoryBackend<Blake2Hasher>, Block> {
|
||||
CachingState::new(
|
||||
InMemory::<Blake2Hasher>::default(),
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
self.shared.clone(),
|
||||
Some(hash)
|
||||
)
|
||||
}
|
||||
|
||||
fn canon_head_state(&self) -> CachingState<Blake2Hasher, InMemory<Blake2Hasher>, Block> {
|
||||
fn canon_head_state(&self) -> CachingState<InMemoryBackend<Blake2Hasher>, Block> {
|
||||
self.head_state(self.canon.last().expect("Expected to be one commit").hash)
|
||||
}
|
||||
|
||||
fn mutate_static(&mut self, action: Action) -> CachingState<Blake2Hasher, InMemory<Blake2Hasher>, Block> {
|
||||
fn mutate_static(
|
||||
&mut self,
|
||||
action: Action,
|
||||
) -> CachingState<InMemoryBackend<Blake2Hasher>, Block> {
|
||||
self.mutate(action).expect("Expected to provide only valid actions to the mutate_static")
|
||||
}
|
||||
|
||||
@@ -1046,7 +1261,10 @@ mod qc {
|
||||
(0u8..255).map(|x| vec![x]).collect()
|
||||
}
|
||||
|
||||
fn mutate(&mut self, action: Action) -> Result<CachingState<Blake2Hasher, InMemory<Blake2Hasher>, Block>, ()> {
|
||||
fn mutate(
|
||||
&mut self,
|
||||
action: Action,
|
||||
) -> Result<CachingState<InMemoryBackend<Blake2Hasher>, Block>, ()> {
|
||||
let state = match action {
|
||||
Action::Fork { depth, hash, changes } => {
|
||||
let pos = self.canon.len() as isize - depth as isize;
|
||||
@@ -1083,7 +1301,7 @@ mod qc {
|
||||
};
|
||||
|
||||
let mut state = CachingState::new(
|
||||
InMemory::<Blake2Hasher>::default(),
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
self.shared.clone(),
|
||||
Some(parent)
|
||||
);
|
||||
@@ -1122,7 +1340,7 @@ mod qc {
|
||||
}
|
||||
|
||||
let mut state = CachingState::new(
|
||||
InMemory::<Blake2Hasher>::default(),
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
self.shared.clone(),
|
||||
Some(parent_hash)
|
||||
);
|
||||
@@ -1169,7 +1387,7 @@ mod qc {
|
||||
self.canon.push(node);
|
||||
|
||||
let mut state = CachingState::new(
|
||||
InMemory::<Blake2Hasher>::default(),
|
||||
InMemoryBackend::<Blake2Hasher>::default(),
|
||||
self.shared.clone(),
|
||||
Some(fork_at)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user