mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 22:11:06 +00:00
Integrate litep2p into Polkadot SDK (#2944)
[litep2p](https://github.com/altonen/litep2p) is a libp2p-compatible P2P networking library. It supports all of the features of `rust-libp2p` that are currently being utilized by Polkadot SDK. Compared to `rust-libp2p`, `litep2p` has a quite different architecture which is why the new `litep2p` network backend is only able to use a little of the existing code in `sc-network`. The design has been mainly influenced by how we'd wish to structure our networking-related code in Polkadot SDK: independent higher-levels protocols directly communicating with the network over links that support bidirectional backpressure. A good example would be `NotificationHandle`/`RequestResponseHandle` abstractions which allow, e.g., `SyncingEngine` to directly communicate with peers to announce/request blocks. I've tried running `polkadot --network-backend litep2p` with a few different peer configurations and there is a noticeable reduction in networking CPU usage. For high load (`--out-peers 200`), networking CPU usage goes down from ~110% to ~30% (80 pp) and for normal load (`--out-peers 40`), the usage goes down from ~55% to ~18% (37 pp). These should not be taken as final numbers because: a) there are still some low-hanging optimization fruits, such as enabling [receive window auto-tuning](https://github.com/libp2p/rust-yamux/pull/176), integrating `Peerset` more closely with `litep2p` or improving memory usage of the WebSocket transport b) fixing bugs/instabilities that incorrectly cause `litep2p` to do less work will increase the networking CPU usage c) verification in a more diverse set of tests/conditions is needed Nevertheless, these numbers should give an early estimate for CPU usage of the new networking backend. This PR consists of three separate changes: * introduce a generic `PeerId` (wrapper around `Multihash`) so that we don't have use `NetworkService::PeerId` in every part of the code that uses a `PeerId` * introduce `NetworkBackend` trait, implement it for the libp2p network stack and make Polkadot SDK generic over `NetworkBackend` * implement `NetworkBackend` for litep2p The new library should be considered experimental which is why `rust-libp2p` will remain as the default option for the time being. This PR currently depends on the master branch of `litep2p` but I'll cut a new release for the library once all review comments have been addresses. --------- Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> Co-authored-by: Dmitry Markin <dmitry@markin.tech> Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Co-authored-by: Alexandru Vasile <alexandru.vasile@parity.io>
This commit is contained in:
@@ -43,10 +43,12 @@ use sc_executor::{
|
||||
use sc_keystore::LocalKeystore;
|
||||
use sc_network::{
|
||||
config::{FullNetworkConfiguration, SyncMode},
|
||||
peer_store::PeerStore,
|
||||
NetworkService, NetworkStateInfo, NetworkStatusProvider,
|
||||
service::{
|
||||
traits::{PeerStore, RequestResponseConfig},
|
||||
NotificationMetrics,
|
||||
},
|
||||
NetworkBackend, NetworkStateInfo,
|
||||
};
|
||||
use sc_network_bitswap::BitswapRequestHandler;
|
||||
use sc_network_common::role::Roles;
|
||||
use sc_network_light::light_client_requests::handler::LightClientRequestHandler;
|
||||
use sc_network_sync::{
|
||||
@@ -342,19 +344,6 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
/// Shared network instance implementing a set of mandatory traits.
|
||||
pub trait SpawnTaskNetwork<Block: BlockT>:
|
||||
NetworkStateInfo + NetworkStatusProvider + Send + Sync + 'static
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, Block> SpawnTaskNetwork<Block> for T
|
||||
where
|
||||
Block: BlockT,
|
||||
T: NetworkStateInfo + NetworkStatusProvider + Send + Sync + 'static,
|
||||
{
|
||||
}
|
||||
|
||||
/// Parameters to pass into `build`.
|
||||
pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> {
|
||||
/// The service configuration.
|
||||
@@ -373,7 +362,7 @@ pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> {
|
||||
pub rpc_builder:
|
||||
Box<dyn Fn(DenyUnsafe, SubscriptionTaskExecutor) -> Result<RpcModule<TRpc>, Error>>,
|
||||
/// A shared network instance.
|
||||
pub network: Arc<dyn SpawnTaskNetwork<TBl>>,
|
||||
pub network: Arc<dyn sc_network::service::traits::NetworkService>,
|
||||
/// A Sender for RPC requests.
|
||||
pub system_rpc_tx: TracingUnboundedSender<sc_rpc::system::Request<TBl>>,
|
||||
/// Controller for transactions handlers
|
||||
@@ -736,11 +725,18 @@ where
|
||||
}
|
||||
|
||||
/// Parameters to pass into `build_network`.
|
||||
pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> {
|
||||
pub struct BuildNetworkParams<
|
||||
'a,
|
||||
TBl: BlockT,
|
||||
TNet: NetworkBackend<TBl, <TBl as BlockT>::Hash>,
|
||||
TExPool,
|
||||
TImpQu,
|
||||
TCl,
|
||||
> {
|
||||
/// The service configuration.
|
||||
pub config: &'a Configuration,
|
||||
/// Full network configuration.
|
||||
pub net_config: FullNetworkConfiguration,
|
||||
pub net_config: FullNetworkConfiguration<TBl, <TBl as BlockT>::Hash, TNet>,
|
||||
/// A shared client returned by `new_full_parts`.
|
||||
pub client: Arc<TCl>,
|
||||
/// A shared transaction pool.
|
||||
@@ -756,15 +752,17 @@ pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> {
|
||||
pub warp_sync_params: Option<WarpSyncParams<TBl>>,
|
||||
/// User specified block relay params. If not specified, the default
|
||||
/// block request handler will be used.
|
||||
pub block_relay: Option<BlockRelayParams<TBl>>,
|
||||
pub block_relay: Option<BlockRelayParams<TBl, TNet>>,
|
||||
/// Metrics.
|
||||
pub metrics: NotificationMetrics,
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
pub fn build_network<TBl, TNet, TExPool, TImpQu, TCl>(
|
||||
params: BuildNetworkParams<TBl, TNet, TExPool, TImpQu, TCl>,
|
||||
) -> Result<
|
||||
(
|
||||
Arc<NetworkService<TBl, <TBl as BlockT>::Hash>>,
|
||||
Arc<dyn sc_network::service::traits::NetworkService>,
|
||||
TracingUnboundedSender<sc_rpc::system::Request<TBl>>,
|
||||
sc_network_transactions::TransactionsHandlerController<<TBl as BlockT>::Hash>,
|
||||
NetworkStarter,
|
||||
@@ -785,6 +783,7 @@ where
|
||||
+ 'static,
|
||||
TExPool: TransactionPool<Block = TBl, Hash = <TBl as BlockT>::Hash> + 'static,
|
||||
TImpQu: ImportQueue<TBl> + 'static,
|
||||
TNet: NetworkBackend<TBl, <TBl as BlockT>::Hash>,
|
||||
{
|
||||
let BuildNetworkParams {
|
||||
config,
|
||||
@@ -796,6 +795,7 @@ where
|
||||
block_announce_validator_builder,
|
||||
warp_sync_params,
|
||||
block_relay,
|
||||
metrics,
|
||||
} = params;
|
||||
|
||||
if warp_sync_params.is_none() && config.network.sync_mode.is_warp() {
|
||||
@@ -830,7 +830,7 @@ where
|
||||
None => {
|
||||
// Custom protocol was not specified, use the default block handler.
|
||||
// Allow both outgoing and incoming requests.
|
||||
let params = BlockRequestHandler::new(
|
||||
let params = BlockRequestHandler::new::<TNet>(
|
||||
chain_sync_network_handle.clone(),
|
||||
&protocol_id,
|
||||
config.chain_spec.fork_id(),
|
||||
@@ -849,13 +849,13 @@ where
|
||||
let num_peer_hint = net_config.network_config.default_peers_set_num_full as usize +
|
||||
net_config.network_config.default_peers_set.reserved_nodes.len();
|
||||
// Allow both outgoing and incoming requests.
|
||||
let (handler, protocol_config) = StateRequestHandler::new(
|
||||
let (handler, protocol_config) = StateRequestHandler::new::<TNet>(
|
||||
&protocol_id,
|
||||
config.chain_spec.fork_id(),
|
||||
client.clone(),
|
||||
num_peer_hint,
|
||||
);
|
||||
let config_name = protocol_config.name.clone();
|
||||
let config_name = protocol_config.protocol_name().clone();
|
||||
|
||||
spawn_handle.spawn("state-request-handler", Some("networking"), handler.run());
|
||||
(protocol_config, config_name)
|
||||
@@ -864,13 +864,13 @@ where
|
||||
let (warp_sync_protocol_config, warp_request_protocol_name) = match warp_sync_params.as_ref() {
|
||||
Some(WarpSyncParams::WithProvider(warp_with_provider)) => {
|
||||
// Allow both outgoing and incoming requests.
|
||||
let (handler, protocol_config) = WarpSyncRequestHandler::new(
|
||||
let (handler, protocol_config) = WarpSyncRequestHandler::new::<_, TNet>(
|
||||
protocol_id.clone(),
|
||||
genesis_hash,
|
||||
config.chain_spec.fork_id(),
|
||||
warp_with_provider.clone(),
|
||||
);
|
||||
let config_name = protocol_config.name.clone();
|
||||
let config_name = protocol_config.protocol_name().clone();
|
||||
|
||||
spawn_handle.spawn("warp-sync-request-handler", Some("networking"), handler.run());
|
||||
(Some(protocol_config), Some(config_name))
|
||||
@@ -880,7 +880,7 @@ where
|
||||
|
||||
let light_client_request_protocol_config = {
|
||||
// Allow both outgoing and incoming requests.
|
||||
let (handler, protocol_config) = LightClientRequestHandler::new(
|
||||
let (handler, protocol_config) = LightClientRequestHandler::new::<TNet>(
|
||||
&protocol_id,
|
||||
config.chain_spec.fork_id(),
|
||||
client.clone(),
|
||||
@@ -898,30 +898,27 @@ where
|
||||
net_config.add_request_response_protocol(config);
|
||||
}
|
||||
|
||||
if config.network.ipfs_server {
|
||||
let (handler, protocol_config) = BitswapRequestHandler::new(client.clone());
|
||||
spawn_handle.spawn("bitswap-request-handler", Some("networking"), handler.run());
|
||||
net_config.add_request_response_protocol(protocol_config);
|
||||
}
|
||||
let bitswap_config = config.network.ipfs_server.then(|| {
|
||||
let (handler, config) = TNet::bitswap_server(client.clone());
|
||||
spawn_handle.spawn("bitswap-request-handler", Some("networking"), handler);
|
||||
|
||||
config
|
||||
});
|
||||
|
||||
// create transactions protocol and add it to the list of supported protocols of
|
||||
let peer_store_handle = net_config.peer_store_handle();
|
||||
let (transactions_handler_proto, transactions_config) =
|
||||
sc_network_transactions::TransactionsHandlerPrototype::new(
|
||||
sc_network_transactions::TransactionsHandlerPrototype::new::<_, TBl, TNet>(
|
||||
protocol_id.clone(),
|
||||
genesis_hash,
|
||||
config.chain_spec.fork_id(),
|
||||
metrics.clone(),
|
||||
Arc::clone(&peer_store_handle),
|
||||
);
|
||||
net_config.add_notification_protocol(transactions_config);
|
||||
|
||||
// Create `PeerStore` and initialize it with bootnode peer ids.
|
||||
let peer_store = PeerStore::new(
|
||||
net_config
|
||||
.network_config
|
||||
.boot_nodes
|
||||
.iter()
|
||||
.map(|bootnode| bootnode.peer_id)
|
||||
.collect(),
|
||||
);
|
||||
// Start task for `PeerStore`
|
||||
let peer_store = net_config.take_peer_store();
|
||||
let peer_store_handle = peer_store.handle();
|
||||
spawn_handle.spawn("peer-store", Some("networking"), peer_store.run());
|
||||
|
||||
@@ -929,6 +926,7 @@ where
|
||||
Roles::from(&config.role),
|
||||
client.clone(),
|
||||
config.prometheus_config.as_ref().map(|config| config.registry.clone()).as_ref(),
|
||||
metrics.clone(),
|
||||
&net_config,
|
||||
protocol_id.clone(),
|
||||
&config.chain_spec.fork_id().map(ToOwned::to_owned),
|
||||
@@ -939,13 +937,13 @@ where
|
||||
block_downloader,
|
||||
state_request_protocol_name,
|
||||
warp_request_protocol_name,
|
||||
peer_store_handle.clone(),
|
||||
Arc::clone(&peer_store_handle),
|
||||
)?;
|
||||
let sync_service_import_queue = sync_service.clone();
|
||||
let sync_service = Arc::new(sync_service);
|
||||
|
||||
let genesis_hash = client.hash(Zero::zero()).ok().flatten().expect("Genesis block exists; qed");
|
||||
let network_params = sc_network::config::Params::<TBl> {
|
||||
let network_params = sc_network::config::Params::<TBl, <TBl as BlockT>::Hash, TNet> {
|
||||
role: config.role.clone(),
|
||||
executor: {
|
||||
let spawn_handle = Clone::clone(&spawn_handle);
|
||||
@@ -954,17 +952,18 @@ where
|
||||
})
|
||||
},
|
||||
network_config: net_config,
|
||||
peer_store: peer_store_handle,
|
||||
genesis_hash,
|
||||
protocol_id: protocol_id.clone(),
|
||||
fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned),
|
||||
metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()),
|
||||
block_announce_config,
|
||||
bitswap_config,
|
||||
notification_metrics: metrics,
|
||||
};
|
||||
|
||||
let has_bootnodes = !network_params.network_config.network_config.boot_nodes.is_empty();
|
||||
let network_mut = sc_network::NetworkWorker::new(network_params)?;
|
||||
let network = network_mut.service().clone();
|
||||
let network_mut = TNet::new(network_params)?;
|
||||
let network = network_mut.network_service().clone();
|
||||
|
||||
let (tx_handler, tx_handler_controller) = transactions_handler_proto.build(
|
||||
network.clone(),
|
||||
@@ -972,12 +971,16 @@ where
|
||||
Arc::new(TransactionPoolAdapter { pool: transaction_pool, client: client.clone() }),
|
||||
config.prometheus_config.as_ref().map(|config| &config.registry),
|
||||
)?;
|
||||
spawn_handle.spawn("network-transactions-handler", Some("networking"), tx_handler.run());
|
||||
spawn_handle.spawn_blocking(
|
||||
"network-transactions-handler",
|
||||
Some("networking"),
|
||||
tx_handler.run(),
|
||||
);
|
||||
|
||||
spawn_handle.spawn_blocking(
|
||||
"chain-sync-network-service-provider",
|
||||
Some("networking"),
|
||||
chain_sync_network_provider.run(network.clone()),
|
||||
chain_sync_network_provider.run(Arc::new(network.clone())),
|
||||
);
|
||||
spawn_handle.spawn("import-queue", None, import_queue.run(Box::new(sync_service_import_queue)));
|
||||
spawn_handle.spawn_blocking("syncing", None, engine.run());
|
||||
@@ -986,9 +989,9 @@ where
|
||||
spawn_handle.spawn(
|
||||
"system-rpc-handler",
|
||||
Some("networking"),
|
||||
build_system_rpc_future(
|
||||
build_system_rpc_future::<_, _, <TBl as BlockT>::Hash>(
|
||||
config.role.clone(),
|
||||
network_mut.service().clone(),
|
||||
network_mut.network_service(),
|
||||
sync_service.clone(),
|
||||
client.clone(),
|
||||
system_rpc_rx,
|
||||
@@ -996,18 +999,22 @@ where
|
||||
),
|
||||
);
|
||||
|
||||
let future =
|
||||
build_network_future(network_mut, client, sync_service.clone(), config.announce_block);
|
||||
let future = build_network_future::<_, _, <TBl as BlockT>::Hash, _>(
|
||||
network_mut,
|
||||
client,
|
||||
sync_service.clone(),
|
||||
config.announce_block,
|
||||
);
|
||||
|
||||
// TODO: Normally, one is supposed to pass a list of notifications protocols supported by the
|
||||
// node through the `NetworkConfiguration` struct. But because this function doesn't know in
|
||||
// advance which components, such as GrandPa or Polkadot, will be plugged on top of the
|
||||
// service, it is unfortunately not possible to do so without some deep refactoring. To bypass
|
||||
// this problem, the `NetworkService` provides a `register_notifications_protocol` method that
|
||||
// can be called even after the network has been initialized. However, we want to avoid the
|
||||
// situation where `register_notifications_protocol` is called *after* the network actually
|
||||
// connects to other peers. For this reason, we delay the process of the network future until
|
||||
// the user calls `NetworkStarter::start_network`.
|
||||
// service, it is unfortunately not possible to do so without some deep refactoring. To
|
||||
// bypass this problem, the `NetworkService` provides a `register_notifications_protocol`
|
||||
// method that can be called even after the network has been initialized. However, we want to
|
||||
// avoid the situation where `register_notifications_protocol` is called *after* the network
|
||||
// actually connects to other peers. For this reason, we delay the process of the network
|
||||
// future until the user calls `NetworkStarter::start_network`.
|
||||
//
|
||||
// This entire hack should eventually be removed in favour of passing the list of protocols
|
||||
// through the configuration.
|
||||
|
||||
@@ -42,9 +42,11 @@ use jsonrpsee::RpcModule;
|
||||
use log::{debug, error, warn};
|
||||
use sc_client_api::{blockchain::HeaderBackend, BlockBackend, BlockchainEvents, ProofProvider};
|
||||
use sc_network::{
|
||||
config::MultiaddrWithPeerId, NetworkBlock, NetworkPeers, NetworkStateInfo, PeerId,
|
||||
config::MultiaddrWithPeerId, service::traits::NetworkService, NetworkBackend, NetworkBlock,
|
||||
NetworkPeers, NetworkStateInfo,
|
||||
};
|
||||
use sc_network_sync::SyncingService;
|
||||
use sc_network_types::PeerId;
|
||||
use sc_utils::mpsc::TracingUnboundedReceiver;
|
||||
use sp_blockchain::HeaderMetadata;
|
||||
use sp_consensus::SyncOracle;
|
||||
@@ -157,8 +159,9 @@ async fn build_network_future<
|
||||
+ Sync
|
||||
+ 'static,
|
||||
H: sc_network_common::ExHashT,
|
||||
N: NetworkBackend<B, <B as BlockT>::Hash>,
|
||||
>(
|
||||
network: sc_network::NetworkWorker<B, H>,
|
||||
network: N,
|
||||
client: Arc<C>,
|
||||
sync_service: Arc<SyncingService<B>>,
|
||||
announce_imported_blocks: bool,
|
||||
@@ -225,7 +228,7 @@ pub async fn build_system_rpc_future<
|
||||
H: sc_network_common::ExHashT,
|
||||
>(
|
||||
role: Role,
|
||||
network_service: Arc<sc_network::NetworkService<B, H>>,
|
||||
network_service: Arc<dyn NetworkService>,
|
||||
sync_service: Arc<SyncingService<B>>,
|
||||
client: Arc<C>,
|
||||
mut rpc_rx: TracingUnboundedReceiver<sc_rpc::system::Request<B>>,
|
||||
@@ -310,14 +313,12 @@ pub async fn build_system_rpc_future<
|
||||
};
|
||||
},
|
||||
sc_rpc::system::Request::NetworkReservedPeers(sender) => {
|
||||
let reserved_peers = network_service.reserved_peers().await;
|
||||
if let Ok(reserved_peers) = reserved_peers {
|
||||
let reserved_peers =
|
||||
reserved_peers.iter().map(|peer_id| peer_id.to_base58()).collect();
|
||||
let _ = sender.send(reserved_peers);
|
||||
} else {
|
||||
break
|
||||
}
|
||||
let Ok(reserved_peers) = network_service.reserved_peers().await else {
|
||||
break;
|
||||
};
|
||||
|
||||
let _ =
|
||||
sender.send(reserved_peers.iter().map(|peer_id| peer_id.to_base58()).collect());
|
||||
},
|
||||
sc_rpc::system::Request::NodeRoles(sender) => {
|
||||
use sc_rpc::system::NodeRole;
|
||||
|
||||
Reference in New Issue
Block a user