mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 02:51:08 +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:
@@ -17,65 +17,52 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
error::Error, MallocSizeOfWasm, RpcHandlers,
|
||||
start_rpc_servers, build_network_future, TransactionPoolAdapter, TaskManager, SpawnTaskHandle,
|
||||
metrics::MetricsService,
|
||||
build_network_future,
|
||||
client::{light, Client, ClientConfig},
|
||||
config::{Configuration, KeystoreConfig, PrometheusConfig, TransactionStorageMode},
|
||||
error::Error,
|
||||
metrics::MetricsService,
|
||||
start_rpc_servers, MallocSizeOfWasm, RpcHandlers, SpawnTaskHandle, TaskManager,
|
||||
TransactionPoolAdapter,
|
||||
};
|
||||
use sc_client_api::{
|
||||
light::RemoteBlockchain, ForkBlocks, BadBlocks, UsageProvider, ExecutorProvider,
|
||||
};
|
||||
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender};
|
||||
use futures::{channel::oneshot, future::ready, FutureExt, StreamExt};
|
||||
use jsonrpc_pubsub::manager::SubscriptionManager;
|
||||
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,
|
||||
};
|
||||
use sc_client_db::{Backend, DatabaseSettings};
|
||||
use sc_executor::{NativeExecutionDispatch, NativeExecutor, RuntimeInfo};
|
||||
use sc_keystore::LocalKeystore;
|
||||
use sc_network::{
|
||||
block_request_handler::{self, BlockRequestHandler},
|
||||
config::{OnDemand, Role, SyncMode},
|
||||
light_client_requests::{self, handler::LightClientRequestHandler},
|
||||
state_request_handler::{self, StateRequestHandler},
|
||||
NetworkService,
|
||||
};
|
||||
use sc_telemetry::{telemetry, ConnectionMessage, Telemetry, TelemetryHandle, SUBSTRATE_INFO};
|
||||
use sc_transaction_pool_api::MaintainedTransactionPool;
|
||||
use sp_api::{CallApiAt, ProvideRuntimeApi};
|
||||
use sp_blockchain::{HeaderBackend, HeaderMetadata};
|
||||
use sp_consensus::{
|
||||
block_validation::{BlockAnnounceValidator, DefaultBlockAnnounceValidator, Chain},
|
||||
block_validation::{BlockAnnounceValidator, Chain, DefaultBlockAnnounceValidator},
|
||||
import_queue::ImportQueue,
|
||||
};
|
||||
use jsonrpc_pubsub::manager::SubscriptionManager;
|
||||
use futures::{
|
||||
FutureExt, StreamExt,
|
||||
future::ready,
|
||||
channel::oneshot,
|
||||
};
|
||||
use sc_keystore::LocalKeystore;
|
||||
use log::info;
|
||||
use sc_network::config::{Role, OnDemand, SyncMode};
|
||||
use sc_network::NetworkService;
|
||||
use sc_network::block_request_handler::{self, BlockRequestHandler};
|
||||
use sc_network::state_request_handler::{self, StateRequestHandler};
|
||||
use sc_network::light_client_requests::{self, handler::LightClientRequestHandler};
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_runtime::traits::{
|
||||
Block as BlockT, HashFor, Zero, BlockIdTo,
|
||||
};
|
||||
use sp_api::{ProvideRuntimeApi, CallApiAt};
|
||||
use sc_executor::{NativeExecutor, NativeExecutionDispatch, RuntimeInfo};
|
||||
use std::{sync::Arc, str::FromStr};
|
||||
use wasm_timer::SystemTime;
|
||||
use sc_telemetry::{
|
||||
telemetry,
|
||||
ConnectionMessage,
|
||||
Telemetry,
|
||||
TelemetryHandle,
|
||||
SUBSTRATE_INFO,
|
||||
};
|
||||
use sc_transaction_pool_api::MaintainedTransactionPool;
|
||||
use prometheus_endpoint::Registry;
|
||||
use sc_client_db::{Backend, DatabaseSettings};
|
||||
use sp_core::traits::{
|
||||
CodeExecutor,
|
||||
SpawnNamed,
|
||||
};
|
||||
use sp_core::traits::{CodeExecutor, SpawnNamed};
|
||||
use sp_keystore::{CryptoStore, SyncCryptoStore, SyncCryptoStorePtr};
|
||||
use sp_runtime::BuildStorage;
|
||||
use sc_client_api::{
|
||||
BlockBackend, BlockchainEvents,
|
||||
StorageProvider,
|
||||
proof_provider::ProofProvider,
|
||||
execution_extensions::ExecutionExtensions
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, BlockIdTo, HashFor, Zero},
|
||||
BuildStorage,
|
||||
};
|
||||
use sp_blockchain::{HeaderMetadata, HeaderBackend};
|
||||
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender};
|
||||
use std::{str::FromStr, sync::Arc};
|
||||
use wasm_timer::SystemTime;
|
||||
|
||||
/// A utility trait for building an RPC extension given a `DenyUnsafe` instance.
|
||||
/// This is useful since at service definition time we don't know whether the
|
||||
@@ -95,7 +82,8 @@ pub trait RpcExtensionBuilder {
|
||||
) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<F, R> RpcExtensionBuilder for F where
|
||||
impl<F, R> RpcExtensionBuilder for F
|
||||
where
|
||||
F: Fn(sc_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor) -> R,
|
||||
R: sc_rpc::RpcExtension<sc_rpc::Metadata>,
|
||||
{
|
||||
@@ -115,7 +103,8 @@ impl<F, R> RpcExtensionBuilder for F where
|
||||
/// `DenyUnsafe` instance and return a static `RpcExtension` instance.
|
||||
pub struct NoopRpcExtensionBuilder<R>(pub R);
|
||||
|
||||
impl<R> RpcExtensionBuilder for NoopRpcExtensionBuilder<R> where
|
||||
impl<R> RpcExtensionBuilder for NoopRpcExtensionBuilder<R>
|
||||
where
|
||||
R: Clone + sc_rpc::RpcExtension<sc_rpc::Metadata>,
|
||||
{
|
||||
type Output = R;
|
||||
@@ -129,7 +118,8 @@ impl<R> RpcExtensionBuilder for NoopRpcExtensionBuilder<R> where
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<R> for NoopRpcExtensionBuilder<R> where
|
||||
impl<R> From<R> for NoopRpcExtensionBuilder<R>
|
||||
where
|
||||
R: sc_rpc::RpcExtension<sc_rpc::Metadata>,
|
||||
{
|
||||
fn from(e: R) -> NoopRpcExtensionBuilder<R> {
|
||||
@@ -137,58 +127,37 @@ impl<R> From<R> for NoopRpcExtensionBuilder<R> where
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Full client type.
|
||||
pub type TFullClient<TBl, TRtApi, TExecDisp> = Client<
|
||||
TFullBackend<TBl>,
|
||||
TFullCallExecutor<TBl, TExecDisp>,
|
||||
TBl,
|
||||
TRtApi,
|
||||
>;
|
||||
pub type TFullClient<TBl, TRtApi, TExecDisp> =
|
||||
Client<TFullBackend<TBl>, TFullCallExecutor<TBl, TExecDisp>, TBl, TRtApi>;
|
||||
|
||||
/// Full client backend type.
|
||||
pub type TFullBackend<TBl> = sc_client_db::Backend<TBl>;
|
||||
|
||||
/// Full client call executor type.
|
||||
pub type TFullCallExecutor<TBl, TExecDisp> = crate::client::LocalCallExecutor<
|
||||
TBl,
|
||||
sc_client_db::Backend<TBl>,
|
||||
NativeExecutor<TExecDisp>,
|
||||
>;
|
||||
pub type TFullCallExecutor<TBl, TExecDisp> =
|
||||
crate::client::LocalCallExecutor<TBl, sc_client_db::Backend<TBl>, NativeExecutor<TExecDisp>>;
|
||||
|
||||
/// Light client type.
|
||||
pub type TLightClient<TBl, TRtApi, TExecDisp> = TLightClientWithBackend<
|
||||
TBl, TRtApi, TExecDisp, TLightBackend<TBl>
|
||||
>;
|
||||
pub type TLightClient<TBl, TRtApi, TExecDisp> =
|
||||
TLightClientWithBackend<TBl, TRtApi, TExecDisp, TLightBackend<TBl>>;
|
||||
|
||||
/// Light client backend type.
|
||||
pub type TLightBackend<TBl> = sc_light::Backend<
|
||||
sc_client_db::light::LightStorage<TBl>,
|
||||
HashFor<TBl>,
|
||||
>;
|
||||
pub type TLightBackend<TBl> =
|
||||
sc_light::Backend<sc_client_db::light::LightStorage<TBl>, HashFor<TBl>>;
|
||||
|
||||
/// Light call executor type.
|
||||
pub type TLightCallExecutor<TBl, TExecDisp> = sc_light::GenesisCallExecutor<
|
||||
sc_light::Backend<
|
||||
sc_client_db::light::LightStorage<TBl>,
|
||||
HashFor<TBl>
|
||||
>,
|
||||
sc_light::Backend<sc_client_db::light::LightStorage<TBl>, HashFor<TBl>>,
|
||||
crate::client::LocalCallExecutor<
|
||||
TBl,
|
||||
sc_light::Backend<
|
||||
sc_client_db::light::LightStorage<TBl>,
|
||||
HashFor<TBl>
|
||||
>,
|
||||
NativeExecutor<TExecDisp>
|
||||
sc_light::Backend<sc_client_db::light::LightStorage<TBl>, HashFor<TBl>>,
|
||||
NativeExecutor<TExecDisp>,
|
||||
>,
|
||||
>;
|
||||
|
||||
type TFullParts<TBl, TRtApi, TExecDisp> = (
|
||||
TFullClient<TBl, TRtApi, TExecDisp>,
|
||||
Arc<TFullBackend<TBl>>,
|
||||
KeystoreContainer,
|
||||
TaskManager,
|
||||
);
|
||||
type TFullParts<TBl, TRtApi, TExecDisp> =
|
||||
(TFullClient<TBl, TRtApi, TExecDisp>, Arc<TFullBackend<TBl>>, KeystoreContainer, TaskManager);
|
||||
|
||||
type TLightParts<TBl, TRtApi, TExecDisp> = (
|
||||
Arc<TLightClient<TBl, TRtApi, TExecDisp>>,
|
||||
@@ -199,10 +168,8 @@ type TLightParts<TBl, TRtApi, TExecDisp> = (
|
||||
);
|
||||
|
||||
/// Light client backend type with a specific hash type.
|
||||
pub type TLightBackendWithHash<TBl, THash> = sc_light::Backend<
|
||||
sc_client_db::light::LightStorage<TBl>,
|
||||
THash,
|
||||
>;
|
||||
pub type TLightBackendWithHash<TBl, THash> =
|
||||
sc_light::Backend<sc_client_db::light::LightStorage<TBl>, THash>;
|
||||
|
||||
/// Light client type with a specific backend.
|
||||
pub type TLightClientWithBackend<TBl, TRtApi, TExecDisp, TBackend> = Client<
|
||||
@@ -220,7 +187,10 @@ trait AsCryptoStoreRef {
|
||||
fn sync_keystore_ref(&self) -> Arc<dyn SyncCryptoStore>;
|
||||
}
|
||||
|
||||
impl<T> AsCryptoStoreRef for Arc<T> where T: CryptoStore + SyncCryptoStore + 'static {
|
||||
impl<T> AsCryptoStoreRef for Arc<T>
|
||||
where
|
||||
T: CryptoStore + SyncCryptoStore + 'static,
|
||||
{
|
||||
fn keystore_ref(&self) -> Arc<dyn CryptoStore> {
|
||||
self.clone()
|
||||
}
|
||||
@@ -239,14 +209,12 @@ impl KeystoreContainer {
|
||||
/// Construct KeystoreContainer
|
||||
pub fn new(config: &KeystoreConfig) -> Result<Self, Error> {
|
||||
let keystore = Arc::new(match config {
|
||||
KeystoreConfig::Path { path, password } => LocalKeystore::open(
|
||||
path.clone(),
|
||||
password.clone(),
|
||||
)?,
|
||||
KeystoreConfig::Path { path, password } =>
|
||||
LocalKeystore::open(path.clone(), password.clone())?,
|
||||
KeystoreConfig::InMemory => LocalKeystore::in_memory(),
|
||||
});
|
||||
|
||||
Ok(Self{remote: Default::default(), local: keystore})
|
||||
Ok(Self { remote: Default::default(), local: keystore })
|
||||
}
|
||||
|
||||
/// Set the remote keystore.
|
||||
@@ -255,7 +223,8 @@ impl KeystoreContainer {
|
||||
/// does not reset any references previously handed out - they will
|
||||
/// stick around.
|
||||
pub fn set_remote_keystore<T>(&mut self, remote: Arc<T>)
|
||||
where T: CryptoStore + SyncCryptoStore + 'static
|
||||
where
|
||||
T: CryptoStore + SyncCryptoStore + 'static,
|
||||
{
|
||||
self.remote = Some(Box::new(remote))
|
||||
}
|
||||
@@ -295,7 +264,8 @@ impl KeystoreContainer {
|
||||
pub fn new_full_client<TBl, TRtApi, TExecDisp>(
|
||||
config: &Configuration,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
) -> Result<TFullClient<TBl, TRtApi, TExecDisp>, Error> where
|
||||
) -> Result<TFullClient<TBl, TRtApi, TExecDisp>, Error>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TExecDisp: NativeExecutionDispatch + 'static,
|
||||
TBl::Hash: FromStr,
|
||||
@@ -307,7 +277,8 @@ pub fn new_full_client<TBl, TRtApi, TExecDisp>(
|
||||
pub fn new_full_parts<TBl, TRtApi, TExecDisp>(
|
||||
config: &Configuration,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
) -> Result<TFullParts<TBl, TRtApi, TExecDisp>, Error> where
|
||||
) -> Result<TFullParts<TBl, TRtApi, TExecDisp>, Error>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TExecDisp: NativeExecutionDispatch + 'static,
|
||||
TBl::Hash: FromStr,
|
||||
@@ -337,15 +308,13 @@ pub fn new_full_parts<TBl, TRtApi, TExecDisp>(
|
||||
let (client, backend) = {
|
||||
let db_config = sc_client_db::DatabaseSettings {
|
||||
state_cache_size: config.state_cache_size,
|
||||
state_cache_child_ratio:
|
||||
config.state_cache_child_ratio.map(|v| (v, 100)),
|
||||
state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)),
|
||||
state_pruning: config.state_pruning.clone(),
|
||||
source: config.database.clone(),
|
||||
keep_blocks: config.keep_blocks.clone(),
|
||||
transaction_storage: config.transaction_storage.clone(),
|
||||
};
|
||||
|
||||
|
||||
let backend = new_db_backend(db_config)?;
|
||||
|
||||
let extensions = sc_client_api::execution_extensions::ExecutionExtensions::new(
|
||||
@@ -354,15 +323,20 @@ pub fn new_full_parts<TBl, TRtApi, TExecDisp>(
|
||||
sc_offchain::OffchainDb::factory_from_backend(&*backend),
|
||||
);
|
||||
|
||||
let wasm_runtime_substitutes = config.chain_spec.code_substitutes().into_iter().map(|(h, c)| {
|
||||
let hash = TBl::Hash::from_str(&h)
|
||||
.map_err(|_|
|
||||
Error::Application(Box::from(
|
||||
format!("Failed to parse `{}` as block hash for code substitutes.", h)
|
||||
))
|
||||
)?;
|
||||
Ok((hash, c))
|
||||
}).collect::<Result<std::collections::HashMap<_, _>, Error>>()?;
|
||||
let wasm_runtime_substitutes = config
|
||||
.chain_spec
|
||||
.code_substitutes()
|
||||
.into_iter()
|
||||
.map(|(h, c)| {
|
||||
let hash = TBl::Hash::from_str(&h).map_err(|_| {
|
||||
Error::Application(Box::from(format!(
|
||||
"Failed to parse `{}` as block hash for code substitutes.",
|
||||
h
|
||||
)))
|
||||
})?;
|
||||
Ok((hash, c))
|
||||
})
|
||||
.collect::<Result<std::collections::HashMap<_, _>, Error>>()?;
|
||||
|
||||
let client = new_client(
|
||||
backend.clone(),
|
||||
@@ -375,10 +349,13 @@ pub fn new_full_parts<TBl, TRtApi, TExecDisp>(
|
||||
config.prometheus_config.as_ref().map(|config| config.registry.clone()),
|
||||
telemetry,
|
||||
ClientConfig {
|
||||
offchain_worker_enabled : config.offchain_worker.enabled,
|
||||
offchain_worker_enabled: config.offchain_worker.enabled,
|
||||
offchain_indexing_api: config.offchain_worker.indexing_enabled,
|
||||
wasm_runtime_overrides: config.wasm_runtime_overrides.clone(),
|
||||
no_genesis: matches!(config.network.sync_mode, sc_network::config::SyncMode::Fast {..}),
|
||||
no_genesis: matches!(
|
||||
config.network.sync_mode,
|
||||
sc_network::config::SyncMode::Fast { .. }
|
||||
),
|
||||
wasm_runtime_substitutes,
|
||||
},
|
||||
)?;
|
||||
@@ -386,19 +363,15 @@ pub fn new_full_parts<TBl, TRtApi, TExecDisp>(
|
||||
(client, backend)
|
||||
};
|
||||
|
||||
Ok((
|
||||
client,
|
||||
backend,
|
||||
keystore_container,
|
||||
task_manager,
|
||||
))
|
||||
Ok((client, backend, keystore_container, task_manager))
|
||||
}
|
||||
|
||||
/// Create the initial parts of a light node.
|
||||
pub fn new_light_parts<TBl, TRtApi, TExecDisp>(
|
||||
config: &Configuration,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
) -> Result<TLightParts<TBl, TRtApi, TExecDisp>, Error> where
|
||||
) -> Result<TLightParts<TBl, TRtApi, TExecDisp>, Error>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TExecDisp: NativeExecutionDispatch + 'static,
|
||||
{
|
||||
@@ -417,8 +390,7 @@ pub fn new_light_parts<TBl, TRtApi, TExecDisp>(
|
||||
let db_storage = {
|
||||
let db_settings = sc_client_db::DatabaseSettings {
|
||||
state_cache_size: config.state_cache_size,
|
||||
state_cache_child_ratio:
|
||||
config.state_cache_child_ratio.map(|v| (v, 100)),
|
||||
state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)),
|
||||
state_pruning: config.state_pruning.clone(),
|
||||
source: config.database.clone(),
|
||||
keep_blocks: config.keep_blocks.clone(),
|
||||
@@ -427,13 +399,11 @@ pub fn new_light_parts<TBl, TRtApi, TExecDisp>(
|
||||
sc_client_db::light::LightStorage::new(db_settings)?
|
||||
};
|
||||
let light_blockchain = sc_light::new_light_blockchain(db_storage);
|
||||
let fetch_checker = Arc::new(
|
||||
sc_light::new_fetch_checker::<_, TBl, _>(
|
||||
light_blockchain.clone(),
|
||||
executor.clone(),
|
||||
Box::new(task_manager.spawn_handle()),
|
||||
),
|
||||
);
|
||||
let fetch_checker = Arc::new(sc_light::new_fetch_checker::<_, TBl, _>(
|
||||
light_blockchain.clone(),
|
||||
executor.clone(),
|
||||
Box::new(task_manager.spawn_handle()),
|
||||
));
|
||||
let on_demand = Arc::new(sc_network::config::OnDemand::new(fetch_checker));
|
||||
let backend = sc_light::new_light_backend(light_blockchain);
|
||||
let client = Arc::new(light::new_light(
|
||||
@@ -451,7 +421,8 @@ pub fn new_light_parts<TBl, TRtApi, TExecDisp>(
|
||||
/// Create an instance of default DB-backend backend.
|
||||
pub fn new_db_backend<Block>(
|
||||
settings: DatabaseSettings,
|
||||
) -> Result<Arc<Backend<Block>>, sp_blockchain::Error> where
|
||||
) -> Result<Arc<Backend<Block>>, sp_blockchain::Error>
|
||||
where
|
||||
Block: BlockT,
|
||||
{
|
||||
const CANONICALIZATION_DELAY: u64 = 4096;
|
||||
@@ -480,11 +451,16 @@ pub fn new_client<E, Block, RA>(
|
||||
>,
|
||||
sp_blockchain::Error,
|
||||
>
|
||||
where
|
||||
Block: BlockT,
|
||||
E: CodeExecutor + RuntimeInfo,
|
||||
where
|
||||
Block: BlockT,
|
||||
E: CodeExecutor + RuntimeInfo,
|
||||
{
|
||||
let executor = crate::client::LocalCallExecutor::new(backend.clone(), executor, spawn_handle, config.clone())?;
|
||||
let executor = crate::client::LocalCallExecutor::new(
|
||||
backend.clone(),
|
||||
executor,
|
||||
spawn_handle,
|
||||
config.clone(),
|
||||
)?;
|
||||
Ok(crate::client::Client::new(
|
||||
backend,
|
||||
executor,
|
||||
@@ -534,10 +510,10 @@ pub fn build_offchain_workers<TBl, TCl>(
|
||||
client: Arc<TCl>,
|
||||
network: Arc<NetworkService<TBl, <TBl as BlockT>::Hash>>,
|
||||
) -> Option<Arc<sc_offchain::OffchainWorkers<TCl, TBl>>>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TCl: Send + Sync + ProvideRuntimeApi<TBl> + BlockchainEvents<TBl> + 'static,
|
||||
<TCl as ProvideRuntimeApi<TBl>>::Api: sc_offchain::OffchainWorkerApi<TBl>,
|
||||
where
|
||||
TBl: BlockT,
|
||||
TCl: Send + Sync + ProvideRuntimeApi<TBl> + BlockchainEvents<TBl> + 'static,
|
||||
<TCl as ProvideRuntimeApi<TBl>>::Api: sc_offchain::OffchainWorkerApi<TBl>,
|
||||
{
|
||||
let offchain_workers = Some(Arc::new(sc_offchain::OffchainWorkers::new(client.clone())));
|
||||
|
||||
@@ -551,7 +527,7 @@ pub fn build_offchain_workers<TBl, TCl>(
|
||||
offchain,
|
||||
Clone::clone(&spawn_handle),
|
||||
network.clone(),
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -562,22 +538,32 @@ pub fn build_offchain_workers<TBl, TCl>(
|
||||
pub fn spawn_tasks<TBl, TBackend, TExPool, TRpc, TCl>(
|
||||
params: SpawnTasksParams<TBl, TCl, TExPool, TRpc, TBackend>,
|
||||
) -> Result<RpcHandlers, Error>
|
||||
where
|
||||
TCl: ProvideRuntimeApi<TBl> + HeaderMetadata<TBl, Error=sp_blockchain::Error> + Chain<TBl> +
|
||||
BlockBackend<TBl> + BlockIdTo<TBl, Error=sp_blockchain::Error> + ProofProvider<TBl> +
|
||||
HeaderBackend<TBl> + BlockchainEvents<TBl> + ExecutorProvider<TBl> + UsageProvider<TBl> +
|
||||
StorageProvider<TBl, TBackend> + CallApiAt<TBl> + Send + 'static,
|
||||
<TCl as ProvideRuntimeApi<TBl>>::Api:
|
||||
sp_api::Metadata<TBl> +
|
||||
sc_offchain::OffchainWorkerApi<TBl> +
|
||||
sp_transaction_pool::runtime_api::TaggedTransactionQueue<TBl> +
|
||||
sp_session::SessionKeys<TBl> +
|
||||
sp_api::ApiExt<TBl, StateBackend = TBackend::State>,
|
||||
TBl: BlockT,
|
||||
TBackend: 'static + sc_client_api::backend::Backend<TBl> + Send,
|
||||
TExPool: MaintainedTransactionPool<Block=TBl, Hash = <TBl as BlockT>::Hash> +
|
||||
MallocSizeOfWasm + 'static,
|
||||
TRpc: sc_rpc::RpcExtension<sc_rpc::Metadata>
|
||||
where
|
||||
TCl: ProvideRuntimeApi<TBl>
|
||||
+ HeaderMetadata<TBl, Error = sp_blockchain::Error>
|
||||
+ Chain<TBl>
|
||||
+ BlockBackend<TBl>
|
||||
+ BlockIdTo<TBl, Error = sp_blockchain::Error>
|
||||
+ ProofProvider<TBl>
|
||||
+ HeaderBackend<TBl>
|
||||
+ BlockchainEvents<TBl>
|
||||
+ ExecutorProvider<TBl>
|
||||
+ UsageProvider<TBl>
|
||||
+ StorageProvider<TBl, TBackend>
|
||||
+ CallApiAt<TBl>
|
||||
+ Send
|
||||
+ 'static,
|
||||
<TCl as ProvideRuntimeApi<TBl>>::Api: sp_api::Metadata<TBl>
|
||||
+ sc_offchain::OffchainWorkerApi<TBl>
|
||||
+ sp_transaction_pool::runtime_api::TaggedTransactionQueue<TBl>
|
||||
+ sp_session::SessionKeys<TBl>
|
||||
+ sp_api::ApiExt<TBl, StateBackend = TBackend::State>,
|
||||
TBl: BlockT,
|
||||
TBackend: 'static + sc_client_api::backend::Backend<TBl> + Send,
|
||||
TExPool: MaintainedTransactionPool<Block = TBl, Hash = <TBl as BlockT>::Hash>
|
||||
+ MallocSizeOfWasm
|
||||
+ 'static,
|
||||
TRpc: sc_rpc::RpcExtension<sc_rpc::Metadata>,
|
||||
{
|
||||
let SpawnTasksParams {
|
||||
mut config,
|
||||
@@ -600,17 +586,11 @@ pub fn spawn_tasks<TBl, TBackend, TExPool, TRpc, TCl>(
|
||||
client.clone(),
|
||||
&BlockId::Hash(chain_info.best_hash),
|
||||
config.dev_key_seed.clone().map(|s| vec![s]).unwrap_or_default(),
|
||||
).map_err(|e| Error::Application(Box::new(e)))?;
|
||||
)
|
||||
.map_err(|e| Error::Application(Box::new(e)))?;
|
||||
|
||||
let telemetry = telemetry
|
||||
.map(|telemetry| {
|
||||
init_telemetry(
|
||||
&mut config,
|
||||
network.clone(),
|
||||
client.clone(),
|
||||
telemetry,
|
||||
)
|
||||
})
|
||||
.map(|telemetry| init_telemetry(&mut config, network.clone(), client.clone(), telemetry))
|
||||
.transpose()?;
|
||||
|
||||
info!("📦 Highest known block at #{}", chain_info.best_number);
|
||||
@@ -625,63 +605,69 @@ pub fn spawn_tasks<TBl, TBackend, TExPool, TRpc, TCl>(
|
||||
|
||||
spawn_handle.spawn(
|
||||
"on-transaction-imported",
|
||||
transaction_notifications(
|
||||
transaction_pool.clone(),
|
||||
network.clone(),
|
||||
telemetry.clone(),
|
||||
),
|
||||
transaction_notifications(transaction_pool.clone(), network.clone(), telemetry.clone()),
|
||||
);
|
||||
|
||||
// Prometheus metrics.
|
||||
let metrics_service = if let Some(PrometheusConfig { port, registry }) =
|
||||
config.prometheus_config.clone()
|
||||
{
|
||||
// Set static metrics.
|
||||
let metrics = MetricsService::with_prometheus(telemetry.clone(), ®istry, &config)?;
|
||||
spawn_handle.spawn(
|
||||
"prometheus-endpoint",
|
||||
prometheus_endpoint::init_prometheus(port, registry).map(drop)
|
||||
);
|
||||
let metrics_service =
|
||||
if let Some(PrometheusConfig { port, registry }) = config.prometheus_config.clone() {
|
||||
// Set static metrics.
|
||||
let metrics = MetricsService::with_prometheus(telemetry.clone(), ®istry, &config)?;
|
||||
spawn_handle.spawn(
|
||||
"prometheus-endpoint",
|
||||
prometheus_endpoint::init_prometheus(port, registry).map(drop),
|
||||
);
|
||||
|
||||
metrics
|
||||
} else {
|
||||
MetricsService::new(telemetry.clone())
|
||||
};
|
||||
metrics
|
||||
} else {
|
||||
MetricsService::new(telemetry.clone())
|
||||
};
|
||||
|
||||
// Periodically updated metrics and telemetry updates.
|
||||
spawn_handle.spawn("telemetry-periodic-send",
|
||||
metrics_service.run(
|
||||
client.clone(),
|
||||
transaction_pool.clone(),
|
||||
network.clone(),
|
||||
)
|
||||
spawn_handle.spawn(
|
||||
"telemetry-periodic-send",
|
||||
metrics_service.run(client.clone(), transaction_pool.clone(), network.clone()),
|
||||
);
|
||||
|
||||
// RPC
|
||||
let gen_handler = |
|
||||
deny_unsafe: sc_rpc::DenyUnsafe,
|
||||
rpc_middleware: sc_rpc_server::RpcMiddleware
|
||||
| gen_handler(
|
||||
deny_unsafe, rpc_middleware, &config, task_manager.spawn_handle(),
|
||||
client.clone(), transaction_pool.clone(), keystore.clone(),
|
||||
on_demand.clone(), remote_blockchain.clone(), &*rpc_extensions_builder,
|
||||
backend.offchain_storage(), system_rpc_tx.clone()
|
||||
);
|
||||
let gen_handler = |deny_unsafe: sc_rpc::DenyUnsafe,
|
||||
rpc_middleware: sc_rpc_server::RpcMiddleware| {
|
||||
gen_handler(
|
||||
deny_unsafe,
|
||||
rpc_middleware,
|
||||
&config,
|
||||
task_manager.spawn_handle(),
|
||||
client.clone(),
|
||||
transaction_pool.clone(),
|
||||
keystore.clone(),
|
||||
on_demand.clone(),
|
||||
remote_blockchain.clone(),
|
||||
&*rpc_extensions_builder,
|
||||
backend.offchain_storage(),
|
||||
system_rpc_tx.clone(),
|
||||
)
|
||||
};
|
||||
let rpc_metrics = sc_rpc_server::RpcMetrics::new(config.prometheus_registry())?;
|
||||
let rpc = start_rpc_servers(&config, gen_handler, rpc_metrics.clone())?;
|
||||
// This is used internally, so don't restrict access to unsafe RPC
|
||||
let rpc_handlers = RpcHandlers(Arc::new(gen_handler(
|
||||
sc_rpc::DenyUnsafe::No,
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics, "inbrowser")
|
||||
).into()));
|
||||
let rpc_handlers = RpcHandlers(Arc::new(
|
||||
gen_handler(
|
||||
sc_rpc::DenyUnsafe::No,
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics, "inbrowser"),
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
|
||||
// Spawn informant task
|
||||
spawn_handle.spawn("informant", sc_informant::build(
|
||||
client.clone(),
|
||||
network.clone(),
|
||||
transaction_pool.clone(),
|
||||
config.informant_output_format,
|
||||
));
|
||||
spawn_handle.spawn(
|
||||
"informant",
|
||||
sc_informant::build(
|
||||
client.clone(),
|
||||
network.clone(),
|
||||
transaction_pool.clone(),
|
||||
config.informant_output_format,
|
||||
),
|
||||
);
|
||||
|
||||
task_manager.keep_alive((config.base_path, rpc, rpc_handlers.clone()));
|
||||
|
||||
@@ -692,10 +678,9 @@ async fn transaction_notifications<TBl, TExPool>(
|
||||
transaction_pool: Arc<TExPool>,
|
||||
network: Arc<NetworkService<TBl, <TBl as BlockT>::Hash>>,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
)
|
||||
where
|
||||
TBl: BlockT,
|
||||
TExPool: MaintainedTransactionPool<Block=TBl, Hash = <TBl as BlockT>::Hash>,
|
||||
) where
|
||||
TBl: BlockT,
|
||||
TExPool: MaintainedTransactionPool<Block = TBl, Hash = <TBl as BlockT>::Hash>,
|
||||
{
|
||||
// transaction notifications
|
||||
transaction_pool
|
||||
@@ -730,9 +715,11 @@ fn init_telemetry<TBl: BlockT, TCl: BlockBackend<TBl>>(
|
||||
chain: config.chain_spec.name().to_owned(),
|
||||
genesis_hash: format!("{:?}", genesis_hash),
|
||||
authority: config.role.is_authority(),
|
||||
startup_time: SystemTime::UNIX_EPOCH.elapsed()
|
||||
startup_time: SystemTime::UNIX_EPOCH
|
||||
.elapsed()
|
||||
.map(|dur| dur.as_millis())
|
||||
.unwrap_or(0).to_string(),
|
||||
.unwrap_or(0)
|
||||
.to_string(),
|
||||
network_id: network.local_peer_id().to_base58(),
|
||||
};
|
||||
|
||||
@@ -753,22 +740,28 @@ fn gen_handler<TBl, TBackend, TExPool, TRpc, TCl>(
|
||||
remote_blockchain: Option<Arc<dyn RemoteBlockchain<TBl>>>,
|
||||
rpc_extensions_builder: &(dyn RpcExtensionBuilder<Output = TRpc> + Send),
|
||||
offchain_storage: Option<<TBackend as sc_client_api::backend::Backend<TBl>>::OffchainStorage>,
|
||||
system_rpc_tx: TracingUnboundedSender<sc_rpc::system::Request<TBl>>
|
||||
system_rpc_tx: TracingUnboundedSender<sc_rpc::system::Request<TBl>>,
|
||||
) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TCl: ProvideRuntimeApi<TBl> + BlockchainEvents<TBl> + HeaderBackend<TBl> +
|
||||
HeaderMetadata<TBl, Error=sp_blockchain::Error> + ExecutorProvider<TBl> +
|
||||
CallApiAt<TBl> + ProofProvider<TBl> +
|
||||
StorageProvider<TBl, TBackend> + BlockBackend<TBl> + Send + Sync + 'static,
|
||||
TExPool: MaintainedTransactionPool<Block=TBl, Hash = <TBl as BlockT>::Hash> + 'static,
|
||||
TBackend: sc_client_api::backend::Backend<TBl> + 'static,
|
||||
TRpc: sc_rpc::RpcExtension<sc_rpc::Metadata>,
|
||||
<TCl as ProvideRuntimeApi<TBl>>::Api:
|
||||
sp_session::SessionKeys<TBl> +
|
||||
sp_api::Metadata<TBl>,
|
||||
where
|
||||
TBl: BlockT,
|
||||
TCl: ProvideRuntimeApi<TBl>
|
||||
+ BlockchainEvents<TBl>
|
||||
+ HeaderBackend<TBl>
|
||||
+ HeaderMetadata<TBl, Error = sp_blockchain::Error>
|
||||
+ ExecutorProvider<TBl>
|
||||
+ CallApiAt<TBl>
|
||||
+ ProofProvider<TBl>
|
||||
+ StorageProvider<TBl, TBackend>
|
||||
+ BlockBackend<TBl>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
TExPool: MaintainedTransactionPool<Block = TBl, Hash = <TBl as BlockT>::Hash> + 'static,
|
||||
TBackend: sc_client_api::backend::Backend<TBl> + 'static,
|
||||
TRpc: sc_rpc::RpcExtension<sc_rpc::Metadata>,
|
||||
<TCl as ProvideRuntimeApi<TBl>>::Api: sp_session::SessionKeys<TBl> + sp_api::Metadata<TBl>,
|
||||
{
|
||||
use sc_rpc::{chain, state, author, system, offchain};
|
||||
use sc_rpc::{author, chain, offchain, state, system};
|
||||
|
||||
let system_info = sc_rpc::system::SystemInfo {
|
||||
chain_name: config.chain_spec.name().into(),
|
||||
@@ -781,43 +774,37 @@ fn gen_handler<TBl, TBackend, TExPool, TRpc, TCl>(
|
||||
let task_executor = sc_rpc::SubscriptionTaskExecutor::new(spawn_handle);
|
||||
let subscriptions = SubscriptionManager::new(Arc::new(task_executor.clone()));
|
||||
|
||||
let (chain, state, child_state) = if let (Some(remote_blockchain), Some(on_demand)) =
|
||||
(remote_blockchain, on_demand) {
|
||||
// Light clients
|
||||
let chain = sc_rpc::chain::new_light(
|
||||
client.clone(),
|
||||
subscriptions.clone(),
|
||||
remote_blockchain.clone(),
|
||||
on_demand.clone(),
|
||||
);
|
||||
let (state, child_state) = sc_rpc::state::new_light(
|
||||
client.clone(),
|
||||
subscriptions.clone(),
|
||||
remote_blockchain.clone(),
|
||||
on_demand,
|
||||
deny_unsafe,
|
||||
);
|
||||
(chain, state, child_state)
|
||||
let (chain, state, child_state) =
|
||||
if let (Some(remote_blockchain), Some(on_demand)) = (remote_blockchain, on_demand) {
|
||||
// Light clients
|
||||
let chain = sc_rpc::chain::new_light(
|
||||
client.clone(),
|
||||
subscriptions.clone(),
|
||||
remote_blockchain.clone(),
|
||||
on_demand.clone(),
|
||||
);
|
||||
let (state, child_state) = sc_rpc::state::new_light(
|
||||
client.clone(),
|
||||
subscriptions.clone(),
|
||||
remote_blockchain.clone(),
|
||||
on_demand,
|
||||
deny_unsafe,
|
||||
);
|
||||
(chain, state, child_state)
|
||||
} else {
|
||||
// Full nodes
|
||||
let chain = sc_rpc::chain::new_full(client.clone(), subscriptions.clone());
|
||||
let (state, child_state) = sc_rpc::state::new_full(
|
||||
client.clone(),
|
||||
subscriptions.clone(),
|
||||
deny_unsafe,
|
||||
config.rpc_max_payload,
|
||||
);
|
||||
(chain, state, child_state)
|
||||
};
|
||||
|
||||
} else {
|
||||
// Full nodes
|
||||
let chain = sc_rpc::chain::new_full(client.clone(), subscriptions.clone());
|
||||
let (state, child_state) = sc_rpc::state::new_full(
|
||||
client.clone(),
|
||||
subscriptions.clone(),
|
||||
deny_unsafe,
|
||||
config.rpc_max_payload,
|
||||
);
|
||||
(chain, state, child_state)
|
||||
};
|
||||
|
||||
let author = sc_rpc::author::Author::new(
|
||||
client,
|
||||
transaction_pool,
|
||||
subscriptions,
|
||||
keystore,
|
||||
deny_unsafe,
|
||||
);
|
||||
let author =
|
||||
sc_rpc::author::Author::new(client, transaction_pool, subscriptions, keystore, deny_unsafe);
|
||||
let system = system::System::new(system_info, system_rpc_tx, deny_unsafe);
|
||||
|
||||
let maybe_offchain_rpc = offchain_storage.map(|storage| {
|
||||
@@ -835,7 +822,7 @@ fn gen_handler<TBl, TBackend, TExPool, TRpc, TCl>(
|
||||
system::SystemApi::to_delegate(system),
|
||||
rpc_extensions_builder.build(deny_unsafe, task_executor),
|
||||
),
|
||||
rpc_middleware
|
||||
rpc_middleware,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -854,32 +841,42 @@ pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> {
|
||||
/// 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
|
||||
>>,
|
||||
pub block_announce_validator_builder:
|
||||
Option<Box<dyn FnOnce(Arc<TCl>) -> Box<dyn BlockAnnounceValidator<TBl> + Send> + Send>>,
|
||||
}
|
||||
|
||||
/// Build the network service, the network status sinks and an RPC sender.
|
||||
pub fn build_network<TBl, TExPool, TImpQu, TCl>(
|
||||
params: BuildNetworkParams<TBl, TExPool, TImpQu, TCl>
|
||||
params: BuildNetworkParams<TBl, TExPool, TImpQu, TCl>,
|
||||
) -> Result<
|
||||
(
|
||||
Arc<NetworkService<TBl, <TBl as BlockT>::Hash>>,
|
||||
TracingUnboundedSender<sc_rpc::system::Request<TBl>>,
|
||||
NetworkStarter,
|
||||
),
|
||||
Error
|
||||
Error,
|
||||
>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TCl: ProvideRuntimeApi<TBl> + HeaderMetadata<TBl, Error=sp_blockchain::Error> + Chain<TBl> +
|
||||
BlockBackend<TBl> + BlockIdTo<TBl, Error=sp_blockchain::Error> + ProofProvider<TBl> +
|
||||
HeaderBackend<TBl> + BlockchainEvents<TBl> + 'static,
|
||||
TExPool: MaintainedTransactionPool<Block=TBl, Hash = <TBl as BlockT>::Hash> + 'static,
|
||||
TImpQu: ImportQueue<TBl> + 'static,
|
||||
where
|
||||
TBl: BlockT,
|
||||
TCl: ProvideRuntimeApi<TBl>
|
||||
+ HeaderMetadata<TBl, Error = sp_blockchain::Error>
|
||||
+ Chain<TBl>
|
||||
+ BlockBackend<TBl>
|
||||
+ BlockIdTo<TBl, Error = sp_blockchain::Error>
|
||||
+ ProofProvider<TBl>
|
||||
+ HeaderBackend<TBl>
|
||||
+ BlockchainEvents<TBl>
|
||||
+ 'static,
|
||||
TExPool: MaintainedTransactionPool<Block = TBl, Hash = <TBl as BlockT>::Hash> + 'static,
|
||||
TImpQu: ImportQueue<TBl> + 'static,
|
||||
{
|
||||
let BuildNetworkParams {
|
||||
config, client, transaction_pool, spawn_handle, import_queue, on_demand,
|
||||
config,
|
||||
client,
|
||||
transaction_pool,
|
||||
spawn_handle,
|
||||
import_queue,
|
||||
on_demand,
|
||||
block_announce_validator_builder,
|
||||
} = params;
|
||||
|
||||
@@ -906,8 +903,8 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
|
||||
let (handler, protocol_config) = BlockRequestHandler::new(
|
||||
&protocol_id,
|
||||
client.clone(),
|
||||
config.network.default_peers_set.in_peers as usize
|
||||
+ config.network.default_peers_set.out_peers as usize,
|
||||
config.network.default_peers_set.in_peers as usize +
|
||||
config.network.default_peers_set.out_peers as usize,
|
||||
);
|
||||
spawn_handle.spawn("block_request_handler", handler.run());
|
||||
protocol_config
|
||||
@@ -923,8 +920,8 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
|
||||
let (handler, protocol_config) = StateRequestHandler::new(
|
||||
&protocol_id,
|
||||
client.clone(),
|
||||
config.network.default_peers_set.in_peers as usize
|
||||
+ config.network.default_peers_set.out_peers as usize,
|
||||
config.network.default_peers_set.in_peers as usize +
|
||||
config.network.default_peers_set.out_peers as usize,
|
||||
);
|
||||
spawn_handle.spawn("state_request_handler", handler.run());
|
||||
protocol_config
|
||||
@@ -937,10 +934,8 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
|
||||
light_client_requests::generate_protocol_config(&protocol_id)
|
||||
} else {
|
||||
// Allow both outgoing and incoming requests.
|
||||
let (handler, protocol_config) = LightClientRequestHandler::new(
|
||||
&protocol_id,
|
||||
client.clone(),
|
||||
);
|
||||
let (handler, protocol_config) =
|
||||
LightClientRequestHandler::new(&protocol_id, client.clone());
|
||||
spawn_handle.spawn("light_client_request_handler", handler.run());
|
||||
protocol_config
|
||||
}
|
||||
@@ -962,7 +957,7 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
|
||||
},
|
||||
network_config: config.network.clone(),
|
||||
chain: client.clone(),
|
||||
on_demand: on_demand,
|
||||
on_demand,
|
||||
transaction_pool: transaction_pool_adapter as _,
|
||||
import_queue: Box::new(import_queue),
|
||||
protocol_id,
|
||||
@@ -976,10 +971,8 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
|
||||
// Storage chains don't keep full block history and can't be synced in full mode.
|
||||
// Force fast sync when storage chain mode is enabled.
|
||||
if matches!(config.transaction_storage, TransactionStorageMode::StorageChain) {
|
||||
network_params.network_config.sync_mode = SyncMode::Fast {
|
||||
storage_chain_mode: true,
|
||||
skip_proofs: false,
|
||||
};
|
||||
network_params.network_config.sync_mode =
|
||||
SyncMode::Fast { storage_chain_mode: true, skip_proofs: false };
|
||||
}
|
||||
|
||||
let has_bootnodes = !network_params.network_config.boot_nodes.is_empty();
|
||||
@@ -1028,7 +1021,7 @@ pub fn build_network<TBl, TExPool, TImpQu, TCl>(
|
||||
);
|
||||
// This `return` might seem unnecessary, but we don't want to make it look like
|
||||
// everything is working as normal even though the user is clearly misusing the API.
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
future.await
|
||||
|
||||
@@ -17,22 +17,20 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::error::Error;
|
||||
use futures::{future, prelude::*};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use sp_runtime::generic::BlockId;
|
||||
use codec::Encode;
|
||||
use sp_consensus::import_queue::ImportQueue;
|
||||
use futures::{future, prelude::*};
|
||||
use sc_client_api::{BlockBackend, UsageProvider};
|
||||
use sp_consensus::import_queue::ImportQueue;
|
||||
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use crate::chain_ops::import_blocks;
|
||||
use std::{pin::Pin, sync::Arc};
|
||||
|
||||
/// Re-validate known block.
|
||||
pub fn check_block<B, IQ, C>(
|
||||
client: Arc<C>,
|
||||
import_queue: IQ,
|
||||
block_id: BlockId<B>
|
||||
block_id: BlockId<B>,
|
||||
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send>>
|
||||
where
|
||||
C: BlockBackend<B> + UsageProvider<B> + Send + Sync + 'static,
|
||||
@@ -46,7 +44,7 @@ where
|
||||
block.encode_to(&mut buf);
|
||||
let reader = std::io::Cursor::new(buf);
|
||||
import_blocks(client, import_queue, reader, true, true)
|
||||
}
|
||||
},
|
||||
Ok(None) => Box::pin(future::err("Unknown block".into())),
|
||||
Err(e) => Box::pin(future::err(format!("Error reading block: {:?}", e).into())),
|
||||
}
|
||||
|
||||
@@ -17,18 +17,16 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::error::Error;
|
||||
use log::info;
|
||||
use futures::{future, prelude::*};
|
||||
use sp_runtime::traits::{
|
||||
Block as BlockT, NumberFor, One, Zero, SaturatedConversion
|
||||
};
|
||||
use sp_runtime::generic::BlockId;
|
||||
use codec::Encode;
|
||||
use futures::{future, prelude::*};
|
||||
use log::info;
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, NumberFor, One, SaturatedConversion, Zero},
|
||||
};
|
||||
|
||||
use std::{io::Write, pin::Pin};
|
||||
use sc_client_api::{BlockBackend, UsageProvider};
|
||||
use std::sync::Arc;
|
||||
use std::task::Poll;
|
||||
use std::{io::Write, pin::Pin, sync::Arc, task::Poll};
|
||||
|
||||
/// Performs the blocks export.
|
||||
pub fn export_blocks<B, C>(
|
||||
@@ -36,7 +34,7 @@ pub fn export_blocks<B, C>(
|
||||
mut output: impl Write + 'static,
|
||||
from: NumberFor<B>,
|
||||
to: Option<NumberFor<B>>,
|
||||
binary: bool
|
||||
binary: bool,
|
||||
) -> Pin<Box<dyn Future<Output = Result<(), Error>>>>
|
||||
where
|
||||
C: BlockBackend<B> + UsageProvider<B> + 'static,
|
||||
@@ -63,7 +61,7 @@ where
|
||||
let client = &client;
|
||||
|
||||
if last < block {
|
||||
return Poll::Ready(Err("Invalid block range specified".into()));
|
||||
return Poll::Ready(Err("Invalid block range specified".into()))
|
||||
}
|
||||
|
||||
if !wrote_header {
|
||||
@@ -78,14 +76,13 @@ where
|
||||
}
|
||||
|
||||
match client.block(&BlockId::number(block))? {
|
||||
Some(block) => {
|
||||
Some(block) =>
|
||||
if binary {
|
||||
output.write_all(&block.encode())?;
|
||||
} else {
|
||||
serde_json::to_writer(&mut output, &block)
|
||||
.map_err(|e| format!("Error writing JSON: {}", e))?;
|
||||
}
|
||||
},
|
||||
},
|
||||
// Reached end of the chain.
|
||||
None => return Poll::Ready(Ok(())),
|
||||
}
|
||||
@@ -93,7 +90,7 @@ where
|
||||
info!("#{}", block);
|
||||
}
|
||||
if block == last {
|
||||
return Poll::Ready(Ok(()));
|
||||
return Poll::Ready(Ok(()))
|
||||
}
|
||||
block += One::one();
|
||||
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::error::Error;
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_core::storage::{StorageKey, well_known_keys, ChildInfo, Storage, StorageChild, StorageMap};
|
||||
use sc_client_api::{StorageProvider, UsageProvider};
|
||||
use sp_core::storage::{well_known_keys, ChildInfo, Storage, StorageChild, StorageKey, StorageMap};
|
||||
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
@@ -35,9 +34,7 @@ where
|
||||
B: BlockT,
|
||||
BA: sc_client_api::backend::Backend<B>,
|
||||
{
|
||||
let block = block.unwrap_or_else(
|
||||
|| BlockId::Hash(client.usage_info().chain.best_hash)
|
||||
);
|
||||
let block = block.unwrap_or_else(|| BlockId::Hash(client.usage_info().chain.best_hash));
|
||||
|
||||
let empty_key = StorageKey(Vec::new());
|
||||
let mut top_storage = client.storage_pairs(&block, &empty_key)?;
|
||||
@@ -47,12 +44,12 @@ where
|
||||
// pairs.
|
||||
while let Some(pos) = top_storage
|
||||
.iter()
|
||||
.position(|(k, _)| k.0.starts_with(well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX)) {
|
||||
.position(|(k, _)| k.0.starts_with(well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX))
|
||||
{
|
||||
let (key, _) = top_storage.swap_remove(pos);
|
||||
|
||||
let key = StorageKey(
|
||||
key.0[well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX.len()..].to_vec(),
|
||||
);
|
||||
let key =
|
||||
StorageKey(key.0[well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX.len()..].to_vec());
|
||||
let child_info = ChildInfo::new_default(&key.0);
|
||||
|
||||
let keys = client.child_storage_keys(&block, &child_info, &empty_key)?;
|
||||
|
||||
@@ -16,29 +16,31 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::error;
|
||||
use crate::error::Error;
|
||||
use sc_chain_spec::ChainSpec;
|
||||
use log::{warn, info};
|
||||
use futures::{future, prelude::*};
|
||||
use sp_runtime::traits::{
|
||||
Block as BlockT, NumberFor, Zero, Header, MaybeSerializeDeserialize,
|
||||
};
|
||||
use sp_runtime::generic::SignedBlock;
|
||||
use crate::{error, error::Error};
|
||||
use codec::{Decode, IoReader as CodecIoReader};
|
||||
use futures::{future, prelude::*};
|
||||
use log::{info, warn};
|
||||
use sc_chain_spec::ChainSpec;
|
||||
use sp_consensus::{
|
||||
import_queue::{BlockImportError, BlockImportResult, ImportQueue, IncomingBlock, Link},
|
||||
BlockOrigin,
|
||||
import_queue::{IncomingBlock, Link, BlockImportError, BlockImportResult, ImportQueue},
|
||||
};
|
||||
use sp_runtime::{
|
||||
generic::SignedBlock,
|
||||
traits::{Block as BlockT, Header, MaybeSerializeDeserialize, NumberFor, Zero},
|
||||
};
|
||||
|
||||
use std::{io::{Read, Seek}, pin::Pin};
|
||||
use std::time::{Duration, Instant};
|
||||
use futures_timer::Delay;
|
||||
use std::task::Poll;
|
||||
use serde_json::{de::IoRead as JsonIoRead, Deserializer, StreamDeserializer};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use sp_runtime::traits::{CheckedDiv, Saturating};
|
||||
use sc_client_api::UsageProvider;
|
||||
use serde_json::{de::IoRead as JsonIoRead, Deserializer, StreamDeserializer};
|
||||
use sp_runtime::traits::{CheckedDiv, Saturating};
|
||||
use std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
io::{Read, Seek},
|
||||
pin::Pin,
|
||||
task::Poll,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
/// Number of blocks we will add to the queue before waiting for the queue to catch up.
|
||||
const MAX_PENDING_BLOCKS: u64 = 1_024;
|
||||
@@ -56,11 +58,11 @@ pub fn build_spec(spec: &dyn ChainSpec, raw: bool) -> error::Result<String> {
|
||||
spec.as_json(raw).map_err(Into::into)
|
||||
}
|
||||
|
||||
|
||||
/// Helper enum that wraps either a binary decoder (from parity-scale-codec), or a JSON decoder
|
||||
/// (from serde_json). Implements the Iterator Trait, calling `next()` will decode the next
|
||||
/// SignedBlock and return it.
|
||||
enum BlockIter<R, B> where
|
||||
enum BlockIter<R, B>
|
||||
where
|
||||
R: std::io::Read + std::io::Seek,
|
||||
{
|
||||
Binary {
|
||||
@@ -79,7 +81,8 @@ enum BlockIter<R, B> where
|
||||
},
|
||||
}
|
||||
|
||||
impl<R, B> BlockIter<R, B> where
|
||||
impl<R, B> BlockIter<R, B>
|
||||
where
|
||||
R: Read + Seek + 'static,
|
||||
B: BlockT + MaybeSerializeDeserialize,
|
||||
{
|
||||
@@ -90,40 +93,32 @@ impl<R, B> BlockIter<R, B> where
|
||||
// of blocks that are going to be decoded. We read it and add it to our enum struct.
|
||||
let num_expected_blocks: u64 = Decode::decode(&mut reader)
|
||||
.map_err(|e| format!("Failed to decode the number of blocks: {:?}", e))?;
|
||||
Ok(BlockIter::Binary {
|
||||
num_expected_blocks,
|
||||
read_block_count: 0,
|
||||
reader,
|
||||
})
|
||||
Ok(BlockIter::Binary { num_expected_blocks, read_block_count: 0, reader })
|
||||
} else {
|
||||
let stream_deser = Deserializer::from_reader(input)
|
||||
.into_iter::<SignedBlock<B>>();
|
||||
Ok(BlockIter::Json {
|
||||
reader: stream_deser,
|
||||
read_block_count: 0,
|
||||
})
|
||||
let stream_deser = Deserializer::from_reader(input).into_iter::<SignedBlock<B>>();
|
||||
Ok(BlockIter::Json { reader: stream_deser, read_block_count: 0 })
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of blocks read thus far.
|
||||
fn read_block_count(&self) -> u64 {
|
||||
match self {
|
||||
BlockIter::Binary { read_block_count, .. }
|
||||
| BlockIter::Json { read_block_count, .. }
|
||||
=> *read_block_count,
|
||||
BlockIter::Binary { read_block_count, .. } |
|
||||
BlockIter::Json { read_block_count, .. } => *read_block_count,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the total number of blocks to be imported, if possible.
|
||||
fn num_expected_blocks(&self) -> Option<u64> {
|
||||
match self {
|
||||
BlockIter::Binary { num_expected_blocks, ..} => Some(*num_expected_blocks),
|
||||
BlockIter::Json {..} => None
|
||||
BlockIter::Binary { num_expected_blocks, .. } => Some(*num_expected_blocks),
|
||||
BlockIter::Json { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, B> Iterator for BlockIter<R, B> where
|
||||
impl<R, B> Iterator for BlockIter<R, B>
|
||||
where
|
||||
R: Read + Seek + 'static,
|
||||
B: BlockT + MaybeSerializeDeserialize,
|
||||
{
|
||||
@@ -133,20 +128,20 @@ impl<R, B> Iterator for BlockIter<R, B> where
|
||||
match self {
|
||||
BlockIter::Binary { num_expected_blocks, read_block_count, reader } => {
|
||||
if read_block_count < num_expected_blocks {
|
||||
let block_result: Result<SignedBlock::<B>, _> = SignedBlock::<B>::decode(reader)
|
||||
.map_err(|e| e.to_string());
|
||||
let block_result: Result<SignedBlock<B>, _> =
|
||||
SignedBlock::<B>::decode(reader).map_err(|e| e.to_string());
|
||||
*read_block_count += 1;
|
||||
Some(block_result)
|
||||
} else {
|
||||
// `read_block_count` == `num_expected_blocks` so we've read enough blocks.
|
||||
None
|
||||
}
|
||||
}
|
||||
},
|
||||
BlockIter::Json { reader, read_block_count } => {
|
||||
let res = Some(reader.next()?.map_err(|e| e.to_string()));
|
||||
*read_block_count += 1;
|
||||
res
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,7 +150,7 @@ impl<R, B> Iterator for BlockIter<R, B> where
|
||||
fn import_block_to_queue<TBl, TImpQu>(
|
||||
signed_block: SignedBlock<TBl>,
|
||||
queue: &mut TImpQu,
|
||||
force: bool
|
||||
force: bool,
|
||||
) where
|
||||
TBl: BlockT + MaybeSerializeDeserialize,
|
||||
TImpQu: 'static + ImportQueue<TBl>,
|
||||
@@ -163,8 +158,9 @@ fn import_block_to_queue<TBl, TImpQu>(
|
||||
let (header, extrinsics) = signed_block.block.deconstruct();
|
||||
let hash = header.hash();
|
||||
// import queue handles verification and importing it into the client.
|
||||
queue.import_blocks(BlockOrigin::File, vec![
|
||||
IncomingBlock::<TBl> {
|
||||
queue.import_blocks(
|
||||
BlockOrigin::File,
|
||||
vec![IncomingBlock::<TBl> {
|
||||
hash,
|
||||
header: Some(header),
|
||||
body: Some(extrinsics),
|
||||
@@ -175,15 +171,15 @@ fn import_block_to_queue<TBl, TImpQu>(
|
||||
import_existing: force,
|
||||
state: None,
|
||||
skip_execution: false,
|
||||
}
|
||||
]);
|
||||
}],
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns true if we have imported every block we were supposed to import, else returns false.
|
||||
fn importing_is_done(
|
||||
num_expected_blocks: Option<u64>,
|
||||
read_block_count: u64,
|
||||
imported_blocks: u64
|
||||
imported_blocks: u64,
|
||||
) -> bool {
|
||||
if let Some(num_expected_blocks) = num_expected_blocks {
|
||||
imported_blocks >= num_expected_blocks
|
||||
@@ -209,7 +205,7 @@ impl<B: BlockT> Speedometer<B> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates `(best_number - last_number) / (now - last_update)` and
|
||||
/// Calculates `(best_number - last_number) / (now - last_update)` and
|
||||
/// logs the speed of import.
|
||||
fn display_speed(&self) {
|
||||
// Number of milliseconds elapsed since last time.
|
||||
@@ -223,24 +219,28 @@ impl<B: BlockT> Speedometer<B> {
|
||||
// Number of blocks that have been imported since last time.
|
||||
let diff = match self.last_number {
|
||||
None => return,
|
||||
Some(n) => self.best_number.saturating_sub(n)
|
||||
Some(n) => self.best_number.saturating_sub(n),
|
||||
};
|
||||
|
||||
if let Ok(diff) = TryInto::<u128>::try_into(diff) {
|
||||
// If the number of blocks can be converted to a regular integer, then it's easy: just
|
||||
// do the math and turn it into a `f64`.
|
||||
let speed = diff.saturating_mul(10_000).checked_div(u128::from(elapsed_ms))
|
||||
.map_or(0.0, |s| s as f64) / 10.0;
|
||||
let speed = diff
|
||||
.saturating_mul(10_000)
|
||||
.checked_div(u128::from(elapsed_ms))
|
||||
.map_or(0.0, |s| s as f64) /
|
||||
10.0;
|
||||
info!("📦 Current best block: {} ({:4.1} bps)", self.best_number, speed);
|
||||
} else {
|
||||
// If the number of blocks can't be converted to a regular integer, then we need a more
|
||||
// algebraic approach and we stay within the realm of integers.
|
||||
let one_thousand = NumberFor::<B>::from(1_000u32);
|
||||
let elapsed = NumberFor::<B>::from(
|
||||
<u32 as TryFrom<_>>::try_from(elapsed_ms).unwrap_or(u32::MAX)
|
||||
);
|
||||
let elapsed =
|
||||
NumberFor::<B>::from(<u32 as TryFrom<_>>::try_from(elapsed_ms).unwrap_or(u32::MAX));
|
||||
|
||||
let speed = diff.saturating_mul(one_thousand).checked_div(&elapsed)
|
||||
let speed = diff
|
||||
.saturating_mul(one_thousand)
|
||||
.checked_div(&elapsed)
|
||||
.unwrap_or_else(Zero::zero);
|
||||
info!("📦 Current best block: {} ({} bps)", self.best_number, speed)
|
||||
}
|
||||
@@ -265,22 +265,23 @@ impl<B: BlockT> Speedometer<B> {
|
||||
}
|
||||
|
||||
/// Different State that the `import_blocks` future could be in.
|
||||
enum ImportState<R, B> where
|
||||
enum ImportState<R, B>
|
||||
where
|
||||
R: Read + Seek + 'static,
|
||||
B: BlockT + MaybeSerializeDeserialize,
|
||||
{
|
||||
/// We are reading from the BlockIter structure, adding those blocks to the queue if possible.
|
||||
Reading{block_iter: BlockIter<R, B>},
|
||||
Reading { block_iter: BlockIter<R, B> },
|
||||
/// The queue is full (contains at least MAX_PENDING_BLOCKS blocks) and we are waiting for it to
|
||||
/// catch up.
|
||||
WaitingForImportQueueToCatchUp{
|
||||
WaitingForImportQueueToCatchUp {
|
||||
block_iter: BlockIter<R, B>,
|
||||
delay: Delay,
|
||||
block: SignedBlock<B>
|
||||
block: SignedBlock<B>,
|
||||
},
|
||||
// We have added all the blocks to the queue but they are still being processed.
|
||||
WaitingForImportQueueToFinish{
|
||||
num_expected_blocks: Option<u64>,
|
||||
WaitingForImportQueueToFinish {
|
||||
num_expected_blocks: Option<u64>,
|
||||
read_block_count: u64,
|
||||
delay: Delay,
|
||||
},
|
||||
@@ -306,10 +307,7 @@ where
|
||||
|
||||
impl WaitLink {
|
||||
fn new() -> WaitLink {
|
||||
WaitLink {
|
||||
imported_blocks: 0,
|
||||
has_error: false,
|
||||
}
|
||||
WaitLink { imported_blocks: 0, has_error: false }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +316,7 @@ where
|
||||
&mut self,
|
||||
imported: usize,
|
||||
_num_expected_blocks: usize,
|
||||
results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>
|
||||
results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>,
|
||||
) {
|
||||
self.imported_blocks += imported as u64;
|
||||
|
||||
@@ -326,7 +324,7 @@ where
|
||||
if let (Err(err), hash) = result {
|
||||
warn!("There was an error importing block with hash {:?}: {:?}", hash, err);
|
||||
self.has_error = true;
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -338,13 +336,13 @@ where
|
||||
let block_iter = match block_iter_res {
|
||||
Ok(block_iter) => block_iter,
|
||||
Err(e) => {
|
||||
// We've encountered an error while creating the block iterator
|
||||
// We've encountered an error while creating the block iterator
|
||||
// so we can just return a future that returns an error.
|
||||
return future::ready(Err(Error::Other(e))).boxed()
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let mut state = Some(ImportState::Reading{block_iter});
|
||||
let mut state = Some(ImportState::Reading { block_iter });
|
||||
let mut speedometer = Speedometer::<B>::new();
|
||||
|
||||
// Importing blocks is implemented as a future, because we want the operation to be
|
||||
@@ -358,7 +356,7 @@ where
|
||||
let client = &client;
|
||||
let queue = &mut import_queue;
|
||||
match state.take().expect("state should never be None; qed") {
|
||||
ImportState::Reading{mut block_iter} => {
|
||||
ImportState::Reading { mut block_iter } => {
|
||||
match block_iter.next() {
|
||||
None => {
|
||||
// The iterator is over: we now need to wait for the import queue to finish.
|
||||
@@ -366,7 +364,9 @@ where
|
||||
let read_block_count = block_iter.read_block_count();
|
||||
let delay = Delay::new(Duration::from_millis(DELAY_TIME));
|
||||
state = Some(ImportState::WaitingForImportQueueToFinish {
|
||||
num_expected_blocks, read_block_count, delay
|
||||
num_expected_blocks,
|
||||
read_block_count,
|
||||
delay,
|
||||
});
|
||||
},
|
||||
Some(block_result) => {
|
||||
@@ -378,32 +378,35 @@ where
|
||||
// until the queue has made some progress.
|
||||
let delay = Delay::new(Duration::from_millis(DELAY_TIME));
|
||||
state = Some(ImportState::WaitingForImportQueueToCatchUp {
|
||||
block_iter, delay, block
|
||||
block_iter,
|
||||
delay,
|
||||
block,
|
||||
});
|
||||
} else {
|
||||
// Queue is not full, we can keep on adding blocks to the queue.
|
||||
import_block_to_queue(block, queue, force);
|
||||
state = Some(ImportState::Reading{block_iter});
|
||||
state = Some(ImportState::Reading { block_iter });
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Poll::Ready(
|
||||
Err(Error::Other(
|
||||
format!("Error reading block #{}: {}", read_block_count, e)
|
||||
)))
|
||||
}
|
||||
},
|
||||
Err(e) =>
|
||||
return Poll::Ready(Err(Error::Other(format!(
|
||||
"Error reading block #{}: {}",
|
||||
read_block_count, e
|
||||
)))),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
ImportState::WaitingForImportQueueToCatchUp{block_iter, mut delay, block} => {
|
||||
ImportState::WaitingForImportQueueToCatchUp { block_iter, mut delay, block } => {
|
||||
let read_block_count = block_iter.read_block_count();
|
||||
if read_block_count - link.imported_blocks >= MAX_PENDING_BLOCKS {
|
||||
// Queue is still full, so wait until there is room to insert our block.
|
||||
match Pin::new(&mut delay).poll(cx) {
|
||||
Poll::Pending => {
|
||||
state = Some(ImportState::WaitingForImportQueueToCatchUp {
|
||||
block_iter, delay, block
|
||||
block_iter,
|
||||
delay,
|
||||
block,
|
||||
});
|
||||
return Poll::Pending
|
||||
},
|
||||
@@ -412,25 +415,30 @@ where
|
||||
},
|
||||
}
|
||||
state = Some(ImportState::WaitingForImportQueueToCatchUp {
|
||||
block_iter, delay, block
|
||||
block_iter,
|
||||
delay,
|
||||
block,
|
||||
});
|
||||
} else {
|
||||
// Queue is no longer full, so we can add our block to the queue.
|
||||
import_block_to_queue(block, queue, force);
|
||||
// Switch back to Reading state.
|
||||
state = Some(ImportState::Reading{block_iter});
|
||||
state = Some(ImportState::Reading { block_iter });
|
||||
}
|
||||
},
|
||||
ImportState::WaitingForImportQueueToFinish {
|
||||
num_expected_blocks, read_block_count, mut delay
|
||||
num_expected_blocks,
|
||||
read_block_count,
|
||||
mut delay,
|
||||
} => {
|
||||
// All the blocks have been added to the queue, which doesn't mean they
|
||||
// All the blocks have been added to the queue, which doesn't mean they
|
||||
// have all been properly imported.
|
||||
if importing_is_done(num_expected_blocks, read_block_count, link.imported_blocks) {
|
||||
// Importing is done, we can log the result and return.
|
||||
info!(
|
||||
"🎉 Imported {} blocks. Best: #{}",
|
||||
read_block_count, client.usage_info().chain.best_number
|
||||
read_block_count,
|
||||
client.usage_info().chain.best_number
|
||||
);
|
||||
return Poll::Ready(Ok(()))
|
||||
} else {
|
||||
@@ -439,7 +447,9 @@ where
|
||||
match Pin::new(&mut delay).poll(cx) {
|
||||
Poll::Pending => {
|
||||
state = Some(ImportState::WaitingForImportQueueToFinish {
|
||||
num_expected_blocks, read_block_count, delay
|
||||
num_expected_blocks,
|
||||
read_block_count,
|
||||
delay,
|
||||
});
|
||||
return Poll::Pending
|
||||
},
|
||||
@@ -449,10 +459,12 @@ where
|
||||
}
|
||||
|
||||
state = Some(ImportState::WaitingForImportQueueToFinish {
|
||||
num_expected_blocks, read_block_count, delay
|
||||
num_expected_blocks,
|
||||
read_block_count,
|
||||
delay,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
queue.poll_actions(cx, &mut link);
|
||||
@@ -461,11 +473,10 @@ where
|
||||
speedometer.notify_user(best_number);
|
||||
|
||||
if link.has_error {
|
||||
return Poll::Ready(Err(
|
||||
Error::Other(
|
||||
format!("Stopping after #{} blocks because of an error", link.imported_blocks)
|
||||
)
|
||||
))
|
||||
return Poll::Ready(Err(Error::Other(format!(
|
||||
"Stopping after #{} blocks because of an error",
|
||||
link.imported_blocks
|
||||
))))
|
||||
}
|
||||
|
||||
cx.waker().wake_by_ref();
|
||||
|
||||
@@ -18,15 +18,15 @@
|
||||
|
||||
use crate::error::Error;
|
||||
use log::info;
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor, Zero};
|
||||
use sc_client_api::{Backend, UsageProvider};
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor, Zero};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Performs a revert of `blocks` blocks.
|
||||
pub fn revert_chain<B, BA, C>(
|
||||
client: Arc<C>,
|
||||
backend: Arc<BA>,
|
||||
blocks: NumberFor<B>
|
||||
blocks: NumberFor<B>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
B: BlockT,
|
||||
|
||||
@@ -20,11 +20,9 @@
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use sp_runtime::{
|
||||
traits::{Block as BlockT, NumberFor},
|
||||
};
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor};
|
||||
|
||||
use sc_client_api::{ForkBlocks, BadBlocks};
|
||||
use sc_client_api::{BadBlocks, ForkBlocks};
|
||||
|
||||
/// Chain specification rules lookup result.
|
||||
pub enum LookupResult<B: BlockT> {
|
||||
@@ -33,7 +31,7 @@ pub enum LookupResult<B: BlockT> {
|
||||
/// The block is known to be bad and should not be imported
|
||||
KnownBad,
|
||||
/// There is a specified canonical block hash for the given height
|
||||
Expected(B::Hash)
|
||||
Expected(B::Hash),
|
||||
}
|
||||
|
||||
/// Chain-specific block filtering rules.
|
||||
@@ -47,10 +45,7 @@ pub struct BlockRules<B: BlockT> {
|
||||
|
||||
impl<B: BlockT> BlockRules<B> {
|
||||
/// New block rules with provided black and white lists.
|
||||
pub fn new(
|
||||
fork_blocks: ForkBlocks<B>,
|
||||
bad_blocks: BadBlocks<B>,
|
||||
) -> Self {
|
||||
pub fn new(fork_blocks: ForkBlocks<B>, bad_blocks: BadBlocks<B>) -> Self {
|
||||
Self {
|
||||
bad: bad_blocks.unwrap_or_else(|| HashSet::new()),
|
||||
forks: fork_blocks.unwrap_or_else(|| vec![]).into_iter().collect(),
|
||||
@@ -66,7 +61,7 @@ impl<B: BlockT> BlockRules<B> {
|
||||
pub fn lookup(&self, number: NumberFor<B>, hash: &B::Hash) -> LookupResult<B> {
|
||||
if let Some(hash_for_height) = self.forks.get(&number) {
|
||||
if hash_for_height != hash {
|
||||
return LookupResult::Expected(hash_for_height.clone());
|
||||
return LookupResult::Expected(hash_for_height.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,23 +16,25 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use std::{sync::Arc, panic::UnwindSafe, result, cell::RefCell};
|
||||
use codec::{Encode, Decode};
|
||||
use super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes};
|
||||
use codec::{Decode, Encode};
|
||||
use sc_client_api::{backend, call_executor::CallExecutor};
|
||||
use sc_executor::{NativeVersion, RuntimeInfo, RuntimeVersion};
|
||||
use sp_api::{ProofRecorder, StorageTransactionCache};
|
||||
use sp_core::{
|
||||
traits::{CodeExecutor, RuntimeCode, SpawnNamed},
|
||||
NativeOrEncoded, NeverNativeValue,
|
||||
};
|
||||
use sp_externalities::Extensions;
|
||||
use sp_runtime::{
|
||||
generic::BlockId, traits::{Block as BlockT, HashFor, NumberFor},
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, HashFor, NumberFor},
|
||||
};
|
||||
use sp_state_machine::{
|
||||
self, OverlayedChanges, Ext, ExecutionManager, StateMachine, ExecutionStrategy,
|
||||
backend::Backend as _, StorageProof,
|
||||
self, backend::Backend as _, ExecutionManager, ExecutionStrategy, Ext, OverlayedChanges,
|
||||
StateMachine, StorageProof,
|
||||
};
|
||||
use sc_executor::{RuntimeVersion, RuntimeInfo, NativeVersion};
|
||||
use sp_externalities::Extensions;
|
||||
use sp_core::{
|
||||
NativeOrEncoded, NeverNativeValue, traits::{CodeExecutor, SpawnNamed, RuntimeCode},
|
||||
};
|
||||
use sp_api::{ProofRecorder, StorageTransactionCache};
|
||||
use sc_client_api::{backend, call_executor::CallExecutor};
|
||||
use super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes};
|
||||
use std::{cell::RefCell, panic::UnwindSafe, result, sync::Arc};
|
||||
|
||||
/// Call executor that executes methods locally, querying all required
|
||||
/// data from local backend.
|
||||
@@ -57,7 +59,8 @@ where
|
||||
spawn_handle: Box<dyn SpawnNamed>,
|
||||
client_config: ClientConfig<Block>,
|
||||
) -> sp_blockchain::Result<Self> {
|
||||
let wasm_override = client_config.wasm_runtime_overrides
|
||||
let wasm_override = client_config
|
||||
.wasm_runtime_overrides
|
||||
.as_ref()
|
||||
.map(|p| WasmOverride::new(p.clone(), executor.clone()))
|
||||
.transpose()?;
|
||||
@@ -91,10 +94,12 @@ where
|
||||
B: backend::Backend<Block>,
|
||||
{
|
||||
let spec = self.runtime_version(id)?.spec_version;
|
||||
let code = if let Some(d) = self.wasm_override
|
||||
let code = if let Some(d) = self
|
||||
.wasm_override
|
||||
.as_ref()
|
||||
.map(|o| o.get(&spec, onchain_code.heap_pages))
|
||||
.flatten() {
|
||||
.flatten()
|
||||
{
|
||||
log::debug!(target: "wasm_overrides", "using WASM override for block {}", id);
|
||||
d
|
||||
} else if let Some(s) = self.wasm_substitutes.get(spec, onchain_code.heap_pages, id) {
|
||||
@@ -113,7 +118,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT, B, E> Clone for LocalCallExecutor<Block, B, E> where E: Clone {
|
||||
impl<Block: BlockT, B, E> Clone for LocalCallExecutor<Block, B, E>
|
||||
where
|
||||
E: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
LocalCallExecutor {
|
||||
backend: self.backend.clone(),
|
||||
@@ -145,13 +153,12 @@ where
|
||||
extensions: Option<Extensions>,
|
||||
) -> sp_blockchain::Result<Vec<u8>> {
|
||||
let mut changes = OverlayedChanges::default();
|
||||
let changes_trie = backend::changes_tries_state_at_block(
|
||||
id, self.backend.changes_trie_storage()
|
||||
)?;
|
||||
let changes_trie =
|
||||
backend::changes_tries_state_at_block(id, self.backend.changes_trie_storage())?;
|
||||
let state = self.backend.state_at(*id)?;
|
||||
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)?;
|
||||
let runtime_code =
|
||||
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
|
||||
let runtime_code = self.check_override(runtime_code, id)?;
|
||||
|
||||
let return_data = StateMachine::new(
|
||||
@@ -164,7 +171,8 @@ where
|
||||
extensions.unwrap_or_default(),
|
||||
&runtime_code,
|
||||
self.spawn_handle.clone(),
|
||||
).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
|
||||
)
|
||||
.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>(
|
||||
strategy.get_manager(),
|
||||
None,
|
||||
)?;
|
||||
@@ -175,7 +183,7 @@ where
|
||||
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,
|
||||
@@ -185,15 +193,17 @@ where
|
||||
method: &str,
|
||||
call_data: &[u8],
|
||||
changes: &RefCell<OverlayedChanges>,
|
||||
storage_transaction_cache: Option<&RefCell<
|
||||
StorageTransactionCache<Block, B::State>
|
||||
>>,
|
||||
storage_transaction_cache: Option<&RefCell<StorageTransactionCache<Block, B::State>>>,
|
||||
execution_manager: ExecutionManager<EM>,
|
||||
native_call: Option<NC>,
|
||||
recorder: &Option<ProofRecorder<Block>>,
|
||||
extensions: Option<Extensions>,
|
||||
) -> Result<NativeOrEncoded<R>, sp_blockchain::Error> where ExecutionManager<EM>: Clone {
|
||||
let changes_trie_state = backend::changes_tries_state_at_block(at, self.backend.changes_trie_storage())?;
|
||||
) -> Result<NativeOrEncoded<R>, sp_blockchain::Error>
|
||||
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 mut state = self.backend.state_at(*at)?;
|
||||
@@ -202,16 +212,17 @@ where
|
||||
|
||||
match recorder {
|
||||
Some(recorder) => {
|
||||
let trie_state = state.as_trie_backend()
|
||||
.ok_or_else(||
|
||||
Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof) as Box<dyn sp_state_machine::Error>
|
||||
)?;
|
||||
let trie_state = state.as_trie_backend().ok_or_else(|| {
|
||||
Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof)
|
||||
as Box<dyn sp_state_machine::Error>
|
||||
})?;
|
||||
|
||||
let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_state);
|
||||
let state_runtime_code =
|
||||
sp_state_machine::backend::BackendRuntimeCode::new(trie_state);
|
||||
// It is important to extract the runtime code here before we create the proof
|
||||
// recorder.
|
||||
let runtime_code = state_runtime_code.runtime_code()
|
||||
.map_err(sp_blockchain::Error::RuntimeCode)?;
|
||||
let runtime_code =
|
||||
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
|
||||
let runtime_code = self.check_override(runtime_code, at)?;
|
||||
|
||||
let backend = sp_state_machine::ProvingBackend::new_with_recorder(
|
||||
@@ -239,8 +250,8 @@ where
|
||||
},
|
||||
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)?;
|
||||
let runtime_code =
|
||||
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
|
||||
let runtime_code = self.check_override(runtime_code, at)?;
|
||||
|
||||
let mut state_machine = StateMachine::new(
|
||||
@@ -253,34 +264,31 @@ where
|
||||
extensions.unwrap_or_default(),
|
||||
&runtime_code,
|
||||
self.spawn_handle.clone(),
|
||||
).with_storage_transaction_cache(storage_transaction_cache.as_mut().map(|c| &mut **c));
|
||||
)
|
||||
.with_storage_transaction_cache(
|
||||
storage_transaction_cache.as_mut().map(|c| &mut **c),
|
||||
);
|
||||
state_machine.execute_using_consensus_failure_handler(
|
||||
execution_manager,
|
||||
native_call.map(|n| || (n)().map_err(|e| Box::new(e) as Box<_>)),
|
||||
)
|
||||
}
|
||||
}.map_err(Into::into)
|
||||
},
|
||||
}
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
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 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, changes_trie_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)?;
|
||||
self.executor.runtime_version(&mut ext, &runtime_code)
|
||||
let runtime_code =
|
||||
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
|
||||
self.executor
|
||||
.runtime_version(&mut ext, &runtime_code)
|
||||
.map_err(|e| sp_blockchain::Error::VersionInvalid(format!("{:?}", e)).into())
|
||||
}
|
||||
|
||||
@@ -289,11 +297,11 @@ where
|
||||
trie_state: &sp_state_machine::TrieBackend<S, HashFor<Block>>,
|
||||
overlay: &mut OverlayedChanges,
|
||||
method: &str,
|
||||
call_data: &[u8]
|
||||
call_data: &[u8],
|
||||
) -> Result<(Vec<u8>, StorageProof), sp_blockchain::Error> {
|
||||
let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(trie_state);
|
||||
let runtime_code = state_runtime_code.runtime_code()
|
||||
.map_err(sp_blockchain::Error::RuntimeCode)?;
|
||||
let runtime_code =
|
||||
state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?;
|
||||
sp_state_machine::prove_execution_on_trie_backend::<_, _, NumberFor<Block>, _, _>(
|
||||
trie_state,
|
||||
overlay,
|
||||
@@ -312,19 +320,16 @@ where
|
||||
}
|
||||
|
||||
impl<Block, B, E> sp_version::GetRuntimeVersion<Block> for LocalCallExecutor<Block, B, E>
|
||||
where
|
||||
B: backend::Backend<Block>,
|
||||
E: CodeExecutor + RuntimeInfo + Clone + 'static,
|
||||
Block: BlockT,
|
||||
where
|
||||
B: backend::Backend<Block>,
|
||||
E: CodeExecutor + RuntimeInfo + Clone + 'static,
|
||||
Block: BlockT,
|
||||
{
|
||||
fn native_version(&self) -> &sp_version::NativeVersion {
|
||||
self.executor.native_version()
|
||||
}
|
||||
|
||||
fn runtime_version(
|
||||
&self,
|
||||
at: &BlockId<Block>,
|
||||
) -> Result<sp_version::RuntimeVersion, String> {
|
||||
fn runtime_version(&self, at: &BlockId<Block>) -> Result<sp_version::RuntimeVersion, String> {
|
||||
CallExecutor::runtime_version(self, at).map_err(|e| format!("{:?}", e))
|
||||
}
|
||||
}
|
||||
@@ -332,10 +337,13 @@ impl<Block, B, E> sp_version::GetRuntimeVersion<Block> for LocalCallExecutor<Blo
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use substrate_test_runtime_client::{LocalExecutor, GenesisInit, runtime};
|
||||
use sc_executor::{NativeExecutor, WasmExecutionMethod};
|
||||
use sp_core::{traits::{WrappedRuntimeCode, FetchRuntimeCode}, testing::TaskExecutor};
|
||||
use sc_client_api::in_mem;
|
||||
use sc_executor::{NativeExecutor, WasmExecutionMethod};
|
||||
use sp_core::{
|
||||
testing::TaskExecutor,
|
||||
traits::{FetchRuntimeCode, WrappedRuntimeCode},
|
||||
};
|
||||
use substrate_test_runtime_client::{runtime, GenesisInit, LocalExecutor};
|
||||
|
||||
#[test]
|
||||
fn should_get_override_if_exists() {
|
||||
@@ -372,7 +380,8 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
Default::default(),
|
||||
).expect("Creates a client");
|
||||
)
|
||||
.expect("Creates a client");
|
||||
|
||||
let call_executor = LocalCallExecutor {
|
||||
backend: backend.clone(),
|
||||
@@ -384,10 +393,12 @@ mod tests {
|
||||
Default::default(),
|
||||
executor.clone(),
|
||||
backend.clone(),
|
||||
).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
};
|
||||
|
||||
let check = call_executor.check_override(onchain_code, &BlockId::Number(Default::default()))
|
||||
let check = call_executor
|
||||
.check_override(onchain_code, &BlockId::Number(Default::default()))
|
||||
.expect("RuntimeCode override");
|
||||
|
||||
assert_eq!(Some(vec![2, 2, 2, 2, 2, 2, 2, 2]), check.fetch_runtime_code().map(Into::into));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,17 +18,12 @@
|
||||
|
||||
//! Tool for creating the genesis block.
|
||||
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Hash as HashT, Zero};
|
||||
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Zero};
|
||||
|
||||
/// Create a genesis block, given the initial storage.
|
||||
pub fn construct_genesis_block<
|
||||
Block: BlockT
|
||||
> (
|
||||
state_root: Block::Hash
|
||||
) -> Block {
|
||||
let extrinsics_root = <<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
Vec::new(),
|
||||
);
|
||||
pub fn construct_genesis_block<Block: BlockT>(state_root: Block::Hash) -> Block {
|
||||
let extrinsics_root =
|
||||
<<<Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(Vec::new());
|
||||
|
||||
Block::new(
|
||||
<<Block as BlockT>::Header as HeaderT>::new(
|
||||
@@ -36,8 +31,8 @@ pub fn construct_genesis_block<
|
||||
extrinsics_root,
|
||||
state_root,
|
||||
Default::default(),
|
||||
Default::default()
|
||||
Default::default(),
|
||||
),
|
||||
Default::default()
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,15 +20,20 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use sc_executor::RuntimeInfo;
|
||||
use sp_core::traits::{CodeExecutor, SpawnNamed};
|
||||
use sc_telemetry::TelemetryHandle;
|
||||
use sp_runtime::BuildStorage;
|
||||
use sp_runtime::traits::{Block as BlockT, HashFor};
|
||||
use sp_blockchain::Result as ClientResult;
|
||||
use prometheus_endpoint::Registry;
|
||||
use sc_executor::RuntimeInfo;
|
||||
use sc_telemetry::TelemetryHandle;
|
||||
use sp_blockchain::Result as ClientResult;
|
||||
use sp_core::traits::{CodeExecutor, SpawnNamed};
|
||||
use sp_runtime::{
|
||||
traits::{Block as BlockT, HashFor},
|
||||
BuildStorage,
|
||||
};
|
||||
|
||||
use super::{call_executor::LocalCallExecutor, client::{Client, ClientConfig}};
|
||||
use super::{
|
||||
call_executor::LocalCallExecutor,
|
||||
client::{Client, ClientConfig},
|
||||
};
|
||||
use sc_client_api::light::Storage as BlockchainStorage;
|
||||
use sc_light::{Backend, GenesisCallExecutor};
|
||||
|
||||
@@ -41,26 +46,26 @@ pub fn new_light<B, S, RA, E>(
|
||||
prometheus_registry: Option<Registry>,
|
||||
telemetry: Option<TelemetryHandle>,
|
||||
) -> ClientResult<
|
||||
Client<
|
||||
Client<
|
||||
Backend<S, HashFor<B>>,
|
||||
GenesisCallExecutor<
|
||||
Backend<S, HashFor<B>>,
|
||||
GenesisCallExecutor<
|
||||
Backend<S, HashFor<B>>,
|
||||
LocalCallExecutor<B, Backend<S, HashFor<B>>, E>
|
||||
>,
|
||||
B,
|
||||
RA
|
||||
>
|
||||
>
|
||||
where
|
||||
B: BlockT,
|
||||
S: BlockchainStorage<B> + 'static,
|
||||
E: CodeExecutor + RuntimeInfo + Clone + 'static,
|
||||
LocalCallExecutor<B, Backend<S, HashFor<B>>, E>,
|
||||
>,
|
||||
B,
|
||||
RA,
|
||||
>,
|
||||
>
|
||||
where
|
||||
B: BlockT,
|
||||
S: BlockchainStorage<B> + 'static,
|
||||
E: CodeExecutor + RuntimeInfo + Clone + 'static,
|
||||
{
|
||||
let local_executor = LocalCallExecutor::new(
|
||||
backend.clone(),
|
||||
code_executor,
|
||||
spawn_handle.clone(),
|
||||
ClientConfig::default()
|
||||
ClientConfig::default(),
|
||||
)?;
|
||||
let executor = GenesisCallExecutor::new(backend.clone(), local_executor);
|
||||
Client::new(
|
||||
|
||||
@@ -45,11 +45,11 @@
|
||||
//! the ways in which the runtime can interface with the outside. Any code that builds a `Client`
|
||||
//! is responsible for putting the right marker.
|
||||
|
||||
pub mod genesis;
|
||||
pub mod light;
|
||||
mod block_rules;
|
||||
mod call_executor;
|
||||
mod client;
|
||||
mod block_rules;
|
||||
pub mod genesis;
|
||||
pub mod light;
|
||||
mod wasm_override;
|
||||
mod wasm_substitutes;
|
||||
|
||||
@@ -58,5 +58,5 @@ pub use self::{
|
||||
client::{Client, ClientConfig},
|
||||
};
|
||||
|
||||
#[cfg(feature="test-helpers")]
|
||||
pub use self::client::{new_with_backend, new_in_mem};
|
||||
#[cfg(feature = "test-helpers")]
|
||||
pub use self::client::{new_in_mem, new_with_backend};
|
||||
|
||||
@@ -35,18 +35,17 @@
|
||||
//! A custom WASM blob will override on-chain WASM if the spec version matches. If it is
|
||||
//! required to overrides multiple runtimes, multiple WASM blobs matching each of the spec versions
|
||||
//! needed must be provided in the given directory.
|
||||
//!
|
||||
use std::{
|
||||
fs, collections::{HashMap, hash_map::DefaultHasher},
|
||||
path::{Path, PathBuf},
|
||||
hash::Hasher as _,
|
||||
};
|
||||
use sp_core::traits::FetchRuntimeCode;
|
||||
use sp_state_machine::BasicExternalities;
|
||||
use sp_blockchain::Result;
|
||||
use sc_executor::RuntimeInfo;
|
||||
use sp_blockchain::Result;
|
||||
use sp_core::traits::{FetchRuntimeCode, RuntimeCode};
|
||||
use sp_state_machine::BasicExternalities;
|
||||
use sp_version::RuntimeVersion;
|
||||
use sp_core::traits::RuntimeCode;
|
||||
use std::{
|
||||
collections::{hash_map::DefaultHasher, HashMap},
|
||||
fs,
|
||||
hash::Hasher as _,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
/// Auxiliary structure that holds a wasm blob and its hash.
|
||||
@@ -62,11 +61,7 @@ impl WasmBlob {
|
||||
}
|
||||
|
||||
fn runtime_code(&self, heap_pages: Option<u64>) -> RuntimeCode {
|
||||
RuntimeCode {
|
||||
code_fetcher: self,
|
||||
hash: self.hash.clone(),
|
||||
heap_pages,
|
||||
}
|
||||
RuntimeCode { code_fetcher: self, hash: self.hash.clone(), heap_pages }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +112,7 @@ pub struct WasmOverride<E> {
|
||||
|
||||
impl<E> WasmOverride<E>
|
||||
where
|
||||
E: RuntimeInfo + Clone + 'static
|
||||
E: RuntimeInfo + Clone + 'static,
|
||||
{
|
||||
pub fn new<P>(path: P, executor: E) -> Result<Self>
|
||||
where
|
||||
@@ -130,26 +125,19 @@ where
|
||||
/// Gets an override by it's runtime spec version.
|
||||
///
|
||||
/// Returns `None` if an override for a spec version does not exist.
|
||||
pub fn get<'a, 'b: 'a>(
|
||||
&'b self,
|
||||
spec: &u32,
|
||||
pages: Option<u64>,
|
||||
) -> Option<RuntimeCode<'a>> {
|
||||
self.overrides
|
||||
.get(spec)
|
||||
.map(|w| w.runtime_code(pages))
|
||||
pub fn get<'a, 'b: 'a>(&'b self, spec: &u32, pages: Option<u64>) -> Option<RuntimeCode<'a>> {
|
||||
self.overrides.get(spec).map(|w| w.runtime_code(pages))
|
||||
}
|
||||
|
||||
/// Scrapes a folder for WASM runtimes.
|
||||
/// Returns a hashmap of the runtime version and wasm runtime code.
|
||||
fn scrape_overrides(dir: &Path, executor: &E) -> Result<HashMap<u32, WasmBlob>> {
|
||||
|
||||
let handle_err = |e: std::io::Error | -> sp_blockchain::Error {
|
||||
let handle_err = |e: std::io::Error| -> sp_blockchain::Error {
|
||||
WasmOverrideError::Io(dir.to_owned(), e).into()
|
||||
};
|
||||
|
||||
if !dir.is_dir() {
|
||||
return Err(WasmOverrideError::NotADirectory(dir.to_owned()).into());
|
||||
return Err(WasmOverrideError::NotADirectory(dir.to_owned()).into())
|
||||
}
|
||||
|
||||
let mut overrides = HashMap::new();
|
||||
@@ -176,13 +164,13 @@ where
|
||||
);
|
||||
duplicates.push(format!("{}", path.display()));
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
if !duplicates.is_empty() {
|
||||
return Err(WasmOverrideError::DuplicateRuntime(duplicates).into());
|
||||
return Err(WasmOverrideError::DuplicateRuntime(duplicates).into())
|
||||
}
|
||||
|
||||
Ok(overrides)
|
||||
@@ -194,7 +182,8 @@ where
|
||||
heap_pages: Option<u64>,
|
||||
) -> Result<RuntimeVersion> {
|
||||
let mut ext = BasicExternalities::default();
|
||||
executor.runtime_version(&mut ext, &code.runtime_code(heap_pages))
|
||||
executor
|
||||
.runtime_version(&mut ext, &code.runtime_code(heap_pages))
|
||||
.map_err(|e| WasmOverrideError::VersionInvalid(format!("{:?}", e)).into())
|
||||
}
|
||||
}
|
||||
@@ -203,28 +192,25 @@ where
|
||||
#[cfg(test)]
|
||||
pub fn dummy_overrides<E>(executor: &E) -> WasmOverride<E>
|
||||
where
|
||||
E: RuntimeInfo + Clone + 'static
|
||||
E: RuntimeInfo + Clone + 'static,
|
||||
{
|
||||
let mut overrides = HashMap::new();
|
||||
overrides.insert(0, WasmBlob::new(vec![0, 0, 0, 0, 0, 0, 0, 0]));
|
||||
overrides.insert(1, WasmBlob::new(vec![1, 1, 1, 1, 1, 1, 1, 1]));
|
||||
overrides.insert(2, WasmBlob::new(vec![2, 2, 2, 2, 2, 2, 2, 2]));
|
||||
WasmOverride {
|
||||
overrides,
|
||||
executor: executor.clone()
|
||||
}
|
||||
WasmOverride { overrides, executor: executor.clone() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sc_executor::{NativeExecutor, WasmExecutionMethod};
|
||||
use substrate_test_runtime_client::LocalExecutor;
|
||||
use std::fs::{self, File};
|
||||
use substrate_test_runtime_client::LocalExecutor;
|
||||
|
||||
fn wasm_test<F>(fun: F)
|
||||
where
|
||||
F: Fn(&Path, &[u8], &NativeExecutor::<LocalExecutor>)
|
||||
F: Fn(&Path, &[u8], &NativeExecutor<LocalExecutor>),
|
||||
{
|
||||
let exec = NativeExecutor::<substrate_test_runtime_client::LocalExecutor>::new(
|
||||
WasmExecutionMethod::Interpreted,
|
||||
@@ -252,8 +238,8 @@ mod tests {
|
||||
fn should_scrape_wasm() {
|
||||
wasm_test(|dir, wasm_bytes, exec| {
|
||||
fs::write(dir.join("test.wasm"), wasm_bytes).expect("Create test file");
|
||||
let overrides = WasmOverride::scrape_overrides(dir, exec)
|
||||
.expect("HashMap of u32 and WasmBlob");
|
||||
let overrides =
|
||||
WasmOverride::scrape_overrides(dir, exec).expect("HashMap of u32 and WasmBlob");
|
||||
let wasm = overrides.get(&2).expect("WASM binary");
|
||||
assert_eq!(wasm.code, substrate_test_runtime::wasm_binary_unwrap().to_vec())
|
||||
});
|
||||
@@ -272,10 +258,10 @@ mod tests {
|
||||
Some(WasmOverrideError::DuplicateRuntime(duplicates)) => {
|
||||
assert_eq!(duplicates.len(), 1);
|
||||
},
|
||||
_ => panic!("Test should end with Msg Error Variant")
|
||||
_ => panic!("Test should end with Msg Error Variant"),
|
||||
}
|
||||
},
|
||||
_ => panic!("Test should end in error")
|
||||
_ => panic!("Test should end in error"),
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -286,8 +272,8 @@ mod tests {
|
||||
File::create(dir.join("README.md")).expect("Create test file");
|
||||
File::create(dir.join("LICENSE")).expect("Create a test file");
|
||||
fs::write(dir.join("test0.wasm"), wasm_bytes).expect("Create test file");
|
||||
let scraped = WasmOverride::scrape_overrides(dir, exec)
|
||||
.expect("HashMap of u32 and WasmBlob");
|
||||
let scraped =
|
||||
WasmOverride::scrape_overrides(dir, exec).expect("HashMap of u32 and WasmBlob");
|
||||
assert_eq!(scraped.len(), 1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,15 +18,22 @@
|
||||
|
||||
//! # WASM substitutes
|
||||
|
||||
use std::{collections::{HashMap, hash_map::DefaultHasher}, hash::Hasher as _, sync::Arc};
|
||||
use sp_core::traits::{FetchRuntimeCode, RuntimeCode};
|
||||
use sp_state_machine::BasicExternalities;
|
||||
use sp_blockchain::{Result, HeaderBackend};
|
||||
use sc_executor::RuntimeInfo;
|
||||
use sp_version::RuntimeVersion;
|
||||
use sc_client_api::backend;
|
||||
use sp_runtime::{traits::{NumberFor, Block as BlockT}, generic::BlockId};
|
||||
use parking_lot::RwLock;
|
||||
use sc_client_api::backend;
|
||||
use sc_executor::RuntimeInfo;
|
||||
use sp_blockchain::{HeaderBackend, Result};
|
||||
use sp_core::traits::{FetchRuntimeCode, RuntimeCode};
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, NumberFor},
|
||||
};
|
||||
use sp_state_machine::BasicExternalities;
|
||||
use sp_version::RuntimeVersion;
|
||||
use std::{
|
||||
collections::{hash_map::DefaultHasher, HashMap},
|
||||
hash::Hasher as _,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
/// A wasm substitute for the on chain wasm.
|
||||
#[derive(Debug)]
|
||||
@@ -51,11 +58,7 @@ impl<Block: BlockT> WasmSubstitute<Block> {
|
||||
}
|
||||
|
||||
fn runtime_code(&self, heap_pages: Option<u64>) -> RuntimeCode {
|
||||
RuntimeCode {
|
||||
code_fetcher: self,
|
||||
hash: self.hash.clone(),
|
||||
heap_pages,
|
||||
}
|
||||
RuntimeCode { code_fetcher: self, hash: self.hash.clone(), heap_pages }
|
||||
}
|
||||
|
||||
/// Returns `true` when the substitute matches for the given `block_id`.
|
||||
@@ -82,7 +85,8 @@ impl<Block: BlockT> WasmSubstitute<Block> {
|
||||
block_number
|
||||
};
|
||||
|
||||
let requested_block_number = backend.blockchain().block_number_from_id(&block_id).ok().flatten();
|
||||
let requested_block_number =
|
||||
backend.blockchain().block_number_from_id(&block_id).ok().flatten();
|
||||
|
||||
Some(block_number) <= requested_block_number
|
||||
}
|
||||
@@ -145,11 +149,14 @@ where
|
||||
executor: Executor,
|
||||
backend: Arc<Backend>,
|
||||
) -> Result<Self> {
|
||||
let substitutes = substitutes.into_iter().map(|(parent_block_hash, code)| {
|
||||
let substitute = WasmSubstitute::new(code, parent_block_hash, &*backend)?;
|
||||
let version = Self::runtime_version(&executor, &substitute)?;
|
||||
Ok((version.spec_version, substitute))
|
||||
}).collect::<Result<HashMap<_, _>>>()?;
|
||||
let substitutes = substitutes
|
||||
.into_iter()
|
||||
.map(|(parent_block_hash, code)| {
|
||||
let substitute = WasmSubstitute::new(code, parent_block_hash, &*backend)?;
|
||||
let version = Self::runtime_version(&executor, &substitute)?;
|
||||
Ok((version.spec_version, substitute))
|
||||
})
|
||||
.collect::<Result<HashMap<_, _>>>()?;
|
||||
|
||||
Ok(Self { executor, substitutes: Arc::new(substitutes), backend })
|
||||
}
|
||||
@@ -172,8 +179,8 @@ where
|
||||
code: &WasmSubstitute<Block>,
|
||||
) -> Result<RuntimeVersion> {
|
||||
let mut ext = BasicExternalities::default();
|
||||
executor.runtime_version(&mut ext, &code.runtime_code(None))
|
||||
executor
|
||||
.runtime_version(&mut ext, &code.runtime_code(None))
|
||||
.map_err(|e| WasmSubstituteError::VersionInvalid(format!("{:?}", e)).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,25 +18,34 @@
|
||||
|
||||
//! Service configuration.
|
||||
|
||||
pub use sc_client_api::execution_extensions::{ExecutionStrategies, ExecutionStrategy};
|
||||
pub use sc_client_db::{
|
||||
Database, PruningMode, DatabaseSettingsSrc as DatabaseConfig,
|
||||
KeepBlocks, TransactionStorageMode
|
||||
};
|
||||
pub use sc_network::Multiaddr;
|
||||
pub use sc_network::config::{
|
||||
ExtTransport, MultiaddrWithPeerId, NetworkConfiguration, Role, NodeKeyConfig,
|
||||
SetConfig, NonDefaultSetConfig, TransportConfig,
|
||||
RequestResponseConfig, IncomingRequest, OutgoingResponse,
|
||||
Database, DatabaseSettingsSrc as DatabaseConfig, KeepBlocks, PruningMode,
|
||||
TransactionStorageMode,
|
||||
};
|
||||
pub use sc_executor::WasmExecutionMethod;
|
||||
pub use sc_client_api::execution_extensions::{ExecutionStrategies, ExecutionStrategy};
|
||||
pub use sc_network::{
|
||||
config::{
|
||||
ExtTransport, IncomingRequest, MultiaddrWithPeerId, NetworkConfiguration, NodeKeyConfig,
|
||||
NonDefaultSetConfig, OutgoingResponse, RequestResponseConfig, Role, SetConfig,
|
||||
TransportConfig,
|
||||
},
|
||||
Multiaddr,
|
||||
};
|
||||
|
||||
use std::{io, future::Future, path::{PathBuf, Path}, pin::Pin, net::SocketAddr, sync::Arc};
|
||||
pub use sc_transaction_pool::Options as TransactionPoolOptions;
|
||||
use sc_chain_spec::ChainSpec;
|
||||
use sp_core::crypto::SecretString;
|
||||
pub use sc_telemetry::TelemetryEndpoints;
|
||||
use prometheus_endpoint::Registry;
|
||||
use sc_chain_spec::ChainSpec;
|
||||
pub use sc_telemetry::TelemetryEndpoints;
|
||||
pub use sc_transaction_pool::Options as TransactionPoolOptions;
|
||||
use sp_core::crypto::SecretString;
|
||||
use std::{
|
||||
future::Future,
|
||||
io,
|
||||
net::SocketAddr,
|
||||
path::{Path, PathBuf},
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
};
|
||||
#[cfg(not(target_os = "unknown"))]
|
||||
use tempfile::TempDir;
|
||||
|
||||
@@ -153,7 +162,7 @@ pub enum KeystoreConfig {
|
||||
/// The path of the keystore.
|
||||
path: PathBuf,
|
||||
/// Node keystore's password.
|
||||
password: Option<SecretString>
|
||||
password: Option<SecretString>,
|
||||
},
|
||||
/// In-memory keystore. Recommended for in-browser nodes.
|
||||
InMemory,
|
||||
@@ -194,7 +203,7 @@ impl PrometheusConfig {
|
||||
Self {
|
||||
port,
|
||||
registry: Registry::new_custom(Some("substrate".into()), None)
|
||||
.expect("this can only fail if the prefix is empty")
|
||||
.expect("this can only fail if the prefix is empty"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,11 +224,13 @@ impl Configuration {
|
||||
let protocol_id_full = match self.chain_spec.protocol_id() {
|
||||
Some(pid) => pid,
|
||||
None => {
|
||||
log::warn!("Using default protocol ID {:?} because none is configured in the \
|
||||
chain specs", crate::DEFAULT_PROTOCOL_ID
|
||||
log::warn!(
|
||||
"Using default protocol ID {:?} because none is configured in the \
|
||||
chain specs",
|
||||
crate::DEFAULT_PROTOCOL_ID
|
||||
);
|
||||
crate::DEFAULT_PROTOCOL_ID
|
||||
}
|
||||
},
|
||||
};
|
||||
sc_network::config::ProtocolId::from(protocol_id_full)
|
||||
}
|
||||
@@ -261,9 +272,7 @@ impl BasePath {
|
||||
/// instance is dropped.
|
||||
#[cfg(not(target_os = "unknown"))]
|
||||
pub fn new_temp_dir() -> io::Result<BasePath> {
|
||||
Ok(BasePath::Temporary(
|
||||
tempfile::Builder::new().prefix("substrate").tempdir()?,
|
||||
))
|
||||
Ok(BasePath::Temporary(tempfile::Builder::new().prefix("substrate").tempdir()?))
|
||||
}
|
||||
|
||||
/// Create a `BasePath` instance based on an existing path on disk.
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
|
||||
//! Errors that can occur during the service operation.
|
||||
|
||||
use sc_network;
|
||||
use sc_keystore;
|
||||
use sp_consensus;
|
||||
use sc_network;
|
||||
use sp_blockchain;
|
||||
use sp_consensus;
|
||||
|
||||
/// Service Result typedef.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
+137
-122
@@ -22,65 +22,62 @@
|
||||
#![warn(missing_docs)]
|
||||
#![recursion_limit = "1024"]
|
||||
|
||||
pub mod config;
|
||||
pub mod chain_ops;
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
|
||||
mod metrics;
|
||||
mod builder;
|
||||
#[cfg(feature = "test-helpers")]
|
||||
pub mod client;
|
||||
#[cfg(not(feature = "test-helpers"))]
|
||||
mod client;
|
||||
mod metrics;
|
||||
mod task_manager;
|
||||
|
||||
use std::{io, pin::Pin};
|
||||
use std::net::SocketAddr;
|
||||
use std::collections::HashMap;
|
||||
use std::task::Poll;
|
||||
use std::{collections::HashMap, io, net::SocketAddr, pin::Pin, task::Poll};
|
||||
|
||||
use futures::{Future, FutureExt, Stream, StreamExt, stream, compat::*};
|
||||
use sc_network::PeerId;
|
||||
use log::{warn, debug, error};
|
||||
use codec::{Encode, Decode};
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
||||
use codec::{Decode, Encode};
|
||||
use futures::{compat::*, stream, Future, FutureExt, Stream, StreamExt};
|
||||
use log::{debug, error, warn};
|
||||
use parity_util_mem::MallocSizeOf;
|
||||
use sc_network::PeerId;
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{Block as BlockT, Header as HeaderT},
|
||||
};
|
||||
use sp_utils::mpsc::TracingUnboundedReceiver;
|
||||
|
||||
pub use self::error::Error;
|
||||
pub use self::builder::{
|
||||
new_full_client, new_db_backend, new_client, new_full_parts, new_light_parts,
|
||||
spawn_tasks, build_network, build_offchain_workers,
|
||||
BuildNetworkParams, KeystoreContainer, NetworkStarter, SpawnTasksParams, TFullClient, TLightClient,
|
||||
TFullBackend, TLightBackend, TLightBackendWithHash, TLightClientWithBackend,
|
||||
TFullCallExecutor, TLightCallExecutor, RpcExtensionBuilder, NoopRpcExtensionBuilder,
|
||||
pub use self::{
|
||||
builder::{
|
||||
build_network, build_offchain_workers, new_client, new_db_backend, new_full_client,
|
||||
new_full_parts, new_light_parts, spawn_tasks, BuildNetworkParams, KeystoreContainer,
|
||||
NetworkStarter, NoopRpcExtensionBuilder, RpcExtensionBuilder, SpawnTasksParams,
|
||||
TFullBackend, TFullCallExecutor, TFullClient, TLightBackend, TLightBackendWithHash,
|
||||
TLightCallExecutor, TLightClient, TLightClientWithBackend,
|
||||
},
|
||||
client::{ClientConfig, LocalCallExecutor},
|
||||
error::Error,
|
||||
};
|
||||
pub use config::{
|
||||
BasePath, Configuration, DatabaseConfig, PruningMode, Role, RpcMethods, TaskExecutor, TaskType,
|
||||
KeepBlocks, TransactionStorageMode,
|
||||
BasePath, Configuration, DatabaseConfig, KeepBlocks, PruningMode, Role, RpcMethods,
|
||||
TaskExecutor, TaskType, TransactionStorageMode,
|
||||
};
|
||||
pub use sc_chain_spec::{
|
||||
ChainSpec, GenericChainSpec, Properties, RuntimeGenesis, Extension as ChainSpecExtension,
|
||||
NoExtension, ChainType,
|
||||
ChainSpec, ChainType, Extension as ChainSpecExtension, GenericChainSpec, NoExtension,
|
||||
Properties, RuntimeGenesis,
|
||||
};
|
||||
pub use sc_transaction_pool_api::{TransactionPool, InPoolTransaction, error::IntoPoolError};
|
||||
pub use sc_transaction_pool::Options as TransactionPoolOptions;
|
||||
pub use sc_rpc::Metadata as RpcMetadata;
|
||||
use sc_client_api::{blockchain::HeaderBackend, BlockchainEvents};
|
||||
pub use sc_executor::NativeExecutionDispatch;
|
||||
#[doc(hidden)]
|
||||
pub use std::{ops::Deref, result::Result, sync::Arc};
|
||||
#[doc(hidden)]
|
||||
pub use sc_network::config::{
|
||||
OnDemand, TransactionImport,
|
||||
TransactionImportFuture,
|
||||
};
|
||||
pub use sc_network::config::{OnDemand, TransactionImport, TransactionImportFuture};
|
||||
pub use sc_rpc::Metadata as RpcMetadata;
|
||||
pub use sc_tracing::TracingReceiver;
|
||||
pub use task_manager::SpawnTaskHandle;
|
||||
pub use task_manager::TaskManager;
|
||||
pub use sc_transaction_pool::Options as TransactionPoolOptions;
|
||||
pub use sc_transaction_pool_api::{error::IntoPoolError, InPoolTransaction, TransactionPool};
|
||||
pub use sp_consensus::import_queue::ImportQueue;
|
||||
pub use self::client::{LocalCallExecutor, ClientConfig};
|
||||
use sc_client_api::{blockchain::HeaderBackend, BlockchainEvents};
|
||||
#[doc(hidden)]
|
||||
pub use std::{ops::Deref, result::Result, sync::Arc};
|
||||
pub use task_manager::{SpawnTaskHandle, TaskManager};
|
||||
|
||||
const DEFAULT_PROTOCOL_ID: &str = "sup";
|
||||
|
||||
@@ -96,7 +93,9 @@ impl<T> MallocSizeOfWasm for T {}
|
||||
|
||||
/// RPC handlers that can perform RPC queries.
|
||||
#[derive(Clone)]
|
||||
pub struct RpcHandlers(Arc<jsonrpc_core::MetaIoHandler<sc_rpc::Metadata, sc_rpc_server::RpcMiddleware>>);
|
||||
pub struct RpcHandlers(
|
||||
Arc<jsonrpc_core::MetaIoHandler<sc_rpc::Metadata, sc_rpc_server::RpcMiddleware>>,
|
||||
);
|
||||
|
||||
impl RpcHandlers {
|
||||
/// Starts an RPC query.
|
||||
@@ -108,17 +107,22 @@ impl RpcHandlers {
|
||||
///
|
||||
/// If the request subscribes you to events, the `Sender` in the `RpcSession` object is used to
|
||||
/// send back spontaneous events.
|
||||
pub fn rpc_query(&self, mem: &RpcSession, request: &str)
|
||||
-> Pin<Box<dyn Future<Output = Option<String>> + Send>> {
|
||||
self.0.handle_request(request, mem.metadata.clone())
|
||||
pub fn rpc_query(
|
||||
&self,
|
||||
mem: &RpcSession,
|
||||
request: &str,
|
||||
) -> Pin<Box<dyn Future<Output = Option<String>> + Send>> {
|
||||
self.0
|
||||
.handle_request(request, mem.metadata.clone())
|
||||
.compat()
|
||||
.map(|res| res.expect("this should never fail"))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
/// Provides access to the underlying `MetaIoHandler`
|
||||
pub fn io_handler(&self)
|
||||
-> Arc<jsonrpc_core::MetaIoHandler<sc_rpc::Metadata, sc_rpc_server::RpcMiddleware>> {
|
||||
pub fn io_handler(
|
||||
&self,
|
||||
) -> Arc<jsonrpc_core::MetaIoHandler<sc_rpc::Metadata, sc_rpc_server::RpcMiddleware>> {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
@@ -149,8 +153,8 @@ pub struct PartialComponents<Client, Backend, SelectChain, ImportQueue, Transact
|
||||
async fn build_network_future<
|
||||
B: BlockT,
|
||||
C: BlockchainEvents<B> + HeaderBackend<B>,
|
||||
H: sc_network::ExHashT
|
||||
> (
|
||||
H: sc_network::ExHashT,
|
||||
>(
|
||||
role: Role,
|
||||
mut network: sc_network::NetworkWorker<B, H>,
|
||||
client: Arc<C>,
|
||||
@@ -171,7 +175,9 @@ async fn build_network_future<
|
||||
// ready. This way, we only get the latest finalized block.
|
||||
stream::poll_fn(move |cx| {
|
||||
let mut last = None;
|
||||
while let Poll::Ready(Some(item)) = Pin::new(&mut finality_notification_stream).poll_next(cx) {
|
||||
while let Poll::Ready(Some(item)) =
|
||||
Pin::new(&mut finality_notification_stream).poll_next(cx)
|
||||
{
|
||||
last = Some(item);
|
||||
}
|
||||
if let Some(last) = last {
|
||||
@@ -179,11 +185,12 @@ async fn build_network_future<
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}).fuse()
|
||||
})
|
||||
.fuse()
|
||||
};
|
||||
|
||||
loop {
|
||||
futures::select!{
|
||||
futures::select! {
|
||||
// List of blocks that the client has imported.
|
||||
notification = imported_blocks_stream.next() => {
|
||||
let notification = match notification {
|
||||
@@ -338,79 +345,90 @@ mod waiting {
|
||||
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
|
||||
#[cfg(not(target_os = "unknown"))]
|
||||
fn start_rpc_servers<
|
||||
H: FnMut(sc_rpc::DenyUnsafe, sc_rpc_server::RpcMiddleware)
|
||||
-> sc_rpc_server::RpcHandler<sc_rpc::Metadata>
|
||||
H: FnMut(
|
||||
sc_rpc::DenyUnsafe,
|
||||
sc_rpc_server::RpcMiddleware,
|
||||
) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>,
|
||||
>(
|
||||
config: &Configuration,
|
||||
mut gen_handler: H,
|
||||
rpc_metrics: sc_rpc_server::RpcMetrics,
|
||||
) -> Result<Box<dyn std::any::Any + Send + Sync>, error::Error> {
|
||||
fn maybe_start_server<T, F>(address: Option<SocketAddr>, mut start: F) -> Result<Option<T>, io::Error>
|
||||
where F: FnMut(&SocketAddr) -> Result<T, io::Error>,
|
||||
{
|
||||
address.map(|mut address| start(&address)
|
||||
.or_else(|e| match e.kind() {
|
||||
io::ErrorKind::AddrInUse |
|
||||
io::ErrorKind::PermissionDenied => {
|
||||
fn maybe_start_server<T, F>(
|
||||
address: Option<SocketAddr>,
|
||||
mut start: F,
|
||||
) -> Result<Option<T>, io::Error>
|
||||
where
|
||||
F: FnMut(&SocketAddr) -> Result<T, io::Error>,
|
||||
{
|
||||
address
|
||||
.map(|mut address| {
|
||||
start(&address).or_else(|e| match e.kind() {
|
||||
io::ErrorKind::AddrInUse | io::ErrorKind::PermissionDenied => {
|
||||
warn!("Unable to bind RPC server to {}. Trying random port.", address);
|
||||
address.set_port(0);
|
||||
start(&address)
|
||||
},
|
||||
_ => Err(e),
|
||||
}
|
||||
) ).transpose()
|
||||
}
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
fn deny_unsafe(addr: &SocketAddr, methods: &RpcMethods) -> sc_rpc::DenyUnsafe {
|
||||
let is_exposed_addr = !addr.ip().is_loopback();
|
||||
match (is_exposed_addr, methods) {
|
||||
| (_, RpcMethods::Unsafe)
|
||||
| (false, RpcMethods::Auto) => sc_rpc::DenyUnsafe::No,
|
||||
_ => sc_rpc::DenyUnsafe::Yes
|
||||
| (_, RpcMethods::Unsafe) | (false, RpcMethods::Auto) => sc_rpc::DenyUnsafe::No,
|
||||
_ => sc_rpc::DenyUnsafe::Yes,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Box::new((
|
||||
config.rpc_ipc.as_ref().map(|path| sc_rpc_server::start_ipc(
|
||||
&*path, gen_handler(
|
||||
sc_rpc::DenyUnsafe::No,
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "ipc")
|
||||
config.rpc_ipc.as_ref().map(|path| {
|
||||
sc_rpc_server::start_ipc(
|
||||
&*path,
|
||||
gen_handler(
|
||||
sc_rpc::DenyUnsafe::No,
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "ipc"),
|
||||
),
|
||||
)
|
||||
)),
|
||||
maybe_start_server(
|
||||
config.rpc_http,
|
||||
|address| sc_rpc_server::start_http(
|
||||
}),
|
||||
maybe_start_server(config.rpc_http, |address| {
|
||||
sc_rpc_server::start_http(
|
||||
address,
|
||||
config.rpc_http_threads,
|
||||
config.rpc_cors.as_ref(),
|
||||
gen_handler(
|
||||
deny_unsafe(&address, &config.rpc_methods),
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "http")
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "http"),
|
||||
),
|
||||
config.rpc_max_payload
|
||||
),
|
||||
)?.map(|s| waiting::HttpServer(Some(s))),
|
||||
maybe_start_server(
|
||||
config.rpc_ws,
|
||||
|address| sc_rpc_server::start_ws(
|
||||
config.rpc_max_payload,
|
||||
)
|
||||
})?
|
||||
.map(|s| waiting::HttpServer(Some(s))),
|
||||
maybe_start_server(config.rpc_ws, |address| {
|
||||
sc_rpc_server::start_ws(
|
||||
address,
|
||||
config.rpc_ws_max_connections,
|
||||
config.rpc_cors.as_ref(),
|
||||
gen_handler(
|
||||
deny_unsafe(&address, &config.rpc_methods),
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "ws")
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "ws"),
|
||||
),
|
||||
config.rpc_max_payload
|
||||
),
|
||||
)?.map(|s| waiting::WsServer(Some(s))),
|
||||
config.rpc_max_payload,
|
||||
)
|
||||
})?
|
||||
.map(|s| waiting::WsServer(Some(s))),
|
||||
)))
|
||||
}
|
||||
|
||||
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
|
||||
#[cfg(target_os = "unknown")]
|
||||
fn start_rpc_servers<
|
||||
H: FnMut(sc_rpc::DenyUnsafe, sc_rpc_server::RpcMiddleware)
|
||||
-> sc_rpc_server::RpcHandler<sc_rpc::Metadata>
|
||||
H: FnMut(
|
||||
sc_rpc::DenyUnsafe,
|
||||
sc_rpc_server::RpcMiddleware,
|
||||
) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>,
|
||||
>(
|
||||
_: &Configuration,
|
||||
_: H,
|
||||
@@ -434,9 +452,7 @@ impl RpcSession {
|
||||
///
|
||||
/// The `RpcSession` must be kept alive in order to receive messages on the sender.
|
||||
pub fn new(sender: futures01::sync::mpsc::Sender<String>) -> RpcSession {
|
||||
RpcSession {
|
||||
metadata: sender.into(),
|
||||
}
|
||||
RpcSession { metadata: sender.into() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,10 +466,9 @@ pub struct TransactionPoolAdapter<C, P> {
|
||||
/// Get transactions for propagation.
|
||||
///
|
||||
/// Function extracted to simplify the test and prevent creating `ServiceFactory`.
|
||||
fn transactions_to_propagate<Pool, B, H, E>(pool: &Pool)
|
||||
-> Vec<(H, B::Extrinsic)>
|
||||
fn transactions_to_propagate<Pool, B, H, E>(pool: &Pool) -> Vec<(H, B::Extrinsic)>
|
||||
where
|
||||
Pool: TransactionPool<Block=B, Hash=H, Error=E>,
|
||||
Pool: TransactionPool<Block = B, Hash = H, Error = E>,
|
||||
B: BlockT,
|
||||
H: std::hash::Hash + Eq + sp_runtime::traits::Member + sp_runtime::traits::MaybeSerialize,
|
||||
E: IntoPoolError + From<sc_transaction_pool_api::error::Error>,
|
||||
@@ -468,11 +483,10 @@ where
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl<B, H, C, Pool, E> sc_network::config::TransactionPool<H, B> for
|
||||
TransactionPoolAdapter<C, Pool>
|
||||
impl<B, H, C, Pool, E> sc_network::config::TransactionPool<H, B> for TransactionPoolAdapter<C, Pool>
|
||||
where
|
||||
C: sc_network::config::Client<B> + Send + Sync,
|
||||
Pool: 'static + TransactionPool<Block=B, Hash=H, Error=E>,
|
||||
Pool: 'static + TransactionPool<Block = B, Hash = H, Error = E>,
|
||||
B: BlockT,
|
||||
H: std::hash::Hash + Eq + sp_runtime::traits::Member + sp_runtime::traits::MaybeSerialize,
|
||||
E: 'static + IntoPoolError + From<sc_transaction_pool_api::error::Error>,
|
||||
@@ -485,10 +499,7 @@ where
|
||||
self.pool.hash_of(transaction)
|
||||
}
|
||||
|
||||
fn import(
|
||||
&self,
|
||||
transaction: B::Extrinsic,
|
||||
) -> TransactionImportFuture {
|
||||
fn import(&self, transaction: B::Extrinsic) -> TransactionImportFuture {
|
||||
if !self.imports_external_transactions {
|
||||
debug!("Transaction rejected");
|
||||
Box::pin(futures::future::ready(TransactionImport::None));
|
||||
@@ -499,28 +510,33 @@ where
|
||||
Ok(uxt) => uxt,
|
||||
Err(e) => {
|
||||
debug!("Transaction invalid: {:?}", e);
|
||||
return Box::pin(futures::future::ready(TransactionImport::Bad));
|
||||
}
|
||||
return Box::pin(futures::future::ready(TransactionImport::Bad))
|
||||
},
|
||||
};
|
||||
|
||||
let best_block_id = BlockId::hash(self.client.info().best_hash);
|
||||
|
||||
let import_future = self.pool.submit_one(&best_block_id, sc_transaction_pool_api::TransactionSource::External, uxt);
|
||||
let import_future = self.pool.submit_one(
|
||||
&best_block_id,
|
||||
sc_transaction_pool_api::TransactionSource::External,
|
||||
uxt,
|
||||
);
|
||||
Box::pin(async move {
|
||||
match import_future.await {
|
||||
Ok(_) => TransactionImport::NewGood,
|
||||
Err(e) => match e.into_pool_error() {
|
||||
Ok(sc_transaction_pool_api::error::Error::AlreadyImported(_)) => TransactionImport::KnownGood,
|
||||
Ok(sc_transaction_pool_api::error::Error::AlreadyImported(_)) =>
|
||||
TransactionImport::KnownGood,
|
||||
Ok(e) => {
|
||||
debug!("Error adding transaction to the pool: {:?}", e);
|
||||
TransactionImport::Bad
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
debug!("Error converting pool error: {:?}", e);
|
||||
// it is not bad at least, just some internal node logic error, so peer is innocent.
|
||||
TransactionImport::KnownGood
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -530,11 +546,10 @@ where
|
||||
}
|
||||
|
||||
fn transaction(&self, hash: &H) -> Option<B::Extrinsic> {
|
||||
self.pool.ready_transaction(hash)
|
||||
.and_then(
|
||||
// Only propagable transactions should be resolved for network service.
|
||||
|tx| if tx.is_propagable() { Some(tx.data().clone()) } else { None }
|
||||
)
|
||||
self.pool.ready_transaction(hash).and_then(
|
||||
// Only propagable transactions should be resolved for network service.
|
||||
|tx| if tx.is_propagable() { Some(tx.data().clone()) } else { None },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,10 +557,13 @@ where
|
||||
mod tests {
|
||||
use super::*;
|
||||
use futures::executor::block_on;
|
||||
use sc_transaction_pool::BasicPool;
|
||||
use sp_consensus::SelectChain;
|
||||
use sp_runtime::traits::BlindCheckable;
|
||||
use substrate_test_runtime_client::{prelude::*, runtime::{Extrinsic, Transfer}};
|
||||
use sc_transaction_pool::BasicPool;
|
||||
use substrate_test_runtime_client::{
|
||||
prelude::*,
|
||||
runtime::{Extrinsic, Transfer},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn should_not_propagate_transactions_that_are_marked_as_such() {
|
||||
@@ -553,13 +571,8 @@ mod tests {
|
||||
let (client, longest_chain) = TestClientBuilder::new().build_with_longest_chain();
|
||||
let client = Arc::new(client);
|
||||
let spawner = sp_core::testing::TaskExecutor::new();
|
||||
let pool = BasicPool::new_full(
|
||||
Default::default(),
|
||||
true.into(),
|
||||
None,
|
||||
spawner,
|
||||
client.clone(),
|
||||
);
|
||||
let pool =
|
||||
BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone());
|
||||
let source = sp_runtime::transaction_validity::TransactionSource::External;
|
||||
let best = block_on(longest_chain.best_chain()).unwrap();
|
||||
let transaction = Transfer {
|
||||
@@ -569,12 +582,14 @@ mod tests {
|
||||
to: Default::default(),
|
||||
}
|
||||
.into_signed_tx();
|
||||
block_on(pool.submit_one(&BlockId::hash(best.hash()), source, transaction.clone()))
|
||||
.unwrap();
|
||||
block_on(pool.submit_one(
|
||||
&BlockId::hash(best.hash()), source, transaction.clone()),
|
||||
).unwrap();
|
||||
block_on(pool.submit_one(
|
||||
&BlockId::hash(best.hash()), source, Extrinsic::IncludeData(vec![1])),
|
||||
).unwrap();
|
||||
&BlockId::hash(best.hash()),
|
||||
source,
|
||||
Extrinsic::IncludeData(vec![1]),
|
||||
))
|
||||
.unwrap();
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
|
||||
// when
|
||||
|
||||
@@ -20,16 +20,15 @@ use std::{convert::TryFrom, time::SystemTime};
|
||||
|
||||
use crate::config::Configuration;
|
||||
use futures_timer::Delay;
|
||||
use prometheus_endpoint::{register, Gauge, U64, Registry, PrometheusError, Opts, GaugeVec};
|
||||
use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_runtime::traits::{NumberFor, Block, SaturatedConversion, UniqueSaturatedInto};
|
||||
use sc_transaction_pool_api::{PoolStatus, MaintainedTransactionPool};
|
||||
use sp_utils::metrics::register_globals;
|
||||
use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64};
|
||||
use sc_client_api::{ClientInfo, UsageProvider};
|
||||
use sc_network::{config::Role, NetworkStatus, NetworkService};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use sc_network::{config::Role, NetworkService, NetworkStatus};
|
||||
use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO};
|
||||
use sc_transaction_pool_api::{MaintainedTransactionPool, PoolStatus};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_runtime::traits::{Block, NumberFor, SaturatedConversion, UniqueSaturatedInto};
|
||||
use sp_utils::metrics::register_globals;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use wasm_timer::Instant;
|
||||
|
||||
struct PrometheusMetrics {
|
||||
@@ -51,54 +50,74 @@ impl PrometheusMetrics {
|
||||
version: &str,
|
||||
roles: u64,
|
||||
) -> Result<Self, PrometheusError> {
|
||||
register(Gauge::<U64>::with_opts(
|
||||
Opts::new(
|
||||
"build_info",
|
||||
"A metric with a constant '1' value labeled by name, version"
|
||||
)
|
||||
register(
|
||||
Gauge::<U64>::with_opts(
|
||||
Opts::new(
|
||||
"build_info",
|
||||
"A metric with a constant '1' value labeled by name, version",
|
||||
)
|
||||
.const_label("name", name)
|
||||
.const_label("version", version)
|
||||
)?, ®istry)?.set(1);
|
||||
.const_label("version", version),
|
||||
)?,
|
||||
®istry,
|
||||
)?
|
||||
.set(1);
|
||||
|
||||
register(Gauge::<U64>::new(
|
||||
"node_roles", "The roles the node is running as",
|
||||
)?, ®istry)?.set(roles);
|
||||
register(Gauge::<U64>::new("node_roles", "The roles the node is running as")?, ®istry)?
|
||||
.set(roles);
|
||||
|
||||
register_globals(registry)?;
|
||||
|
||||
let start_time_since_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap_or_default();
|
||||
register(Gauge::<U64>::new(
|
||||
"process_start_time_seconds",
|
||||
"Number of seconds between the UNIX epoch and the moment the process started",
|
||||
)?, registry)?.set(start_time_since_epoch.as_secs());
|
||||
let start_time_since_epoch =
|
||||
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default();
|
||||
register(
|
||||
Gauge::<U64>::new(
|
||||
"process_start_time_seconds",
|
||||
"Number of seconds between the UNIX epoch and the moment the process started",
|
||||
)?,
|
||||
registry,
|
||||
)?
|
||||
.set(start_time_since_epoch.as_secs());
|
||||
|
||||
Ok(Self {
|
||||
// generic internals
|
||||
block_height: register(GaugeVec::new(
|
||||
Opts::new("block_height", "Block height info of the chain"),
|
||||
&["status"]
|
||||
)?, registry)?,
|
||||
block_height: register(
|
||||
GaugeVec::new(
|
||||
Opts::new("block_height", "Block height info of the chain"),
|
||||
&["status"],
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
|
||||
number_leaves: register(Gauge::new(
|
||||
"number_leaves", "Number of known chain leaves (aka forks)",
|
||||
)?, registry)?,
|
||||
number_leaves: register(
|
||||
Gauge::new("number_leaves", "Number of known chain leaves (aka forks)")?,
|
||||
registry,
|
||||
)?,
|
||||
|
||||
ready_transactions_number: register(Gauge::new(
|
||||
"ready_transactions_number", "Number of transactions in the ready queue",
|
||||
)?, registry)?,
|
||||
ready_transactions_number: register(
|
||||
Gauge::new(
|
||||
"ready_transactions_number",
|
||||
"Number of transactions in the ready queue",
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
|
||||
// I/ O
|
||||
database_cache: register(Gauge::new(
|
||||
"database_cache_bytes", "RocksDB cache size in bytes",
|
||||
)?, registry)?,
|
||||
state_cache: register(Gauge::new(
|
||||
"state_cache_bytes", "State cache size in bytes",
|
||||
)?, registry)?,
|
||||
state_db: register(GaugeVec::new(
|
||||
Opts::new("state_db_cache_bytes", "State DB cache in bytes"),
|
||||
&["subtype"]
|
||||
)?, registry)?,
|
||||
database_cache: register(
|
||||
Gauge::new("database_cache_bytes", "RocksDB cache size in bytes")?,
|
||||
registry,
|
||||
)?,
|
||||
state_cache: register(
|
||||
Gauge::new("state_cache_bytes", "State cache size in bytes")?,
|
||||
registry,
|
||||
)?,
|
||||
state_db: register(
|
||||
GaugeVec::new(
|
||||
Opts::new("state_db_cache_bytes", "State DB cache in bytes"),
|
||||
&["subtype"],
|
||||
)?,
|
||||
registry,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -179,11 +198,7 @@ impl MetricsService {
|
||||
let net_status = network.status().await.ok();
|
||||
|
||||
// Update / Send the metrics.
|
||||
self.update(
|
||||
&client.usage_info(),
|
||||
&transactions.status(),
|
||||
net_status,
|
||||
);
|
||||
self.update(&client.usage_info(), &transactions.status(), net_status);
|
||||
|
||||
// Schedule next tick.
|
||||
timer.reset(timer_interval);
|
||||
@@ -220,14 +235,8 @@ impl MetricsService {
|
||||
);
|
||||
|
||||
if let Some(metrics) = self.metrics.as_ref() {
|
||||
metrics
|
||||
.block_height
|
||||
.with_label_values(&["finalized"])
|
||||
.set(finalized_number);
|
||||
metrics
|
||||
.block_height
|
||||
.with_label_values(&["best"])
|
||||
.set(best_number);
|
||||
metrics.block_height.with_label_values(&["finalized"]).set(finalized_number);
|
||||
metrics.block_height.with_label_values(&["best"]).set(best_number);
|
||||
|
||||
if let Ok(leaves) = u64::try_from(info.chain.number_leaves) {
|
||||
metrics.number_leaves.set(leaves);
|
||||
@@ -239,15 +248,17 @@ impl MetricsService {
|
||||
metrics.database_cache.set(info.memory.database_cache.as_bytes() as u64);
|
||||
metrics.state_cache.set(info.memory.state_cache.as_bytes() as u64);
|
||||
|
||||
metrics.state_db.with_label_values(&["non_canonical"]).set(
|
||||
info.memory.state_db.non_canonical.as_bytes() as u64,
|
||||
);
|
||||
metrics
|
||||
.state_db
|
||||
.with_label_values(&["non_canonical"])
|
||||
.set(info.memory.state_db.non_canonical.as_bytes() as u64);
|
||||
if let Some(pruning) = info.memory.state_db.pruning {
|
||||
metrics.state_db.with_label_values(&["pruning"]).set(pruning.as_bytes() as u64);
|
||||
}
|
||||
metrics.state_db.with_label_values(&["pinned"]).set(
|
||||
info.memory.state_db.pinned.as_bytes() as u64,
|
||||
);
|
||||
metrics
|
||||
.state_db
|
||||
.with_label_values(&["pinned"])
|
||||
.set(info.memory.state_db.pinned.as_bytes() as u64);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,14 +270,13 @@ impl MetricsService {
|
||||
|
||||
let diff_bytes_inbound = total_bytes_inbound - self.last_total_bytes_inbound;
|
||||
let diff_bytes_outbound = total_bytes_outbound - self.last_total_bytes_outbound;
|
||||
let (avg_bytes_per_sec_inbound, avg_bytes_per_sec_outbound) =
|
||||
if elapsed > 0 {
|
||||
self.last_total_bytes_inbound = total_bytes_inbound;
|
||||
self.last_total_bytes_outbound = total_bytes_outbound;
|
||||
(diff_bytes_inbound / elapsed, diff_bytes_outbound / elapsed)
|
||||
} else {
|
||||
(diff_bytes_inbound, diff_bytes_outbound)
|
||||
};
|
||||
let (avg_bytes_per_sec_inbound, avg_bytes_per_sec_outbound) = if elapsed > 0 {
|
||||
self.last_total_bytes_inbound = total_bytes_inbound;
|
||||
self.last_total_bytes_outbound = total_bytes_outbound;
|
||||
(diff_bytes_inbound / elapsed, diff_bytes_outbound / elapsed)
|
||||
} else {
|
||||
(diff_bytes_inbound, diff_bytes_outbound)
|
||||
};
|
||||
|
||||
telemetry!(
|
||||
self.telemetry;
|
||||
@@ -278,9 +288,10 @@ impl MetricsService {
|
||||
);
|
||||
|
||||
if let Some(metrics) = self.metrics.as_ref() {
|
||||
let best_seen_block: Option<u64> = net_status
|
||||
.best_seen_block
|
||||
.map(|num: NumberFor<T>| UniqueSaturatedInto::<u64>::unique_saturated_into(num));
|
||||
let best_seen_block: Option<u64> =
|
||||
net_status.best_seen_block.map(|num: NumberFor<T>| {
|
||||
UniqueSaturatedInto::<u64>::unique_saturated_into(num)
|
||||
});
|
||||
|
||||
if let Some(best_seen_block) = best_seen_block {
|
||||
metrics.block_height.with_label_values(&["sync_target"]).set(best_seen_block);
|
||||
|
||||
@@ -18,22 +18,24 @@
|
||||
|
||||
//! Substrate service tasks management module.
|
||||
|
||||
use std::{panic, result::Result, pin::Pin};
|
||||
use crate::{
|
||||
config::{JoinFuture, TaskExecutor, TaskType},
|
||||
Error,
|
||||
};
|
||||
use exit_future::Signal;
|
||||
use log::{debug, error};
|
||||
use futures::{
|
||||
Future, FutureExt, StreamExt,
|
||||
future::{select, Either, BoxFuture, join_all, try_join_all, pending},
|
||||
future::{join_all, pending, select, try_join_all, BoxFuture, Either},
|
||||
sink::SinkExt,
|
||||
Future, FutureExt, StreamExt,
|
||||
};
|
||||
use log::{debug, error};
|
||||
use prometheus_endpoint::{
|
||||
exponential_buckets, register,
|
||||
PrometheusError,
|
||||
CounterVec, HistogramOpts, HistogramVec, Opts, Registry, U64
|
||||
exponential_buckets, register, CounterVec, HistogramOpts, HistogramVec, Opts, PrometheusError,
|
||||
Registry, U64,
|
||||
};
|
||||
use sp_utils::mpsc::{TracingUnboundedSender, TracingUnboundedReceiver, tracing_unbounded};
|
||||
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
|
||||
use std::{panic, pin::Pin, result::Result};
|
||||
use tracing_futures::Instrument;
|
||||
use crate::{config::{TaskExecutor, TaskType, JoinFuture}, Error};
|
||||
|
||||
mod prometheus_future;
|
||||
#[cfg(test)]
|
||||
@@ -62,7 +64,11 @@ impl SpawnTaskHandle {
|
||||
}
|
||||
|
||||
/// Spawns the blocking task with the given name. See also `spawn`.
|
||||
pub fn spawn_blocking(&self, name: &'static str, task: impl Future<Output = ()> + Send + 'static) {
|
||||
pub fn spawn_blocking(
|
||||
&self,
|
||||
name: &'static str,
|
||||
task: impl Future<Output = ()> + Send + 'static,
|
||||
) {
|
||||
self.spawn_inner(name, task, TaskType::Blocking)
|
||||
}
|
||||
|
||||
@@ -75,7 +81,7 @@ impl SpawnTaskHandle {
|
||||
) {
|
||||
if self.task_notifier.is_closed() {
|
||||
debug!("Attempt to spawn a new task has been prevented: {}", name);
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
let on_exit = self.on_exit.clone();
|
||||
@@ -95,7 +101,8 @@ impl SpawnTaskHandle {
|
||||
let task = {
|
||||
let poll_duration = metrics.poll_duration.with_label_values(&[name]);
|
||||
let poll_start = metrics.poll_start.with_label_values(&[name]);
|
||||
let inner = prometheus_future::with_poll_durations(poll_duration, poll_start, task);
|
||||
let inner =
|
||||
prometheus_future::with_poll_durations(poll_duration, poll_start, task);
|
||||
// The logic of `AssertUnwindSafe` here is ok considering that we throw
|
||||
// away the `Future` after it has panicked.
|
||||
panic::AssertUnwindSafe(inner).catch_unwind()
|
||||
@@ -106,16 +113,15 @@ impl SpawnTaskHandle {
|
||||
Either::Right((Err(payload), _)) => {
|
||||
metrics.tasks_ended.with_label_values(&[name, "panic"]).inc();
|
||||
panic::resume_unwind(payload)
|
||||
}
|
||||
},
|
||||
Either::Right((Ok(()), _)) => {
|
||||
metrics.tasks_ended.with_label_values(&[name, "finished"]).inc();
|
||||
}
|
||||
},
|
||||
Either::Left(((), _)) => {
|
||||
// The `on_exit` has triggered.
|
||||
metrics.tasks_ended.with_label_values(&[name, "interrupted"]).inc();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
} else {
|
||||
futures::pin_mut!(task);
|
||||
let _ = select(on_exit, task).await;
|
||||
@@ -162,10 +168,7 @@ impl SpawnEssentialTaskHandle {
|
||||
essential_failed_tx: TracingUnboundedSender<()>,
|
||||
spawn_task_handle: SpawnTaskHandle,
|
||||
) -> SpawnEssentialTaskHandle {
|
||||
SpawnEssentialTaskHandle {
|
||||
essential_failed_tx,
|
||||
inner: spawn_task_handle,
|
||||
}
|
||||
SpawnEssentialTaskHandle { essential_failed_tx, inner: spawn_task_handle }
|
||||
}
|
||||
|
||||
/// Spawns the given task with the given name.
|
||||
@@ -193,12 +196,10 @@ impl SpawnEssentialTaskHandle {
|
||||
task_type: TaskType,
|
||||
) {
|
||||
let essential_failed = self.essential_failed_tx.clone();
|
||||
let essential_task = std::panic::AssertUnwindSafe(task)
|
||||
.catch_unwind()
|
||||
.map(move |_| {
|
||||
log::error!("Essential task `{}` failed. Shutting down service.", name);
|
||||
let _ = essential_failed.close_channel();
|
||||
});
|
||||
let essential_task = std::panic::AssertUnwindSafe(task).catch_unwind().map(move |_| {
|
||||
log::error!("Essential task `{}` failed. Shutting down service.", name);
|
||||
let _ = essential_failed.close_channel();
|
||||
});
|
||||
|
||||
let _ = self.inner.spawn_inner(name, essential_task, task_type);
|
||||
}
|
||||
@@ -260,10 +261,8 @@ impl TaskManager {
|
||||
// NOTE: for_each_concurrent will await on all the JoinHandle futures at the same time. It
|
||||
// is possible to limit this but it's actually better for the memory foot print to await
|
||||
// them all to not accumulate anything on that stream.
|
||||
let completion_future = executor.spawn(
|
||||
Box::pin(background_tasks.for_each_concurrent(None, |x| x)),
|
||||
TaskType::Async,
|
||||
);
|
||||
let completion_future = executor
|
||||
.spawn(Box::pin(background_tasks.for_each_concurrent(None, |x| x)), TaskType::Async);
|
||||
|
||||
Ok(Self {
|
||||
on_exit,
|
||||
@@ -323,16 +322,21 @@ impl TaskManager {
|
||||
///
|
||||
/// This function will not wait until the end of the remaining task. You must call and await
|
||||
/// `clean_shutdown()` after this.
|
||||
pub fn future<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
|
||||
pub fn future<'a>(
|
||||
&'a mut self,
|
||||
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
|
||||
Box::pin(async move {
|
||||
let mut t1 = self.essential_failed_rx.next().fuse();
|
||||
let mut t2 = self.on_exit.clone().fuse();
|
||||
let mut t3 = try_join_all(
|
||||
self.children.iter_mut().map(|x| x.future())
|
||||
self.children
|
||||
.iter_mut()
|
||||
.map(|x| x.future())
|
||||
// Never end this future if there is no error because if there is no children,
|
||||
// it must not stop
|
||||
.chain(std::iter::once(pending().boxed()))
|
||||
).fuse();
|
||||
.chain(std::iter::once(pending().boxed())),
|
||||
)
|
||||
.fuse();
|
||||
|
||||
futures::select! {
|
||||
_ = t1 => Err(Error::Other("Essential task failed.".into())),
|
||||
|
||||
@@ -20,20 +20,20 @@
|
||||
|
||||
use futures::prelude::*;
|
||||
use prometheus_endpoint::{Counter, Histogram, U64};
|
||||
use std::{fmt, pin::Pin, task::{Context, Poll}};
|
||||
use std::{
|
||||
fmt,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
/// Wraps around a `Future`. Report the polling duration to the `Histogram` and when the polling
|
||||
/// starts to the `Counter`.
|
||||
pub fn with_poll_durations<T>(
|
||||
poll_duration: Histogram,
|
||||
poll_start: Counter<U64>,
|
||||
inner: T
|
||||
inner: T,
|
||||
) -> PrometheusFuture<T> {
|
||||
PrometheusFuture {
|
||||
inner,
|
||||
poll_duration,
|
||||
poll_start,
|
||||
}
|
||||
PrometheusFuture { inner, poll_duration, poll_start }
|
||||
}
|
||||
|
||||
/// Wraps around `Future` and adds diagnostics to it.
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::config::TaskExecutor;
|
||||
use crate::task_manager::TaskManager;
|
||||
use crate::{config::TaskExecutor, task_manager::TaskManager};
|
||||
use futures::{future::FutureExt, pin_mut, select};
|
||||
use parking_lot::Mutex;
|
||||
use std::{any::Any, sync::Arc, time::Duration};
|
||||
@@ -205,7 +204,9 @@ fn ensure_task_manager_future_ends_with_error_when_essential_task_fails() {
|
||||
runtime.block_on(async { tokio::time::delay_for(Duration::from_secs(1)).await });
|
||||
assert_eq!(drop_tester, 2);
|
||||
spawn_essential_handle.spawn("task3", async { panic!("task failed") });
|
||||
runtime.block_on(task_manager.future()).expect_err("future()'s Result must be Err");
|
||||
runtime
|
||||
.block_on(task_manager.future())
|
||||
.expect_err("future()'s Result must be Err");
|
||||
assert_eq!(drop_tester, 2);
|
||||
runtime.block_on(task_manager.clean_shutdown());
|
||||
assert_eq!(drop_tester, 0);
|
||||
@@ -265,7 +266,9 @@ fn ensure_task_manager_future_ends_with_error_when_childs_essential_task_fails()
|
||||
runtime.block_on(async { tokio::time::delay_for(Duration::from_secs(1)).await });
|
||||
assert_eq!(drop_tester, 4);
|
||||
spawn_essential_handle_child_1.spawn("task5", async { panic!("task failed") });
|
||||
runtime.block_on(task_manager.future()).expect_err("future()'s Result must be Err");
|
||||
runtime
|
||||
.block_on(task_manager.future())
|
||||
.expect_err("future()'s Result must be Err");
|
||||
assert_eq!(drop_tester, 4);
|
||||
runtime.block_on(task_manager.clean_shutdown());
|
||||
assert_eq!(drop_tester, 0);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use sp_core::offchain::{OffchainStorage, storage::InMemOffchainStorage};
|
||||
use sp_core::offchain::{storage::InMemOffchainStorage, OffchainStorage};
|
||||
use std::sync::Arc;
|
||||
|
||||
type TestBackend = sc_client_api::in_mem::Backend<substrate_test_runtime::Block>;
|
||||
@@ -32,12 +32,13 @@ fn test_leaves_with_complex_block_tree() {
|
||||
fn test_blockchain_query_by_number_gets_canonical() {
|
||||
let backend = Arc::new(TestBackend::new());
|
||||
|
||||
substrate_test_runtime_client::trait_tests::test_blockchain_query_by_number_gets_canonical(backend);
|
||||
substrate_test_runtime_client::trait_tests::test_blockchain_query_by_number_gets_canonical(
|
||||
backend,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn in_memory_offchain_storage() {
|
||||
|
||||
let mut storage = InMemOffchainStorage::default();
|
||||
assert_eq!(storage.get(b"A", b"B"), None);
|
||||
assert_eq!(storage.get(b"B", b"A"), None);
|
||||
|
||||
@@ -16,53 +16,52 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use sc_light::{
|
||||
call_executor::{
|
||||
GenesisCallExecutor,
|
||||
check_execution_proof,
|
||||
},
|
||||
fetcher::LightDataChecker,
|
||||
blockchain::{BlockchainCache, Blockchain},
|
||||
backend::{Backend, GenesisOrUnavailableState},
|
||||
use super::prepare_client_with_key_changes;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use parking_lot::Mutex;
|
||||
use sc_block_builder::BlockBuilderProvider;
|
||||
use sc_client_api::{
|
||||
backend::NewBlockState,
|
||||
blockchain::Info,
|
||||
cht,
|
||||
in_mem::{Backend as InMemBackend, Blockchain as InMemoryBlockchain},
|
||||
AuxStore, Backend as ClientBackend, BlockBackend, BlockImportOperation, CallExecutor,
|
||||
ChangesProof, ExecutionStrategy, FetchChecker, ProofProvider, ProvideChtRoots,
|
||||
RemoteBodyRequest, RemoteCallRequest, RemoteChangesRequest, RemoteHeaderRequest,
|
||||
RemoteReadChildRequest, RemoteReadRequest, Storage, StorageProof, StorageProvider,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use sc_executor::{NativeExecutor, NativeVersion, RuntimeVersion, WasmExecutionMethod};
|
||||
use sc_light::{
|
||||
backend::{Backend, GenesisOrUnavailableState},
|
||||
blockchain::{Blockchain, BlockchainCache},
|
||||
call_executor::{check_execution_proof, GenesisCallExecutor},
|
||||
fetcher::LightDataChecker,
|
||||
};
|
||||
use sp_api::{ProofRecorder, StorageTransactionCache};
|
||||
use sp_blockchain::{
|
||||
well_known_cache_keys, BlockStatus, CachedHeaderMetadata, Error as ClientError, HeaderBackend,
|
||||
Result as ClientResult,
|
||||
};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_core::{testing::TaskExecutor, NativeOrEncoded, H256};
|
||||
use sp_externalities::Extensions;
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::{BlakeTwo256, Block as _, HashFor, Header as HeaderT, NumberFor},
|
||||
Digest, Justifications,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
use sp_state_machine::{ExecutionManager, OverlayedChanges};
|
||||
use std::{cell::RefCell, collections::HashMap, panic::UnwindSafe, sync::Arc};
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::{Hash, Block, Header}, TestClient, ClientBlockImportExt,
|
||||
};
|
||||
use sp_api::{StorageTransactionCache, ProofRecorder};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sc_executor::{NativeExecutor, WasmExecutionMethod, RuntimeVersion, NativeVersion};
|
||||
use sp_core::{H256, NativeOrEncoded, testing::TaskExecutor};
|
||||
use sc_client_api::{
|
||||
blockchain::Info, backend::NewBlockState, Backend as ClientBackend, ProofProvider,
|
||||
in_mem::{Backend as InMemBackend, Blockchain as InMemoryBlockchain}, ProvideChtRoots,
|
||||
AuxStore, Storage, CallExecutor, cht, ExecutionStrategy, StorageProof, BlockImportOperation,
|
||||
RemoteCallRequest, StorageProvider, ChangesProof, RemoteBodyRequest, RemoteReadRequest,
|
||||
RemoteChangesRequest, FetchChecker, RemoteReadChildRequest, RemoteHeaderRequest, BlockBackend,
|
||||
};
|
||||
use sp_externalities::Extensions;
|
||||
use sc_block_builder::BlockBuilderProvider;
|
||||
use sp_blockchain::{
|
||||
BlockStatus, Result as ClientResult, Error as ClientError, CachedHeaderMetadata,
|
||||
HeaderBackend, well_known_cache_keys
|
||||
};
|
||||
use std::panic::UnwindSafe;
|
||||
use std::cell::RefCell;
|
||||
use sp_state_machine::{OverlayedChanges, ExecutionManager};
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use super::prepare_client_with_key_changes;
|
||||
use substrate_test_runtime_client::{
|
||||
AccountKeyring, runtime::{self, Extrinsic},
|
||||
runtime::{self, Block, Extrinsic, Hash, Header},
|
||||
AccountKeyring, ClientBlockImportExt, TestClient,
|
||||
};
|
||||
|
||||
use sp_core::{blake2_256, ChangesTrieConfiguration, storage::{well_known_keys, StorageKey, ChildInfo}};
|
||||
use sp_core::{
|
||||
blake2_256,
|
||||
storage::{well_known_keys, ChildInfo, StorageKey},
|
||||
ChangesTrieConfiguration,
|
||||
};
|
||||
use sp_state_machine::Backend as _;
|
||||
|
||||
pub type DummyBlockchain = Blockchain<DummyStorage>;
|
||||
@@ -115,7 +114,8 @@ impl sp_blockchain::HeaderMetadata<Block> for DummyStorage {
|
||||
type Error = ClientError;
|
||||
|
||||
fn header_metadata(&self, hash: Hash) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
|
||||
self.header(BlockId::hash(hash))?.map(|header| CachedHeaderMetadata::from(&header))
|
||||
self.header(BlockId::hash(hash))?
|
||||
.map(|header| CachedHeaderMetadata::from(&header))
|
||||
.ok_or(ClientError::UnknownBlock("header not found".to_owned()))
|
||||
}
|
||||
fn insert_header_metadata(&self, _hash: Hash, _metadata: CachedHeaderMetadata<Block>) {}
|
||||
@@ -127,9 +127,13 @@ impl AuxStore for DummyStorage {
|
||||
'a,
|
||||
'b: 'a,
|
||||
'c: 'a,
|
||||
I: IntoIterator<Item=&'a(&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item=&'a &'b [u8]>,
|
||||
>(&self, insert: I, _delete: D) -> ClientResult<()> {
|
||||
I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
|
||||
D: IntoIterator<Item = &'a &'b [u8]>,
|
||||
>(
|
||||
&self,
|
||||
insert: I,
|
||||
_delete: D,
|
||||
) -> ClientResult<()> {
|
||||
for (k, v) in insert.into_iter() {
|
||||
self.aux_store.lock().insert(k.to_vec(), v.to_vec());
|
||||
}
|
||||
@@ -182,9 +186,10 @@ impl ProvideChtRoots<Block> for DummyStorage {
|
||||
cht::block_to_cht_number(cht_size, block)
|
||||
.and_then(|cht_num| self.changes_tries_cht_roots.get(&cht_num))
|
||||
.cloned()
|
||||
.ok_or_else(|| ClientError::Backend(
|
||||
format!("Test error: CHT for block #{} not found", block)
|
||||
).into())
|
||||
.ok_or_else(|| {
|
||||
ClientError::Backend(format!("Test error: CHT for block #{} not found", block))
|
||||
.into()
|
||||
})
|
||||
.map(Some)
|
||||
}
|
||||
}
|
||||
@@ -210,7 +215,7 @@ impl CallExecutor<Block> for DummyCallExecutor {
|
||||
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<R, sp_api::ApiError> + UnwindSafe,
|
||||
@@ -220,17 +225,22 @@ impl CallExecutor<Block> for DummyCallExecutor {
|
||||
_method: &str,
|
||||
_call_data: &[u8],
|
||||
_changes: &RefCell<OverlayedChanges>,
|
||||
_storage_transaction_cache: Option<&RefCell<
|
||||
StorageTransactionCache<
|
||||
Block,
|
||||
<Self::Backend as sc_client_api::backend::Backend<Block>>::State,
|
||||
>
|
||||
>>,
|
||||
_storage_transaction_cache: Option<
|
||||
&RefCell<
|
||||
StorageTransactionCache<
|
||||
Block,
|
||||
<Self::Backend as sc_client_api::backend::Backend<Block>>::State,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
_execution_manager: ExecutionManager<EM>,
|
||||
_native_call: Option<NC>,
|
||||
_proof_recorder: &Option<ProofRecorder<Block>>,
|
||||
_extensions: Option<Extensions>,
|
||||
) -> ClientResult<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone {
|
||||
) -> ClientResult<NativeOrEncoded<R>>
|
||||
where
|
||||
ExecutionManager<EM>: Clone,
|
||||
{
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
@@ -243,7 +253,7 @@ impl CallExecutor<Block> for DummyCallExecutor {
|
||||
_trie_state: &sp_state_machine::TrieBackend<S, HashFor<Block>>,
|
||||
_overlay: &mut OverlayedChanges,
|
||||
_method: &str,
|
||||
_call_data: &[u8]
|
||||
_call_data: &[u8],
|
||||
) -> Result<(Vec<u8>, StorageProof), ClientError> {
|
||||
unreachable!()
|
||||
}
|
||||
@@ -260,11 +270,11 @@ fn local_executor() -> NativeExecutor<substrate_test_runtime_client::LocalExecut
|
||||
#[test]
|
||||
fn local_state_is_created_when_genesis_state_is_available() {
|
||||
let def = Default::default();
|
||||
let header0 = substrate_test_runtime_client::runtime::Header::new(0, def, def, def, Default::default());
|
||||
let header0 =
|
||||
substrate_test_runtime_client::runtime::Header::new(0, def, def, def, Default::default());
|
||||
|
||||
let backend: Backend<_, BlakeTwo256> = Backend::new(
|
||||
Arc::new(DummyBlockchain::new(DummyStorage::new())),
|
||||
);
|
||||
let backend: Backend<_, BlakeTwo256> =
|
||||
Backend::new(Arc::new(DummyBlockchain::new(DummyStorage::new())));
|
||||
let mut op = backend.begin_operation().unwrap();
|
||||
op.set_block_data(header0, None, None, None, NewBlockState::Final).unwrap();
|
||||
op.set_genesis_state(Default::default(), true).unwrap();
|
||||
@@ -278,9 +288,8 @@ fn local_state_is_created_when_genesis_state_is_available() {
|
||||
|
||||
#[test]
|
||||
fn unavailable_state_is_created_when_genesis_state_is_unavailable() {
|
||||
let backend: Backend<_, BlakeTwo256> = Backend::new(
|
||||
Arc::new(DummyBlockchain::new(DummyStorage::new())),
|
||||
);
|
||||
let backend: Backend<_, BlakeTwo256> =
|
||||
Backend::new(Arc::new(DummyBlockchain::new(DummyStorage::new())));
|
||||
|
||||
match backend.state_at(BlockId::Number(0)).unwrap() {
|
||||
GenesisOrUnavailableState::Unavailable => (),
|
||||
@@ -305,11 +314,8 @@ fn execution_proof_is_generated_and_checked() {
|
||||
let remote_header = remote_client.header(&remote_block_id).unwrap().unwrap();
|
||||
|
||||
// 'fetch' execution proof from remote node
|
||||
let (remote_result, remote_execution_proof) = remote_client.execution_proof(
|
||||
&remote_block_id,
|
||||
method,
|
||||
&[]
|
||||
).unwrap();
|
||||
let (remote_result, remote_execution_proof) =
|
||||
remote_client.execution_proof(&remote_block_id, method, &[]).unwrap();
|
||||
|
||||
// check remote execution proof locally
|
||||
let local_result = check_execution_proof::<_, _, BlakeTwo256>(
|
||||
@@ -323,7 +329,8 @@ fn execution_proof_is_generated_and_checked() {
|
||||
retry_count: None,
|
||||
},
|
||||
remote_execution_proof,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
(remote_result, local_result)
|
||||
}
|
||||
@@ -333,17 +340,20 @@ fn execution_proof_is_generated_and_checked() {
|
||||
let remote_header = remote_client.header(&remote_block_id).unwrap().unwrap();
|
||||
|
||||
// 'fetch' execution proof from remote node
|
||||
let (_, remote_execution_proof) = remote_client.execution_proof(
|
||||
&remote_block_id,
|
||||
"Core_initialize_block",
|
||||
&Header::new(
|
||||
at,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
).encode(),
|
||||
).unwrap();
|
||||
let (_, remote_execution_proof) = remote_client
|
||||
.execution_proof(
|
||||
&remote_block_id,
|
||||
"Core_initialize_block",
|
||||
&Header::new(
|
||||
at,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
)
|
||||
.encode(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// check remote execution proof locally
|
||||
let execution_result = check_execution_proof::<_, _, BlakeTwo256>(
|
||||
@@ -359,7 +369,8 @@ fn execution_proof_is_generated_and_checked() {
|
||||
Default::default(),
|
||||
remote_header.hash(),
|
||||
remote_header.digest().clone(), // this makes next header wrong
|
||||
).encode(),
|
||||
)
|
||||
.encode(),
|
||||
retry_count: None,
|
||||
},
|
||||
remote_execution_proof,
|
||||
@@ -379,7 +390,8 @@ fn execution_proof_is_generated_and_checked() {
|
||||
BlockOrigin::Own,
|
||||
remote_client.new_block(digest).unwrap().build().unwrap().block,
|
||||
Justifications::from((*b"TEST", Default::default())),
|
||||
)).unwrap();
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// check method that doesn't requires environment
|
||||
@@ -401,22 +413,26 @@ fn execution_proof_is_generated_and_checked() {
|
||||
fn code_is_executed_at_genesis_only() {
|
||||
let backend = Arc::new(InMemBackend::<Block>::new());
|
||||
let def = H256::default();
|
||||
let header0 = substrate_test_runtime_client::runtime::Header::new(0, def, def, def, Default::default());
|
||||
let header0 =
|
||||
substrate_test_runtime_client::runtime::Header::new(0, def, def, def, Default::default());
|
||||
let hash0 = header0.hash();
|
||||
let header1 = substrate_test_runtime_client::runtime::Header::new(1, def, def, hash0, Default::default());
|
||||
let header1 =
|
||||
substrate_test_runtime_client::runtime::Header::new(1, def, def, hash0, Default::default());
|
||||
let hash1 = header1.hash();
|
||||
backend.blockchain().insert(hash0, header0, None, None, NewBlockState::Final).unwrap();
|
||||
backend.blockchain().insert(hash1, header1, None, None, NewBlockState::Final).unwrap();
|
||||
backend
|
||||
.blockchain()
|
||||
.insert(hash0, header0, None, None, NewBlockState::Final)
|
||||
.unwrap();
|
||||
backend
|
||||
.blockchain()
|
||||
.insert(hash1, header1, None, None, NewBlockState::Final)
|
||||
.unwrap();
|
||||
|
||||
let genesis_executor = GenesisCallExecutor::new(backend, DummyCallExecutor);
|
||||
assert_eq!(
|
||||
genesis_executor.call(
|
||||
&BlockId::Number(0),
|
||||
"test_method",
|
||||
&[],
|
||||
ExecutionStrategy::NativeElseWasm,
|
||||
None,
|
||||
).unwrap(),
|
||||
genesis_executor
|
||||
.call(&BlockId::Number(0), "test_method", &[], ExecutionStrategy::NativeElseWasm, None,)
|
||||
.unwrap(),
|
||||
vec![42],
|
||||
);
|
||||
|
||||
@@ -434,7 +450,6 @@ fn code_is_executed_at_genesis_only() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type TestChecker = LightDataChecker<
|
||||
NativeExecutor<substrate_test_runtime_client::LocalExecutor>,
|
||||
BlakeTwo256,
|
||||
@@ -448,27 +463,28 @@ fn prepare_for_read_proof_check() -> (TestChecker, Header, StorageProof, u32) {
|
||||
let remote_block_id = BlockId::Number(0);
|
||||
let remote_block_hash = remote_client.block_hash(0).unwrap().unwrap();
|
||||
let mut remote_block_header = remote_client.header(&remote_block_id).unwrap().unwrap();
|
||||
remote_block_header.state_root = remote_client.state_at(&remote_block_id).unwrap()
|
||||
.storage_root(::std::iter::empty()).0.into();
|
||||
remote_block_header.state_root = remote_client
|
||||
.state_at(&remote_block_id)
|
||||
.unwrap()
|
||||
.storage_root(::std::iter::empty())
|
||||
.0
|
||||
.into();
|
||||
|
||||
// 'fetch' read proof from remote node
|
||||
let heap_pages = remote_client.storage(&remote_block_id, &StorageKey(well_known_keys::HEAP_PAGES.to_vec()))
|
||||
let heap_pages = remote_client
|
||||
.storage(&remote_block_id, &StorageKey(well_known_keys::HEAP_PAGES.to_vec()))
|
||||
.unwrap()
|
||||
.and_then(|v| Decode::decode(&mut &v.0[..]).ok()).unwrap();
|
||||
let remote_read_proof = remote_client.read_proof(
|
||||
&remote_block_id,
|
||||
&mut std::iter::once(well_known_keys::HEAP_PAGES),
|
||||
).unwrap();
|
||||
.and_then(|v| Decode::decode(&mut &v.0[..]).ok())
|
||||
.unwrap();
|
||||
let remote_read_proof = remote_client
|
||||
.read_proof(&remote_block_id, &mut std::iter::once(well_known_keys::HEAP_PAGES))
|
||||
.unwrap();
|
||||
|
||||
// check remote read proof locally
|
||||
let local_storage = InMemoryBlockchain::<Block>::new();
|
||||
local_storage.insert(
|
||||
remote_block_hash,
|
||||
remote_block_header.clone(),
|
||||
None,
|
||||
None,
|
||||
NewBlockState::Final,
|
||||
).unwrap();
|
||||
local_storage
|
||||
.insert(remote_block_hash, remote_block_header.clone(), None, None, NewBlockState::Final)
|
||||
.unwrap();
|
||||
let local_checker = LightDataChecker::new(
|
||||
Arc::new(DummyBlockchain::new(DummyStorage::new())),
|
||||
local_executor(),
|
||||
@@ -478,45 +494,39 @@ fn prepare_for_read_proof_check() -> (TestChecker, Header, StorageProof, u32) {
|
||||
}
|
||||
|
||||
fn prepare_for_read_child_proof_check() -> (TestChecker, Header, StorageProof, Vec<u8>) {
|
||||
use substrate_test_runtime_client::DefaultTestClientBuilderExt;
|
||||
use substrate_test_runtime_client::TestClientBuilderExt;
|
||||
use substrate_test_runtime_client::{DefaultTestClientBuilderExt, TestClientBuilderExt};
|
||||
let child_info = ChildInfo::new_default(b"child1");
|
||||
let child_info = &child_info;
|
||||
// prepare remote client
|
||||
let remote_client = substrate_test_runtime_client::TestClientBuilder::new()
|
||||
.add_extra_child_storage(
|
||||
child_info,
|
||||
b"key1".to_vec(),
|
||||
b"value1".to_vec(),
|
||||
).build();
|
||||
.add_extra_child_storage(child_info, b"key1".to_vec(), b"value1".to_vec())
|
||||
.build();
|
||||
let remote_block_id = BlockId::Number(0);
|
||||
let remote_block_hash = remote_client.block_hash(0).unwrap().unwrap();
|
||||
let mut remote_block_header = remote_client.header(&remote_block_id).unwrap().unwrap();
|
||||
remote_block_header.state_root = remote_client.state_at(&remote_block_id).unwrap()
|
||||
.storage_root(::std::iter::empty()).0.into();
|
||||
remote_block_header.state_root = remote_client
|
||||
.state_at(&remote_block_id)
|
||||
.unwrap()
|
||||
.storage_root(::std::iter::empty())
|
||||
.0
|
||||
.into();
|
||||
|
||||
// 'fetch' child read proof from remote node
|
||||
let child_value = remote_client.child_storage(
|
||||
&remote_block_id,
|
||||
child_info,
|
||||
&StorageKey(b"key1".to_vec()),
|
||||
).unwrap().unwrap().0;
|
||||
let child_value = remote_client
|
||||
.child_storage(&remote_block_id, child_info, &StorageKey(b"key1".to_vec()))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.0;
|
||||
assert_eq!(b"value1"[..], child_value[..]);
|
||||
let remote_read_proof = remote_client.read_child_proof(
|
||||
&remote_block_id,
|
||||
child_info,
|
||||
&mut std::iter::once("key1".as_bytes()),
|
||||
).unwrap();
|
||||
let remote_read_proof = remote_client
|
||||
.read_child_proof(&remote_block_id, child_info, &mut std::iter::once("key1".as_bytes()))
|
||||
.unwrap();
|
||||
|
||||
// check locally
|
||||
let local_storage = InMemoryBlockchain::<Block>::new();
|
||||
local_storage.insert(
|
||||
remote_block_hash,
|
||||
remote_block_header.clone(),
|
||||
None,
|
||||
None,
|
||||
NewBlockState::Final,
|
||||
).unwrap();
|
||||
local_storage
|
||||
.insert(remote_block_hash, remote_block_header.clone(), None, None, NewBlockState::Final)
|
||||
.unwrap();
|
||||
let local_checker = LightDataChecker::new(
|
||||
Arc::new(DummyBlockchain::new(DummyStorage::new())),
|
||||
local_executor(),
|
||||
@@ -533,18 +543,21 @@ fn prepare_for_header_proof_check(insert_cht: bool) -> (TestChecker, Hash, Heade
|
||||
let block = remote_client.new_block(Default::default()).unwrap().build().unwrap().block;
|
||||
futures::executor::block_on(remote_client.import(BlockOrigin::Own, block)).unwrap();
|
||||
local_headers_hashes.push(
|
||||
remote_client.block_hash(i + 1)
|
||||
.map_err(|_| ClientError::Backend("TestError".into()))
|
||||
remote_client
|
||||
.block_hash(i + 1)
|
||||
.map_err(|_| ClientError::Backend("TestError".into())),
|
||||
);
|
||||
}
|
||||
|
||||
// 'fetch' header proof from remote node
|
||||
let remote_block_id = BlockId::Number(1);
|
||||
let (remote_block_header, remote_header_proof) = remote_client.header_proof_with_cht_size(&remote_block_id, 4).unwrap();
|
||||
let (remote_block_header, remote_header_proof) =
|
||||
remote_client.header_proof_with_cht_size(&remote_block_id, 4).unwrap();
|
||||
|
||||
// check remote read proof locally
|
||||
let local_storage = InMemoryBlockchain::<Block>::new();
|
||||
let local_cht_root = cht::compute_root::<Header, BlakeTwo256, _>(4, 0, local_headers_hashes).unwrap();
|
||||
let local_cht_root =
|
||||
cht::compute_root::<Header, BlakeTwo256, _>(4, 0, local_headers_hashes).unwrap();
|
||||
if insert_cht {
|
||||
local_storage.insert_cht_root(1, local_cht_root);
|
||||
}
|
||||
@@ -557,7 +570,7 @@ fn prepare_for_header_proof_check(insert_cht: bool) -> (TestChecker, Hash, Heade
|
||||
}
|
||||
|
||||
fn header_with_computed_extrinsics_root(extrinsics: Vec<Extrinsic>) -> Header {
|
||||
use sp_trie::{TrieConfiguration, trie_types::Layout};
|
||||
use sp_trie::{trie_types::Layout, TrieConfiguration};
|
||||
let iter = extrinsics.iter().map(Encode::encode);
|
||||
let extrinsics_root = Layout::<BlakeTwo256>::ordered_trie_root(iter);
|
||||
|
||||
@@ -567,66 +580,106 @@ fn header_with_computed_extrinsics_root(extrinsics: Vec<Extrinsic>) -> Header {
|
||||
|
||||
#[test]
|
||||
fn storage_read_proof_is_generated_and_checked() {
|
||||
let (local_checker, remote_block_header, remote_read_proof, heap_pages) = prepare_for_read_proof_check();
|
||||
assert_eq!((&local_checker as &dyn FetchChecker<Block>).check_read_proof(&RemoteReadRequest::<Header> {
|
||||
block: remote_block_header.hash(),
|
||||
header: remote_block_header,
|
||||
keys: vec![well_known_keys::HEAP_PAGES.to_vec()],
|
||||
retry_count: None,
|
||||
}, remote_read_proof).unwrap().remove(well_known_keys::HEAP_PAGES).unwrap().unwrap()[0], heap_pages as u8);
|
||||
let (local_checker, remote_block_header, remote_read_proof, heap_pages) =
|
||||
prepare_for_read_proof_check();
|
||||
assert_eq!(
|
||||
(&local_checker as &dyn FetchChecker<Block>)
|
||||
.check_read_proof(
|
||||
&RemoteReadRequest::<Header> {
|
||||
block: remote_block_header.hash(),
|
||||
header: remote_block_header,
|
||||
keys: vec![well_known_keys::HEAP_PAGES.to_vec()],
|
||||
retry_count: None,
|
||||
},
|
||||
remote_read_proof
|
||||
)
|
||||
.unwrap()
|
||||
.remove(well_known_keys::HEAP_PAGES)
|
||||
.unwrap()
|
||||
.unwrap()[0],
|
||||
heap_pages as u8
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn storage_child_read_proof_is_generated_and_checked() {
|
||||
let child_info = ChildInfo::new_default(&b"child1"[..]);
|
||||
let (
|
||||
local_checker,
|
||||
remote_block_header,
|
||||
remote_read_proof,
|
||||
result,
|
||||
) = prepare_for_read_child_proof_check();
|
||||
assert_eq!((&local_checker as &dyn FetchChecker<Block>).check_read_child_proof(
|
||||
&RemoteReadChildRequest::<Header> {
|
||||
block: remote_block_header.hash(),
|
||||
header: remote_block_header,
|
||||
storage_key: child_info.prefixed_storage_key(),
|
||||
keys: vec![b"key1".to_vec()],
|
||||
retry_count: None,
|
||||
},
|
||||
remote_read_proof
|
||||
).unwrap().remove(b"key1".as_ref()).unwrap().unwrap(), result);
|
||||
let (local_checker, remote_block_header, remote_read_proof, result) =
|
||||
prepare_for_read_child_proof_check();
|
||||
assert_eq!(
|
||||
(&local_checker as &dyn FetchChecker<Block>)
|
||||
.check_read_child_proof(
|
||||
&RemoteReadChildRequest::<Header> {
|
||||
block: remote_block_header.hash(),
|
||||
header: remote_block_header,
|
||||
storage_key: child_info.prefixed_storage_key(),
|
||||
keys: vec![b"key1".to_vec()],
|
||||
retry_count: None,
|
||||
},
|
||||
remote_read_proof
|
||||
)
|
||||
.unwrap()
|
||||
.remove(b"key1".as_ref())
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
result
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn header_proof_is_generated_and_checked() {
|
||||
let (local_checker, local_cht_root, remote_block_header, remote_header_proof) = prepare_for_header_proof_check(true);
|
||||
assert_eq!((&local_checker as &dyn FetchChecker<Block>).check_header_proof(&RemoteHeaderRequest::<Header> {
|
||||
cht_root: local_cht_root,
|
||||
block: 1,
|
||||
retry_count: None,
|
||||
}, Some(remote_block_header.clone()), remote_header_proof).unwrap(), remote_block_header);
|
||||
let (local_checker, local_cht_root, remote_block_header, remote_header_proof) =
|
||||
prepare_for_header_proof_check(true);
|
||||
assert_eq!(
|
||||
(&local_checker as &dyn FetchChecker<Block>)
|
||||
.check_header_proof(
|
||||
&RemoteHeaderRequest::<Header> {
|
||||
cht_root: local_cht_root,
|
||||
block: 1,
|
||||
retry_count: None,
|
||||
},
|
||||
Some(remote_block_header.clone()),
|
||||
remote_header_proof
|
||||
)
|
||||
.unwrap(),
|
||||
remote_block_header
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_header_proof_fails_if_cht_root_is_invalid() {
|
||||
let (local_checker, _, mut remote_block_header, remote_header_proof) = prepare_for_header_proof_check(true);
|
||||
let (local_checker, _, mut remote_block_header, remote_header_proof) =
|
||||
prepare_for_header_proof_check(true);
|
||||
remote_block_header.number = 100;
|
||||
assert!((&local_checker as &dyn FetchChecker<Block>).check_header_proof(&RemoteHeaderRequest::<Header> {
|
||||
cht_root: Default::default(),
|
||||
block: 1,
|
||||
retry_count: None,
|
||||
}, Some(remote_block_header.clone()), remote_header_proof).is_err());
|
||||
assert!((&local_checker as &dyn FetchChecker<Block>)
|
||||
.check_header_proof(
|
||||
&RemoteHeaderRequest::<Header> {
|
||||
cht_root: Default::default(),
|
||||
block: 1,
|
||||
retry_count: None,
|
||||
},
|
||||
Some(remote_block_header.clone()),
|
||||
remote_header_proof
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_header_proof_fails_if_invalid_header_provided() {
|
||||
let (local_checker, local_cht_root, mut remote_block_header, remote_header_proof) = prepare_for_header_proof_check(true);
|
||||
let (local_checker, local_cht_root, mut remote_block_header, remote_header_proof) =
|
||||
prepare_for_header_proof_check(true);
|
||||
remote_block_header.number = 100;
|
||||
assert!((&local_checker as &dyn FetchChecker<Block>).check_header_proof(&RemoteHeaderRequest::<Header> {
|
||||
cht_root: local_cht_root,
|
||||
block: 1,
|
||||
retry_count: None,
|
||||
}, Some(remote_block_header.clone()), remote_header_proof).is_err());
|
||||
assert!((&local_checker as &dyn FetchChecker<Block>)
|
||||
.check_header_proof(
|
||||
&RemoteHeaderRequest::<Header> {
|
||||
cht_root: local_cht_root,
|
||||
block: 1,
|
||||
retry_count: None,
|
||||
},
|
||||
Some(remote_block_header.clone()),
|
||||
remote_header_proof
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -647,9 +700,9 @@ fn changes_proof_is_generated_and_checked_when_headers_are_not_pruned() {
|
||||
|
||||
// 'fetch' changes proof from remote node
|
||||
let key = StorageKey(key);
|
||||
let remote_proof = remote_client.key_changes_proof(
|
||||
begin_hash, end_hash, begin_hash, max_hash, None, &key
|
||||
).unwrap();
|
||||
let remote_proof = remote_client
|
||||
.key_changes_proof(begin_hash, end_hash, begin_hash, max_hash, None, &key)
|
||||
.unwrap();
|
||||
|
||||
// check proof on local client
|
||||
let local_roots_range = local_roots.clone()[(begin - 1) as usize..].to_vec();
|
||||
@@ -668,20 +721,23 @@ fn changes_proof_is_generated_and_checked_when_headers_are_not_pruned() {
|
||||
storage_key: None,
|
||||
retry_count: None,
|
||||
};
|
||||
let local_result = local_checker.check_changes_proof(&request, ChangesProof {
|
||||
max_block: remote_proof.max_block,
|
||||
proof: remote_proof.proof,
|
||||
roots: remote_proof.roots,
|
||||
roots_proof: remote_proof.roots_proof,
|
||||
}).unwrap();
|
||||
let local_result = local_checker
|
||||
.check_changes_proof(
|
||||
&request,
|
||||
ChangesProof {
|
||||
max_block: remote_proof.max_block,
|
||||
proof: remote_proof.proof,
|
||||
roots: remote_proof.roots,
|
||||
roots_proof: remote_proof.roots_proof,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// ..and ensure that result is the same as on remote node
|
||||
if local_result != expected_result {
|
||||
panic!(
|
||||
"Failed test {}: local = {:?}, expected = {:?}",
|
||||
index,
|
||||
local_result,
|
||||
expected_result,
|
||||
index, local_result, expected_result,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -702,12 +758,17 @@ fn changes_proof_is_generated_and_checked_when_headers_are_pruned() {
|
||||
let b1 = remote_client.block_hash_from_id(&BlockId::Number(1)).unwrap().unwrap();
|
||||
let b3 = remote_client.block_hash_from_id(&BlockId::Number(3)).unwrap().unwrap();
|
||||
let b4 = remote_client.block_hash_from_id(&BlockId::Number(4)).unwrap().unwrap();
|
||||
let remote_proof = remote_client.key_changes_proof_with_cht_size(
|
||||
b1, b4, b3, b4, None, &dave, 4
|
||||
).unwrap();
|
||||
let remote_proof = remote_client
|
||||
.key_changes_proof_with_cht_size(b1, b4, b3, b4, None, &dave, 4)
|
||||
.unwrap();
|
||||
|
||||
// prepare local checker, having a root of changes trie CHT#0
|
||||
let local_cht_root = cht::compute_root::<Header, BlakeTwo256, _>(4, 0, remote_roots.iter().cloned().map(|ct| Ok(Some(ct)))).unwrap();
|
||||
let local_cht_root = cht::compute_root::<Header, BlakeTwo256, _>(
|
||||
4,
|
||||
0,
|
||||
remote_roots.iter().cloned().map(|ct| Ok(Some(ct))),
|
||||
)
|
||||
.unwrap();
|
||||
let mut local_storage = DummyStorage::new();
|
||||
local_storage.changes_tries_cht_roots.insert(0, local_cht_root);
|
||||
let local_checker = TestChecker::new(
|
||||
@@ -732,12 +793,18 @@ fn changes_proof_is_generated_and_checked_when_headers_are_pruned() {
|
||||
key: dave.0,
|
||||
retry_count: None,
|
||||
};
|
||||
let local_result = local_checker.check_changes_proof_with_cht_size(&request, ChangesProof {
|
||||
max_block: remote_proof.max_block,
|
||||
proof: remote_proof.proof,
|
||||
roots: remote_proof.roots,
|
||||
roots_proof: remote_proof.roots_proof,
|
||||
}, 4).unwrap();
|
||||
let local_result = local_checker
|
||||
.check_changes_proof_with_cht_size(
|
||||
&request,
|
||||
ChangesProof {
|
||||
max_block: remote_proof.max_block,
|
||||
proof: remote_proof.proof,
|
||||
roots: remote_proof.roots,
|
||||
roots_proof: remote_proof.roots_proof,
|
||||
},
|
||||
4,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(local_result, vec![(4, 0), (1, 1), (1, 0)]);
|
||||
}
|
||||
@@ -760,8 +827,9 @@ fn check_changes_proof_fails_if_proof_is_wrong() {
|
||||
|
||||
// 'fetch' changes proof from remote node
|
||||
let key = StorageKey(key);
|
||||
let remote_proof = remote_client.key_changes_proof(
|
||||
begin_hash, end_hash, begin_hash, max_hash, None, &key).unwrap();
|
||||
let remote_proof = remote_client
|
||||
.key_changes_proof(begin_hash, end_hash, begin_hash, max_hash, None, &key)
|
||||
.unwrap();
|
||||
|
||||
let local_roots_range = local_roots.clone()[(begin - 1) as usize..].to_vec();
|
||||
let config = ChangesTrieConfiguration::new(4, 2);
|
||||
@@ -781,34 +849,54 @@ fn check_changes_proof_fails_if_proof_is_wrong() {
|
||||
};
|
||||
|
||||
// check proof on local client using max from the future
|
||||
assert!(local_checker.check_changes_proof(&request, ChangesProof {
|
||||
max_block: remote_proof.max_block + 1,
|
||||
proof: remote_proof.proof.clone(),
|
||||
roots: remote_proof.roots.clone(),
|
||||
roots_proof: remote_proof.roots_proof.clone(),
|
||||
}).is_err());
|
||||
assert!(local_checker
|
||||
.check_changes_proof(
|
||||
&request,
|
||||
ChangesProof {
|
||||
max_block: remote_proof.max_block + 1,
|
||||
proof: remote_proof.proof.clone(),
|
||||
roots: remote_proof.roots.clone(),
|
||||
roots_proof: remote_proof.roots_proof.clone(),
|
||||
}
|
||||
)
|
||||
.is_err());
|
||||
|
||||
// check proof on local client using broken proof
|
||||
assert!(local_checker.check_changes_proof(&request, ChangesProof {
|
||||
max_block: remote_proof.max_block,
|
||||
proof: local_roots_range.clone().into_iter().map(|v| v.as_ref().to_vec()).collect(),
|
||||
roots: remote_proof.roots,
|
||||
roots_proof: remote_proof.roots_proof,
|
||||
}).is_err());
|
||||
assert!(local_checker
|
||||
.check_changes_proof(
|
||||
&request,
|
||||
ChangesProof {
|
||||
max_block: remote_proof.max_block,
|
||||
proof: local_roots_range.clone().into_iter().map(|v| v.as_ref().to_vec()).collect(),
|
||||
roots: remote_proof.roots,
|
||||
roots_proof: remote_proof.roots_proof,
|
||||
}
|
||||
)
|
||||
.is_err());
|
||||
|
||||
// extra roots proofs are provided
|
||||
assert!(local_checker.check_changes_proof(&request, ChangesProof {
|
||||
max_block: remote_proof.max_block,
|
||||
proof: remote_proof.proof.clone(),
|
||||
roots: vec![(begin - 1, Default::default())].into_iter().collect(),
|
||||
roots_proof: StorageProof::empty(),
|
||||
}).is_err());
|
||||
assert!(local_checker.check_changes_proof(&request, ChangesProof {
|
||||
max_block: remote_proof.max_block,
|
||||
proof: remote_proof.proof.clone(),
|
||||
roots: vec![(end + 1, Default::default())].into_iter().collect(),
|
||||
roots_proof: StorageProof::empty(),
|
||||
}).is_err());
|
||||
assert!(local_checker
|
||||
.check_changes_proof(
|
||||
&request,
|
||||
ChangesProof {
|
||||
max_block: remote_proof.max_block,
|
||||
proof: remote_proof.proof.clone(),
|
||||
roots: vec![(begin - 1, Default::default())].into_iter().collect(),
|
||||
roots_proof: StorageProof::empty(),
|
||||
}
|
||||
)
|
||||
.is_err());
|
||||
assert!(local_checker
|
||||
.check_changes_proof(
|
||||
&request,
|
||||
ChangesProof {
|
||||
max_block: remote_proof.max_block,
|
||||
proof: remote_proof.proof.clone(),
|
||||
roots: vec![(end + 1, Default::default())].into_iter().collect(),
|
||||
roots_proof: StorageProof::empty(),
|
||||
}
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -817,7 +905,11 @@ fn check_changes_tries_proof_fails_if_proof_is_wrong() {
|
||||
// (1, 4, dave.clone(), vec![(4, 0), (1, 1), (1, 0)]),
|
||||
let (remote_client, remote_roots, _) = prepare_client_with_key_changes();
|
||||
let local_cht_root = cht::compute_root::<Header, BlakeTwo256, _>(
|
||||
4, 0, remote_roots.iter().cloned().map(|ct| Ok(Some(ct)))).unwrap();
|
||||
4,
|
||||
0,
|
||||
remote_roots.iter().cloned().map(|ct| Ok(Some(ct))),
|
||||
)
|
||||
.unwrap();
|
||||
let dave = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec();
|
||||
let dave = StorageKey(dave);
|
||||
|
||||
@@ -828,9 +920,9 @@ fn check_changes_tries_proof_fails_if_proof_is_wrong() {
|
||||
let b1 = remote_client.block_hash_from_id(&BlockId::Number(1)).unwrap().unwrap();
|
||||
let b3 = remote_client.block_hash_from_id(&BlockId::Number(3)).unwrap().unwrap();
|
||||
let b4 = remote_client.block_hash_from_id(&BlockId::Number(4)).unwrap().unwrap();
|
||||
let remote_proof = remote_client.key_changes_proof_with_cht_size(
|
||||
b1, b4, b3, b4, None, &dave, 4
|
||||
).unwrap();
|
||||
let remote_proof = remote_client
|
||||
.key_changes_proof_with_cht_size(b1, b4, b3, b4, None, &dave, 4)
|
||||
.unwrap();
|
||||
|
||||
// fails when changes trie CHT is missing from the local db
|
||||
let local_checker = TestChecker::new(
|
||||
@@ -838,8 +930,9 @@ fn check_changes_tries_proof_fails_if_proof_is_wrong() {
|
||||
local_executor(),
|
||||
Box::new(TaskExecutor::new()),
|
||||
);
|
||||
assert!(local_checker.check_changes_tries_proof(4, &remote_proof.roots,
|
||||
remote_proof.roots_proof.clone()).is_err());
|
||||
assert!(local_checker
|
||||
.check_changes_tries_proof(4, &remote_proof.roots, remote_proof.roots_proof.clone())
|
||||
.is_err());
|
||||
|
||||
// fails when proof is broken
|
||||
let mut local_storage = DummyStorage::new();
|
||||
@@ -849,17 +942,15 @@ fn check_changes_tries_proof_fails_if_proof_is_wrong() {
|
||||
local_executor(),
|
||||
Box::new(TaskExecutor::new()),
|
||||
);
|
||||
let result = local_checker.check_changes_tries_proof(
|
||||
4, &remote_proof.roots, StorageProof::empty()
|
||||
);
|
||||
let result =
|
||||
local_checker.check_changes_tries_proof(4, &remote_proof.roots, StorageProof::empty());
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_body_proof_faulty() {
|
||||
let header = header_with_computed_extrinsics_root(
|
||||
vec![Extrinsic::IncludeData(vec![1, 2, 3, 4])]
|
||||
);
|
||||
let header =
|
||||
header_with_computed_extrinsics_root(vec![Extrinsic::IncludeData(vec![1, 2, 3, 4])]);
|
||||
let block = Block::new(header.clone(), Vec::new());
|
||||
|
||||
let local_checker = TestChecker::new(
|
||||
@@ -868,10 +959,7 @@ fn check_body_proof_faulty() {
|
||||
Box::new(TaskExecutor::new()),
|
||||
);
|
||||
|
||||
let body_request = RemoteBodyRequest {
|
||||
header: header.clone(),
|
||||
retry_count: None,
|
||||
};
|
||||
let body_request = RemoteBodyRequest { header: header.clone(), retry_count: None };
|
||||
|
||||
assert!(
|
||||
local_checker.check_body_proof(&body_request, block.extrinsics).is_err(),
|
||||
@@ -892,10 +980,7 @@ fn check_body_proof_of_same_data_should_succeed() {
|
||||
Box::new(TaskExecutor::new()),
|
||||
);
|
||||
|
||||
let body_request = RemoteBodyRequest {
|
||||
header: header.clone(),
|
||||
retry_count: None,
|
||||
};
|
||||
let body_request = RemoteBodyRequest { header: header.clone(), retry_count: None };
|
||||
|
||||
assert!(local_checker.check_body_proof(&body_request, block.extrinsics).is_ok());
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,38 +18,27 @@
|
||||
|
||||
//! Service integration test utils.
|
||||
|
||||
use std::iter;
|
||||
use std::sync::Arc;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::pin::Pin;
|
||||
use std::time::Duration;
|
||||
use log::{info, debug};
|
||||
use futures01::{Future, Stream, Poll};
|
||||
use futures::{FutureExt as _, TryFutureExt as _};
|
||||
use tempfile::TempDir;
|
||||
use tokio::{runtime::Runtime, prelude::FutureExt};
|
||||
use tokio::timer::Interval;
|
||||
use sc_service::{
|
||||
TaskManager,
|
||||
SpawnTaskHandle,
|
||||
GenericChainSpec,
|
||||
ChainSpecExtension,
|
||||
Configuration,
|
||||
KeepBlocks, TransactionStorageMode,
|
||||
config::{BasePath, DatabaseConfig, KeystoreConfig},
|
||||
RuntimeGenesis,
|
||||
Role,
|
||||
Error,
|
||||
TaskExecutor,
|
||||
client::Client,
|
||||
};
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sc_network::{multiaddr, Multiaddr};
|
||||
use sc_network::config::{NetworkConfiguration, TransportConfig};
|
||||
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||
use sc_transaction_pool_api::TransactionPool;
|
||||
use sc_client_api::{Backend, CallExecutor};
|
||||
use futures01::{Future, Poll, Stream};
|
||||
use log::{debug, info};
|
||||
use parking_lot::Mutex;
|
||||
use sc_client_api::{Backend, CallExecutor};
|
||||
use sc_network::{
|
||||
config::{NetworkConfiguration, TransportConfig},
|
||||
multiaddr, Multiaddr,
|
||||
};
|
||||
use sc_service::{
|
||||
client::Client,
|
||||
config::{BasePath, DatabaseConfig, KeystoreConfig},
|
||||
ChainSpecExtension, Configuration, Error, GenericChainSpec, KeepBlocks, Role, RuntimeGenesis,
|
||||
SpawnTaskHandle, TaskExecutor, TaskManager, TransactionStorageMode,
|
||||
};
|
||||
use sc_transaction_pool_api::TransactionPool;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||
use std::{iter, net::Ipv4Addr, pin::Pin, sync::Arc, time::Duration};
|
||||
use tempfile::TempDir;
|
||||
use tokio::{prelude::FutureExt, runtime::Runtime, timer::Interval};
|
||||
|
||||
#[cfg(test)]
|
||||
mod client;
|
||||
@@ -67,7 +56,9 @@ struct TestNet<G, E, F, L, U> {
|
||||
nodes: usize,
|
||||
}
|
||||
|
||||
pub trait TestNetNode: Clone + Future<Item = (), Error = sc_service::Error> + Send + 'static {
|
||||
pub trait TestNetNode:
|
||||
Clone + Future<Item = (), Error = sc_service::Error> + Send + 'static
|
||||
{
|
||||
type Block: BlockT;
|
||||
type Backend: Backend<Self::Block>;
|
||||
type Executor: CallExecutor<Self::Block> + Send + Sync;
|
||||
@@ -76,7 +67,9 @@ pub trait TestNetNode: Clone + Future<Item = (), Error = sc_service::Error> + Se
|
||||
|
||||
fn client(&self) -> Arc<Client<Self::Backend, Self::Executor, Self::Block, Self::RuntimeApi>>;
|
||||
fn transaction_pool(&self) -> Arc<Self::TransactionPool>;
|
||||
fn network(&self) -> Arc<sc_network::NetworkService<Self::Block, <Self::Block as BlockT>::Hash>>;
|
||||
fn network(
|
||||
&self,
|
||||
) -> Arc<sc_network::NetworkService<Self::Block, <Self::Block as BlockT>::Hash>>;
|
||||
fn spawn_handle(&self) -> SpawnTaskHandle;
|
||||
}
|
||||
|
||||
@@ -88,23 +81,21 @@ pub struct TestNetComponents<TBl: BlockT, TBackend, TExec, TRtApi, TExPool> {
|
||||
}
|
||||
|
||||
impl<TBl: BlockT, TBackend, TExec, TRtApi, TExPool>
|
||||
TestNetComponents<TBl, TBackend, TExec, TRtApi, TExPool> {
|
||||
TestNetComponents<TBl, TBackend, TExec, TRtApi, TExPool>
|
||||
{
|
||||
pub fn new(
|
||||
task_manager: TaskManager,
|
||||
client: Arc<Client<TBackend, TExec, TBl, TRtApi>>,
|
||||
network: Arc<sc_network::NetworkService<TBl, <TBl as BlockT>::Hash>>,
|
||||
transaction_pool: Arc<TExPool>,
|
||||
) -> Self {
|
||||
Self {
|
||||
client, transaction_pool, network,
|
||||
task_manager: Arc::new(Mutex::new(task_manager)),
|
||||
}
|
||||
Self { client, transaction_pool, network, task_manager: Arc::new(Mutex::new(task_manager)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<TBl: BlockT, TBackend, TExec, TRtApi, TExPool> Clone for
|
||||
TestNetComponents<TBl, TBackend, TExec, TRtApi, TExPool> {
|
||||
impl<TBl: BlockT, TBackend, TExec, TRtApi, TExPool> Clone
|
||||
for TestNetComponents<TBl, TBackend, TExec, TRtApi, TExPool>
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
task_manager: self.task_manager.clone(),
|
||||
@@ -115,8 +106,8 @@ TestNetComponents<TBl, TBackend, TExec, TRtApi, TExPool> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<TBl: BlockT, TBackend, TExec, TRtApi, TExPool> Future for
|
||||
TestNetComponents<TBl, TBackend, TExec, TRtApi, TExPool>
|
||||
impl<TBl: BlockT, TBackend, TExec, TRtApi, TExPool> Future
|
||||
for TestNetComponents<TBl, TBackend, TExec, TRtApi, TExPool>
|
||||
{
|
||||
type Item = ();
|
||||
type Error = sc_service::Error;
|
||||
@@ -126,14 +117,14 @@ impl<TBl: BlockT, TBackend, TExec, TRtApi, TExPool> Future for
|
||||
}
|
||||
}
|
||||
|
||||
impl<TBl, TBackend, TExec, TRtApi, TExPool> TestNetNode for
|
||||
TestNetComponents<TBl, TBackend, TExec, TRtApi, TExPool>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TBackend: sc_client_api::Backend<TBl> + Send + Sync + 'static,
|
||||
TExec: CallExecutor<TBl> + Send + Sync + 'static,
|
||||
TRtApi: Send + Sync + 'static,
|
||||
TExPool: TransactionPool<Block = TBl> + Send + Sync + 'static,
|
||||
impl<TBl, TBackend, TExec, TRtApi, TExPool> TestNetNode
|
||||
for TestNetComponents<TBl, TBackend, TExec, TRtApi, TExPool>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TBackend: sc_client_api::Backend<TBl> + Send + Sync + 'static,
|
||||
TExec: CallExecutor<TBl> + Send + Sync + 'static,
|
||||
TRtApi: Send + Sync + 'static,
|
||||
TExPool: TransactionPool<Block = TBl> + Send + Sync + 'static,
|
||||
{
|
||||
type Block = TBl;
|
||||
type Backend = TBackend;
|
||||
@@ -147,7 +138,9 @@ TestNetComponents<TBl, TBackend, TExec, TRtApi, TExPool>
|
||||
fn transaction_pool(&self) -> Arc<Self::TransactionPool> {
|
||||
self.transaction_pool.clone()
|
||||
}
|
||||
fn network(&self) -> Arc<sc_network::NetworkService<Self::Block, <Self::Block as BlockT>::Hash>> {
|
||||
fn network(
|
||||
&self,
|
||||
) -> Arc<sc_network::NetworkService<Self::Block, <Self::Block as BlockT>::Hash>> {
|
||||
self.network.clone()
|
||||
}
|
||||
fn spawn_handle(&self) -> SpawnTaskHandle {
|
||||
@@ -156,33 +149,32 @@ TestNetComponents<TBl, TBackend, TExec, TRtApi, TExPool>
|
||||
}
|
||||
|
||||
impl<G, E, F, L, U> TestNet<G, E, F, L, U>
|
||||
where F: Clone + Send + 'static, L: Clone + Send +'static, U: Clone + Send + 'static
|
||||
where
|
||||
F: Clone + Send + 'static,
|
||||
L: Clone + Send + 'static,
|
||||
U: Clone + Send + 'static,
|
||||
{
|
||||
pub fn run_until_all_full<FP, LP>(
|
||||
&mut self,
|
||||
full_predicate: FP,
|
||||
light_predicate: LP,
|
||||
)
|
||||
where
|
||||
FP: Send + Fn(usize, &F) -> bool + 'static,
|
||||
LP: Send + Fn(usize, &L) -> bool + 'static,
|
||||
pub fn run_until_all_full<FP, LP>(&mut self, full_predicate: FP, light_predicate: LP)
|
||||
where
|
||||
FP: Send + Fn(usize, &F) -> bool + 'static,
|
||||
LP: Send + Fn(usize, &L) -> bool + 'static,
|
||||
{
|
||||
let full_nodes = self.full_nodes.clone();
|
||||
let light_nodes = self.light_nodes.clone();
|
||||
let interval = Interval::new_interval(Duration::from_millis(100))
|
||||
.map_err(|_| ())
|
||||
.for_each(move |_| {
|
||||
let full_ready = full_nodes.iter().all(|&(ref id, ref service, _, _)|
|
||||
full_predicate(*id, service)
|
||||
);
|
||||
let full_ready = full_nodes
|
||||
.iter()
|
||||
.all(|&(ref id, ref service, _, _)| full_predicate(*id, service));
|
||||
|
||||
if !full_ready {
|
||||
return Ok(());
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let light_ready = light_nodes.iter().all(|&(ref id, ref service, _)|
|
||||
light_predicate(*id, service)
|
||||
);
|
||||
let light_ready = light_nodes
|
||||
.iter()
|
||||
.all(|&(ref id, ref service, _)| light_predicate(*id, service));
|
||||
|
||||
if !light_ready {
|
||||
Ok(())
|
||||
@@ -200,7 +192,10 @@ where F: Clone + Send + 'static, L: Clone + Send +'static, U: Clone + Send + 'st
|
||||
}
|
||||
}
|
||||
|
||||
fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'static + Send + Sync> (
|
||||
fn node_config<
|
||||
G: RuntimeGenesis + 'static,
|
||||
E: ChainSpecExtension + Clone + 'static + Send + Sync,
|
||||
>(
|
||||
index: usize,
|
||||
spec: &GenericChainSpec<G, E>,
|
||||
role: Role,
|
||||
@@ -208,8 +203,7 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
|
||||
key_seed: Option<String>,
|
||||
base_port: u16,
|
||||
root: &TempDir,
|
||||
) -> Configuration
|
||||
{
|
||||
) -> Configuration {
|
||||
let root = root.path().join(format!("node-{}", index));
|
||||
|
||||
let mut network_config = NetworkConfiguration::new(
|
||||
@@ -224,7 +218,7 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
|
||||
network_config.listen_addresses.push(
|
||||
iter::once(multiaddr::Protocol::Ip4(Ipv4Addr::new(127, 0, 0, 1)))
|
||||
.chain(iter::once(multiaddr::Protocol::Tcp(base_port + index as u16)))
|
||||
.collect()
|
||||
.collect(),
|
||||
);
|
||||
|
||||
network_config.transport = TransportConfig::Normal {
|
||||
@@ -241,14 +235,8 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
|
||||
transaction_pool: Default::default(),
|
||||
network: network_config,
|
||||
keystore_remote: Default::default(),
|
||||
keystore: KeystoreConfig::Path {
|
||||
path: root.join("key"),
|
||||
password: None
|
||||
},
|
||||
database: DatabaseConfig::RocksDb {
|
||||
path: root.join("db"),
|
||||
cache_size: 128,
|
||||
},
|
||||
keystore: KeystoreConfig::Path { path: root.join("key"), password: None },
|
||||
database: DatabaseConfig::RocksDb { path: root.join("db"), cache_size: 128 },
|
||||
state_cache_size: 16777216,
|
||||
state_cache_child_ratio: None,
|
||||
state_pruning: Default::default(),
|
||||
@@ -284,7 +272,8 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
|
||||
}
|
||||
}
|
||||
|
||||
impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
|
||||
impl<G, E, F, L, U> TestNet<G, E, F, L, U>
|
||||
where
|
||||
F: TestNetNode,
|
||||
L: TestNetNode,
|
||||
E: ChainSpecExtension + Clone + 'static + Send + Sync,
|
||||
@@ -295,11 +284,8 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
|
||||
spec: GenericChainSpec<G, E>,
|
||||
full: impl Iterator<Item = impl FnOnce(Configuration) -> Result<(F, U), Error>>,
|
||||
light: impl Iterator<Item = impl FnOnce(Configuration) -> Result<L, Error>>,
|
||||
authorities: impl Iterator<Item = (
|
||||
String,
|
||||
impl FnOnce(Configuration) -> Result<(F, U), Error>
|
||||
)>,
|
||||
base_port: u16
|
||||
authorities: impl Iterator<Item = (String, impl FnOnce(Configuration) -> Result<(F, U), Error>)>,
|
||||
base_port: u16,
|
||||
) -> TestNet<G, E, F, L, U> {
|
||||
sp_tracing::try_init_simple();
|
||||
fdlimit::raise_fd_limit();
|
||||
@@ -322,7 +308,7 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
|
||||
temp: &TempDir,
|
||||
full: impl Iterator<Item = impl FnOnce(Configuration) -> Result<(F, U), Error>>,
|
||||
light: impl Iterator<Item = impl FnOnce(Configuration) -> Result<L, Error>>,
|
||||
authorities: impl Iterator<Item = (String, impl FnOnce(Configuration) -> Result<(F, U), Error>)>
|
||||
authorities: impl Iterator<Item = (String, impl FnOnce(Configuration) -> Result<(F, U), Error>)>,
|
||||
) {
|
||||
let executor = self.runtime.executor();
|
||||
let task_executor: TaskExecutor = {
|
||||
@@ -330,7 +316,8 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
|
||||
(move |fut: Pin<Box<dyn futures::Future<Output = ()> + Send>>, _| {
|
||||
executor.spawn(fut.unit_error().compat());
|
||||
async {}
|
||||
}).into()
|
||||
})
|
||||
.into()
|
||||
};
|
||||
|
||||
for (key, authority) in authorities {
|
||||
@@ -344,10 +331,12 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
|
||||
&temp,
|
||||
);
|
||||
let addr = node_config.network.listen_addresses.iter().next().unwrap().clone();
|
||||
let (service, user_data) = authority(node_config).expect("Error creating test node service");
|
||||
let (service, user_data) =
|
||||
authority(node_config).expect("Error creating test node service");
|
||||
|
||||
executor.spawn(service.clone().map_err(|_| ()));
|
||||
let addr = addr.with(multiaddr::Protocol::P2p(service.network().local_peer_id().clone().into()));
|
||||
let addr = addr
|
||||
.with(multiaddr::Protocol::P2p(service.network().local_peer_id().clone().into()));
|
||||
self.authority_nodes.push((self.nodes, service, user_data, addr));
|
||||
self.nodes += 1;
|
||||
}
|
||||
@@ -366,7 +355,8 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
|
||||
let (service, user_data) = full(node_config).expect("Error creating test node service");
|
||||
|
||||
executor.spawn(service.clone().map_err(|_| ()));
|
||||
let addr = addr.with(multiaddr::Protocol::P2p(service.network().local_peer_id().clone().into()));
|
||||
let addr = addr
|
||||
.with(multiaddr::Protocol::P2p(service.network().local_peer_id().clone().into()));
|
||||
self.full_nodes.push((self.nodes, service, user_data, addr));
|
||||
self.nodes += 1;
|
||||
}
|
||||
@@ -385,7 +375,8 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
|
||||
let service = light(node_config).expect("Error creating test node service");
|
||||
|
||||
executor.spawn(service.clone().map_err(|_| ()));
|
||||
let addr = addr.with(multiaddr::Protocol::P2p(service.network().local_peer_id().clone().into()));
|
||||
let addr = addr
|
||||
.with(multiaddr::Protocol::P2p(service.network().local_peer_id().clone().into()));
|
||||
self.light_nodes.push((self.nodes, service, addr));
|
||||
self.nodes += 1;
|
||||
}
|
||||
@@ -393,7 +384,10 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
|
||||
}
|
||||
|
||||
fn tempdir_with_prefix(prefix: &str) -> TempDir {
|
||||
tempfile::Builder::new().prefix(prefix).tempdir().expect("Error creating test dir")
|
||||
tempfile::Builder::new()
|
||||
.prefix(prefix)
|
||||
.tempdir()
|
||||
.expect("Error creating test dir")
|
||||
}
|
||||
|
||||
pub fn connectivity<G, E, Fb, F, Lb, L>(
|
||||
@@ -420,8 +414,8 @@ pub fn connectivity<G, E, Fb, F, Lb, L>(
|
||||
let mut network = TestNet::new(
|
||||
&temp,
|
||||
spec.clone(),
|
||||
(0..NUM_FULL_NODES).map(|_| { |cfg| full_builder(cfg).map(|s| (s, ())) }),
|
||||
(0..NUM_LIGHT_NODES).map(|_| { |cfg| light_builder(cfg) }),
|
||||
(0..NUM_FULL_NODES).map(|_| |cfg| full_builder(cfg).map(|s| (s, ()))),
|
||||
(0..NUM_LIGHT_NODES).map(|_| |cfg| light_builder(cfg)),
|
||||
// Note: this iterator is empty but we can't just use `iter::empty()`, otherwise
|
||||
// the type of the closure cannot be inferred.
|
||||
(0..0).map(|_| (String::new(), { |cfg| full_builder(cfg).map(|s| (s, ())) })),
|
||||
@@ -430,11 +424,15 @@ pub fn connectivity<G, E, Fb, F, Lb, L>(
|
||||
info!("Checking star topology");
|
||||
let first_address = network.full_nodes[0].3.clone();
|
||||
for (_, service, _, _) in network.full_nodes.iter().skip(1) {
|
||||
service.network().add_reserved_peer(first_address.to_string())
|
||||
service
|
||||
.network()
|
||||
.add_reserved_peer(first_address.to_string())
|
||||
.expect("Error adding reserved peer");
|
||||
}
|
||||
for (_, service, _) in network.light_nodes.iter() {
|
||||
service.network().add_reserved_peer(first_address.to_string())
|
||||
service
|
||||
.network()
|
||||
.add_reserved_peer(first_address.to_string())
|
||||
.expect("Error adding reserved peer");
|
||||
}
|
||||
|
||||
@@ -464,8 +462,8 @@ pub fn connectivity<G, E, Fb, F, Lb, L>(
|
||||
let mut network = TestNet::new(
|
||||
&temp,
|
||||
spec,
|
||||
(0..NUM_FULL_NODES).map(|_| { |cfg| full_builder(cfg).map(|s| (s, ())) }),
|
||||
(0..NUM_LIGHT_NODES).map(|_| { |cfg| light_builder(cfg) }),
|
||||
(0..NUM_FULL_NODES).map(|_| |cfg| full_builder(cfg).map(|s| (s, ()))),
|
||||
(0..NUM_LIGHT_NODES).map(|_| |cfg| light_builder(cfg)),
|
||||
// Note: this iterator is empty but we can't just use `iter::empty()`, otherwise
|
||||
// the type of the closure cannot be inferred.
|
||||
(0..0).map(|_| (String::new(), { |cfg| full_builder(cfg).map(|s| (s, ())) })),
|
||||
@@ -477,14 +475,18 @@ pub fn connectivity<G, E, Fb, F, Lb, L>(
|
||||
for i in 0..max_nodes {
|
||||
if i != 0 {
|
||||
if let Some((_, service, _, node_id)) = network.full_nodes.get(i) {
|
||||
service.network().add_reserved_peer(address.to_string())
|
||||
service
|
||||
.network()
|
||||
.add_reserved_peer(address.to_string())
|
||||
.expect("Error adding reserved peer");
|
||||
address = node_id.clone();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((_, service, node_id)) = network.light_nodes.get(i) {
|
||||
service.network().add_reserved_peer(address.to_string())
|
||||
service
|
||||
.network()
|
||||
.add_reserved_peer(address.to_string())
|
||||
.expect("Error adding reserved peer");
|
||||
address = node_id.clone();
|
||||
}
|
||||
@@ -512,7 +514,7 @@ pub fn sync<G, E, Fb, F, Lb, L, B, ExF, U>(
|
||||
full_builder: Fb,
|
||||
light_builder: Lb,
|
||||
mut make_block_and_import: B,
|
||||
mut extrinsic_factory: ExF
|
||||
mut extrinsic_factory: ExF,
|
||||
) where
|
||||
Fb: Fn(Configuration) -> Result<(F, U), Error>,
|
||||
F: TestNetNode,
|
||||
@@ -532,8 +534,8 @@ pub fn sync<G, E, Fb, F, Lb, L, B, ExF, U>(
|
||||
let mut network = TestNet::new(
|
||||
&temp,
|
||||
spec,
|
||||
(0..NUM_FULL_NODES).map(|_| { |cfg| full_builder(cfg) }),
|
||||
(0..NUM_LIGHT_NODES).map(|_| { |cfg| light_builder(cfg) }),
|
||||
(0..NUM_FULL_NODES).map(|_| |cfg| full_builder(cfg)),
|
||||
(0..NUM_LIGHT_NODES).map(|_| |cfg| light_builder(cfg)),
|
||||
// Note: this iterator is empty but we can't just use `iter::empty()`, otherwise
|
||||
// the type of the closure cannot be inferred.
|
||||
(0..0).map(|_| (String::new(), { |cfg| full_builder(cfg) })),
|
||||
@@ -542,7 +544,7 @@ pub fn sync<G, E, Fb, F, Lb, L, B, ExF, U>(
|
||||
info!("Checking block sync");
|
||||
let first_address = {
|
||||
let &mut (_, ref first_service, ref mut first_user_data, _) = &mut network.full_nodes[0];
|
||||
for i in 0 .. NUM_BLOCKS {
|
||||
for i in 0..NUM_BLOCKS {
|
||||
if i % 128 == 0 {
|
||||
info!("Generating #{}", i + 1);
|
||||
}
|
||||
@@ -550,24 +552,29 @@ pub fn sync<G, E, Fb, F, Lb, L, B, ExF, U>(
|
||||
make_block_and_import(&first_service, first_user_data);
|
||||
}
|
||||
let info = network.full_nodes[0].1.client().info();
|
||||
network.full_nodes[0].1.network().new_best_block_imported(info.best_hash, info.best_number);
|
||||
network.full_nodes[0]
|
||||
.1
|
||||
.network()
|
||||
.new_best_block_imported(info.best_hash, info.best_number);
|
||||
network.full_nodes[0].3.clone()
|
||||
};
|
||||
|
||||
info!("Running sync");
|
||||
for (_, service, _, _) in network.full_nodes.iter().skip(1) {
|
||||
service.network().add_reserved_peer(first_address.to_string())
|
||||
service
|
||||
.network()
|
||||
.add_reserved_peer(first_address.to_string())
|
||||
.expect("Error adding reserved peer");
|
||||
}
|
||||
for (_, service, _) in network.light_nodes.iter() {
|
||||
service.network().add_reserved_peer(first_address.to_string())
|
||||
service
|
||||
.network()
|
||||
.add_reserved_peer(first_address.to_string())
|
||||
.expect("Error adding reserved peer");
|
||||
}
|
||||
network.run_until_all_full(
|
||||
|_index, service|
|
||||
service.client().info().best_number == (NUM_BLOCKS as u32).into(),
|
||||
|_index, service|
|
||||
service.client().info().best_number == (NUM_BLOCKS as u32).into(),
|
||||
|_index, service| service.client().info().best_number == (NUM_BLOCKS as u32).into(),
|
||||
|_index, service| service.client().info().best_number == (NUM_BLOCKS as u32).into(),
|
||||
);
|
||||
|
||||
info!("Checking extrinsic propagation");
|
||||
@@ -577,9 +584,12 @@ pub fn sync<G, E, Fb, F, Lb, L, B, ExF, U>(
|
||||
let extrinsic = extrinsic_factory(&first_service, first_user_data);
|
||||
let source = sc_transaction_pool_api::TransactionSource::External;
|
||||
|
||||
futures::executor::block_on(
|
||||
first_service.transaction_pool().submit_one(&best_block, source, extrinsic)
|
||||
).expect("failed to submit extrinsic");
|
||||
futures::executor::block_on(first_service.transaction_pool().submit_one(
|
||||
&best_block,
|
||||
source,
|
||||
extrinsic,
|
||||
))
|
||||
.expect("failed to submit extrinsic");
|
||||
|
||||
network.run_until_all_full(
|
||||
|_index, service| service.transaction_pool().ready().count() == 1,
|
||||
@@ -591,7 +601,7 @@ pub fn consensus<G, E, Fb, F, Lb, L>(
|
||||
spec: GenericChainSpec<G, E>,
|
||||
full_builder: Fb,
|
||||
light_builder: Lb,
|
||||
authorities: impl IntoIterator<Item = String>
|
||||
authorities: impl IntoIterator<Item = String>,
|
||||
) where
|
||||
Fb: Fn(Configuration) -> Result<F, Error>,
|
||||
F: TestNetNode,
|
||||
@@ -607,54 +617,64 @@ pub fn consensus<G, E, Fb, F, Lb, L>(
|
||||
let mut network = TestNet::new(
|
||||
&temp,
|
||||
spec,
|
||||
(0..NUM_FULL_NODES / 2).map(|_| { |cfg| full_builder(cfg).map(|s| (s, ())) }),
|
||||
(0..NUM_LIGHT_NODES / 2).map(|_| { |cfg| light_builder(cfg) }),
|
||||
authorities.into_iter().map(|key| (key, { |cfg| full_builder(cfg).map(|s| (s, ())) })),
|
||||
(0..NUM_FULL_NODES / 2).map(|_| |cfg| full_builder(cfg).map(|s| (s, ()))),
|
||||
(0..NUM_LIGHT_NODES / 2).map(|_| |cfg| light_builder(cfg)),
|
||||
authorities
|
||||
.into_iter()
|
||||
.map(|key| (key, { |cfg| full_builder(cfg).map(|s| (s, ())) })),
|
||||
30600,
|
||||
);
|
||||
|
||||
info!("Checking consensus");
|
||||
let first_address = network.authority_nodes[0].3.clone();
|
||||
for (_, service, _, _) in network.full_nodes.iter() {
|
||||
service.network().add_reserved_peer(first_address.to_string())
|
||||
service
|
||||
.network()
|
||||
.add_reserved_peer(first_address.to_string())
|
||||
.expect("Error adding reserved peer");
|
||||
}
|
||||
for (_, service, _) in network.light_nodes.iter() {
|
||||
service.network().add_reserved_peer(first_address.to_string())
|
||||
service
|
||||
.network()
|
||||
.add_reserved_peer(first_address.to_string())
|
||||
.expect("Error adding reserved peer");
|
||||
}
|
||||
for (_, service, _, _) in network.authority_nodes.iter().skip(1) {
|
||||
service.network().add_reserved_peer(first_address.to_string())
|
||||
service
|
||||
.network()
|
||||
.add_reserved_peer(first_address.to_string())
|
||||
.expect("Error adding reserved peer");
|
||||
}
|
||||
network.run_until_all_full(
|
||||
|_index, service|
|
||||
service.client().info().finalized_number >= (NUM_BLOCKS as u32 / 2).into(),
|
||||
|_index, service|
|
||||
service.client().info().best_number >= (NUM_BLOCKS as u32 / 2).into(),
|
||||
|_index, service| {
|
||||
service.client().info().finalized_number >= (NUM_BLOCKS as u32 / 2).into()
|
||||
},
|
||||
|_index, service| service.client().info().best_number >= (NUM_BLOCKS as u32 / 2).into(),
|
||||
);
|
||||
|
||||
info!("Adding more peers");
|
||||
network.insert_nodes(
|
||||
&temp,
|
||||
(0..NUM_FULL_NODES / 2).map(|_| { |cfg| full_builder(cfg).map(|s| (s, ())) }),
|
||||
(0..NUM_LIGHT_NODES / 2).map(|_| { |cfg| light_builder(cfg) }),
|
||||
(0..NUM_FULL_NODES / 2).map(|_| |cfg| full_builder(cfg).map(|s| (s, ()))),
|
||||
(0..NUM_LIGHT_NODES / 2).map(|_| |cfg| light_builder(cfg)),
|
||||
// Note: this iterator is empty but we can't just use `iter::empty()`, otherwise
|
||||
// the type of the closure cannot be inferred.
|
||||
(0..0).map(|_| (String::new(), { |cfg| full_builder(cfg).map(|s| (s, ())) })),
|
||||
);
|
||||
for (_, service, _, _) in network.full_nodes.iter() {
|
||||
service.network().add_reserved_peer(first_address.to_string())
|
||||
service
|
||||
.network()
|
||||
.add_reserved_peer(first_address.to_string())
|
||||
.expect("Error adding reserved peer");
|
||||
}
|
||||
for (_, service, _) in network.light_nodes.iter() {
|
||||
service.network().add_reserved_peer(first_address.to_string())
|
||||
service
|
||||
.network()
|
||||
.add_reserved_peer(first_address.to_string())
|
||||
.expect("Error adding reserved peer");
|
||||
}
|
||||
network.run_until_all_full(
|
||||
|_index, service|
|
||||
service.client().info().finalized_number >= (NUM_BLOCKS as u32).into(),
|
||||
|_index, service|
|
||||
service.client().info().best_number >= (NUM_BLOCKS as u32).into(),
|
||||
|_index, service| service.client().info().finalized_number >= (NUM_BLOCKS as u32).into(),
|
||||
|_index, service| service.client().info().best_number >= (NUM_BLOCKS as u32).into(),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user