Kill the light client, CHTs and change tries. (#10080)

* Remove light client, change tries and CHTs

* Update tests

* fmt

* Restore changes_root

* Fixed benches

* Cargo fmt

* fmt

* fmt
This commit is contained in:
Arkadiy Paronyan
2021-11-12 14:15:01 +01:00
committed by GitHub
parent 112b7dac47
commit 4cbbf0cf43
141 changed files with 532 additions and 17807 deletions
+8 -19
View File
@@ -30,9 +30,8 @@ use log::info;
use prometheus_endpoint::Registry;
use sc_chain_spec::get_extension;
use sc_client_api::{
execution_extensions::ExecutionExtensions, light::RemoteBlockchain,
proof_provider::ProofProvider, BadBlocks, BlockBackend, BlockchainEvents, ExecutorProvider,
ForkBlocks, StorageProvider, UsageProvider,
execution_extensions::ExecutionExtensions, proof_provider::ProofProvider, BadBlocks,
BlockBackend, BlockchainEvents, ExecutorProvider, ForkBlocks, StorageProvider, UsageProvider,
};
use sc_client_db::{Backend, DatabaseSettings};
use sc_consensus::import_queue::ImportQueue;
@@ -40,7 +39,7 @@ use sc_executor::RuntimeVersionOf;
use sc_keystore::LocalKeystore;
use sc_network::{
block_request_handler::{self, BlockRequestHandler},
config::{OnDemand, Role, SyncMode},
config::{Role, SyncMode},
light_client_requests::{self, handler::LightClientRequestHandler},
state_request_handler::{self, StateRequestHandler},
warp_request_handler::{self, RequestHandler as WarpSyncRequestHandler, WarpSyncProvider},
@@ -381,23 +380,19 @@ where
pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> {
/// The service configuration.
pub config: Configuration,
/// A shared client returned by `new_full_parts`/`new_light_parts`.
/// A shared client returned by `new_full_parts`.
pub client: Arc<TCl>,
/// A shared backend returned by `new_full_parts`/`new_light_parts`.
/// A shared backend returned by `new_full_parts`.
pub backend: Arc<Backend>,
/// A task manager returned by `new_full_parts`/`new_light_parts`.
/// A task manager returned by `new_full_parts`.
pub task_manager: &'a mut TaskManager,
/// A shared keystore returned by `new_full_parts`/`new_light_parts`.
/// A shared keystore returned by `new_full_parts`.
pub keystore: SyncCryptoStorePtr,
/// An optional, shared data fetcher for light clients.
pub on_demand: Option<Arc<OnDemand<TBl>>>,
/// A shared transaction pool.
pub transaction_pool: Arc<TExPool>,
/// A RPC extension builder. Use `NoopRpcExtensionBuilder` if you just want to pass in the
/// extensions directly.
pub rpc_extensions_builder: Box<dyn RpcExtensionBuilder<Output = TRpc> + Send>,
/// An optional, shared remote blockchain instance. Used for light clients.
pub remote_blockchain: Option<Arc<dyn RemoteBlockchain<TBl>>>,
/// A shared network instance.
pub network: Arc<NetworkService<TBl, <TBl as BlockT>::Hash>>,
/// A Sender for RPC requests.
@@ -475,12 +470,10 @@ where
mut config,
task_manager,
client,
on_demand: _,
backend,
keystore,
transaction_pool,
rpc_extensions_builder,
remote_blockchain: _,
network,
system_rpc_tx,
telemetry,
@@ -725,7 +718,7 @@ where
pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> {
/// The service configuration.
pub config: &'a Configuration,
/// A shared client returned by `new_full_parts`/`new_light_parts`.
/// A shared client returned by `new_full_parts`.
pub client: Arc<TCl>,
/// A shared transaction pool.
pub transaction_pool: Arc<TExPool>,
@@ -733,8 +726,6 @@ pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> {
pub spawn_handle: SpawnTaskHandle,
/// An import queue.
pub import_queue: TImpQu,
/// An optional, shared data fetcher for light clients.
pub on_demand: Option<Arc<OnDemand<TBl>>>,
/// A block announce validator builder.
pub block_announce_validator_builder:
Option<Box<dyn FnOnce(Arc<TCl>) -> Box<dyn BlockAnnounceValidator<TBl> + Send> + Send>>,
@@ -773,7 +764,6 @@ where
transaction_pool,
spawn_handle,
import_queue,
on_demand,
block_announce_validator_builder,
warp_sync,
} = params;
@@ -869,7 +859,6 @@ where
},
network_config: config.network.clone(),
chain: client.clone(),
on_demand,
transaction_pool: transaction_pool_adapter as _,
import_queue: Box::new(import_queue),
protocol_id,
@@ -26,10 +26,7 @@ use sp_core::{
NativeOrEncoded, NeverNativeValue,
};
use sp_externalities::Extensions;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, NumberFor},
};
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
use sp_state_machine::{
self, backend::Backend as _, ExecutionManager, ExecutionStrategy, Ext, OverlayedChanges,
StateMachine, StorageProof,
@@ -153,8 +150,6 @@ where
extensions: Option<Extensions>,
) -> sp_blockchain::Result<Vec<u8>> {
let mut changes = OverlayedChanges::default();
let changes_trie =
backend::changes_tries_state_at_block(at, self.backend.changes_trie_storage())?;
let state = self.backend.state_at(*at)?;
let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
let runtime_code =
@@ -168,7 +163,6 @@ where
let return_data = StateMachine::new(
&state,
changes_trie,
&mut changes,
&self.executor,
method,
@@ -208,8 +202,6 @@ where
where
ExecutionManager<EM>: Clone,
{
let changes_trie_state =
backend::changes_tries_state_at_block(at, self.backend.changes_trie_storage())?;
let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut());
let state = self.backend.state_at(*at)?;
@@ -243,7 +235,6 @@ where
let mut state_machine = StateMachine::new(
&backend,
changes_trie_state,
changes,
&self.executor,
method,
@@ -262,7 +253,6 @@ where
None => {
let mut state_machine = StateMachine::new(
&state,
changes_trie_state,
changes,
&self.executor,
method,
@@ -286,11 +276,9 @@ where
fn runtime_version(&self, id: &BlockId<Block>) -> sp_blockchain::Result<RuntimeVersion> {
let mut overlay = OverlayedChanges::default();
let changes_trie_state =
backend::changes_tries_state_at_block(id, self.backend.changes_trie_storage())?;
let state = self.backend.state_at(*id)?;
let mut cache = StorageTransactionCache::<Block, B::State>::default();
let mut ext = Ext::new(&mut overlay, &mut cache, &state, changes_trie_state, None);
let mut ext = Ext::new(&mut overlay, &mut cache, &state, None);
let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state);
let runtime_code =
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
@@ -317,7 +305,7 @@ where
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
let runtime_code = self.check_override(runtime_code, at)?;
sp_state_machine::prove_execution_on_trie_backend::<_, _, NumberFor<Block>, _, _>(
sp_state_machine::prove_execution_on_trie_backend(
&trie_backend,
&mut Default::default(),
&self.executor,
+16 -385
View File
@@ -23,7 +23,6 @@ use super::{
genesis,
};
use codec::{Decode, Encode};
use hash_db::Prefix;
use log::{info, trace, warn};
use parking_lot::{Mutex, RwLock};
use prometheus_endpoint::Registry;
@@ -31,18 +30,15 @@ use rand::Rng;
use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider, RecordProof};
use sc_client_api::{
backend::{
self, apply_aux, changes_tries_state_at_block, BlockImportOperation, ClientImportOperation,
Finalizer, ImportSummary, LockImportRun, NewBlockState, PrunableStateChangesTrieStorage,
StorageProvider,
self, apply_aux, BlockImportOperation, ClientImportOperation, Finalizer, ImportSummary,
LockImportRun, NewBlockState, StorageProvider,
},
cht,
client::{
BadBlocks, BlockBackend, BlockImportNotification, BlockOf, BlockchainEvents, ClientInfo,
FinalityNotification, FinalityNotifications, ForkBlocks, ImportNotifications,
ProvideUncles,
},
execution_extensions::ExecutionExtensions,
light::ChangesProof,
notifications::{StorageEventStream, StorageNotifications},
CallExecutor, ExecutorProvider, KeyIterator, ProofProvider, UsageProvider,
};
@@ -56,39 +52,36 @@ use sp_api::{
ProvideRuntimeApi,
};
use sp_blockchain::{
self as blockchain, well_known_cache_keys::Id as CacheKeyId, Backend as ChainBackend, Cache,
CachedHeaderMetadata, Error, HeaderBackend as ChainHeaderBackend, HeaderMetadata, ProvideCache,
self as blockchain, well_known_cache_keys::Id as CacheKeyId, Backend as ChainBackend,
CachedHeaderMetadata, Error, HeaderBackend as ChainHeaderBackend, HeaderMetadata,
};
use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError};
use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender};
use sp_core::{
convert_hash,
storage::{
well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, StorageChild, StorageData,
StorageKey,
},
ChangesTrieConfiguration, NativeOrEncoded,
NativeOrEncoded,
};
#[cfg(feature = "test-helpers")]
use sp_keystore::SyncCryptoStorePtr;
use sp_runtime::{
generic::{BlockId, DigestItem, SignedBlock},
generic::{BlockId, SignedBlock},
traits::{
Block as BlockT, DigestFor, HashFor, Header as HeaderT, NumberFor, One,
SaturatedConversion, Zero,
Block as BlockT, HashFor, Header as HeaderT, NumberFor, One, SaturatedConversion, Zero,
},
BuildStorage, Justification, Justifications,
BuildStorage, Digest, Justification, Justifications,
};
use sp_state_machine::{
key_changes, key_changes_proof, prove_child_read, prove_range_read_with_child_with_size,
prove_read, read_range_proof_check_with_child_on_proving_backend, Backend as StateBackend,
ChangesTrieAnchorBlockId, ChangesTrieConfigurationRange, ChangesTrieRootsStorage,
ChangesTrieStorage, DBValue, KeyValueStates, KeyValueStorageLevel, MAX_NESTED_TRIE_DEPTH,
prove_child_read, prove_range_read_with_child_with_size, prove_read,
read_range_proof_check_with_child_on_proving_backend, Backend as StateBackend, KeyValueStates,
KeyValueStorageLevel, MAX_NESTED_TRIE_DEPTH,
};
use sp_trie::{CompactProof, StorageProof};
use std::{
collections::{BTreeMap, HashMap, HashSet},
collections::{HashMap, HashSet},
marker::PhantomData,
panic::UnwindSafe,
path::PathBuf,
@@ -413,250 +406,6 @@ where
self.executor.runtime_version(id)
}
/// Reads given header and generates CHT-based header proof for CHT of given size.
pub fn header_proof_with_cht_size(
&self,
id: &BlockId<Block>,
cht_size: NumberFor<Block>,
) -> sp_blockchain::Result<(Block::Header, StorageProof)> {
let proof_error = || {
sp_blockchain::Error::Backend(format!("Failed to generate header proof for {:?}", id))
};
let header = self.backend.blockchain().expect_header(*id)?;
let block_num = *header.number();
let cht_num = cht::block_to_cht_number(cht_size, block_num).ok_or_else(proof_error)?;
let cht_start = cht::start_number(cht_size, cht_num);
let mut current_num = cht_start;
let cht_range = ::std::iter::from_fn(|| {
let old_current_num = current_num;
current_num = current_num + One::one();
Some(old_current_num)
});
let headers = cht_range.map(|num| self.block_hash(num));
let proof = cht::build_proof::<Block::Header, HashFor<Block>, _, _>(
cht_size,
cht_num,
std::iter::once(block_num),
headers,
)?;
Ok((header, proof))
}
/// Does the same work as `key_changes_proof`, but assumes that CHTs are of passed size.
pub fn key_changes_proof_with_cht_size(
&self,
first: Block::Hash,
last: Block::Hash,
min: Block::Hash,
max: Block::Hash,
storage_key: Option<&PrefixedStorageKey>,
key: &StorageKey,
cht_size: NumberFor<Block>,
) -> sp_blockchain::Result<ChangesProof<Block::Header>> {
struct AccessedRootsRecorder<'a, Block: BlockT> {
storage: &'a dyn ChangesTrieStorage<HashFor<Block>, NumberFor<Block>>,
min: NumberFor<Block>,
required_roots_proofs: Mutex<BTreeMap<NumberFor<Block>, Block::Hash>>,
}
impl<'a, Block: BlockT> ChangesTrieRootsStorage<HashFor<Block>, NumberFor<Block>>
for AccessedRootsRecorder<'a, Block>
{
fn build_anchor(
&self,
hash: Block::Hash,
) -> Result<ChangesTrieAnchorBlockId<Block::Hash, NumberFor<Block>>, String> {
self.storage.build_anchor(hash)
}
fn root(
&self,
anchor: &ChangesTrieAnchorBlockId<Block::Hash, NumberFor<Block>>,
block: NumberFor<Block>,
) -> Result<Option<Block::Hash>, String> {
let root = self.storage.root(anchor, block)?;
if block < self.min {
if let Some(ref root) = root {
self.required_roots_proofs.lock().insert(block, root.clone());
}
}
Ok(root)
}
}
impl<'a, Block: BlockT> ChangesTrieStorage<HashFor<Block>, NumberFor<Block>>
for AccessedRootsRecorder<'a, Block>
{
fn as_roots_storage(
&self,
) -> &dyn sp_state_machine::ChangesTrieRootsStorage<HashFor<Block>, NumberFor<Block>> {
self
}
fn with_cached_changed_keys(
&self,
root: &Block::Hash,
functor: &mut dyn FnMut(&HashMap<Option<PrefixedStorageKey>, HashSet<Vec<u8>>>),
) -> bool {
self.storage.with_cached_changed_keys(root, functor)
}
fn get(&self, key: &Block::Hash, prefix: Prefix) -> Result<Option<DBValue>, String> {
self.storage.get(key, prefix)
}
}
let first_number =
self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(first))?;
let (storage, configs) = self.require_changes_trie(first_number, last, true)?;
let min_number =
self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(min))?;
let recording_storage = AccessedRootsRecorder::<Block> {
storage: storage.storage(),
min: min_number,
required_roots_proofs: Mutex::new(BTreeMap::new()),
};
let max_number = std::cmp::min(
self.backend.blockchain().info().best_number,
self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(max))?,
);
// fetch key changes proof
let mut proof = Vec::new();
for (config_zero, config_end, config) in configs {
let last_number =
self.backend.blockchain().expect_block_number_from_id(&BlockId::Hash(last))?;
let config_range = ChangesTrieConfigurationRange {
config: &config,
zero: config_zero,
end: config_end.map(|(config_end_number, _)| config_end_number),
};
let proof_range = key_changes_proof::<HashFor<Block>, _>(
config_range,
&recording_storage,
first_number,
&ChangesTrieAnchorBlockId { hash: convert_hash(&last), number: last_number },
max_number,
storage_key,
&key.0,
)
.map_err(|err| sp_blockchain::Error::ChangesTrieAccessFailed(err))?;
proof.extend(proof_range);
}
// now gather proofs for all changes tries roots that were touched during key_changes_proof
// execution AND are unknown (i.e. replaced with CHT) to the requester
let roots = recording_storage.required_roots_proofs.into_inner();
let roots_proof = self.changes_trie_roots_proof(cht_size, roots.keys().cloned())?;
Ok(ChangesProof {
max_block: max_number,
proof,
roots: roots.into_iter().map(|(n, h)| (n, convert_hash(&h))).collect(),
roots_proof,
})
}
/// Generate CHT-based proof for roots of changes tries at given blocks.
fn changes_trie_roots_proof<I: IntoIterator<Item = NumberFor<Block>>>(
&self,
cht_size: NumberFor<Block>,
blocks: I,
) -> sp_blockchain::Result<StorageProof> {
// most probably we have touched several changes tries that are parts of the single CHT
// => GroupBy changes tries by CHT number and then gather proof for the whole group at once
let mut proofs = Vec::new();
cht::for_each_cht_group::<Block::Header, _, _, _>(
cht_size,
blocks,
|_, cht_num, cht_blocks| {
let cht_proof =
self.changes_trie_roots_proof_at_cht(cht_size, cht_num, cht_blocks)?;
proofs.push(cht_proof);
Ok(())
},
(),
)?;
Ok(StorageProof::merge(proofs))
}
/// Generates CHT-based proof for roots of changes tries at given blocks
/// (that are part of single CHT).
fn changes_trie_roots_proof_at_cht(
&self,
cht_size: NumberFor<Block>,
cht_num: NumberFor<Block>,
blocks: Vec<NumberFor<Block>>,
) -> sp_blockchain::Result<StorageProof> {
let cht_start = cht::start_number(cht_size, cht_num);
let mut current_num = cht_start;
let cht_range = ::std::iter::from_fn(|| {
let old_current_num = current_num;
current_num = current_num + One::one();
Some(old_current_num)
});
let roots = cht_range.map(|num| {
self.header(&BlockId::Number(num)).map(|block| {
block
.and_then(|block| block.digest().log(DigestItem::as_changes_trie_root).cloned())
})
});
let proof = cht::build_proof::<Block::Header, HashFor<Block>, _, _>(
cht_size, cht_num, blocks, roots,
)?;
Ok(proof)
}
/// Returns changes trie storage and all configurations that have been active
/// in the range [first; last].
///
/// Configurations are returned in descending order (and obviously never overlap).
/// If fail_if_disabled is false, returns maximal consequent configurations ranges,
/// starting from last and stopping on either first, or when CT have been disabled.
/// If fail_if_disabled is true, fails when there's a subrange where CT have been disabled
/// inside first..last blocks range.
fn require_changes_trie(
&self,
first: NumberFor<Block>,
last: Block::Hash,
fail_if_disabled: bool,
) -> sp_blockchain::Result<(
&dyn PrunableStateChangesTrieStorage<Block>,
Vec<(NumberFor<Block>, Option<(NumberFor<Block>, Block::Hash)>, ChangesTrieConfiguration)>,
)> {
let storage = self
.backend
.changes_trie_storage()
.ok_or_else(|| sp_blockchain::Error::ChangesTriesNotSupported)?;
let mut configs = Vec::with_capacity(1);
let mut current = last;
loop {
let config_range = storage.configuration_at(&BlockId::Hash(current))?;
match config_range.config {
Some(config) => configs.push((config_range.zero.0, config_range.end, config)),
None if !fail_if_disabled => return Ok((storage, configs)),
None => return Err(sp_blockchain::Error::ChangesTriesNotSupported),
}
if config_range.zero.0 < first {
break
}
current = *self
.backend
.blockchain()
.expect_header(BlockId::Hash(config_range.zero.1))?
.parent_hash();
}
Ok((storage, configs))
}
/// Apply a checked and validated block to an operation. If a justification is provided
/// then `finalized` *must* be true.
fn apply_block(
@@ -811,7 +560,7 @@ where
sc_consensus::StorageChanges::Changes(storage_changes) => {
self.backend
.begin_state_operation(&mut operation.op, BlockId::Hash(parent_hash))?;
let (main_sc, child_sc, offchain_sc, tx, _, changes_trie_tx, tx_index) =
let (main_sc, child_sc, offchain_sc, tx, _, tx_index) =
storage_changes.into_inner();
if self.config.offchain_indexing_api {
@@ -822,9 +571,6 @@ where
operation.op.update_storage(main_sc.clone(), child_sc.clone())?;
operation.op.update_transaction_index(tx_index)?;
if let Some(changes_trie_transaction) = changes_trie_tx {
operation.op.update_changes_trie(changes_trie_transaction)?;
}
Some((main_sc, child_sc))
},
sc_consensus::StorageChanges::Import(changes) => {
@@ -1003,11 +749,8 @@ where
)?;
let state = self.backend.state_at(at)?;
let changes_trie_state =
changes_tries_state_at_block(&at, self.backend.changes_trie_storage())?;
let gen_storage_changes = runtime_api
.into_storage_changes(&state, changes_trie_state.as_ref(), *parent_hash)
.into_storage_changes(&state, *parent_hash)
.map_err(sp_blockchain::Error::Storage)?;
if import_block.header.state_root() != &gen_storage_changes.transaction_storage_root
@@ -1356,25 +1099,6 @@ where
.map(|(r, p)| (r, StorageProof::merge(vec![p, code_proof])))
}
fn header_proof(
&self,
id: &BlockId<Block>,
) -> sp_blockchain::Result<(Block::Header, StorageProof)> {
self.header_proof_with_cht_size(id, cht::size())
}
fn key_changes_proof(
&self,
first: Block::Hash,
last: Block::Hash,
min: Block::Hash,
max: Block::Hash,
storage_key: Option<&PrefixedStorageKey>,
key: &StorageKey,
) -> sp_blockchain::Result<ChangesProof<Block::Header>> {
self.key_changes_proof_with_cht_size(first, last, min, max, storage_key, key, cht::size())
}
fn read_proof_collection(
&self,
id: &BlockId<Block>,
@@ -1540,7 +1264,7 @@ where
fn new_block_at<R: Into<RecordProof>>(
&self,
parent: &BlockId<Block>,
inherent_digests: DigestFor<Block>,
inherent_digests: Digest,
record_proof: R,
) -> sp_blockchain::Result<sc_block_builder::BlockBuilder<Block, Self, B>> {
sc_block_builder::BlockBuilder::new(
@@ -1555,7 +1279,7 @@ where
fn new_block(
&self,
inherent_digests: DigestFor<Block>,
inherent_digests: Digest,
) -> sp_blockchain::Result<sc_block_builder::BlockBuilder<Block, Self, B>> {
let info = self.chain_info();
sc_block_builder::BlockBuilder::new(
@@ -1703,89 +1427,6 @@ where
.child_storage_hash(child_info, &key.0)
.map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?)
}
fn max_key_changes_range(
&self,
first: NumberFor<Block>,
last: BlockId<Block>,
) -> sp_blockchain::Result<Option<(NumberFor<Block>, BlockId<Block>)>> {
let last_number = self.backend.blockchain().expect_block_number_from_id(&last)?;
let last_hash = self.backend.blockchain().expect_block_hash_from_id(&last)?;
if first > last_number {
return Err(sp_blockchain::Error::ChangesTrieAccessFailed(
"Invalid changes trie range".into(),
))
}
let (storage, configs) = match self.require_changes_trie(first, last_hash, false).ok() {
Some((storage, configs)) => (storage, configs),
None => return Ok(None),
};
let first_available_changes_trie = configs.last().map(|config| config.0);
match first_available_changes_trie {
Some(first_available_changes_trie) => {
let oldest_unpruned = storage.oldest_pruned_digest_range_end();
let first = std::cmp::max(first_available_changes_trie, oldest_unpruned);
Ok(Some((first, last)))
},
None => Ok(None),
}
}
fn key_changes(
&self,
first: NumberFor<Block>,
last: BlockId<Block>,
storage_key: Option<&PrefixedStorageKey>,
key: &StorageKey,
) -> sp_blockchain::Result<Vec<(NumberFor<Block>, u32)>> {
let last_number = self.backend.blockchain().expect_block_number_from_id(&last)?;
let last_hash = self.backend.blockchain().expect_block_hash_from_id(&last)?;
let (storage, configs) = self.require_changes_trie(first, last_hash, true)?;
let mut result = Vec::new();
let best_number = self.backend.blockchain().info().best_number;
for (config_zero, config_end, config) in configs {
let range_first = ::std::cmp::max(first, config_zero + One::one());
let range_anchor = match config_end {
Some((config_end_number, config_end_hash)) =>
if last_number > config_end_number {
ChangesTrieAnchorBlockId {
hash: config_end_hash,
number: config_end_number,
}
} else {
ChangesTrieAnchorBlockId {
hash: convert_hash(&last_hash),
number: last_number,
}
},
None =>
ChangesTrieAnchorBlockId { hash: convert_hash(&last_hash), number: last_number },
};
let config_range = ChangesTrieConfigurationRange {
config: &config,
zero: config_zero.clone(),
end: config_end.map(|(config_end_number, _)| config_end_number),
};
let result_range: Vec<(NumberFor<Block>, u32)> = key_changes::<HashFor<Block>, _>(
config_range,
storage.storage(),
range_first,
&range_anchor,
best_number,
storage_key,
&key.0,
)
.and_then(|r| r.map(|r| r.map(|(block, tx)| (block, tx))).collect::<Result<_, _>>())
.map_err(|err| sp_blockchain::Error::ChangesTrieAccessFailed(err))?;
result.extend(result_range);
}
Ok(result)
}
}
impl<B, E, Block, RA> HeaderMetadata<Block> for Client<B, E, Block, RA>
@@ -1913,16 +1554,6 @@ where
}
}
impl<B, E, Block, RA> ProvideCache<Block> for Client<B, E, Block, RA>
where
B: backend::Backend<Block>,
Block: BlockT,
{
fn cache(&self) -> Option<Arc<dyn Cache<Block>>> {
self.backend.blockchain().cache()
}
}
impl<B, E, Block, RA> ProvideRuntimeApi<Block> for Client<B, E, Block, RA>
where
B: backend::Backend<Block>,
+1 -1
View File
@@ -68,7 +68,7 @@ use sc_client_api::{blockchain::HeaderBackend, BlockchainEvents};
pub use sc_consensus::ImportQueue;
pub use sc_executor::NativeExecutionDispatch;
#[doc(hidden)]
pub use sc_network::config::{OnDemand, TransactionImport, TransactionImportFuture};
pub use sc_network::config::{TransactionImport, TransactionImportFuture};
pub use sc_rpc::Metadata as RpcMetadata;
pub use sc_tracing::TracingReceiver;
pub use sc_transaction_pool::Options as TransactionPoolOptions;
-1
View File
@@ -19,7 +19,6 @@ tokio = { version = "1.10.0", features = ["time"] }
log = "0.4.8"
fdlimit = "0.2.1"
parking_lot = "0.11.1"
sc-light = { version = "4.0.0-dev", path = "../../light" }
sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" }
sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" }
sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" }
@@ -21,7 +21,6 @@ use std::sync::Arc;
type TestBackend = sc_client_api::in_mem::Backend<substrate_test_runtime::Block>;
#[test]
fn test_leaves_with_complex_block_tree() {
let backend = Arc::new(TestBackend::new());
+8 -266
View File
@@ -27,29 +27,25 @@ use sc_client_db::{
use sc_consensus::{
BlockCheckParams, BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult,
};
use sc_service::client::{self, new_in_mem, Client, LocalCallExecutor};
use sc_service::client::{new_in_mem, Client, LocalCallExecutor};
use sp_api::ProvideRuntimeApi;
use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError, SelectChain};
use sp_core::{blake2_256, testing::TaskExecutor, ChangesTrieConfiguration, H256};
use sp_core::{testing::TaskExecutor, H256};
use sp_runtime::{
generic::BlockId,
traits::{BlakeTwo256, Block as BlockT, Header as HeaderT},
ConsensusEngineId, DigestItem, Justifications,
ConsensusEngineId, Justifications,
};
use sp_state_machine::{
backend::Backend as _, ExecutionStrategy, InMemoryBackend, OverlayedChanges, StateMachine,
};
use sp_storage::{ChildInfo, StorageKey};
use sp_trie::{trie_types::Layout, TrieConfiguration};
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
use std::{collections::HashSet, sync::Arc};
use substrate_test_runtime::TestAPI;
use substrate_test_runtime_client::{
prelude::*,
runtime::{
self,
genesismap::{insert_genesis_block, GenesisConfig},
Block, BlockNumber, Digest, Hash, Header, RuntimeApi, Transfer,
},
@@ -57,6 +53,8 @@ use substrate_test_runtime_client::{
Sr25519Keyring, TestClientBuilder, TestClientBuilderExt,
};
mod db;
const TEST_ENGINE_ID: ConsensusEngineId = *b"TEST";
pub struct ExecutorDispatch;
@@ -77,86 +75,6 @@ fn executor() -> sc_executor::NativeElseWasmExecutor<ExecutorDispatch> {
sc_executor::NativeElseWasmExecutor::new(sc_executor::WasmExecutionMethod::Interpreted, None, 8)
}
pub fn prepare_client_with_key_changes() -> (
client::Client<
substrate_test_runtime_client::Backend,
substrate_test_runtime_client::ExecutorDispatch,
Block,
RuntimeApi,
>,
Vec<H256>,
Vec<(u64, u64, Vec<u8>, Vec<(u64, u32)>)>,
) {
// prepare block structure
let blocks_transfers = vec![
vec![
(AccountKeyring::Alice, AccountKeyring::Dave),
(AccountKeyring::Bob, AccountKeyring::Dave),
],
vec![(AccountKeyring::Charlie, AccountKeyring::Eve)],
vec![],
vec![(AccountKeyring::Alice, AccountKeyring::Dave)],
];
// prepare client ang import blocks
let mut local_roots = Vec::new();
let config = Some(ChangesTrieConfiguration::new(4, 2));
let mut remote_client = TestClientBuilder::new().changes_trie_config(config).build();
let mut nonces: HashMap<_, u64> = Default::default();
for (i, block_transfers) in blocks_transfers.into_iter().enumerate() {
let mut builder = remote_client.new_block(Default::default()).unwrap();
for (from, to) in block_transfers {
builder
.push_transfer(Transfer {
from: from.into(),
to: to.into(),
amount: 1,
nonce: *nonces.entry(from).and_modify(|n| *n = *n + 1).or_default(),
})
.unwrap();
}
let block = builder.build().unwrap().block;
block_on(remote_client.import(BlockOrigin::Own, block)).unwrap();
let header = remote_client.header(&BlockId::Number(i as u64 + 1)).unwrap().unwrap();
let trie_root = header
.digest()
.log(DigestItem::as_changes_trie_root)
.map(|root| H256::from_slice(root.as_ref()))
.unwrap();
local_roots.push(trie_root);
}
// prepare test cases
let alice = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Alice.into())).to_vec();
let bob = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Bob.into())).to_vec();
let charlie =
blake2_256(&runtime::system::balance_of_key(AccountKeyring::Charlie.into())).to_vec();
let dave = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec();
let eve = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Eve.into())).to_vec();
let ferdie =
blake2_256(&runtime::system::balance_of_key(AccountKeyring::Ferdie.into())).to_vec();
let test_cases = vec![
(1, 4, alice.clone(), vec![(4, 0), (1, 0)]),
(1, 3, alice.clone(), vec![(1, 0)]),
(2, 4, alice.clone(), vec![(4, 0)]),
(2, 3, alice.clone(), vec![]),
(1, 4, bob.clone(), vec![(1, 1)]),
(1, 1, bob.clone(), vec![(1, 1)]),
(2, 4, bob.clone(), vec![]),
(1, 4, charlie.clone(), vec![(2, 0)]),
(1, 4, dave.clone(), vec![(4, 0), (1, 1), (1, 0)]),
(1, 1, dave.clone(), vec![(1, 1), (1, 0)]),
(3, 4, dave.clone(), vec![(4, 0)]),
(1, 4, eve.clone(), vec![(2, 0)]),
(1, 1, eve.clone(), vec![]),
(3, 4, eve.clone(), vec![]),
(1, 4, ferdie.clone(), vec![]),
];
(remote_client, local_roots, test_cases)
}
fn construct_block(
backend: &InMemoryBackend<BlakeTwo256>,
number: BlockNumber,
@@ -184,7 +102,6 @@ fn construct_block(
StateMachine::new(
backend,
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
&mut overlay,
&executor(),
"Core_initialize_block",
@@ -199,7 +116,6 @@ fn construct_block(
for tx in transactions.iter() {
StateMachine::new(
backend,
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
&mut overlay,
&executor(),
"BlockBuilder_apply_extrinsic",
@@ -214,7 +130,6 @@ fn construct_block(
let ret_data = StateMachine::new(
backend,
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
&mut overlay,
&executor(),
"BlockBuilder_finalize_block",
@@ -248,7 +163,6 @@ fn block1(genesis_hash: Hash, backend: &InMemoryBackend<BlakeTwo256>) -> (Vec<u8
#[test]
fn construct_genesis_should_work_with_native() {
let mut storage = GenesisConfig::new(
None,
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
1000,
@@ -267,7 +181,6 @@ fn construct_genesis_should_work_with_native() {
let _ = StateMachine::new(
&backend,
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
&mut overlay,
&executor(),
"Core_execute_block",
@@ -283,7 +196,6 @@ fn construct_genesis_should_work_with_native() {
#[test]
fn construct_genesis_should_work_with_wasm() {
let mut storage = GenesisConfig::new(
None,
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
1000,
@@ -302,7 +214,6 @@ fn construct_genesis_should_work_with_wasm() {
let _ = StateMachine::new(
&backend,
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
&mut overlay,
&executor(),
"Core_execute_block",
@@ -318,7 +229,6 @@ fn construct_genesis_should_work_with_wasm() {
#[test]
fn construct_genesis_with_bad_transaction_should_panic() {
let mut storage = GenesisConfig::new(
None,
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
68,
@@ -337,7 +247,6 @@ fn construct_genesis_with_bad_transaction_should_panic() {
let r = StateMachine::new(
&backend,
sp_state_machine::disabled_changes_trie_state::<_, u64>(),
&mut overlay,
&executor(),
"Core_execute_block",
@@ -906,23 +815,6 @@ fn best_containing_on_longest_chain_with_max_depth_higher_than_best() {
);
}
#[test]
fn key_changes_works() {
let (client, _, test_cases) = prepare_client_with_key_changes();
for (index, (begin, end, key, expected_result)) in test_cases.into_iter().enumerate() {
let end = client.block_hash(end).unwrap().unwrap();
let actual_result =
client.key_changes(begin, BlockId::Hash(end), None, &StorageKey(key)).unwrap();
if actual_result != expected_result {
panic!(
"Failed test {}: actual = {:?}, expected = {:?}",
index, actual_result, expected_result,
);
}
}
}
#[test]
fn import_with_justification() {
let mut client = substrate_test_runtime_client::new();
@@ -1229,12 +1121,8 @@ fn doesnt_import_blocks_that_revert_finality() {
ClientExt::finalize_block(&client, BlockId::Hash(a2.hash()), None).unwrap();
let import_err = block_on(client.import(BlockOrigin::Own, b3)).err().unwrap();
let expected_err = ConsensusError::ClientImport(
sp_blockchain::Error::RuntimeApiError(sp_api::ApiError::Application(Box::new(
sp_blockchain::Error::NotInFinalizedChain,
)))
.to_string(),
);
let expected_err =
ConsensusError::ClientImport(sp_blockchain::Error::NotInFinalizedChain.to_string());
assert_eq!(import_err.to_string(), expected_err.to_string());
@@ -1536,152 +1424,6 @@ fn returns_status_for_pruned_blocks() {
);
}
#[test]
fn imports_blocks_with_changes_tries_config_change() {
// create client with initial 4^2 configuration
let mut client = TestClientBuilder::with_default_backend()
.changes_trie_config(Some(ChangesTrieConfiguration {
digest_interval: 4,
digest_levels: 2,
}))
.build();
// ===================================================================
// blocks 1,2,3,4,5,6,7,8,9,10 are empty
// block 11 changes the key
// block 12 is the L1 digest that covers this change
// blocks 13,14,15,16,17,18,19,20,21,22 are empty
// block 23 changes the configuration to 5^1 AND is skewed digest
// ===================================================================
// blocks 24,25 are changing the key
// block 26 is empty
// block 27 changes the key
// block 28 is the L1 digest (NOT SKEWED!!!) that covers changes AND changes configuration to
// `3^1`
// ===================================================================
// block 29 is empty
// block 30 changes the key
// block 31 is L1 digest that covers this change
// ===================================================================
(1..11).for_each(|number| {
let block = client
.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
.unwrap()
.build()
.unwrap()
.block;
block_on(client.import(BlockOrigin::Own, block)).unwrap();
});
(11..12).for_each(|number| {
let mut block = client
.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
.unwrap();
block
.push_storage_change(vec![42], Some(number.to_le_bytes().to_vec()))
.unwrap();
let block = block.build().unwrap().block;
block_on(client.import(BlockOrigin::Own, block)).unwrap();
});
(12..23).for_each(|number| {
let block = client
.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
.unwrap()
.build()
.unwrap()
.block;
block_on(client.import(BlockOrigin::Own, block)).unwrap();
});
(23..24).for_each(|number| {
let mut block = client
.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
.unwrap();
block
.push_changes_trie_configuration_update(Some(ChangesTrieConfiguration {
digest_interval: 5,
digest_levels: 1,
}))
.unwrap();
let block = block.build().unwrap().block;
block_on(client.import(BlockOrigin::Own, block)).unwrap();
});
(24..26).for_each(|number| {
let mut block = client
.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
.unwrap();
block
.push_storage_change(vec![42], Some(number.to_le_bytes().to_vec()))
.unwrap();
let block = block.build().unwrap().block;
block_on(client.import(BlockOrigin::Own, block)).unwrap();
});
(26..27).for_each(|number| {
let block = client
.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
.unwrap()
.build()
.unwrap()
.block;
block_on(client.import(BlockOrigin::Own, block)).unwrap();
});
(27..28).for_each(|number| {
let mut block = client
.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
.unwrap();
block
.push_storage_change(vec![42], Some(number.to_le_bytes().to_vec()))
.unwrap();
let block = block.build().unwrap().block;
block_on(client.import(BlockOrigin::Own, block)).unwrap();
});
(28..29).for_each(|number| {
let mut block = client
.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
.unwrap();
block
.push_changes_trie_configuration_update(Some(ChangesTrieConfiguration {
digest_interval: 3,
digest_levels: 1,
}))
.unwrap();
let block = block.build().unwrap().block;
block_on(client.import(BlockOrigin::Own, block)).unwrap();
});
(29..30).for_each(|number| {
let block = client
.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
.unwrap()
.build()
.unwrap()
.block;
block_on(client.import(BlockOrigin::Own, block)).unwrap();
});
(30..31).for_each(|number| {
let mut block = client
.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
.unwrap();
block
.push_storage_change(vec![42], Some(number.to_le_bytes().to_vec()))
.unwrap();
let block = block.build().unwrap().block;
block_on(client.import(BlockOrigin::Own, block)).unwrap();
});
(31..32).for_each(|number| {
let block = client
.new_block_at(&BlockId::Number(number - 1), Default::default(), false)
.unwrap()
.build()
.unwrap()
.block;
block_on(client.import(BlockOrigin::Own, block)).unwrap();
});
// now check that configuration cache works
assert_eq!(
client.key_changes(1, BlockId::Number(31), None, &StorageKey(vec![42])).unwrap(),
vec![(30, 0), (27, 0), (25, 0), (24, 0), (11, 0)]
);
}
#[test]
fn storage_keys_iter_prefix_and_start_key_works() {
let child_info = ChildInfo::new_default(b"child");