mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 12:48:00 +00:00
Run cargo fmt on the whole code base (#9394)
* Run cargo fmt on the whole code base * Second run * Add CI check * Fix compilation * More unnecessary braces * Handle weights * Use --all * Use correct attributes... * Fix UI tests * AHHHHHHHHH * 🤦 * Docs * Fix compilation * 🤷 * Please stop * 🤦 x 2 * More * make rustfmt.toml consistent with polkadot Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
@@ -18,30 +18,32 @@
|
||||
|
||||
//! Substrate Client data backend
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use sp_core::ChangesTrieConfigurationRange;
|
||||
use sp_core::offchain::OffchainStorage;
|
||||
use sp_runtime::{generic::BlockId, Justification, Justifications, Storage};
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor, HashFor};
|
||||
use sp_state_machine::{
|
||||
ChangesTrieState, ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction,
|
||||
StorageCollection, ChildStorageCollection, OffchainChangesCollection, IndexOperation,
|
||||
};
|
||||
use sp_storage::{StorageData, StorageKey, PrefixedStorageKey, ChildInfo};
|
||||
use crate::{
|
||||
blockchain::{
|
||||
Backend as BlockchainBackend, well_known_cache_keys
|
||||
},
|
||||
blockchain::{well_known_cache_keys, Backend as BlockchainBackend},
|
||||
light::RemoteBlockchain,
|
||||
UsageInfo,
|
||||
};
|
||||
use parking_lot::RwLock;
|
||||
use sp_blockchain;
|
||||
use sp_consensus::BlockOrigin;
|
||||
use parking_lot::RwLock;
|
||||
use sp_core::{offchain::OffchainStorage, ChangesTrieConfigurationRange};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, HashFor, NumberFor},
|
||||
Justification, Justifications, Storage,
|
||||
};
|
||||
use sp_state_machine::{
|
||||
ChangesTrieState, ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction,
|
||||
ChildStorageCollection, IndexOperation, OffchainChangesCollection, StorageCollection,
|
||||
};
|
||||
use sp_storage::{ChildInfo, PrefixedStorageKey, StorageData, StorageKey};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
pub use sp_state_machine::Backend as StateBackend;
|
||||
pub use sp_consensus::ImportedState;
|
||||
pub use sp_state_machine::Backend as StateBackend;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// Extracts the state backend type for the given backend.
|
||||
@@ -90,16 +92,17 @@ pub fn apply_aux<'a, 'b: 'a, 'c: 'a, B, Block, D, I>(
|
||||
insert: I,
|
||||
delete: D,
|
||||
) -> sp_blockchain::Result<()>
|
||||
where
|
||||
Block: BlockT,
|
||||
B: Backend<Block>,
|
||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
||||
where
|
||||
Block: BlockT,
|
||||
B: Backend<Block>,
|
||||
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||
{
|
||||
operation.op.insert_aux(
|
||||
insert.into_iter()
|
||||
insert
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.to_vec(), Some(v.to_vec())))
|
||||
.chain(delete.into_iter().map(|k| (k.to_vec(), None)))
|
||||
.chain(delete.into_iter().map(|k| (k.to_vec(), None))),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -165,7 +168,11 @@ pub trait BlockImportOperation<Block: BlockT> {
|
||||
|
||||
/// Set genesis state. If `commit` is `false` the state is saved in memory, but is not written
|
||||
/// to the database.
|
||||
fn set_genesis_state(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash>;
|
||||
fn set_genesis_state(
|
||||
&mut self,
|
||||
storage: Storage,
|
||||
commit: bool,
|
||||
) -> sp_blockchain::Result<Block::Hash>;
|
||||
|
||||
/// Inject storage data into the database replacing any existing data.
|
||||
fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<Block::Hash>;
|
||||
@@ -182,7 +189,7 @@ pub trait BlockImportOperation<Block: BlockT> {
|
||||
&mut self,
|
||||
_offchain_update: OffchainChangesCollection,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inject changes trie data into the database.
|
||||
@@ -195,7 +202,8 @@ pub trait BlockImportOperation<Block: BlockT> {
|
||||
///
|
||||
/// Values are `None` if should be deleted.
|
||||
fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()>
|
||||
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>;
|
||||
where
|
||||
I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>)>;
|
||||
|
||||
/// Mark a block as finalized.
|
||||
fn mark_finalized(
|
||||
@@ -209,16 +217,17 @@ pub trait BlockImportOperation<Block: BlockT> {
|
||||
fn mark_head(&mut self, id: BlockId<Block>) -> sp_blockchain::Result<()>;
|
||||
|
||||
/// Add a transaction index operation.
|
||||
fn update_transaction_index(&mut self, index: Vec<IndexOperation>) -> sp_blockchain::Result<()>;
|
||||
fn update_transaction_index(&mut self, index: Vec<IndexOperation>)
|
||||
-> sp_blockchain::Result<()>;
|
||||
}
|
||||
|
||||
/// Interface for performing operations on the backend.
|
||||
pub trait LockImportRun<Block: BlockT, B: Backend<Block>> {
|
||||
/// Lock the import lock, and run operations inside.
|
||||
fn lock_import_and_run<R, Err, F>(&self, f: F) -> Result<R, Err>
|
||||
where
|
||||
F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>,
|
||||
Err: From<sp_blockchain::Error>;
|
||||
where
|
||||
F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>,
|
||||
Err: From<sp_blockchain::Error>;
|
||||
}
|
||||
|
||||
/// Finalize Facilities
|
||||
@@ -270,9 +279,13 @@ pub trait AuxStore {
|
||||
'a,
|
||||
'b: 'a,
|
||||
'c: 'a,
|
||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()>;
|
||||
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||
>(
|
||||
&self,
|
||||
insert: I,
|
||||
delete: D,
|
||||
) -> sp_blockchain::Result<()>;
|
||||
|
||||
/// Query auxiliary data from key-value store.
|
||||
fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>>;
|
||||
@@ -287,16 +300,10 @@ pub struct KeyIterator<'a, State, Block> {
|
||||
_phantom: PhantomData<Block>,
|
||||
}
|
||||
|
||||
impl <'a, State, Block> KeyIterator<'a, State, Block> {
|
||||
impl<'a, State, Block> KeyIterator<'a, State, Block> {
|
||||
/// create a KeyIterator instance
|
||||
pub fn new(state: State, prefix: Option<&'a StorageKey>, current_key: Vec<u8>) -> Self {
|
||||
Self {
|
||||
state,
|
||||
child_storage: None,
|
||||
prefix,
|
||||
current_key,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
Self { state, child_storage: None, prefix, current_key, _phantom: PhantomData }
|
||||
}
|
||||
|
||||
/// Create a `KeyIterator` instance for a child storage.
|
||||
@@ -306,17 +313,12 @@ impl <'a, State, Block> KeyIterator<'a, State, Block> {
|
||||
prefix: Option<&'a StorageKey>,
|
||||
current_key: Vec<u8>,
|
||||
) -> Self {
|
||||
Self {
|
||||
state,
|
||||
child_storage: Some(child_info),
|
||||
prefix,
|
||||
current_key,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
Self { state, child_storage: Some(child_info), prefix, current_key, _phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where
|
||||
impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block>
|
||||
where
|
||||
Block: BlockT,
|
||||
State: StateBackend<HashFor<Block>>,
|
||||
{
|
||||
@@ -327,11 +329,13 @@ impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where
|
||||
self.state.next_child_storage_key(child_info, &self.current_key)
|
||||
} else {
|
||||
self.state.next_storage_key(&self.current_key)
|
||||
}.ok().flatten()?;
|
||||
}
|
||||
.ok()
|
||||
.flatten()?;
|
||||
// this terminates the iterator the first time it fails.
|
||||
if let Some(prefix) = self.prefix {
|
||||
if !next_key.starts_with(&prefix.0[..]) {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
}
|
||||
self.current_key = next_key.clone();
|
||||
@@ -342,19 +346,31 @@ impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where
|
||||
/// Provides acess to storage primitives
|
||||
pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
/// Given a `BlockId` and a key, return the value under the key in that block.
|
||||
fn storage(&self, id: &BlockId<Block>, key: &StorageKey) -> sp_blockchain::Result<Option<StorageData>>;
|
||||
fn storage(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
key: &StorageKey,
|
||||
) -> sp_blockchain::Result<Option<StorageData>>;
|
||||
|
||||
/// Given a `BlockId` and a key prefix, return the matching storage keys in that block.
|
||||
fn storage_keys(&self, id: &BlockId<Block>, key_prefix: &StorageKey) -> sp_blockchain::Result<Vec<StorageKey>>;
|
||||
fn storage_keys(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
key_prefix: &StorageKey,
|
||||
) -> sp_blockchain::Result<Vec<StorageKey>>;
|
||||
|
||||
/// Given a `BlockId` and a key, return the value under the hash in that block.
|
||||
fn storage_hash(&self, id: &BlockId<Block>, key: &StorageKey) -> sp_blockchain::Result<Option<Block::Hash>>;
|
||||
fn storage_hash(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
key: &StorageKey,
|
||||
) -> sp_blockchain::Result<Option<Block::Hash>>;
|
||||
|
||||
/// Given a `BlockId` and a key prefix, return the matching child storage keys and values in that block.
|
||||
fn storage_pairs(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
key_prefix: &StorageKey
|
||||
key_prefix: &StorageKey,
|
||||
) -> sp_blockchain::Result<Vec<(StorageKey, StorageData)>>;
|
||||
|
||||
/// Given a `BlockId` and a key prefix, return a `KeyIterator` iterates matching storage keys in that block.
|
||||
@@ -362,7 +378,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
prefix: Option<&'a StorageKey>,
|
||||
start_key: Option<&StorageKey>
|
||||
start_key: Option<&StorageKey>,
|
||||
) -> sp_blockchain::Result<KeyIterator<'a, B::State, Block>>;
|
||||
|
||||
/// Given a `BlockId`, a key and a child storage key, return the value under the key in that block.
|
||||
@@ -370,7 +386,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
child_info: &ChildInfo,
|
||||
key: &StorageKey
|
||||
key: &StorageKey,
|
||||
) -> sp_blockchain::Result<Option<StorageData>>;
|
||||
|
||||
/// Given a `BlockId`, a key prefix, and a child storage key, return the matching child storage keys.
|
||||
@@ -378,7 +394,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
child_info: &ChildInfo,
|
||||
key_prefix: &StorageKey
|
||||
key_prefix: &StorageKey,
|
||||
) -> sp_blockchain::Result<Vec<StorageKey>>;
|
||||
|
||||
/// Given a `BlockId` and a key `prefix` and a child storage key,
|
||||
@@ -388,7 +404,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
id: &BlockId<Block>,
|
||||
child_info: ChildInfo,
|
||||
prefix: Option<&'a StorageKey>,
|
||||
start_key: Option<&StorageKey>
|
||||
start_key: Option<&StorageKey>,
|
||||
) -> sp_blockchain::Result<KeyIterator<'a, B::State, Block>>;
|
||||
|
||||
/// Given a `BlockId`, a key and a child storage key, return the hash under the key in that block.
|
||||
@@ -396,7 +412,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
child_info: &ChildInfo,
|
||||
key: &StorageKey
|
||||
key: &StorageKey,
|
||||
) -> sp_blockchain::Result<Option<Block::Hash>>;
|
||||
|
||||
/// Get longest range within [first; last] that is possible to use in `key_changes`
|
||||
@@ -418,7 +434,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
first: NumberFor<Block>,
|
||||
last: BlockId<Block>,
|
||||
storage_key: Option<&PrefixedStorageKey>,
|
||||
key: &StorageKey
|
||||
key: &StorageKey,
|
||||
) -> sp_blockchain::Result<Vec<(NumberFor<Block>, u32)>>;
|
||||
}
|
||||
|
||||
@@ -511,20 +527,20 @@ pub trait Backend<Block: BlockT>: AuxStore + Send + Sync {
|
||||
) -> sp_blockchain::Result<(NumberFor<Block>, HashSet<Block::Hash>)>;
|
||||
|
||||
/// Discard non-best, unfinalized leaf block.
|
||||
fn remove_leaf_block(
|
||||
&self,
|
||||
hash: &Block::Hash,
|
||||
) -> sp_blockchain::Result<()>;
|
||||
fn remove_leaf_block(&self, hash: &Block::Hash) -> sp_blockchain::Result<()>;
|
||||
|
||||
/// Insert auxiliary data into key-value store.
|
||||
fn insert_aux<
|
||||
'a,
|
||||
'b: 'a,
|
||||
'c: 'a,
|
||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()>
|
||||
{
|
||||
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||
>(
|
||||
&self,
|
||||
insert: I,
|
||||
delete: D,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
AuxStore::insert_aux(self, insert, delete)
|
||||
}
|
||||
/// Query auxiliary data from key-value store.
|
||||
@@ -548,9 +564,10 @@ pub trait PrunableStateChangesTrieStorage<Block: BlockT>:
|
||||
/// Get reference to StateChangesTrieStorage.
|
||||
fn storage(&self) -> &dyn StateChangesTrieStorage<HashFor<Block>, NumberFor<Block>>;
|
||||
/// Get configuration at given block.
|
||||
fn configuration_at(&self, at: &BlockId<Block>) -> sp_blockchain::Result<
|
||||
ChangesTrieConfigurationRange<NumberFor<Block>, Block::Hash>
|
||||
>;
|
||||
fn configuration_at(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
) -> sp_blockchain::Result<ChangesTrieConfigurationRange<NumberFor<Block>, Block::Hash>>;
|
||||
/// Get end block (inclusive) of oldest pruned max-level (or skewed) digest trie blocks range.
|
||||
/// It is guaranteed that we have no any changes tries before (and including) this block.
|
||||
/// It is guaranteed that all existing changes tries after this block are not yet pruned (if created).
|
||||
@@ -584,7 +601,8 @@ pub fn changes_tries_state_at_block<'a, Block: BlockT>(
|
||||
|
||||
let config_range = storage.configuration_at(block)?;
|
||||
match config_range.config {
|
||||
Some(config) => Ok(Some(ChangesTrieState::new(config, config_range.zero.0, storage.storage()))),
|
||||
Some(config) =>
|
||||
Ok(Some(ChangesTrieState::new(config, config_range.zero.0, storage.storage()))),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
|
||||
//! A method call executor interface.
|
||||
|
||||
use std::{panic::UnwindSafe, result, cell::RefCell};
|
||||
use codec::{Encode, Decode};
|
||||
use sp_runtime::{
|
||||
generic::BlockId, traits::{Block as BlockT, HashFor},
|
||||
};
|
||||
use sp_state_machine::{
|
||||
OverlayedChanges, ExecutionManager, ExecutionStrategy, StorageProof,
|
||||
};
|
||||
use sc_executor::{RuntimeVersion, NativeVersion};
|
||||
use sp_externalities::Extensions;
|
||||
use codec::{Decode, Encode};
|
||||
use sc_executor::{NativeVersion, RuntimeVersion};
|
||||
use sp_core::NativeOrEncoded;
|
||||
use sp_externalities::Extensions;
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, HashFor},
|
||||
};
|
||||
use sp_state_machine::{ExecutionManager, ExecutionStrategy, OverlayedChanges, StorageProof};
|
||||
use std::{cell::RefCell, panic::UnwindSafe, result};
|
||||
|
||||
use sp_api::{ProofRecorder, StorageTransactionCache};
|
||||
use crate::execution_extensions::ExecutionExtensions;
|
||||
use sp_api::{ProofRecorder, StorageTransactionCache};
|
||||
|
||||
/// Executor Provider
|
||||
pub trait ExecutorProvider<Block: BlockT> {
|
||||
@@ -73,7 +72,7 @@ pub trait CallExecutor<B: BlockT> {
|
||||
fn contextual_call<
|
||||
EM: Fn(
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
Result<NativeOrEncoded<R>, Self::Error>
|
||||
Result<NativeOrEncoded<R>, Self::Error>,
|
||||
) -> Result<NativeOrEncoded<R>, Self::Error>,
|
||||
R: Encode + Decode + PartialEq,
|
||||
NC: FnOnce() -> result::Result<R, sp_api::ApiError> + UnwindSafe,
|
||||
@@ -83,14 +82,18 @@ pub trait CallExecutor<B: BlockT> {
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
changes: &RefCell<OverlayedChanges>,
|
||||
storage_transaction_cache: Option<&RefCell<
|
||||
StorageTransactionCache<B, <Self::Backend as crate::backend::Backend<B>>::State>,
|
||||
>>,
|
||||
storage_transaction_cache: Option<
|
||||
&RefCell<
|
||||
StorageTransactionCache<B, <Self::Backend as crate::backend::Backend<B>>::State>,
|
||||
>,
|
||||
>,
|
||||
execution_manager: ExecutionManager<EM>,
|
||||
native_call: Option<NC>,
|
||||
proof_recorder: &Option<ProofRecorder<B>>,
|
||||
extensions: Option<Extensions>,
|
||||
) -> sp_blockchain::Result<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone;
|
||||
) -> sp_blockchain::Result<NativeOrEncoded<R>>
|
||||
where
|
||||
ExecutionManager<EM>: Clone;
|
||||
|
||||
/// Extract RuntimeVersion of given block
|
||||
///
|
||||
@@ -105,12 +108,13 @@ pub trait CallExecutor<B: BlockT> {
|
||||
mut state: S,
|
||||
overlay: &mut OverlayedChanges,
|
||||
method: &str,
|
||||
call_data: &[u8]
|
||||
call_data: &[u8],
|
||||
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error> {
|
||||
let trie_state = state.as_trie_backend()
|
||||
.ok_or_else(||
|
||||
sp_blockchain::Error::from_state(Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof) as Box<_>)
|
||||
)?;
|
||||
let trie_state = state.as_trie_backend().ok_or_else(|| {
|
||||
sp_blockchain::Error::from_state(Box::new(
|
||||
sp_state_machine::ExecutionError::UnableToGenerateProof,
|
||||
) as Box<_>)
|
||||
})?;
|
||||
self.prove_at_trie_state(trie_state, overlay, method, call_data)
|
||||
}
|
||||
|
||||
@@ -122,7 +126,7 @@ pub trait CallExecutor<B: BlockT> {
|
||||
trie_state: &sp_state_machine::TrieBackend<S, HashFor<B>>,
|
||||
overlay: &mut OverlayedChanges,
|
||||
method: &str,
|
||||
call_data: &[u8]
|
||||
call_data: &[u8],
|
||||
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error>;
|
||||
|
||||
/// Get runtime version if supported.
|
||||
|
||||
+115
-107
@@ -25,15 +25,15 @@
|
||||
//! root hash. A correct proof implies that the claimed block is identical to the one
|
||||
//! we discarded.
|
||||
|
||||
use hash_db;
|
||||
use codec::Encode;
|
||||
use hash_db;
|
||||
use sp_trie;
|
||||
|
||||
use sp_core::{H256, convert_hash};
|
||||
use sp_runtime::traits::{Header as HeaderT, AtLeast32Bit, Zero, One};
|
||||
use sp_core::{convert_hash, H256};
|
||||
use sp_runtime::traits::{AtLeast32Bit, Header as HeaderT, One, Zero};
|
||||
use sp_state_machine::{
|
||||
MemoryDB, TrieBackend, Backend as StateBackend, StorageProof, InMemoryBackend,
|
||||
prove_read_on_trie_backend, read_proof_check, read_proof_check_on_proving_backend
|
||||
prove_read_on_trie_backend, read_proof_check, read_proof_check_on_proving_backend,
|
||||
Backend as StateBackend, InMemoryBackend, MemoryDB, StorageProof, TrieBackend,
|
||||
};
|
||||
|
||||
use sp_blockchain::{Error as ClientError, Result as ClientResult};
|
||||
@@ -49,17 +49,17 @@ pub fn size<N: From<u32>>() -> N {
|
||||
|
||||
/// Returns Some(cht_number) if CHT is need to be built when the block with given number is canonized.
|
||||
pub fn is_build_required<N>(cht_size: N, block_num: N) -> Option<N>
|
||||
where
|
||||
N: Clone + AtLeast32Bit,
|
||||
where
|
||||
N: Clone + AtLeast32Bit,
|
||||
{
|
||||
let block_cht_num = block_to_cht_number(cht_size.clone(), block_num.clone())?;
|
||||
let two = N::one() + N::one();
|
||||
if block_cht_num < two {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
let cht_start = start_number(cht_size, block_cht_num.clone());
|
||||
if cht_start != block_num {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
Some(block_cht_num - two)
|
||||
@@ -67,13 +67,13 @@ pub fn is_build_required<N>(cht_size: N, block_num: N) -> Option<N>
|
||||
|
||||
/// Returns Some(max_cht_number) if CHT has ever been built given maximal canonical block number.
|
||||
pub fn max_cht_number<N>(cht_size: N, max_canonical_block: N) -> Option<N>
|
||||
where
|
||||
N: Clone + AtLeast32Bit,
|
||||
where
|
||||
N: Clone + AtLeast32Bit,
|
||||
{
|
||||
let max_cht_number = block_to_cht_number(cht_size, max_canonical_block)?;
|
||||
let two = N::one() + N::one();
|
||||
if max_cht_number < two {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
Some(max_cht_number - two)
|
||||
}
|
||||
@@ -86,16 +86,16 @@ pub fn compute_root<Header, Hasher, I>(
|
||||
cht_num: Header::Number,
|
||||
hashes: I,
|
||||
) -> ClientResult<Hasher::Out>
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord,
|
||||
I: IntoIterator<Item=ClientResult<Option<Header::Hash>>>,
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord,
|
||||
I: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
|
||||
{
|
||||
use sp_trie::TrieConfiguration;
|
||||
Ok(sp_trie::trie_types::Layout::<Hasher>::trie_root(
|
||||
build_pairs::<Header, I>(cht_size, cht_num, hashes)?
|
||||
))
|
||||
Ok(sp_trie::trie_types::Layout::<Hasher>::trie_root(build_pairs::<Header, I>(
|
||||
cht_size, cht_num, hashes,
|
||||
)?))
|
||||
}
|
||||
|
||||
/// Build CHT-based header proof.
|
||||
@@ -103,26 +103,28 @@ pub fn build_proof<Header, Hasher, BlocksI, HashesI>(
|
||||
cht_size: Header::Number,
|
||||
cht_num: Header::Number,
|
||||
blocks: BlocksI,
|
||||
hashes: HashesI
|
||||
hashes: HashesI,
|
||||
) -> ClientResult<StorageProof>
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
BlocksI: IntoIterator<Item=Header::Number>,
|
||||
HashesI: IntoIterator<Item=ClientResult<Option<Header::Hash>>>,
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
BlocksI: IntoIterator<Item = Header::Number>,
|
||||
HashesI: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
|
||||
{
|
||||
let transaction = build_pairs::<Header, _>(cht_size, cht_num, hashes)?
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, Some(v)))
|
||||
.collect::<Vec<_>>();
|
||||
let mut storage = InMemoryBackend::<Hasher>::default().update(vec![(None, transaction)]);
|
||||
let trie_storage = storage.as_trie_backend()
|
||||
let trie_storage = storage
|
||||
.as_trie_backend()
|
||||
.expect("InMemoryState::as_trie_backend always returns Some; qed");
|
||||
prove_read_on_trie_backend(
|
||||
trie_storage,
|
||||
blocks.into_iter().map(|number| encode_cht_key(number)),
|
||||
).map_err(ClientError::from_state)
|
||||
)
|
||||
.map_err(ClientError::from_state)
|
||||
}
|
||||
|
||||
/// Check CHT-based header proof.
|
||||
@@ -132,25 +134,24 @@ pub fn check_proof<Header, Hasher>(
|
||||
remote_hash: Header::Hash,
|
||||
remote_proof: StorageProof,
|
||||
) -> ClientResult<()>
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
{
|
||||
do_check_proof::<Header, Hasher, _>(
|
||||
local_root,
|
||||
local_number,
|
||||
remote_hash,
|
||||
move |local_root, local_cht_key|
|
||||
move |local_root, local_cht_key| {
|
||||
read_proof_check::<Hasher, _>(
|
||||
local_root,
|
||||
remote_proof,
|
||||
::std::iter::once(local_cht_key),
|
||||
)
|
||||
.map(|mut map| map
|
||||
.remove(local_cht_key)
|
||||
.expect("checked proof of local_cht_key; qed"))
|
||||
.map_err(ClientError::from_state),
|
||||
.map(|mut map| map.remove(local_cht_key).expect("checked proof of local_cht_key; qed"))
|
||||
.map_err(ClientError::from_state)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -161,20 +162,19 @@ pub fn check_proof_on_proving_backend<Header, Hasher>(
|
||||
remote_hash: Header::Hash,
|
||||
proving_backend: &TrieBackend<MemoryDB<Hasher>, Hasher>,
|
||||
) -> ClientResult<()>
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord + codec::Codec,
|
||||
{
|
||||
do_check_proof::<Header, Hasher, _>(
|
||||
local_root,
|
||||
local_number,
|
||||
remote_hash,
|
||||
|_, local_cht_key|
|
||||
read_proof_check_on_proving_backend::<Hasher>(
|
||||
proving_backend,
|
||||
local_cht_key,
|
||||
).map_err(ClientError::from_state),
|
||||
|_, local_cht_key| {
|
||||
read_proof_check_on_proving_backend::<Hasher>(proving_backend, local_cht_key)
|
||||
.map_err(ClientError::from_state)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -185,22 +185,22 @@ fn do_check_proof<Header, Hasher, F>(
|
||||
remote_hash: Header::Hash,
|
||||
checker: F,
|
||||
) -> ClientResult<()>
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord,
|
||||
F: FnOnce(Hasher::Out, &[u8]) -> ClientResult<Option<Vec<u8>>>,
|
||||
where
|
||||
Header: HeaderT,
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord,
|
||||
F: FnOnce(Hasher::Out, &[u8]) -> ClientResult<Option<Vec<u8>>>,
|
||||
{
|
||||
let root: Hasher::Out = convert_hash(&local_root);
|
||||
let local_cht_key = encode_cht_key(local_number);
|
||||
let local_cht_value = checker(root, &local_cht_key)?;
|
||||
let local_cht_value = local_cht_value.ok_or_else(|| ClientError::InvalidCHTProof)?;
|
||||
let local_hash = decode_cht_value(&local_cht_value).ok_or_else(|| ClientError::InvalidCHTProof)?;
|
||||
let local_hash =
|
||||
decode_cht_value(&local_cht_value).ok_or_else(|| ClientError::InvalidCHTProof)?;
|
||||
match &local_hash[..] == remote_hash.as_ref() {
|
||||
true => Ok(()),
|
||||
false => Err(ClientError::InvalidCHTProof.into()),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Group ordered blocks by CHT number and call functor with blocks of each group.
|
||||
@@ -210,29 +210,31 @@ pub fn for_each_cht_group<Header, I, F, P>(
|
||||
mut functor: F,
|
||||
mut functor_param: P,
|
||||
) -> ClientResult<()>
|
||||
where
|
||||
Header: HeaderT,
|
||||
I: IntoIterator<Item=Header::Number>,
|
||||
F: FnMut(P, Header::Number, Vec<Header::Number>) -> ClientResult<P>,
|
||||
where
|
||||
Header: HeaderT,
|
||||
I: IntoIterator<Item = Header::Number>,
|
||||
F: FnMut(P, Header::Number, Vec<Header::Number>) -> ClientResult<P>,
|
||||
{
|
||||
let mut current_cht_num = None;
|
||||
let mut current_cht_blocks = Vec::new();
|
||||
for block in blocks {
|
||||
let new_cht_num = block_to_cht_number(cht_size, block).ok_or_else(|| ClientError::Backend(format!(
|
||||
"Cannot compute CHT root for the block #{}", block))
|
||||
)?;
|
||||
let new_cht_num = block_to_cht_number(cht_size, block).ok_or_else(|| {
|
||||
ClientError::Backend(format!("Cannot compute CHT root for the block #{}", block))
|
||||
})?;
|
||||
|
||||
let advance_to_next_cht = current_cht_num.is_some() && current_cht_num != Some(new_cht_num);
|
||||
if advance_to_next_cht {
|
||||
let current_cht_num = current_cht_num.expect("advance_to_next_cht is true;
|
||||
it is true only when current_cht_num is Some; qed");
|
||||
assert!(new_cht_num > current_cht_num, "for_each_cht_group only supports ordered iterators");
|
||||
let current_cht_num = current_cht_num.expect(
|
||||
"advance_to_next_cht is true;
|
||||
it is true only when current_cht_num is Some; qed",
|
||||
);
|
||||
assert!(
|
||||
new_cht_num > current_cht_num,
|
||||
"for_each_cht_group only supports ordered iterators"
|
||||
);
|
||||
|
||||
functor_param = functor(
|
||||
functor_param,
|
||||
current_cht_num,
|
||||
std::mem::take(&mut current_cht_blocks),
|
||||
)?;
|
||||
functor_param =
|
||||
functor(functor_param, current_cht_num, std::mem::take(&mut current_cht_blocks))?;
|
||||
}
|
||||
|
||||
current_cht_blocks.push(block);
|
||||
@@ -240,11 +242,7 @@ pub fn for_each_cht_group<Header, I, F, P>(
|
||||
}
|
||||
|
||||
if let Some(current_cht_num) = current_cht_num {
|
||||
functor(
|
||||
functor_param,
|
||||
current_cht_num,
|
||||
std::mem::take(&mut current_cht_blocks),
|
||||
)?;
|
||||
functor(functor_param, current_cht_num, std::mem::take(&mut current_cht_blocks))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -254,26 +252,22 @@ pub fn for_each_cht_group<Header, I, F, P>(
|
||||
fn build_pairs<Header, I>(
|
||||
cht_size: Header::Number,
|
||||
cht_num: Header::Number,
|
||||
hashes: I
|
||||
hashes: I,
|
||||
) -> ClientResult<Vec<(Vec<u8>, Vec<u8>)>>
|
||||
where
|
||||
Header: HeaderT,
|
||||
I: IntoIterator<Item=ClientResult<Option<Header::Hash>>>,
|
||||
where
|
||||
Header: HeaderT,
|
||||
I: IntoIterator<Item = ClientResult<Option<Header::Hash>>>,
|
||||
{
|
||||
let start_num = start_number(cht_size, cht_num);
|
||||
let mut pairs = Vec::new();
|
||||
let mut hash_index = Header::Number::zero();
|
||||
for hash in hashes.into_iter() {
|
||||
let hash = hash?.ok_or_else(|| ClientError::from(
|
||||
ClientError::MissingHashRequiredForCHT
|
||||
))?;
|
||||
pairs.push((
|
||||
encode_cht_key(start_num + hash_index).to_vec(),
|
||||
encode_cht_value(hash)
|
||||
));
|
||||
let hash =
|
||||
hash?.ok_or_else(|| ClientError::from(ClientError::MissingHashRequiredForCHT))?;
|
||||
pairs.push((encode_cht_key(start_num + hash_index).to_vec(), encode_cht_value(hash)));
|
||||
hash_index += Header::Number::one();
|
||||
if hash_index == cht_size {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +319,6 @@ pub fn decode_cht_value(value: &[u8]) -> Option<H256> {
|
||||
32 => Some(H256::from_slice(&value[0..32])),
|
||||
_ => None,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -379,8 +372,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn build_pairs_fails_when_no_enough_blocks() {
|
||||
assert!(build_pairs::<Header, _>(SIZE as _, 0,
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize / 2)).is_err());
|
||||
assert!(build_pairs::<Header, _>(
|
||||
SIZE as _,
|
||||
0,
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize / 2)
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -391,9 +388,12 @@ mod tests {
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
||||
.take(SIZE as usize / 2)
|
||||
.chain(::std::iter::once(Ok(None)))
|
||||
.chain(::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(2))))
|
||||
.take(SIZE as usize / 2 - 1))
|
||||
).is_err());
|
||||
.chain(
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(2))))
|
||||
.take(SIZE as usize / 2 - 1)
|
||||
)
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -401,9 +401,9 @@ mod tests {
|
||||
assert!(compute_root::<Header, BlakeTwo256, _>(
|
||||
SIZE as _,
|
||||
42,
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
||||
.take(SIZE as usize)
|
||||
).is_ok());
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -413,9 +413,9 @@ mod tests {
|
||||
SIZE as _,
|
||||
0,
|
||||
vec![(SIZE * 1000) as u64],
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
||||
.take(SIZE as usize)
|
||||
).is_err());
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -424,9 +424,9 @@ mod tests {
|
||||
SIZE as _,
|
||||
0,
|
||||
vec![(SIZE / 2) as u64],
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1))))
|
||||
.take(SIZE as usize)
|
||||
).is_ok());
|
||||
::std::iter::repeat_with(|| Ok(Some(H256::from_low_u64_be(1)))).take(SIZE as usize)
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -447,19 +447,27 @@ mod tests {
|
||||
let _ = for_each_cht_group::<Header, _, _, _>(
|
||||
cht_size,
|
||||
vec![
|
||||
cht_size * 2 + 1, cht_size * 2 + 2, cht_size * 2 + 5,
|
||||
cht_size * 4 + 1, cht_size * 4 + 7,
|
||||
cht_size * 6 + 1
|
||||
], |_, cht_num, blocks| {
|
||||
cht_size * 2 + 1,
|
||||
cht_size * 2 + 2,
|
||||
cht_size * 2 + 5,
|
||||
cht_size * 4 + 1,
|
||||
cht_size * 4 + 7,
|
||||
cht_size * 6 + 1,
|
||||
],
|
||||
|_, cht_num, blocks| {
|
||||
match cht_num {
|
||||
2 => assert_eq!(blocks, vec![cht_size * 2 + 1, cht_size * 2 + 2, cht_size * 2 + 5]),
|
||||
2 => assert_eq!(
|
||||
blocks,
|
||||
vec![cht_size * 2 + 1, cht_size * 2 + 2, cht_size * 2 + 5]
|
||||
),
|
||||
4 => assert_eq!(blocks, vec![cht_size * 4 + 1, cht_size * 4 + 7]),
|
||||
6 => assert_eq!(blocks, vec![cht_size * 6 + 1]),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}, ()
|
||||
},
|
||||
(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,19 @@
|
||||
|
||||
//! A set of APIs supported by the client along with their primitives.
|
||||
|
||||
use std::{fmt, collections::HashSet, sync::Arc, convert::TryFrom};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_core::storage::StorageKey;
|
||||
use sp_runtime::{
|
||||
traits::{Block as BlockT, NumberFor},
|
||||
generic::{BlockId, SignedBlock},
|
||||
traits::{Block as BlockT, NumberFor},
|
||||
Justifications,
|
||||
};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use std::{collections::HashSet, convert::TryFrom, fmt, sync::Arc};
|
||||
|
||||
use crate::blockchain::Info;
|
||||
use crate::notifications::StorageEventStream;
|
||||
use sp_utils::mpsc::TracingUnboundedReceiver;
|
||||
use sp_blockchain;
|
||||
use crate::{blockchain::Info, notifications::StorageEventStream};
|
||||
use sc_transaction_pool_api::ChainEvent;
|
||||
use sp_blockchain;
|
||||
use sp_utils::mpsc::TracingUnboundedReceiver;
|
||||
|
||||
/// Type that implements `futures::Stream` of block import events.
|
||||
pub type ImportNotifications<Block> = TracingUnboundedReceiver<BlockImportNotification<Block>>;
|
||||
@@ -82,7 +81,7 @@ pub trait BlockBackend<Block: BlockT> {
|
||||
/// Get block body by ID. Returns `None` if the body is not stored.
|
||||
fn block_body(
|
||||
&self,
|
||||
id: &BlockId<Block>
|
||||
id: &BlockId<Block>,
|
||||
) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
|
||||
|
||||
/// Get all indexed transactions for a block,
|
||||
@@ -99,7 +98,8 @@ pub trait BlockBackend<Block: BlockT> {
|
||||
fn block(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<SignedBlock<Block>>>;
|
||||
|
||||
/// Get block status.
|
||||
fn block_status(&self, id: &BlockId<Block>) -> sp_blockchain::Result<sp_consensus::BlockStatus>;
|
||||
fn block_status(&self, id: &BlockId<Block>)
|
||||
-> sp_blockchain::Result<sp_consensus::BlockStatus>;
|
||||
|
||||
/// Get block justifications for the block with the given id.
|
||||
fn justifications(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<Justifications>>;
|
||||
@@ -107,14 +107,11 @@ pub trait BlockBackend<Block: BlockT> {
|
||||
/// Get block hash by number.
|
||||
fn block_hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>>;
|
||||
|
||||
/// Get single indexed transaction by content hash.
|
||||
/// Get single indexed transaction by content hash.
|
||||
///
|
||||
/// Note that this will only fetch transactions
|
||||
/// that are indexed by the runtime with `storage_index_transaction`.
|
||||
fn indexed_transaction(
|
||||
&self,
|
||||
hash: &Block::Hash,
|
||||
) -> sp_blockchain::Result<Option<Vec<u8>>>;
|
||||
fn indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>>;
|
||||
|
||||
/// Check if transaction index exists.
|
||||
fn has_indexed_transaction(&self, hash: &Block::Hash) -> sp_blockchain::Result<bool> {
|
||||
@@ -125,8 +122,11 @@ pub trait BlockBackend<Block: BlockT> {
|
||||
/// Provide a list of potential uncle headers for a given block.
|
||||
pub trait ProvideUncles<Block: BlockT> {
|
||||
/// Gets the uncles of the block with `target_hash` going back `max_generation` ancestors.
|
||||
fn uncles(&self, target_hash: Block::Hash, max_generation: NumberFor<Block>)
|
||||
-> sp_blockchain::Result<Vec<Block::Header>>;
|
||||
fn uncles(
|
||||
&self,
|
||||
target_hash: Block::Hash,
|
||||
max_generation: NumberFor<Block>,
|
||||
) -> sp_blockchain::Result<Vec<Block::Header>>;
|
||||
}
|
||||
|
||||
/// Client info
|
||||
@@ -284,10 +284,7 @@ impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
|
||||
|
||||
fn try_from(n: BlockImportNotification<B>) -> Result<Self, ()> {
|
||||
if n.is_new_best {
|
||||
Ok(Self::NewBestBlock {
|
||||
hash: n.hash,
|
||||
tree_route: n.tree_route,
|
||||
})
|
||||
Ok(Self::NewBestBlock { hash: n.hash, tree_route: n.tree_route })
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
@@ -296,8 +293,6 @@ impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
|
||||
|
||||
impl<B: BlockT> From<FinalityNotification<B>> for ChainEvent<B> {
|
||||
fn from(n: FinalityNotification<B>) -> Self {
|
||||
Self::Finalized {
|
||||
hash: n.hash,
|
||||
}
|
||||
Self::Finalized { hash: n.hash }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,22 +22,19 @@
|
||||
//! strategy for the runtime calls and provide the right `Externalities`
|
||||
//! extensions to support APIs for particular execution context & capabilities.
|
||||
|
||||
use std::sync::{Weak, Arc};
|
||||
use codec::Decode;
|
||||
use sp_core::{
|
||||
ExecutionContext,
|
||||
offchain::{self, OffchainWorkerExt, TransactionPoolExt, OffchainDbExt},
|
||||
};
|
||||
use sp_keystore::{KeystoreExt, SyncCryptoStorePtr};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits,
|
||||
};
|
||||
use sp_state_machine::{ExecutionManager, DefaultHandler};
|
||||
pub use sp_state_machine::ExecutionStrategy;
|
||||
use sp_externalities::Extensions;
|
||||
use parking_lot::RwLock;
|
||||
use sc_transaction_pool_api::OffchainSubmitTransaction;
|
||||
use sp_core::{
|
||||
offchain::{self, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt},
|
||||
ExecutionContext,
|
||||
};
|
||||
use sp_externalities::Extensions;
|
||||
use sp_keystore::{KeystoreExt, SyncCryptoStorePtr};
|
||||
use sp_runtime::{generic::BlockId, traits};
|
||||
pub use sp_state_machine::ExecutionStrategy;
|
||||
use sp_state_machine::{DefaultHandler, ExecutionManager};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
/// Execution strategies settings.
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -151,7 +148,8 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
||||
|
||||
/// Register transaction pool extension.
|
||||
pub fn register_transaction_pool<T>(&self, pool: &Arc<T>)
|
||||
where T: OffchainSubmitTransaction<Block> + 'static
|
||||
where
|
||||
T: OffchainSubmitTransaction<Block> + 'static,
|
||||
{
|
||||
*self.transaction_pool.write() = Some(Arc::downgrade(&pool) as _);
|
||||
}
|
||||
@@ -171,14 +169,10 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
||||
|
||||
if capabilities.has(offchain::Capability::TransactionPool) {
|
||||
if let Some(pool) = self.transaction_pool.read().as_ref().and_then(|x| x.upgrade()) {
|
||||
extensions.register(
|
||||
TransactionPoolExt(
|
||||
Box::new(TransactionPoolAdapter {
|
||||
at: *at,
|
||||
pool,
|
||||
}) as _
|
||||
),
|
||||
);
|
||||
extensions
|
||||
.register(TransactionPoolExt(
|
||||
Box::new(TransactionPoolAdapter { at: *at, pool }) as _,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,19 +180,18 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
||||
capabilities.has(offchain::Capability::OffchainDbWrite)
|
||||
{
|
||||
if let Some(offchain_db) = self.offchain_db.as_ref() {
|
||||
extensions.register(
|
||||
OffchainDbExt::new(offchain::LimitedExternalities::new(
|
||||
capabilities,
|
||||
offchain_db.create(),
|
||||
))
|
||||
);
|
||||
extensions.register(OffchainDbExt::new(offchain::LimitedExternalities::new(
|
||||
capabilities,
|
||||
offchain_db.create(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
if let ExecutionContext::OffchainCall(Some(ext)) = context {
|
||||
extensions.register(
|
||||
OffchainWorkerExt::new(offchain::LimitedExternalities::new(capabilities, ext.0)),
|
||||
);
|
||||
extensions.register(OffchainWorkerExt::new(offchain::LimitedExternalities::new(
|
||||
capabilities,
|
||||
ext.0,
|
||||
)));
|
||||
}
|
||||
|
||||
extensions
|
||||
@@ -212,21 +205,14 @@ impl<Block: traits::Block> ExecutionExtensions<Block> {
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
context: ExecutionContext,
|
||||
) -> (
|
||||
ExecutionManager<DefaultHandler<R, E>>,
|
||||
Extensions,
|
||||
) {
|
||||
) -> (ExecutionManager<DefaultHandler<R, E>>, Extensions) {
|
||||
let manager = match context {
|
||||
ExecutionContext::BlockConstruction =>
|
||||
self.strategies.block_construction.get_manager(),
|
||||
ExecutionContext::Syncing =>
|
||||
self.strategies.syncing.get_manager(),
|
||||
ExecutionContext::Importing =>
|
||||
self.strategies.importing.get_manager(),
|
||||
ExecutionContext::BlockConstruction => self.strategies.block_construction.get_manager(),
|
||||
ExecutionContext::Syncing => self.strategies.syncing.get_manager(),
|
||||
ExecutionContext::Importing => self.strategies.importing.get_manager(),
|
||||
ExecutionContext::OffchainCall(Some((_, capabilities))) if capabilities.has_all() =>
|
||||
self.strategies.offchain_worker.get_manager(),
|
||||
ExecutionContext::OffchainCall(_) =>
|
||||
self.strategies.other.get_manager(),
|
||||
ExecutionContext::OffchainCall(_) => self.strategies.other.get_manager(),
|
||||
};
|
||||
|
||||
(manager, self.extensions(at, context))
|
||||
@@ -245,7 +231,7 @@ impl<Block: traits::Block> offchain::TransactionPool for TransactionPoolAdapter<
|
||||
Ok(xt) => xt,
|
||||
Err(e) => {
|
||||
log::warn!("Unable to decode extrinsic: {:?}: {}", data, e);
|
||||
return Err(());
|
||||
return Err(())
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
+231
-137
@@ -18,30 +18,31 @@
|
||||
|
||||
//! In memory client backend
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use parking_lot::RwLock;
|
||||
use sp_core::{
|
||||
storage::well_known_keys, offchain::storage::InMemOffchainStorage as OffchainStorage,
|
||||
};
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Zero, NumberFor, HashFor};
|
||||
use sp_runtime::{Justification, Justifications, Storage};
|
||||
use sp_state_machine::{
|
||||
ChangesTrieTransaction, InMemoryBackend, Backend as StateBackend, StorageCollection,
|
||||
ChildStorageCollection, IndexOperation,
|
||||
};
|
||||
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata};
|
||||
use sp_core::{
|
||||
offchain::storage::InMemOffchainStorage as OffchainStorage, storage::well_known_keys,
|
||||
};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, HashFor, Header as HeaderT, NumberFor, Zero},
|
||||
Justification, Justifications, Storage,
|
||||
};
|
||||
use sp_state_machine::{
|
||||
Backend as StateBackend, ChangesTrieTransaction, ChildStorageCollection, InMemoryBackend,
|
||||
IndexOperation, StorageCollection,
|
||||
};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
ptr,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backend::{self, NewBlockState, ProvideChtRoots},
|
||||
blockchain::{
|
||||
self, BlockStatus, HeaderBackend, well_known_cache_keys::Id as CacheKeyId
|
||||
},
|
||||
UsageInfo,
|
||||
light,
|
||||
blockchain::{self, well_known_cache_keys::Id as CacheKeyId, BlockStatus, HeaderBackend},
|
||||
leaves::LeafSet,
|
||||
light, UsageInfo,
|
||||
};
|
||||
|
||||
struct PendingBlock<B: BlockT> {
|
||||
@@ -56,7 +57,11 @@ enum StoredBlock<B: BlockT> {
|
||||
}
|
||||
|
||||
impl<B: BlockT> StoredBlock<B> {
|
||||
fn new(header: B::Header, body: Option<Vec<B::Extrinsic>>, just: Option<Justifications>) -> Self {
|
||||
fn new(
|
||||
header: B::Header,
|
||||
body: Option<Vec<B::Extrinsic>>,
|
||||
just: Option<Justifications>,
|
||||
) -> Self {
|
||||
match body {
|
||||
Some(body) => StoredBlock::Full(B::new(header, body), just),
|
||||
None => StoredBlock::Header(header, just),
|
||||
@@ -72,7 +77,7 @@ impl<B: BlockT> StoredBlock<B> {
|
||||
|
||||
fn justifications(&self) -> Option<&Justifications> {
|
||||
match *self {
|
||||
StoredBlock::Header(_, ref j) | StoredBlock::Full(_, ref j) => j.as_ref()
|
||||
StoredBlock::Header(_, ref j) | StoredBlock::Full(_, ref j) => j.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +94,7 @@ impl<B: BlockT> StoredBlock<B> {
|
||||
StoredBlock::Full(block, just) => {
|
||||
let (header, body) = block.deconstruct();
|
||||
(header, Some(body), just)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,9 +128,7 @@ impl<Block: BlockT> Default for Blockchain<Block> {
|
||||
impl<Block: BlockT + Clone> Clone for Blockchain<Block> {
|
||||
fn clone(&self) -> Self {
|
||||
let storage = Arc::new(RwLock::new(self.storage.read().clone()));
|
||||
Blockchain {
|
||||
storage,
|
||||
}
|
||||
Blockchain { storage }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,23 +143,20 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
|
||||
/// Create new in-memory blockchain storage.
|
||||
pub fn new() -> Blockchain<Block> {
|
||||
let storage = Arc::new(RwLock::new(
|
||||
BlockchainStorage {
|
||||
blocks: HashMap::new(),
|
||||
hashes: HashMap::new(),
|
||||
best_hash: Default::default(),
|
||||
best_number: Zero::zero(),
|
||||
finalized_hash: Default::default(),
|
||||
finalized_number: Zero::zero(),
|
||||
genesis_hash: Default::default(),
|
||||
header_cht_roots: HashMap::new(),
|
||||
changes_trie_cht_roots: HashMap::new(),
|
||||
leaves: LeafSet::new(),
|
||||
aux: HashMap::new(),
|
||||
}));
|
||||
Blockchain {
|
||||
storage,
|
||||
}
|
||||
let storage = Arc::new(RwLock::new(BlockchainStorage {
|
||||
blocks: HashMap::new(),
|
||||
hashes: HashMap::new(),
|
||||
best_hash: Default::default(),
|
||||
best_number: Zero::zero(),
|
||||
finalized_hash: Default::default(),
|
||||
finalized_number: Zero::zero(),
|
||||
genesis_hash: Default::default(),
|
||||
header_cht_roots: HashMap::new(),
|
||||
changes_trie_cht_roots: HashMap::new(),
|
||||
leaves: LeafSet::new(),
|
||||
aux: HashMap::new(),
|
||||
}));
|
||||
Blockchain { storage }
|
||||
}
|
||||
|
||||
/// Insert a block header and associated data.
|
||||
@@ -175,8 +175,12 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
|
||||
{
|
||||
let mut storage = self.storage.write();
|
||||
storage.leaves.import(hash.clone(), number.clone(), header.parent_hash().clone());
|
||||
storage.blocks.insert(hash.clone(), StoredBlock::new(header, body, justifications));
|
||||
storage
|
||||
.leaves
|
||||
.import(hash.clone(), number.clone(), header.parent_hash().clone());
|
||||
storage
|
||||
.blocks
|
||||
.insert(hash.clone(), StoredBlock::new(header, body, justifications));
|
||||
|
||||
if let NewBlockState::Final = new_state {
|
||||
storage.finalized_hash = hash;
|
||||
@@ -200,7 +204,7 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
pub fn equals_to(&self, other: &Self) -> bool {
|
||||
// Check ptr equality first to avoid double read locks.
|
||||
if ptr::eq(self, other) {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
self.canon_equals_to(other) && self.storage.read().blocks == other.storage.read().blocks
|
||||
}
|
||||
@@ -209,14 +213,14 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
pub fn canon_equals_to(&self, other: &Self) -> bool {
|
||||
// Check ptr equality first to avoid double read locks.
|
||||
if ptr::eq(self, other) {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
let this = self.storage.read();
|
||||
let other = other.storage.read();
|
||||
this.hashes == other.hashes
|
||||
&& this.best_hash == other.best_hash
|
||||
&& this.best_number == other.best_number
|
||||
&& this.genesis_hash == other.genesis_hash
|
||||
this.hashes == other.hashes &&
|
||||
this.best_hash == other.best_hash &&
|
||||
this.best_number == other.best_number &&
|
||||
this.genesis_hash == other.genesis_hash
|
||||
}
|
||||
|
||||
/// Insert header CHT root.
|
||||
@@ -226,7 +230,8 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
|
||||
/// Set an existing block as head.
|
||||
pub fn set_head(&self, id: BlockId<Block>) -> sp_blockchain::Result<()> {
|
||||
let header = self.header(id)?
|
||||
let header = self
|
||||
.header(id)?
|
||||
.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", id)))?;
|
||||
|
||||
self.apply_head(&header)
|
||||
@@ -270,7 +275,11 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn finalize_header(&self, id: BlockId<Block>, justification: Option<Justification>) -> sp_blockchain::Result<()> {
|
||||
fn finalize_header(
|
||||
&self,
|
||||
id: BlockId<Block>,
|
||||
justification: Option<Justification>,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
let hash = match self.header(id)? {
|
||||
Some(h) => h.hash(),
|
||||
None => return Err(sp_blockchain::Error::UnknownBlock(format!("{}", id))),
|
||||
@@ -280,11 +289,13 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
storage.finalized_hash = hash;
|
||||
|
||||
if justification.is_some() {
|
||||
let block = storage.blocks.get_mut(&hash)
|
||||
let block = storage
|
||||
.blocks
|
||||
.get_mut(&hash)
|
||||
.expect("hash was fetched from a block in the db; qed");
|
||||
|
||||
let block_justifications = match block {
|
||||
StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j
|
||||
StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j,
|
||||
};
|
||||
|
||||
*block_justifications = justification.map(Justifications::from);
|
||||
@@ -293,9 +304,11 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn append_justification(&self, id: BlockId<Block>, justification: Justification)
|
||||
-> sp_blockchain::Result<()>
|
||||
{
|
||||
fn append_justification(
|
||||
&self,
|
||||
id: BlockId<Block>,
|
||||
justification: Justification,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
let hash = self.expect_block_hash_from_id(&id)?;
|
||||
let mut storage = self.storage.write();
|
||||
|
||||
@@ -305,14 +318,14 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
.expect("hash was fetched from a block in the db; qed");
|
||||
|
||||
let block_justifications = match block {
|
||||
StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j
|
||||
StoredBlock::Header(_, ref mut j) | StoredBlock::Full(_, ref mut j) => j,
|
||||
};
|
||||
|
||||
if let Some(stored_justifications) = block_justifications {
|
||||
if !stored_justifications.append(justification) {
|
||||
return Err(sp_blockchain::Error::BadJustification(
|
||||
"Duplicate consensus engine ID".into()
|
||||
));
|
||||
"Duplicate consensus engine ID".into(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
*block_justifications = Some(Justifications::from(justification));
|
||||
@@ -333,10 +346,13 @@ impl<Block: BlockT> Blockchain<Block> {
|
||||
}
|
||||
|
||||
impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
||||
fn header(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<<Block as BlockT>::Header>> {
|
||||
Ok(self.id(id).and_then(|hash| {
|
||||
self.storage.read().blocks.get(&hash).map(|b| b.header().clone())
|
||||
}))
|
||||
fn header(
|
||||
&self,
|
||||
id: BlockId<Block>,
|
||||
) -> sp_blockchain::Result<Option<<Block as BlockT>::Header>> {
|
||||
Ok(self
|
||||
.id(id)
|
||||
.and_then(|hash| self.storage.read().blocks.get(&hash).map(|b| b.header().clone())))
|
||||
}
|
||||
|
||||
fn info(&self) -> blockchain::Info<Block> {
|
||||
@@ -352,7 +368,7 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
||||
} else {
|
||||
None
|
||||
},
|
||||
number_leaves: storage.leaves.count()
|
||||
number_leaves: storage.leaves.count(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,7 +383,10 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
||||
Ok(self.storage.read().blocks.get(&hash).map(|b| *b.header().number()))
|
||||
}
|
||||
|
||||
fn hash(&self, number: <<Block as BlockT>::Header as HeaderT>::Number) -> sp_blockchain::Result<Option<Block::Hash>> {
|
||||
fn hash(
|
||||
&self,
|
||||
number: <<Block as BlockT>::Header as HeaderT>::Number,
|
||||
) -> sp_blockchain::Result<Option<Block::Hash>> {
|
||||
Ok(self.id(BlockId::Number(number)))
|
||||
}
|
||||
}
|
||||
@@ -375,9 +394,15 @@ impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
|
||||
impl<Block: BlockT> HeaderMetadata<Block> for Blockchain<Block> {
|
||||
type Error = sp_blockchain::Error;
|
||||
|
||||
fn header_metadata(&self, hash: Block::Hash) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
|
||||
self.header(BlockId::hash(hash))?.map(|header| CachedHeaderMetadata::from(&header))
|
||||
.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("header not found: {}", hash)))
|
||||
fn header_metadata(
|
||||
&self,
|
||||
hash: Block::Hash,
|
||||
) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
|
||||
self.header(BlockId::hash(hash))?
|
||||
.map(|header| CachedHeaderMetadata::from(&header))
|
||||
.ok_or_else(|| {
|
||||
sp_blockchain::Error::UnknownBlock(format!("header not found: {}", hash))
|
||||
})
|
||||
}
|
||||
|
||||
fn insert_header_metadata(&self, _hash: Block::Hash, _metadata: CachedHeaderMetadata<Block>) {
|
||||
@@ -389,17 +414,27 @@ impl<Block: BlockT> HeaderMetadata<Block> for Blockchain<Block> {
|
||||
}
|
||||
|
||||
impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> {
|
||||
fn body(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
|
||||
fn body(
|
||||
&self,
|
||||
id: BlockId<Block>,
|
||||
) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
|
||||
Ok(self.id(id).and_then(|hash| {
|
||||
self.storage.read().blocks.get(&hash)
|
||||
self.storage
|
||||
.read()
|
||||
.blocks
|
||||
.get(&hash)
|
||||
.and_then(|b| b.extrinsics().map(|x| x.to_vec()))
|
||||
}))
|
||||
}
|
||||
|
||||
fn justifications(&self, id: BlockId<Block>) -> sp_blockchain::Result<Option<Justifications>> {
|
||||
Ok(self.id(id).and_then(|hash| self.storage.read().blocks.get(&hash).and_then(|b|
|
||||
b.justifications().map(|x| x.clone()))
|
||||
))
|
||||
Ok(self.id(id).and_then(|hash| {
|
||||
self.storage
|
||||
.read()
|
||||
.blocks
|
||||
.get(&hash)
|
||||
.and_then(|b| b.justifications().map(|x| x.clone()))
|
||||
}))
|
||||
}
|
||||
|
||||
fn last_finalized(&self) -> sp_blockchain::Result<Block::Hash> {
|
||||
@@ -418,16 +453,13 @@ impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn indexed_transaction(
|
||||
&self,
|
||||
_hash: &Block::Hash,
|
||||
) -> sp_blockchain::Result<Option<Vec<u8>>> {
|
||||
fn indexed_transaction(&self, _hash: &Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>> {
|
||||
unimplemented!("Not supported by the in-mem backend.")
|
||||
}
|
||||
|
||||
fn block_indexed_body(
|
||||
&self,
|
||||
_id: BlockId<Block>
|
||||
_id: BlockId<Block>,
|
||||
) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>> {
|
||||
unimplemented!("Not supported by the in-mem backend.")
|
||||
}
|
||||
@@ -444,9 +476,13 @@ impl<Block: BlockT> backend::AuxStore for Blockchain<Block> {
|
||||
'a,
|
||||
'b: 'a,
|
||||
'c: 'a,
|
||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()> {
|
||||
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||
>(
|
||||
&self,
|
||||
insert: I,
|
||||
delete: D,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
let mut storage = self.storage.write();
|
||||
for (k, v) in insert {
|
||||
storage.aux.insert(k.to_vec(), v.to_vec());
|
||||
@@ -463,8 +499,8 @@ impl<Block: BlockT> backend::AuxStore for Blockchain<Block> {
|
||||
}
|
||||
|
||||
impl<Block: BlockT> light::Storage<Block> for Blockchain<Block>
|
||||
where
|
||||
Block::Hash: From<[u8; 32]>,
|
||||
where
|
||||
Block::Hash: From<[u8; 32]>,
|
||||
{
|
||||
fn import_header(
|
||||
&self,
|
||||
@@ -507,8 +543,14 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
|
||||
_cht_size: NumberFor<Block>,
|
||||
block: NumberFor<Block>,
|
||||
) -> sp_blockchain::Result<Option<Block::Hash>> {
|
||||
self.storage.read().header_cht_roots.get(&block).cloned()
|
||||
.ok_or_else(|| sp_blockchain::Error::Backend(format!("Header CHT for block {} not exists", block)))
|
||||
self.storage
|
||||
.read()
|
||||
.header_cht_roots
|
||||
.get(&block)
|
||||
.cloned()
|
||||
.ok_or_else(|| {
|
||||
sp_blockchain::Error::Backend(format!("Header CHT for block {} not exists", block))
|
||||
})
|
||||
.map(Some)
|
||||
}
|
||||
|
||||
@@ -517,8 +559,17 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
|
||||
_cht_size: NumberFor<Block>,
|
||||
block: NumberFor<Block>,
|
||||
) -> sp_blockchain::Result<Option<Block::Hash>> {
|
||||
self.storage.read().changes_trie_cht_roots.get(&block).cloned()
|
||||
.ok_or_else(|| sp_blockchain::Error::Backend(format!("Changes trie CHT for block {} not exists", block)))
|
||||
self.storage
|
||||
.read()
|
||||
.changes_trie_cht_roots
|
||||
.get(&block)
|
||||
.cloned()
|
||||
.ok_or_else(|| {
|
||||
sp_blockchain::Error::Backend(format!(
|
||||
"Changes trie CHT for block {} not exists",
|
||||
block
|
||||
))
|
||||
})
|
||||
.map(Some)
|
||||
}
|
||||
}
|
||||
@@ -527,25 +578,30 @@ impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
|
||||
pub struct BlockImportOperation<Block: BlockT> {
|
||||
pending_block: Option<PendingBlock<Block>>,
|
||||
old_state: InMemoryBackend<HashFor<Block>>,
|
||||
new_state: Option<<InMemoryBackend<HashFor<Block>> as StateBackend<HashFor<Block>>>::Transaction>,
|
||||
new_state:
|
||||
Option<<InMemoryBackend<HashFor<Block>> as StateBackend<HashFor<Block>>>::Transaction>,
|
||||
aux: Vec<(Vec<u8>, Option<Vec<u8>>)>,
|
||||
finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>,
|
||||
set_head: Option<BlockId<Block>>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> BlockImportOperation<Block> where
|
||||
impl<Block: BlockT> BlockImportOperation<Block>
|
||||
where
|
||||
Block::Hash: Ord,
|
||||
{
|
||||
fn apply_storage(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash> {
|
||||
fn apply_storage(
|
||||
&mut self,
|
||||
storage: Storage,
|
||||
commit: bool,
|
||||
) -> sp_blockchain::Result<Block::Hash> {
|
||||
check_genesis_storage(&storage)?;
|
||||
|
||||
let child_delta = storage.children_default.iter()
|
||||
.map(|(_storage_key, child_content)|
|
||||
(
|
||||
&child_content.child_info,
|
||||
child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref())))
|
||||
)
|
||||
);
|
||||
let child_delta = storage.children_default.iter().map(|(_storage_key, child_content)| {
|
||||
(
|
||||
&child_content.child_info,
|
||||
child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))),
|
||||
)
|
||||
});
|
||||
|
||||
let (root, transaction) = self.old_state.full_storage_root(
|
||||
storage.top.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))),
|
||||
@@ -559,7 +615,8 @@ impl<Block: BlockT> BlockImportOperation<Block> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperation<Block> where
|
||||
impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperation<Block>
|
||||
where
|
||||
Block::Hash: Ord,
|
||||
{
|
||||
type State = InMemoryBackend<HashFor<Block>>;
|
||||
@@ -577,10 +634,8 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
state: NewBlockState,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
assert!(self.pending_block.is_none(), "Only one block per operation is allowed");
|
||||
self.pending_block = Some(PendingBlock {
|
||||
block: StoredBlock::new(header, body, justifications),
|
||||
state,
|
||||
});
|
||||
self.pending_block =
|
||||
Some(PendingBlock { block: StoredBlock::new(header, body, justifications), state });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -601,7 +656,11 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_genesis_state(&mut self, storage: Storage, commit: bool) -> sp_blockchain::Result<Block::Hash> {
|
||||
fn set_genesis_state(
|
||||
&mut self,
|
||||
storage: Storage,
|
||||
commit: bool,
|
||||
) -> sp_blockchain::Result<Block::Hash> {
|
||||
self.apply_storage(storage, commit)
|
||||
}
|
||||
|
||||
@@ -610,7 +669,8 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
}
|
||||
|
||||
fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()>
|
||||
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
|
||||
where
|
||||
I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>)>,
|
||||
{
|
||||
self.aux.append(&mut ops.into_iter().collect());
|
||||
Ok(())
|
||||
@@ -639,7 +699,10 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_transaction_index(&mut self, _index: Vec<IndexOperation>) -> sp_blockchain::Result<()> {
|
||||
fn update_transaction_index(
|
||||
&mut self,
|
||||
_index: Vec<IndexOperation>,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -648,13 +711,19 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
///
|
||||
/// > **Warning**: Doesn't support all the features necessary for a proper database. Only use this
|
||||
/// > struct for testing purposes. Do **NOT** use in production.
|
||||
pub struct Backend<Block: BlockT> where Block::Hash: Ord {
|
||||
pub struct Backend<Block: BlockT>
|
||||
where
|
||||
Block::Hash: Ord,
|
||||
{
|
||||
states: RwLock<HashMap<Block::Hash, InMemoryBackend<HashFor<Block>>>>,
|
||||
blockchain: Blockchain<Block>,
|
||||
import_lock: RwLock<()>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> Backend<Block> where Block::Hash: Ord {
|
||||
impl<Block: BlockT> Backend<Block>
|
||||
where
|
||||
Block::Hash: Ord,
|
||||
{
|
||||
/// Create a new instance of in-mem backend.
|
||||
pub fn new() -> Self {
|
||||
Backend {
|
||||
@@ -665,14 +734,21 @@ impl<Block: BlockT> Backend<Block> where Block::Hash: Ord {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT> backend::AuxStore for Backend<Block> where Block::Hash: Ord {
|
||||
impl<Block: BlockT> backend::AuxStore for Backend<Block>
|
||||
where
|
||||
Block::Hash: Ord,
|
||||
{
|
||||
fn insert_aux<
|
||||
'a,
|
||||
'b: 'a,
|
||||
'c: 'a,
|
||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
||||
>(&self, insert: I, delete: D) -> sp_blockchain::Result<()> {
|
||||
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||
>(
|
||||
&self,
|
||||
insert: I,
|
||||
delete: D,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
self.blockchain.insert_aux(insert, delete)
|
||||
}
|
||||
|
||||
@@ -681,7 +757,10 @@ impl<Block: BlockT> backend::AuxStore for Backend<Block> where Block::Hash: Ord
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash: Ord {
|
||||
impl<Block: BlockT> backend::Backend<Block> for Backend<Block>
|
||||
where
|
||||
Block::Hash: Ord,
|
||||
{
|
||||
type BlockImportOperation = BlockImportOperation<Block>;
|
||||
type Blockchain = Blockchain<Block>;
|
||||
type State = InMemoryBackend<HashFor<Block>>;
|
||||
@@ -708,10 +787,7 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn commit_operation(
|
||||
&self,
|
||||
operation: Self::BlockImportOperation,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
fn commit_operation(&self, operation: Self::BlockImportOperation) -> sp_blockchain::Result<()> {
|
||||
if !operation.finalized_blocks.is_empty() {
|
||||
for (block, justification) in operation.finalized_blocks {
|
||||
self.blockchain.finalize_header(block, justification)?;
|
||||
@@ -779,13 +855,13 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
||||
|
||||
fn state_at(&self, block: BlockId<Block>) -> sp_blockchain::Result<Self::State> {
|
||||
match block {
|
||||
BlockId::Hash(h) if h == Default::default() => {
|
||||
return Ok(Self::State::default());
|
||||
},
|
||||
BlockId::Hash(h) if h == Default::default() => return Ok(Self::State::default()),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
self.blockchain.id(block).and_then(|id| self.states.read().get(&id).cloned())
|
||||
self.blockchain
|
||||
.id(block)
|
||||
.and_then(|id| self.states.read().get(&id).cloned())
|
||||
.ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", block)))
|
||||
}
|
||||
|
||||
@@ -797,10 +873,7 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
||||
Ok((Zero::zero(), HashSet::new()))
|
||||
}
|
||||
|
||||
fn remove_leaf_block(
|
||||
&self,
|
||||
_hash: &Block::Hash,
|
||||
) -> sp_blockchain::Result<()> {
|
||||
fn remove_leaf_block(&self, _hash: &Block::Hash) -> sp_blockchain::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -811,9 +884,13 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
|
||||
|
||||
impl<Block: BlockT> backend::LocalBackend<Block> for Backend<Block> where Block::Hash: Ord {}
|
||||
|
||||
impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block> where Block::Hash: Ord {
|
||||
impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block>
|
||||
where
|
||||
Block::Hash: Ord,
|
||||
{
|
||||
fn is_local_state_available(&self, block: &BlockId<Block>) -> bool {
|
||||
self.blockchain.expect_block_number_from_id(block)
|
||||
self.blockchain
|
||||
.expect_block_number_from_id(block)
|
||||
.map(|num| num.is_zero())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
@@ -826,12 +903,15 @@ impl<Block: BlockT> backend::RemoteBackend<Block> for Backend<Block> where Block
|
||||
/// Check that genesis storage is valid.
|
||||
pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
|
||||
if storage.top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) {
|
||||
return Err(sp_blockchain::Error::InvalidState.into());
|
||||
return Err(sp_blockchain::Error::InvalidState.into())
|
||||
}
|
||||
|
||||
if storage.children_default.keys()
|
||||
.any(|child_key| !well_known_keys::is_child_storage_key(&child_key)) {
|
||||
return Err(sp_blockchain::Error::InvalidState.into());
|
||||
if storage
|
||||
.children_default
|
||||
.keys()
|
||||
.any(|child_key| !well_known_keys::is_child_storage_key(&child_key))
|
||||
{
|
||||
return Err(sp_blockchain::Error::InvalidState.into())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -839,10 +919,10 @@ pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{NewBlockState, in_mem::Blockchain};
|
||||
use crate::{in_mem::Blockchain, NewBlockState};
|
||||
use sp_api::{BlockId, HeaderT};
|
||||
use sp_runtime::{ConsensusEngineId, Justifications};
|
||||
use sp_blockchain::Backend;
|
||||
use sp_runtime::{ConsensusEngineId, Justifications};
|
||||
use substrate_test_runtime::{Block, Header, H256};
|
||||
|
||||
pub const ID1: ConsensusEngineId = *b"TST1";
|
||||
@@ -853,7 +933,13 @@ mod tests {
|
||||
0 => Default::default(),
|
||||
_ => header(number - 1).hash(),
|
||||
};
|
||||
Header::new(number, H256::from_low_u64_be(0), H256::from_low_u64_be(0), parent_hash, Default::default())
|
||||
Header::new(
|
||||
number,
|
||||
H256::from_low_u64_be(0),
|
||||
H256::from_low_u64_be(0),
|
||||
parent_hash,
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
fn test_blockchain() -> Blockchain<Block> {
|
||||
@@ -862,10 +948,18 @@ mod tests {
|
||||
let just1 = Some(Justifications::from((ID1, vec![1])));
|
||||
let just2 = None;
|
||||
let just3 = Some(Justifications::from((ID1, vec![3])));
|
||||
blockchain.insert(header(0).hash(), header(0), just0, None, NewBlockState::Final).unwrap();
|
||||
blockchain.insert(header(1).hash(), header(1), just1, None, NewBlockState::Final).unwrap();
|
||||
blockchain.insert(header(2).hash(), header(2), just2, None, NewBlockState::Best).unwrap();
|
||||
blockchain.insert(header(3).hash(), header(3), just3, None, NewBlockState::Final).unwrap();
|
||||
blockchain
|
||||
.insert(header(0).hash(), header(0), just0, None, NewBlockState::Final)
|
||||
.unwrap();
|
||||
blockchain
|
||||
.insert(header(1).hash(), header(1), just1, None, NewBlockState::Final)
|
||||
.unwrap();
|
||||
blockchain
|
||||
.insert(header(2).hash(), header(2), just2, None, NewBlockState::Best)
|
||||
.unwrap();
|
||||
blockchain
|
||||
.insert(header(3).hash(), header(3), just3, None, NewBlockState::Final)
|
||||
.unwrap();
|
||||
blockchain
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,11 @@
|
||||
|
||||
//! Helper for managing the set of available leaves in the chain for DB implementations.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::cmp::Reverse;
|
||||
use codec::{Decode, Encode};
|
||||
use sp_blockchain::{Error, Result};
|
||||
use sp_database::{Database, Transaction};
|
||||
use sp_runtime::traits::AtLeast32Bit;
|
||||
use codec::{Encode, Decode};
|
||||
use sp_blockchain::{Error, Result};
|
||||
use std::{cmp::Reverse, collections::BTreeMap};
|
||||
|
||||
type DbHash = sp_core::H256;
|
||||
|
||||
@@ -57,7 +56,7 @@ impl<H, N: Ord> FinalizationDisplaced<H, N> {
|
||||
}
|
||||
|
||||
/// Iterate over all displaced leaves.
|
||||
pub fn leaves(&self) -> impl IntoIterator<Item=&H> {
|
||||
pub fn leaves(&self) -> impl IntoIterator<Item = &H> {
|
||||
self.leaves.values().flatten()
|
||||
}
|
||||
}
|
||||
@@ -72,17 +71,14 @@ pub struct LeafSet<H, N> {
|
||||
pending_removed: Vec<H>,
|
||||
}
|
||||
|
||||
impl<H, N> LeafSet<H, N> where
|
||||
impl<H, N> LeafSet<H, N>
|
||||
where
|
||||
H: Clone + PartialEq + Decode + Encode,
|
||||
N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode,
|
||||
{
|
||||
/// Construct a new, blank leaf set.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
storage: BTreeMap::new(),
|
||||
pending_added: Vec::new(),
|
||||
pending_removed: Vec::new(),
|
||||
}
|
||||
Self { storage: BTreeMap::new(), pending_added: Vec::new(), pending_removed: Vec::new() }
|
||||
}
|
||||
|
||||
/// Read the leaf list from the DB, using given prefix for keys.
|
||||
@@ -98,14 +94,10 @@ impl<H, N> LeafSet<H, N> where
|
||||
for (number, hashes) in vals.into_iter() {
|
||||
storage.insert(Reverse(number), hashes);
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
Ok(Self {
|
||||
storage,
|
||||
pending_added: Vec::new(),
|
||||
pending_removed: Vec::new(),
|
||||
})
|
||||
Ok(Self { storage, pending_added: Vec::new(), pending_removed: Vec::new() })
|
||||
}
|
||||
|
||||
/// update the leaf list on import. returns a displaced leaf if there was one.
|
||||
@@ -119,10 +111,7 @@ impl<H, N> LeafSet<H, N> where
|
||||
self.pending_removed.push(parent_hash.clone());
|
||||
Some(ImportDisplaced {
|
||||
new_hash: hash.clone(),
|
||||
displaced: LeafSetItem {
|
||||
hash: parent_hash,
|
||||
number: new_number,
|
||||
},
|
||||
displaced: LeafSetItem { hash: parent_hash, number: new_number },
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -144,16 +133,15 @@ impl<H, N> LeafSet<H, N> where
|
||||
/// will be pruned soon afterwards anyway.
|
||||
pub fn finalize_height(&mut self, number: N) -> FinalizationDisplaced<H, N> {
|
||||
let boundary = if number == N::zero() {
|
||||
return FinalizationDisplaced { leaves: BTreeMap::new() };
|
||||
return FinalizationDisplaced { leaves: BTreeMap::new() }
|
||||
} else {
|
||||
number - N::one()
|
||||
};
|
||||
|
||||
let below_boundary = self.storage.split_off(&Reverse(boundary));
|
||||
self.pending_removed.extend(below_boundary.values().flat_map(|h| h.iter()).cloned());
|
||||
FinalizationDisplaced {
|
||||
leaves: below_boundary,
|
||||
}
|
||||
self.pending_removed
|
||||
.extend(below_boundary.values().flat_map(|h| h.iter()).cloned());
|
||||
FinalizationDisplaced { leaves: below_boundary }
|
||||
}
|
||||
|
||||
/// Undo all pending operations.
|
||||
@@ -169,7 +157,9 @@ impl<H, N> LeafSet<H, N> where
|
||||
/// Revert to the given block height by dropping all leaves in the leaf set
|
||||
/// with a block number higher than the target.
|
||||
pub fn revert(&mut self, best_hash: H, best_number: N) {
|
||||
let items = self.storage.iter()
|
||||
let items = self
|
||||
.storage
|
||||
.iter()
|
||||
.flat_map(|(number, hashes)| hashes.iter().map(move |h| (h.clone(), number.clone())))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -185,7 +175,8 @@ impl<H, N> LeafSet<H, N> where
|
||||
}
|
||||
|
||||
let best_number = Reverse(best_number);
|
||||
let leaves_contains_best = self.storage
|
||||
let leaves_contains_best = self
|
||||
.storage
|
||||
.get(&best_number)
|
||||
.map_or(false, |hashes| hashes.contains(&best_hash));
|
||||
|
||||
@@ -209,7 +200,12 @@ impl<H, N> LeafSet<H, N> where
|
||||
}
|
||||
|
||||
/// Write the leaf list to the database transaction.
|
||||
pub fn prepare_transaction(&mut self, tx: &mut Transaction<DbHash>, column: u32, prefix: &[u8]) {
|
||||
pub fn prepare_transaction(
|
||||
&mut self,
|
||||
tx: &mut Transaction<DbHash>,
|
||||
column: u32,
|
||||
prefix: &[u8],
|
||||
) {
|
||||
let leaves: Vec<_> = self.storage.iter().map(|(n, h)| (n.0.clone(), h.clone())).collect();
|
||||
tx.set_from_vec(column, prefix, leaves.encode());
|
||||
self.pending_added.clear();
|
||||
@@ -218,7 +214,9 @@ impl<H, N> LeafSet<H, N> where
|
||||
|
||||
/// Check if given block is a leaf.
|
||||
pub fn contains(&self, number: N, hash: H) -> bool {
|
||||
self.storage.get(&Reverse(number)).map_or(false, |hashes| hashes.contains(&hash))
|
||||
self.storage
|
||||
.get(&Reverse(number))
|
||||
.map_or(false, |hashes| hashes.contains(&hash))
|
||||
}
|
||||
|
||||
fn insert_leaf(&mut self, number: Reverse<N>, hash: H) {
|
||||
@@ -230,14 +228,18 @@ impl<H, N> LeafSet<H, N> where
|
||||
let mut empty = false;
|
||||
let removed = self.storage.get_mut(number).map_or(false, |leaves| {
|
||||
let mut found = false;
|
||||
leaves.retain(|h| if h == hash {
|
||||
found = true;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
leaves.retain(|h| {
|
||||
if h == hash {
|
||||
found = true;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
if leaves.is_empty() { empty = true }
|
||||
if leaves.is_empty() {
|
||||
empty = true
|
||||
}
|
||||
|
||||
found
|
||||
});
|
||||
@@ -255,7 +257,8 @@ pub struct Undo<'a, H: 'a, N: 'a> {
|
||||
inner: &'a mut LeafSet<H, N>,
|
||||
}
|
||||
|
||||
impl<'a, H: 'a, N: 'a> Undo<'a, H, N> where
|
||||
impl<'a, H: 'a, N: 'a> Undo<'a, H, N>
|
||||
where
|
||||
H: Clone + PartialEq + Decode + Encode,
|
||||
N: std::fmt::Debug + Clone + AtLeast32Bit + Decode + Encode,
|
||||
{
|
||||
@@ -329,7 +332,7 @@ mod tests {
|
||||
fn two_leaves_same_height_can_be_included() {
|
||||
let mut set = LeafSet::new();
|
||||
|
||||
set.import(1_1u32, 10u32,0u32);
|
||||
set.import(1_1u32, 10u32, 0u32);
|
||||
set.import(1_2, 10, 0);
|
||||
|
||||
assert!(set.storage.contains_key(&Reverse(10)));
|
||||
|
||||
@@ -21,30 +21,28 @@
|
||||
|
||||
pub mod backend;
|
||||
pub mod call_executor;
|
||||
pub mod client;
|
||||
pub mod cht;
|
||||
pub mod client;
|
||||
pub mod execution_extensions;
|
||||
pub mod in_mem;
|
||||
pub mod light;
|
||||
pub mod leaves;
|
||||
pub mod light;
|
||||
pub mod notifications;
|
||||
pub mod proof_provider;
|
||||
|
||||
pub use sp_blockchain as blockchain;
|
||||
pub use backend::*;
|
||||
pub use notifications::*;
|
||||
pub use call_executor::*;
|
||||
pub use client::*;
|
||||
pub use light::*;
|
||||
pub use notifications::*;
|
||||
pub use proof_provider::*;
|
||||
pub use sp_blockchain as blockchain;
|
||||
pub use sp_blockchain::HeaderBackend;
|
||||
|
||||
pub use sp_state_machine::{StorageProof, ExecutionStrategy};
|
||||
pub use sp_storage::{StorageData, StorageKey, PrefixedStorageKey, ChildInfo};
|
||||
pub use sp_state_machine::{ExecutionStrategy, StorageProof};
|
||||
pub use sp_storage::{ChildInfo, PrefixedStorageKey, StorageData, StorageKey};
|
||||
|
||||
/// Usage Information Provider interface
|
||||
///
|
||||
pub trait UsageProvider<Block: sp_runtime::traits::Block> {
|
||||
/// Get usage info about current client.
|
||||
fn usage_info(&self) -> ClientInfo<Block>;
|
||||
@@ -52,7 +50,7 @@ pub trait UsageProvider<Block: sp_runtime::traits::Block> {
|
||||
|
||||
/// Utility methods for the client.
|
||||
pub mod utils {
|
||||
use sp_blockchain::{HeaderBackend, HeaderMetadata, Error};
|
||||
use sp_blockchain::{Error, HeaderBackend, HeaderMetadata};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
@@ -66,19 +64,24 @@ pub mod utils {
|
||||
client: &'a T,
|
||||
current: Option<(Block::Hash, Block::Hash)>,
|
||||
) -> impl Fn(&Block::Hash, &Block::Hash) -> Result<bool, Error> + 'a
|
||||
where T: HeaderBackend<Block> + HeaderMetadata<Block, Error = Error>,
|
||||
where
|
||||
T: HeaderBackend<Block> + HeaderMetadata<Block, Error = Error>,
|
||||
{
|
||||
move |base, hash| {
|
||||
if base == hash { return Ok(false); }
|
||||
if base == hash {
|
||||
return Ok(false)
|
||||
}
|
||||
|
||||
let current = current.as_ref().map(|(c, p)| (c.borrow(), p.borrow()));
|
||||
|
||||
let mut hash = hash;
|
||||
if let Some((current_hash, current_parent_hash)) = current {
|
||||
if base == current_hash { return Ok(false); }
|
||||
if base == current_hash {
|
||||
return Ok(false)
|
||||
}
|
||||
if hash == current_hash {
|
||||
if base == current_parent_hash {
|
||||
return Ok(true);
|
||||
return Ok(true)
|
||||
} else {
|
||||
hash = current_parent_hash;
|
||||
}
|
||||
|
||||
@@ -18,23 +18,26 @@
|
||||
|
||||
//! Substrate light client interfaces
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::future::Future;
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
future::Future,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use sp_runtime::{
|
||||
traits::{
|
||||
Block as BlockT, Header as HeaderT, NumberFor,
|
||||
},
|
||||
generic::BlockId
|
||||
use crate::{
|
||||
backend::{AuxStore, NewBlockState},
|
||||
ProvideChtRoots, UsageInfo,
|
||||
};
|
||||
use sp_core::{ChangesTrieConfigurationRange, storage::PrefixedStorageKey};
|
||||
use sp_state_machine::StorageProof;
|
||||
use sp_blockchain::{
|
||||
HeaderMetadata, well_known_cache_keys, HeaderBackend, Cache as BlockchainCache,
|
||||
Error as ClientError, Result as ClientResult,
|
||||
well_known_cache_keys, Cache as BlockchainCache, Error as ClientError, HeaderBackend,
|
||||
HeaderMetadata, Result as ClientResult,
|
||||
};
|
||||
use crate::{backend::{AuxStore, NewBlockState}, UsageInfo, ProvideChtRoots};
|
||||
use sp_core::{storage::PrefixedStorageKey, ChangesTrieConfigurationRange};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, Header as HeaderT, NumberFor},
|
||||
};
|
||||
use sp_state_machine::StorageProof;
|
||||
|
||||
/// Remote call request.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
@@ -142,48 +145,48 @@ pub struct RemoteBodyRequest<Header: HeaderT> {
|
||||
/// is correct (see FetchedDataChecker) and return already checked data.
|
||||
pub trait Fetcher<Block: BlockT>: Send + Sync {
|
||||
/// Remote header future.
|
||||
type RemoteHeaderResult: Future<Output = Result<
|
||||
Block::Header,
|
||||
ClientError,
|
||||
>> + Unpin + Send + 'static;
|
||||
type RemoteHeaderResult: Future<Output = Result<Block::Header, ClientError>>
|
||||
+ Unpin
|
||||
+ Send
|
||||
+ 'static;
|
||||
/// Remote storage read future.
|
||||
type RemoteReadResult: Future<Output = Result<
|
||||
HashMap<Vec<u8>, Option<Vec<u8>>>,
|
||||
ClientError,
|
||||
>> + Unpin + Send + 'static;
|
||||
type RemoteReadResult: Future<Output = Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError>>
|
||||
+ Unpin
|
||||
+ Send
|
||||
+ 'static;
|
||||
/// Remote call result future.
|
||||
type RemoteCallResult: Future<Output = Result<
|
||||
Vec<u8>,
|
||||
ClientError,
|
||||
>> + Unpin + Send + 'static;
|
||||
type RemoteCallResult: Future<Output = Result<Vec<u8>, ClientError>> + Unpin + Send + 'static;
|
||||
/// Remote changes result future.
|
||||
type RemoteChangesResult: Future<Output = Result<
|
||||
Vec<(NumberFor<Block>, u32)>,
|
||||
ClientError,
|
||||
>> + Unpin + Send + 'static;
|
||||
type RemoteChangesResult: Future<Output = Result<Vec<(NumberFor<Block>, u32)>, ClientError>>
|
||||
+ Unpin
|
||||
+ Send
|
||||
+ 'static;
|
||||
/// Remote block body result future.
|
||||
type RemoteBodyResult: Future<Output = Result<
|
||||
Vec<Block::Extrinsic>,
|
||||
ClientError,
|
||||
>> + Unpin + Send + 'static;
|
||||
type RemoteBodyResult: Future<Output = Result<Vec<Block::Extrinsic>, ClientError>>
|
||||
+ Unpin
|
||||
+ Send
|
||||
+ 'static;
|
||||
|
||||
/// Fetch remote header.
|
||||
fn remote_header(&self, request: RemoteHeaderRequest<Block::Header>) -> Self::RemoteHeaderResult;
|
||||
/// Fetch remote storage value.
|
||||
fn remote_read(
|
||||
fn remote_header(
|
||||
&self,
|
||||
request: RemoteReadRequest<Block::Header>
|
||||
) -> Self::RemoteReadResult;
|
||||
request: RemoteHeaderRequest<Block::Header>,
|
||||
) -> Self::RemoteHeaderResult;
|
||||
/// Fetch remote storage value.
|
||||
fn remote_read(&self, request: RemoteReadRequest<Block::Header>) -> Self::RemoteReadResult;
|
||||
/// Fetch remote storage child value.
|
||||
fn remote_read_child(
|
||||
&self,
|
||||
request: RemoteReadChildRequest<Block::Header>
|
||||
request: RemoteReadChildRequest<Block::Header>,
|
||||
) -> Self::RemoteReadResult;
|
||||
/// Fetch remote call result.
|
||||
fn remote_call(&self, request: RemoteCallRequest<Block::Header>) -> Self::RemoteCallResult;
|
||||
/// Fetch remote changes ((block number, extrinsic index)) where given key has been changed
|
||||
/// at a given blocks range.
|
||||
fn remote_changes(&self, request: RemoteChangesRequest<Block::Header>) -> Self::RemoteChangesResult;
|
||||
fn remote_changes(
|
||||
&self,
|
||||
request: RemoteChangesRequest<Block::Header>,
|
||||
) -> Self::RemoteChangesResult;
|
||||
/// Fetch remote block body
|
||||
fn remote_body(&self, request: RemoteBodyRequest<Block::Header>) -> Self::RemoteBodyResult;
|
||||
}
|
||||
@@ -222,20 +225,22 @@ pub trait FetchChecker<Block: BlockT>: Send + Sync {
|
||||
fn check_changes_proof(
|
||||
&self,
|
||||
request: &RemoteChangesRequest<Block::Header>,
|
||||
proof: ChangesProof<Block::Header>
|
||||
proof: ChangesProof<Block::Header>,
|
||||
) -> ClientResult<Vec<(NumberFor<Block>, u32)>>;
|
||||
/// Check remote body proof.
|
||||
fn check_body_proof(
|
||||
&self,
|
||||
request: &RemoteBodyRequest<Block::Header>,
|
||||
body: Vec<Block::Extrinsic>
|
||||
body: Vec<Block::Extrinsic>,
|
||||
) -> ClientResult<Vec<Block::Extrinsic>>;
|
||||
}
|
||||
|
||||
|
||||
/// Light client blockchain storage.
|
||||
pub trait Storage<Block: BlockT>: AuxStore + HeaderBackend<Block>
|
||||
+ HeaderMetadata<Block, Error=ClientError> + ProvideChtRoots<Block>
|
||||
pub trait Storage<Block: BlockT>:
|
||||
AuxStore
|
||||
+ HeaderBackend<Block>
|
||||
+ HeaderMetadata<Block, Error = ClientError>
|
||||
+ ProvideChtRoots<Block>
|
||||
{
|
||||
/// Store new header. Should refuse to revert any finalized blocks.
|
||||
///
|
||||
@@ -280,10 +285,10 @@ pub enum LocalOrRemote<Data, Request> {
|
||||
/// locally, or fetches required data from remote node.
|
||||
pub trait RemoteBlockchain<Block: BlockT>: Send + Sync {
|
||||
/// Get block header.
|
||||
fn header(&self, id: BlockId<Block>) -> ClientResult<LocalOrRemote<
|
||||
Block::Header,
|
||||
RemoteHeaderRequest<Block::Header>,
|
||||
>>;
|
||||
fn header(
|
||||
&self,
|
||||
id: BlockId<Block>,
|
||||
) -> ClientResult<LocalOrRemote<Block::Header, RemoteHeaderRequest<Block::Header>>>;
|
||||
}
|
||||
|
||||
/// Returns future that resolves header either locally, or remotely.
|
||||
@@ -295,11 +300,8 @@ pub fn future_header<Block: BlockT, F: Fetcher<Block>>(
|
||||
use futures::future::{ready, Either, FutureExt};
|
||||
|
||||
match blockchain.header(id) {
|
||||
Ok(LocalOrRemote::Remote(request)) => Either::Left(
|
||||
fetcher
|
||||
.remote_header(request)
|
||||
.then(|header| ready(header.map(Some)))
|
||||
),
|
||||
Ok(LocalOrRemote::Remote(request)) =>
|
||||
Either::Left(fetcher.remote_header(request).then(|header| ready(header.map(Some)))),
|
||||
Ok(LocalOrRemote::Unknown) => Either::Right(ready(Ok(None))),
|
||||
Ok(LocalOrRemote::Local(local_header)) => Either::Right(ready(Ok(Some(local_header)))),
|
||||
Err(err) => Either::Right(ready(Err(err))),
|
||||
@@ -308,11 +310,11 @@ pub fn future_header<Block: BlockT, F: Fetcher<Block>>(
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use futures::future::Ready;
|
||||
use parking_lot::Mutex;
|
||||
use sp_blockchain::Error as ClientError;
|
||||
use sp_test_primitives::{Block, Header, Extrinsic};
|
||||
use super::*;
|
||||
use sp_test_primitives::{Block, Extrinsic, Header};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Not implemented on test node")]
|
||||
@@ -322,12 +324,11 @@ pub mod tests {
|
||||
fn into(self) -> ClientError {
|
||||
ClientError::Application(Box::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub type OkCallFetcher = Mutex<Vec<u8>>;
|
||||
|
||||
fn not_implemented_in_tests<T>() -> Ready<Result<T, ClientError>>
|
||||
{
|
||||
fn not_implemented_in_tests<T>() -> Ready<Result<T, ClientError>> {
|
||||
futures::future::ready(Err(MockError.into()))
|
||||
}
|
||||
|
||||
@@ -346,7 +347,10 @@ pub mod tests {
|
||||
not_implemented_in_tests()
|
||||
}
|
||||
|
||||
fn remote_read_child(&self, _request: RemoteReadChildRequest<Header>) -> Self::RemoteReadResult {
|
||||
fn remote_read_child(
|
||||
&self,
|
||||
_request: RemoteReadChildRequest<Header>,
|
||||
) -> Self::RemoteReadResult {
|
||||
not_implemented_in_tests()
|
||||
}
|
||||
|
||||
@@ -354,7 +358,10 @@ pub mod tests {
|
||||
futures::future::ready(Ok((*self.lock()).clone()))
|
||||
}
|
||||
|
||||
fn remote_changes(&self, _request: RemoteChangesRequest<Header>) -> Self::RemoteChangesResult {
|
||||
fn remote_changes(
|
||||
&self,
|
||||
_request: RemoteChangesRequest<Header>,
|
||||
) -> Self::RemoteChangesResult {
|
||||
not_implemented_in_tests()
|
||||
}
|
||||
|
||||
|
||||
@@ -19,15 +19,15 @@
|
||||
//! Storage notifications
|
||||
|
||||
use std::{
|
||||
collections::{HashSet, HashMap},
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use fnv::{FnvHashSet, FnvHashMap};
|
||||
use sp_core::storage::{StorageKey, StorageData};
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use prometheus_endpoint::{register, CounterVec, Opts, Registry, U64};
|
||||
use sp_core::storage::{StorageData, StorageKey};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use sp_utils::mpsc::{TracingUnboundedSender, TracingUnboundedReceiver, tracing_unbounded};
|
||||
use prometheus_endpoint::{Registry, CounterVec, Opts, U64, register};
|
||||
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
|
||||
|
||||
/// Storage change set
|
||||
#[derive(Debug)]
|
||||
@@ -40,29 +40,34 @@ pub struct StorageChangeSet {
|
||||
|
||||
impl StorageChangeSet {
|
||||
/// Convert the change set into iterator over storage items.
|
||||
pub fn iter<'a>(&'a self)
|
||||
-> impl Iterator<Item=(Option<&'a StorageKey>, &'a StorageKey, Option<&'a StorageData>)> + 'a {
|
||||
let top = self.changes
|
||||
pub fn iter<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (Option<&'a StorageKey>, &'a StorageKey, Option<&'a StorageData>)> + 'a
|
||||
{
|
||||
let top = self
|
||||
.changes
|
||||
.iter()
|
||||
.filter(move |&(key, _)| match self.filter {
|
||||
Some(ref filter) => filter.contains(key),
|
||||
None => true,
|
||||
})
|
||||
.map(move |(k,v)| (None, k, v.as_ref()));
|
||||
let children = self.child_changes
|
||||
.map(move |(k, v)| (None, k, v.as_ref()));
|
||||
let children = self
|
||||
.child_changes
|
||||
.iter()
|
||||
.filter_map(move |(sk, changes)|
|
||||
self.child_filters.as_ref().and_then(|cf|
|
||||
cf.get(sk).map(|filter| changes
|
||||
.filter_map(move |(sk, changes)| {
|
||||
self.child_filters.as_ref().and_then(|cf| {
|
||||
cf.get(sk).map(|filter| {
|
||||
changes
|
||||
.iter()
|
||||
.filter(move |&(key, _)| match filter {
|
||||
Some(ref filter) => filter.contains(key),
|
||||
None => true,
|
||||
})
|
||||
.map(move |(k,v)| (Some(sk), k, v.as_ref()))
|
||||
)
|
||||
)
|
||||
)
|
||||
.map(move |(k, v)| (Some(sk), k, v.as_ref()))
|
||||
})
|
||||
})
|
||||
})
|
||||
.flatten();
|
||||
top.chain(children)
|
||||
}
|
||||
@@ -82,15 +87,18 @@ pub struct StorageNotifications<Block: BlockT> {
|
||||
next_id: SubscriberId,
|
||||
wildcard_listeners: FnvHashSet<SubscriberId>,
|
||||
listeners: HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
||||
child_listeners: HashMap<StorageKey, (
|
||||
HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
||||
FnvHashSet<SubscriberId>
|
||||
)>,
|
||||
sinks: FnvHashMap<SubscriberId, (
|
||||
TracingUnboundedSender<(Block::Hash, StorageChangeSet)>,
|
||||
Option<HashSet<StorageKey>>,
|
||||
Option<HashMap<StorageKey, Option<HashSet<StorageKey>>>>,
|
||||
)>,
|
||||
child_listeners: HashMap<
|
||||
StorageKey,
|
||||
(HashMap<StorageKey, FnvHashSet<SubscriberId>>, FnvHashSet<SubscriberId>),
|
||||
>,
|
||||
sinks: FnvHashMap<
|
||||
SubscriberId,
|
||||
(
|
||||
TracingUnboundedSender<(Block::Hash, StorageChangeSet)>,
|
||||
Option<HashSet<StorageKey>>,
|
||||
Option<HashMap<StorageKey, Option<HashSet<StorageKey>>>>,
|
||||
),
|
||||
>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> Default for StorageNotifications<Block> {
|
||||
@@ -110,16 +118,17 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
/// Initialize a new StorageNotifications
|
||||
/// optionally pass a prometheus registry to send subscriber metrics to
|
||||
pub fn new(prometheus_registry: Option<Registry>) -> Self {
|
||||
let metrics = prometheus_registry.and_then(|r|
|
||||
let metrics = prometheus_registry.and_then(|r| {
|
||||
CounterVec::new(
|
||||
Opts::new(
|
||||
"storage_notification_subscribers",
|
||||
"Number of subscribers in storage notification sytem"
|
||||
"Number of subscribers in storage notification sytem",
|
||||
),
|
||||
&["action"], //added | removed
|
||||
).and_then(|g| register(g, &r))
|
||||
&["action"], // added | removed
|
||||
)
|
||||
.and_then(|g| register(g, &r))
|
||||
.ok()
|
||||
);
|
||||
});
|
||||
|
||||
StorageNotifications {
|
||||
metrics,
|
||||
@@ -137,17 +146,16 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
pub fn trigger(
|
||||
&mut self,
|
||||
hash: &Block::Hash,
|
||||
changeset: impl Iterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
||||
changeset: impl Iterator<Item = (Vec<u8>, Option<Vec<u8>>)>,
|
||||
child_changeset: impl Iterator<
|
||||
Item=(Vec<u8>, impl Iterator<Item=(Vec<u8>, Option<Vec<u8>>)>)
|
||||
Item = (Vec<u8>, impl Iterator<Item = (Vec<u8>, Option<Vec<u8>>)>),
|
||||
>,
|
||||
) {
|
||||
|
||||
let has_wildcard = !self.wildcard_listeners.is_empty();
|
||||
|
||||
// early exit if no listeners
|
||||
if !has_wildcard && self.listeners.is_empty() && self.child_listeners.is_empty() {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
let mut subscribers = self.wildcard_listeners.clone();
|
||||
@@ -193,24 +201,29 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
|
||||
// Don't send empty notifications
|
||||
if changes.is_empty() && child_changes.is_empty() {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
let changes = Arc::new(changes);
|
||||
let child_changes = Arc::new(child_changes);
|
||||
// Trigger the events
|
||||
|
||||
let to_remove = self.sinks
|
||||
let to_remove = self
|
||||
.sinks
|
||||
.iter()
|
||||
.filter_map(|(subscriber, &(ref sink, ref filter, ref child_filters))| {
|
||||
let should_remove = {
|
||||
if subscribers.contains(subscriber) {
|
||||
sink.unbounded_send((hash.clone(), StorageChangeSet {
|
||||
changes: changes.clone(),
|
||||
child_changes: child_changes.clone(),
|
||||
filter: filter.clone(),
|
||||
child_filters: child_filters.clone(),
|
||||
})).is_err()
|
||||
sink.unbounded_send((
|
||||
hash.clone(),
|
||||
StorageChangeSet {
|
||||
changes: changes.clone(),
|
||||
child_changes: child_changes.clone(),
|
||||
filter: filter.clone(),
|
||||
child_filters: child_filters.clone(),
|
||||
},
|
||||
))
|
||||
.is_err()
|
||||
} else {
|
||||
sink.is_closed()
|
||||
}
|
||||
@@ -221,7 +234,8 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect::<Vec<_>>();
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for sub_id in to_remove {
|
||||
self.remove_subscriber(sub_id);
|
||||
@@ -233,13 +247,12 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
filters: &Option<HashSet<StorageKey>>,
|
||||
listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
||||
wildcards: &mut FnvHashSet<SubscriberId>,
|
||||
){
|
||||
) {
|
||||
match filters {
|
||||
None => {
|
||||
wildcards.remove(subscriber);
|
||||
},
|
||||
Some(filters) => {
|
||||
|
||||
Some(filters) =>
|
||||
for key in filters.iter() {
|
||||
let remove_key = match listeners.get_mut(key) {
|
||||
Some(ref mut set) => {
|
||||
@@ -252,8 +265,7 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
if remove_key {
|
||||
listeners.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +279,6 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
);
|
||||
if let Some(child_filters) = child_filters.as_ref() {
|
||||
for (c_key, filters) in child_filters {
|
||||
|
||||
if let Some((listeners, wildcards)) = self.child_listeners.get_mut(&c_key) {
|
||||
Self::remove_subscriber_from(
|
||||
&subscriber,
|
||||
@@ -293,20 +304,24 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
filter_keys: &Option<impl AsRef<[StorageKey]>>,
|
||||
listeners: &mut HashMap<StorageKey, FnvHashSet<SubscriberId>>,
|
||||
wildcards: &mut FnvHashSet<SubscriberId>,
|
||||
) -> Option<HashSet<StorageKey>>
|
||||
{
|
||||
) -> Option<HashSet<StorageKey>> {
|
||||
match filter_keys {
|
||||
None => {
|
||||
wildcards.insert(current_id);
|
||||
None
|
||||
},
|
||||
Some(keys) => Some(keys.as_ref().iter().map(|key| {
|
||||
listeners
|
||||
.entry(key.clone())
|
||||
.or_insert_with(Default::default)
|
||||
.insert(current_id);
|
||||
key.clone()
|
||||
}).collect())
|
||||
Some(keys) => Some(
|
||||
keys.as_ref()
|
||||
.iter()
|
||||
.map(|key| {
|
||||
listeners
|
||||
.entry(key.clone())
|
||||
.or_insert_with(Default::default)
|
||||
.insert(current_id);
|
||||
key.clone()
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,21 +342,20 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
&mut self.wildcard_listeners,
|
||||
);
|
||||
let child_keys = filter_child_keys.map(|filter_child_keys| {
|
||||
filter_child_keys.iter().map(|(c_key, o_keys)| {
|
||||
let (c_listeners, c_wildcards) = self.child_listeners
|
||||
.entry(c_key.clone())
|
||||
.or_insert_with(Default::default);
|
||||
filter_child_keys
|
||||
.iter()
|
||||
.map(|(c_key, o_keys)| {
|
||||
let (c_listeners, c_wildcards) =
|
||||
self.child_listeners.entry(c_key.clone()).or_insert_with(Default::default);
|
||||
|
||||
(c_key.clone(), Self::listen_from(
|
||||
current_id,
|
||||
o_keys,
|
||||
&mut *c_listeners,
|
||||
&mut *c_wildcards,
|
||||
))
|
||||
}).collect()
|
||||
(
|
||||
c_key.clone(),
|
||||
Self::listen_from(current_id, o_keys, &mut *c_listeners, &mut *c_wildcards),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
|
||||
// insert sink
|
||||
let (tx, rx) = tracing_unbounded("mpsc_storage_notification_items");
|
||||
self.sinks.insert(current_id, (tx, keys, child_keys));
|
||||
@@ -356,8 +370,8 @@ impl<Block: BlockT> StorageNotifications<Block> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use sp_runtime::testing::{H256 as Hash, Block as RawBlock, ExtrinsicWrapper};
|
||||
use super::*;
|
||||
use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash};
|
||||
use std::iter::{empty, Empty};
|
||||
|
||||
type TestChangeSet = (
|
||||
@@ -369,10 +383,12 @@ mod tests {
|
||||
impl From<TestChangeSet> for StorageChangeSet {
|
||||
fn from(changes: TestChangeSet) -> Self {
|
||||
// warning hardcoded child trie wildcard to test upon
|
||||
let child_filters = Some([
|
||||
(StorageKey(vec![4]), None),
|
||||
(StorageKey(vec![5]), None),
|
||||
].iter().cloned().collect());
|
||||
let child_filters = Some(
|
||||
[(StorageKey(vec![4]), None), (StorageKey(vec![5]), None)]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
);
|
||||
StorageChangeSet {
|
||||
changes: Arc::new(changes.0),
|
||||
child_changes: Arc::new(changes.1),
|
||||
@@ -396,34 +412,40 @@ mod tests {
|
||||
// given
|
||||
let mut notifications = StorageNotifications::<Block>::default();
|
||||
let child_filter = [(StorageKey(vec![4]), None)];
|
||||
let mut recv = futures::executor::block_on_stream(
|
||||
notifications.listen(None, Some(&child_filter[..]))
|
||||
);
|
||||
let mut recv =
|
||||
futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter[..])));
|
||||
|
||||
// when
|
||||
let changeset = vec![
|
||||
(vec![2], Some(vec![3])),
|
||||
(vec![3], None),
|
||||
];
|
||||
let c_changeset_1 = vec![
|
||||
(vec![5], Some(vec![4])),
|
||||
(vec![6], None),
|
||||
];
|
||||
let changeset = vec![(vec![2], Some(vec![3])), (vec![3], None)];
|
||||
let c_changeset_1 = vec![(vec![5], Some(vec![4])), (vec![6], None)];
|
||||
let c_changeset = vec![(vec![4], c_changeset_1)];
|
||||
notifications.trigger(
|
||||
&Hash::from_low_u64_be(1),
|
||||
changeset.into_iter(),
|
||||
c_changeset.into_iter().map(|(a,b)| (a, b.into_iter())),
|
||||
c_changeset.into_iter().map(|(a, b)| (a, b.into_iter())),
|
||||
);
|
||||
|
||||
// then
|
||||
assert_eq!(recv.next().unwrap(), (Hash::from_low_u64_be(1), (vec![
|
||||
(StorageKey(vec![2]), Some(StorageData(vec![3]))),
|
||||
(StorageKey(vec![3]), None),
|
||||
], vec![(StorageKey(vec![4]), vec![
|
||||
(StorageKey(vec![5]), Some(StorageData(vec![4]))),
|
||||
(StorageKey(vec![6]), None),
|
||||
])]).into()));
|
||||
assert_eq!(
|
||||
recv.next().unwrap(),
|
||||
(
|
||||
Hash::from_low_u64_be(1),
|
||||
(
|
||||
vec![
|
||||
(StorageKey(vec![2]), Some(StorageData(vec![3]))),
|
||||
(StorageKey(vec![3]), None),
|
||||
],
|
||||
vec![(
|
||||
StorageKey(vec![4]),
|
||||
vec![
|
||||
(StorageKey(vec![5]), Some(StorageData(vec![4]))),
|
||||
(StorageKey(vec![6]), None),
|
||||
]
|
||||
)]
|
||||
)
|
||||
.into()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -432,44 +454,52 @@ mod tests {
|
||||
let mut notifications = StorageNotifications::<Block>::default();
|
||||
let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))];
|
||||
let mut recv1 = futures::executor::block_on_stream(
|
||||
notifications.listen(Some(&[StorageKey(vec![1])]), None)
|
||||
notifications.listen(Some(&[StorageKey(vec![1])]), None),
|
||||
);
|
||||
let mut recv2 = futures::executor::block_on_stream(
|
||||
notifications.listen(Some(&[StorageKey(vec![2])]), None)
|
||||
notifications.listen(Some(&[StorageKey(vec![2])]), None),
|
||||
);
|
||||
let mut recv3 = futures::executor::block_on_stream(
|
||||
notifications.listen(Some(&[]), Some(&child_filter))
|
||||
notifications.listen(Some(&[]), Some(&child_filter)),
|
||||
);
|
||||
|
||||
// when
|
||||
let changeset = vec![
|
||||
(vec![2], Some(vec![3])),
|
||||
(vec![1], None),
|
||||
];
|
||||
let c_changeset_1 = vec![
|
||||
(vec![5], Some(vec![4])),
|
||||
(vec![6], None),
|
||||
];
|
||||
let changeset = vec![(vec![2], Some(vec![3])), (vec![1], None)];
|
||||
let c_changeset_1 = vec![(vec![5], Some(vec![4])), (vec![6], None)];
|
||||
|
||||
let c_changeset = vec![(vec![4], c_changeset_1)];
|
||||
notifications.trigger(
|
||||
&Hash::from_low_u64_be(1),
|
||||
changeset.into_iter(),
|
||||
c_changeset.into_iter().map(|(a,b)| (a, b.into_iter())),
|
||||
c_changeset.into_iter().map(|(a, b)| (a, b.into_iter())),
|
||||
);
|
||||
|
||||
// then
|
||||
assert_eq!(recv1.next().unwrap(), (Hash::from_low_u64_be(1), (vec![
|
||||
(StorageKey(vec![1]), None),
|
||||
], vec![]).into()));
|
||||
assert_eq!(recv2.next().unwrap(), (Hash::from_low_u64_be(1), (vec![
|
||||
(StorageKey(vec![2]), Some(StorageData(vec![3]))),
|
||||
], vec![]).into()));
|
||||
assert_eq!(recv3.next().unwrap(), (Hash::from_low_u64_be(1), (vec![],
|
||||
vec![
|
||||
(StorageKey(vec![4]), vec![(StorageKey(vec![5]), Some(StorageData(vec![4])))]),
|
||||
]).into()));
|
||||
|
||||
assert_eq!(
|
||||
recv1.next().unwrap(),
|
||||
(Hash::from_low_u64_be(1), (vec![(StorageKey(vec![1]), None),], vec![]).into())
|
||||
);
|
||||
assert_eq!(
|
||||
recv2.next().unwrap(),
|
||||
(
|
||||
Hash::from_low_u64_be(1),
|
||||
(vec![(StorageKey(vec![2]), Some(StorageData(vec![3]))),], vec![]).into()
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
recv3.next().unwrap(),
|
||||
(
|
||||
Hash::from_low_u64_be(1),
|
||||
(
|
||||
vec![],
|
||||
vec![(
|
||||
StorageKey(vec![4]),
|
||||
vec![(StorageKey(vec![5]), Some(StorageData(vec![4])))]
|
||||
),]
|
||||
)
|
||||
.into()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -479,27 +509,21 @@ mod tests {
|
||||
{
|
||||
let child_filter = [(StorageKey(vec![4]), Some(vec![StorageKey(vec![5])]))];
|
||||
let _recv1 = futures::executor::block_on_stream(
|
||||
notifications.listen(Some(&[StorageKey(vec![1])]), None)
|
||||
notifications.listen(Some(&[StorageKey(vec![1])]), None),
|
||||
);
|
||||
let _recv2 = futures::executor::block_on_stream(
|
||||
notifications.listen(Some(&[StorageKey(vec![2])]), None)
|
||||
);
|
||||
let _recv3 = futures::executor::block_on_stream(
|
||||
notifications.listen(None, None)
|
||||
);
|
||||
let _recv4 = futures::executor::block_on_stream(
|
||||
notifications.listen(None, Some(&child_filter))
|
||||
notifications.listen(Some(&[StorageKey(vec![2])]), None),
|
||||
);
|
||||
let _recv3 = futures::executor::block_on_stream(notifications.listen(None, None));
|
||||
let _recv4 =
|
||||
futures::executor::block_on_stream(notifications.listen(None, Some(&child_filter)));
|
||||
assert_eq!(notifications.listeners.len(), 2);
|
||||
assert_eq!(notifications.wildcard_listeners.len(), 2);
|
||||
assert_eq!(notifications.child_listeners.len(), 1);
|
||||
}
|
||||
|
||||
// when
|
||||
let changeset = vec![
|
||||
(vec![2], Some(vec![3])),
|
||||
(vec![1], None),
|
||||
];
|
||||
let changeset = vec![(vec![2], Some(vec![3])), (vec![1], None)];
|
||||
let c_changeset = empty::<(_, Empty<_>)>();
|
||||
notifications.trigger(&Hash::from_low_u64_be(1), changeset.into_iter(), c_changeset);
|
||||
|
||||
|
||||
@@ -17,12 +17,9 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! Proof utilities
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT},
|
||||
};
|
||||
use crate::{StorageProof, ChangesProof};
|
||||
use sp_storage::{ChildInfo, StorageKey, PrefixedStorageKey};
|
||||
use crate::{ChangesProof, StorageProof};
|
||||
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||
use sp_storage::{ChildInfo, PrefixedStorageKey, StorageKey};
|
||||
|
||||
/// Interface for providing block proving utilities.
|
||||
pub trait ProofProvider<Block: BlockT> {
|
||||
@@ -30,7 +27,7 @@ pub trait ProofProvider<Block: BlockT> {
|
||||
fn read_proof(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
keys: &mut dyn Iterator<Item=&[u8]>,
|
||||
keys: &mut dyn Iterator<Item = &[u8]>,
|
||||
) -> sp_blockchain::Result<StorageProof>;
|
||||
|
||||
/// Reads child storage value at a given block + storage_key + key, returning
|
||||
@@ -39,7 +36,7 @@ pub trait ProofProvider<Block: BlockT> {
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
child_info: &ChildInfo,
|
||||
keys: &mut dyn Iterator<Item=&[u8]>,
|
||||
keys: &mut dyn Iterator<Item = &[u8]>,
|
||||
) -> sp_blockchain::Result<StorageProof>;
|
||||
|
||||
/// Execute a call to a contract on top of state in a block of given hash
|
||||
@@ -53,7 +50,10 @@ pub trait ProofProvider<Block: BlockT> {
|
||||
call_data: &[u8],
|
||||
) -> sp_blockchain::Result<(Vec<u8>, StorageProof)>;
|
||||
/// Reads given header and generates CHT-based header proof.
|
||||
fn header_proof(&self, id: &BlockId<Block>) -> sp_blockchain::Result<(Block::Header, StorageProof)>;
|
||||
fn header_proof(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
) -> sp_blockchain::Result<(Block::Header, StorageProof)>;
|
||||
|
||||
/// Get proof for computation of (block, extrinsic) pairs where key has been changed at given blocks range.
|
||||
/// `min` is the hash of the first block, which changes trie root is known to the requester - when we're using
|
||||
|
||||
Reference in New Issue
Block a user