feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
[package]
|
||||
description = "Integration tests for Bizinikiwi network protocol"
|
||||
name = "pezsc-network-test"
|
||||
version = "0.8.0"
|
||||
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
publish = false
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
async-channel = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
futures-timer = { workspace = true }
|
||||
libp2p = { workspace = true }
|
||||
log = { workspace = true, default-features = true }
|
||||
parking_lot = { workspace = true, default-features = true }
|
||||
rand = { workspace = true, default-features = true }
|
||||
pezsc-block-builder = { workspace = true, default-features = true }
|
||||
pezsc-client-api = { workspace = true, default-features = true }
|
||||
pezsc-consensus = { workspace = true, default-features = true }
|
||||
pezsc-network = { workspace = true, default-features = true }
|
||||
pezsc-network-common = { workspace = true, default-features = true }
|
||||
pezsc-network-light = { workspace = true, default-features = true }
|
||||
pezsc-network-sync = { workspace = true, default-features = true }
|
||||
pezsc-network-types = { workspace = true, default-features = true }
|
||||
pezsc-service = { workspace = true }
|
||||
pezsc-utils = { workspace = true, default-features = true }
|
||||
pezsp-blockchain = { workspace = true, default-features = true }
|
||||
pezsp-consensus = { workspace = true, default-features = true }
|
||||
pezsp-core = { workspace = true, default-features = true }
|
||||
pezsp-runtime = { workspace = true, default-features = true }
|
||||
pezsp-tracing = { workspace = true, default-features = true }
|
||||
bizinikiwi-test-runtime = { workspace = true }
|
||||
bizinikiwi-test-runtime-client = { workspace = true }
|
||||
tokio = { workspace = true, default-features = true }
|
||||
|
||||
[features]
|
||||
runtime-benchmarks = [
|
||||
"pezsc-block-builder/runtime-benchmarks",
|
||||
"pezsc-client-api/runtime-benchmarks",
|
||||
"pezsc-consensus/runtime-benchmarks",
|
||||
"pezsc-network-common/runtime-benchmarks",
|
||||
"pezsc-network-light/runtime-benchmarks",
|
||||
"pezsc-network-sync/runtime-benchmarks",
|
||||
"pezsc-network/runtime-benchmarks",
|
||||
"pezsc-service/runtime-benchmarks",
|
||||
"pezsp-blockchain/runtime-benchmarks",
|
||||
"pezsp-consensus/runtime-benchmarks",
|
||||
"pezsp-runtime/runtime-benchmarks",
|
||||
"bizinikiwi-test-runtime-client/runtime-benchmarks",
|
||||
"bizinikiwi-test-runtime/runtime-benchmarks",
|
||||
]
|
||||
@@ -0,0 +1,134 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! Testing block import logic.
|
||||
|
||||
use super::*;
|
||||
use futures::executor::block_on;
|
||||
use pezsc_consensus::{
|
||||
import_single_block, BasicQueue, BlockImportError, BlockImportStatus, ImportedAux,
|
||||
IncomingBlock,
|
||||
};
|
||||
use pezsp_consensus::BlockOrigin;
|
||||
use bizinikiwi_test_runtime_client::{
|
||||
self,
|
||||
prelude::*,
|
||||
runtime::{Block, Hash},
|
||||
};
|
||||
|
||||
fn prepare_good_block() -> (TestClient, Hash, u64, PeerId, IncomingBlock<Block>) {
|
||||
let client = bizinikiwi_test_runtime_client::new();
|
||||
let block = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(client.chain_info().best_hash)
|
||||
.with_parent_block_number(client.chain_info().best_number)
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::File, block)).unwrap();
|
||||
|
||||
let (hash, number) = (client.block_hash(1).unwrap().unwrap(), 1);
|
||||
let header = client.header(hash).unwrap();
|
||||
let justifications = client.justifications(hash).unwrap();
|
||||
let peer_id = PeerId::random();
|
||||
(
|
||||
client,
|
||||
hash,
|
||||
number,
|
||||
peer_id,
|
||||
IncomingBlock {
|
||||
hash,
|
||||
header,
|
||||
body: Some(Vec::new()),
|
||||
indexed_body: None,
|
||||
justifications,
|
||||
origin: Some(peer_id.into()),
|
||||
allow_missing_state: false,
|
||||
import_existing: false,
|
||||
state: None,
|
||||
skip_execution: false,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_single_good_block_works() {
|
||||
let (_, _hash, number, peer_id, block) = prepare_good_block();
|
||||
|
||||
let mut expected_aux = ImportedAux::default();
|
||||
expected_aux.is_new_best = true;
|
||||
|
||||
match block_on(import_single_block(
|
||||
&mut bizinikiwi_test_runtime_client::new(),
|
||||
BlockOrigin::File,
|
||||
block,
|
||||
&PassThroughVerifier::new(true),
|
||||
)) {
|
||||
Ok(BlockImportStatus::ImportedUnknown(ref num, ref aux, ref org))
|
||||
if *num == number && *aux == expected_aux && *org == Some(peer_id.into()) => {},
|
||||
r @ _ => panic!("{:?}", r),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_single_good_known_block_is_ignored() {
|
||||
let (mut client, _hash, number, _, block) = prepare_good_block();
|
||||
match block_on(import_single_block(
|
||||
&mut client,
|
||||
BlockOrigin::File,
|
||||
block,
|
||||
&PassThroughVerifier::new(true),
|
||||
)) {
|
||||
Ok(BlockImportStatus::ImportedKnown(ref n, _)) if *n == number => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_single_good_block_without_header_fails() {
|
||||
let (_, _, _, peer_id, mut block) = prepare_good_block();
|
||||
block.header = None;
|
||||
match block_on(import_single_block(
|
||||
&mut bizinikiwi_test_runtime_client::new(),
|
||||
BlockOrigin::File,
|
||||
block,
|
||||
&PassThroughVerifier::new(true),
|
||||
)) {
|
||||
Err(BlockImportError::IncompleteHeader(ref org)) if *org == Some(peer_id.into()) => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_import_queue_drops() {
|
||||
let executor = pezsp_core::testing::TaskExecutor::new();
|
||||
// Perform this test multiple times since it exhibits non-deterministic behavior.
|
||||
for _ in 0..100 {
|
||||
let verifier = PassThroughVerifier::new(true);
|
||||
|
||||
let queue = BasicQueue::new(
|
||||
verifier,
|
||||
Box::new(bizinikiwi_test_runtime_client::new()),
|
||||
None,
|
||||
&executor,
|
||||
None,
|
||||
);
|
||||
drop(queue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// 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::conformance::setup::{
|
||||
connect_backends, connect_notifications, create_network_backend, NetworkBackendClient,
|
||||
};
|
||||
|
||||
use pezsc_network::{
|
||||
request_responses::OutgoingResponse, service::traits::NotificationEvent, IfDisconnected,
|
||||
Litep2pNetworkBackend, NetworkWorker,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_connectivity() {
|
||||
// Libp2p dials litep2p.
|
||||
connect_backends(
|
||||
&create_network_backend::<NetworkWorker<_, _>>(),
|
||||
&create_network_backend::<Litep2pNetworkBackend>(),
|
||||
)
|
||||
.await;
|
||||
|
||||
// Litep2p dials libp2p.
|
||||
connect_backends(
|
||||
&create_network_backend::<Litep2pNetworkBackend>(),
|
||||
&create_network_backend::<NetworkWorker<_, _>>(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_request_response() {
|
||||
async fn inner_check_request_response(left: NetworkBackendClient, right: NetworkBackendClient) {
|
||||
connect_backends(&left, &right).await;
|
||||
|
||||
let rx = right.receiver.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(request) = rx.recv().await {
|
||||
request
|
||||
.pending_response
|
||||
.send(OutgoingResponse {
|
||||
result: Ok(request.payload),
|
||||
reputation_changes: vec![],
|
||||
sent_feedback: None,
|
||||
})
|
||||
.expect("Valid response; qed");
|
||||
}
|
||||
});
|
||||
|
||||
let channels = (0..32)
|
||||
.map(|i| {
|
||||
let (tx, rx) = futures::channel::oneshot::channel();
|
||||
left.network_service.start_request(
|
||||
right.network_service.local_peer_id().into(),
|
||||
"/request-response/1".into(),
|
||||
vec![1, 2, 3, i],
|
||||
None,
|
||||
tx,
|
||||
IfDisconnected::ImmediateError,
|
||||
);
|
||||
|
||||
(i, rx)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (id, channel) in channels {
|
||||
let response = channel
|
||||
.await
|
||||
.expect("Channel should not be closed")
|
||||
.expect(format!("Channel {} should have a response", id).as_str());
|
||||
assert_eq!(response.0, vec![1, 2, 3, id]);
|
||||
}
|
||||
}
|
||||
|
||||
inner_check_request_response(
|
||||
create_network_backend::<NetworkWorker<_, _>>(),
|
||||
create_network_backend::<Litep2pNetworkBackend>(),
|
||||
)
|
||||
.await;
|
||||
|
||||
inner_check_request_response(
|
||||
create_network_backend::<Litep2pNetworkBackend>(),
|
||||
create_network_backend::<NetworkWorker<_, _>>(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_notifications() {
|
||||
async fn inner_check_notifications(left: NetworkBackendClient, right: NetworkBackendClient) {
|
||||
const MAX_NOTIFICATIONS: usize = 128;
|
||||
connect_notifications(&left, &right).await;
|
||||
|
||||
let right_peer = right.network_service.local_peer_id();
|
||||
let (tx, rx) = async_channel::bounded(1);
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut notifications_left = left.notification_service.lock().await;
|
||||
for _ in 0..MAX_NOTIFICATIONS {
|
||||
notifications_left
|
||||
.send_async_notification(&right_peer, vec![1, 2, 3])
|
||||
.await
|
||||
.expect("qed; cannot fail");
|
||||
}
|
||||
let _ = rx.recv().await;
|
||||
});
|
||||
|
||||
let mut notifications_right = right.notification_service.lock().await;
|
||||
let mut notification_index = 0;
|
||||
while let Some(event) = notifications_right.next_event().await {
|
||||
match event {
|
||||
NotificationEvent::NotificationReceived { notification, .. } => {
|
||||
notification_index += 1;
|
||||
|
||||
if notification_index >= MAX_NOTIFICATIONS {
|
||||
let _ = tx.send(()).await;
|
||||
break;
|
||||
}
|
||||
|
||||
assert_eq!(notification, vec![1, 2, 3]);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check libp2p -> litep2p.
|
||||
inner_check_notifications(
|
||||
create_network_backend::<NetworkWorker<_, _>>(),
|
||||
create_network_backend::<Litep2pNetworkBackend>(),
|
||||
)
|
||||
.await;
|
||||
|
||||
// Check litep2p -> libp2p.
|
||||
inner_check_notifications(
|
||||
create_network_backend::<Litep2pNetworkBackend>(),
|
||||
create_network_backend::<NetworkWorker<_, _>>(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_notifications_ping_pong() {
|
||||
async fn inner_check_notifications_ping_pong(
|
||||
left: NetworkBackendClient,
|
||||
right: NetworkBackendClient,
|
||||
) {
|
||||
const MAX_NOTIFICATIONS: usize = 128;
|
||||
connect_notifications(&left, &right).await;
|
||||
|
||||
let left_peer = left.network_service.local_peer_id();
|
||||
let right_peer = right.network_service.local_peer_id();
|
||||
|
||||
let mut notification_index = 0;
|
||||
tokio::spawn(async move {
|
||||
let mut notifications_left = left.notification_service.lock().await;
|
||||
|
||||
notifications_left
|
||||
.send_async_notification(&right_peer, vec![1, 2, 3])
|
||||
.await
|
||||
.expect("qed; cannot fail");
|
||||
|
||||
while let Some(event) = notifications_left.next_event().await {
|
||||
match event {
|
||||
NotificationEvent::NotificationReceived { notification, .. } => {
|
||||
assert_eq!(notification, vec![1, 2, 3, 4, 5]);
|
||||
|
||||
notification_index += 1;
|
||||
|
||||
if notification_index >= MAX_NOTIFICATIONS {
|
||||
break;
|
||||
}
|
||||
|
||||
notifications_left
|
||||
.send_async_notification(&right_peer, vec![1, 2, 3])
|
||||
.await
|
||||
.expect("qed; cannot fail");
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
for _ in 0..MAX_NOTIFICATIONS {}
|
||||
});
|
||||
|
||||
let mut notifications_right = right.notification_service.lock().await;
|
||||
let mut notification_index = 0;
|
||||
while let Some(event) = notifications_right.next_event().await {
|
||||
match event {
|
||||
NotificationEvent::NotificationReceived { notification, .. } => {
|
||||
assert_eq!(notification, vec![1, 2, 3]);
|
||||
|
||||
notification_index += 1;
|
||||
|
||||
if notification_index >= MAX_NOTIFICATIONS {
|
||||
break;
|
||||
}
|
||||
|
||||
notifications_right
|
||||
.send_async_notification(&left_peer, vec![1, 2, 3, 4, 5])
|
||||
.await
|
||||
.expect("qed; cannot fail");
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check libp2p -> litep2p.
|
||||
inner_check_notifications_ping_pong(
|
||||
create_network_backend::<NetworkWorker<_, _>>(),
|
||||
create_network_backend::<Litep2pNetworkBackend>(),
|
||||
)
|
||||
.await;
|
||||
|
||||
// Check litep2p -> libp2p.
|
||||
inner_check_notifications_ping_pong(
|
||||
create_network_backend::<Litep2pNetworkBackend>(),
|
||||
create_network_backend::<NetworkWorker<_, _>>(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
mod high_level;
|
||||
mod setup;
|
||||
@@ -0,0 +1,225 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// 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 pezsc_network::{
|
||||
config::{
|
||||
FullNetworkConfiguration, IncomingRequest, MultiaddrWithPeerId, NetworkConfiguration,
|
||||
NonReservedPeerMode, NotificationHandshake, OutgoingResponse, Params, ProtocolId, Role,
|
||||
SetConfig,
|
||||
},
|
||||
service::traits::{NetworkService, NotificationEvent},
|
||||
IfDisconnected, NetworkBackend, NetworkRequest, NotificationMetrics, NotificationService,
|
||||
Roles,
|
||||
};
|
||||
|
||||
use pezsc_network_common::sync::message::BlockAnnouncesHandshake;
|
||||
use pezsp_runtime::traits::Zero;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use bizinikiwi_test_runtime_client::runtime;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
/// High level network backend (litep2p or libp2p) test client.
|
||||
pub struct NetworkBackendClient {
|
||||
pub network_service: Arc<dyn NetworkService>,
|
||||
pub notification_service: Arc<Mutex<Box<dyn NotificationService>>>,
|
||||
pub receiver: async_channel::Receiver<IncomingRequest>,
|
||||
}
|
||||
|
||||
/// Configure the network backend client for tests based on the given service.
|
||||
///
|
||||
/// This will setup:
|
||||
/// - `/request-response/1` request response protocol with bounded channel of 32 requests
|
||||
/// - `/block-announces/1` notification protocol
|
||||
pub fn create_network_backend<N>() -> NetworkBackendClient
|
||||
where
|
||||
N: NetworkBackend<runtime::Block, runtime::Hash>,
|
||||
{
|
||||
let (tx, rx) = async_channel::bounded(32);
|
||||
let request_response_config = N::request_response_config(
|
||||
"/request-response/1".into(),
|
||||
vec![],
|
||||
1024,
|
||||
1024,
|
||||
Duration::from_secs(2),
|
||||
Some(tx),
|
||||
);
|
||||
|
||||
let role = Role::Full;
|
||||
let net_conf = NetworkConfiguration::new_local();
|
||||
let mut network_config = FullNetworkConfiguration::new(&net_conf, None);
|
||||
network_config.add_request_response_protocol(request_response_config);
|
||||
let genesis_hash = runtime::Hash::zero();
|
||||
let (block_announce_config, notification_service) = N::notification_config(
|
||||
"/block-announces/1".into(),
|
||||
vec![],
|
||||
1024,
|
||||
Some(NotificationHandshake::new(BlockAnnouncesHandshake::<runtime::Block>::build(
|
||||
Roles::from(&Role::Full),
|
||||
Zero::zero(),
|
||||
genesis_hash,
|
||||
genesis_hash,
|
||||
))),
|
||||
SetConfig {
|
||||
in_peers: 1,
|
||||
out_peers: 1,
|
||||
reserved_nodes: vec![],
|
||||
non_reserved_mode: NonReservedPeerMode::Accept,
|
||||
},
|
||||
NotificationMetrics::new(None),
|
||||
network_config.peer_store_handle(),
|
||||
);
|
||||
let worker = N::new(Params::<runtime::Block, runtime::Hash, N> {
|
||||
block_announce_config,
|
||||
role,
|
||||
executor: Box::new(|f| {
|
||||
tokio::spawn(f);
|
||||
}),
|
||||
genesis_hash: runtime::Hash::zero(),
|
||||
network_config,
|
||||
protocol_id: ProtocolId::from("test"),
|
||||
fork_id: None,
|
||||
metrics_registry: None,
|
||||
bitswap_config: None,
|
||||
notification_metrics: NotificationMetrics::new(None),
|
||||
})
|
||||
.unwrap();
|
||||
let network_service = worker.network_service();
|
||||
|
||||
// Run the worker in the backend.
|
||||
tokio::spawn(worker.run());
|
||||
|
||||
NetworkBackendClient {
|
||||
network_service,
|
||||
notification_service: Arc::new(Mutex::new(notification_service)),
|
||||
receiver: rx,
|
||||
}
|
||||
}
|
||||
|
||||
/// Connect two backends together and submit one request with `IfDisconnected::TryConnect` option
|
||||
/// expecting the left backend to dial the right one.
|
||||
pub async fn connect_backends(left: &NetworkBackendClient, right: &NetworkBackendClient) {
|
||||
let right_peer_id = right.network_service.local_peer_id();
|
||||
|
||||
// Ensure the right backend responds to a first request
|
||||
let rx = right.receiver.clone();
|
||||
tokio::spawn(async move {
|
||||
let request = rx.recv().await.expect("Left backend should receive a request");
|
||||
assert_eq!(request.payload, vec![1, 2, 3]);
|
||||
request
|
||||
.pending_response
|
||||
.send(OutgoingResponse {
|
||||
result: Ok(vec![4, 5, 6]),
|
||||
reputation_changes: vec![],
|
||||
sent_feedback: None,
|
||||
})
|
||||
.expect("Left backend should send a response");
|
||||
});
|
||||
|
||||
// Connect the two backends
|
||||
while left.network_service.listen_addresses().is_empty() {
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
}
|
||||
while right.network_service.listen_addresses().is_empty() {
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
}
|
||||
let right_listen_address = right
|
||||
.network_service
|
||||
.listen_addresses()
|
||||
.first()
|
||||
.expect("qed; non empty")
|
||||
.clone();
|
||||
|
||||
left.network_service
|
||||
.add_known_address(right_peer_id, right_listen_address.clone().into());
|
||||
|
||||
let result = left
|
||||
.network_service
|
||||
.request(
|
||||
right_peer_id,
|
||||
"/request-response/1".into(),
|
||||
vec![1, 2, 3],
|
||||
None,
|
||||
IfDisconnected::TryConnect,
|
||||
)
|
||||
.await
|
||||
.expect("Left backend should send a request");
|
||||
assert_eq!(result.0, vec![4, 5, 6]);
|
||||
assert_eq!(result.1, "/request-response/1".into());
|
||||
}
|
||||
|
||||
/// Ensure connectivity on the notification protocol level.
|
||||
pub async fn connect_notifications(left: &NetworkBackendClient, right: &NetworkBackendClient) {
|
||||
let right_peer_id = right.network_service.local_peer_id();
|
||||
|
||||
while left.network_service.listen_addresses().is_empty() {
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
}
|
||||
while right.network_service.listen_addresses().is_empty() {
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
}
|
||||
|
||||
let right_listen_address = right
|
||||
.network_service
|
||||
.listen_addresses()
|
||||
.first()
|
||||
.expect("qed; non empty")
|
||||
.clone();
|
||||
|
||||
left.network_service
|
||||
.add_reserved_peer(MultiaddrWithPeerId {
|
||||
multiaddr: right_listen_address.into(),
|
||||
peer_id: right_peer_id,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut notifications_left = left.notification_service.lock().await;
|
||||
let mut notifications_right = right.notification_service.lock().await;
|
||||
let mut opened = 0;
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(event) = notifications_left.next_event() => {
|
||||
match event {
|
||||
NotificationEvent::NotificationStreamOpened { .. } => {
|
||||
opened += 1;
|
||||
if opened >= 2 {
|
||||
break;
|
||||
}
|
||||
},
|
||||
NotificationEvent::ValidateInboundSubstream { result_tx, .. } => {
|
||||
result_tx.send(pezsc_network::service::traits::ValidationResult::Accept).unwrap();
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
},
|
||||
Some(event) = notifications_right.next_event() => {
|
||||
match event {
|
||||
NotificationEvent::ValidateInboundSubstream { result_tx, .. } => {
|
||||
result_tx.send(pezsc_network::service::traits::ValidationResult::Accept).unwrap();
|
||||
},
|
||||
NotificationEvent::NotificationStreamOpened { .. } => {
|
||||
opened += 1;
|
||||
if opened >= 2 {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,423 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! Fuzz test emulates network events and peer connection handling by `ProtocolController`
|
||||
//! and `PeerStore` to discover possible inconsistencies in peer management.
|
||||
|
||||
use futures::prelude::*;
|
||||
use libp2p::PeerId;
|
||||
use rand::{
|
||||
distributions::{Distribution, Uniform, WeightedIndex},
|
||||
seq::IteratorRandom,
|
||||
};
|
||||
use pezsc_network::{
|
||||
peer_store::{PeerStore, PeerStoreProvider},
|
||||
protocol_controller::{IncomingIndex, Message, ProtoSetConfig, ProtocolController, SetId},
|
||||
ReputationChange,
|
||||
};
|
||||
use pezsc_utils::mpsc::tracing_unbounded;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
/// Peer events as observed by `Notifications` / fuzz test.
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
enum Event {
|
||||
/// Either API requested to disconnect from the peer, or the peer dropped.
|
||||
Disconnected,
|
||||
/// Incoming request.
|
||||
Incoming,
|
||||
/// Answer from PSM: accept.
|
||||
PsmAccept,
|
||||
/// Answer from PSM: reject.
|
||||
PsmReject,
|
||||
/// Command from PSM: connect.
|
||||
PsmConnect,
|
||||
/// Command from PSM: drop connection.
|
||||
PsmDrop,
|
||||
}
|
||||
|
||||
/// Simplified peer state as thought by `Notifications` / fuzz test.
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
enum State {
|
||||
/// Peer is not connected.
|
||||
Disconnected,
|
||||
/// We have an inbound connection, but have not decided yet whether to accept it.
|
||||
Incoming(IncomingIndex),
|
||||
/// Peer is connected via an inbound connection.
|
||||
Inbound,
|
||||
/// Peer is connected via an outbound connection.
|
||||
Outbound,
|
||||
}
|
||||
|
||||
/// Bare simplified state without incoming index.
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
enum BareState {
|
||||
/// Peer is not connected.
|
||||
Disconnected,
|
||||
/// We have an inbound connection, but have not decided yet whether to accept it.
|
||||
Incoming,
|
||||
/// Peer is connected via an inbound connection.
|
||||
Inbound,
|
||||
/// Peer is connected via an outbound connection.
|
||||
Outbound,
|
||||
}
|
||||
|
||||
fn discard_incoming_index(state: State) -> BareState {
|
||||
match state {
|
||||
State::Disconnected => BareState::Disconnected,
|
||||
State::Incoming(_) => BareState::Incoming,
|
||||
State::Inbound => BareState::Inbound,
|
||||
State::Outbound => BareState::Outbound,
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn run() {
|
||||
pezsp_tracing::try_init_simple();
|
||||
|
||||
for _ in 0..50 {
|
||||
test_once().await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn test_once() {
|
||||
// Allowed events that can be received in a specific state.
|
||||
let allowed_events: HashMap<BareState, HashSet<Event>> = [
|
||||
(
|
||||
BareState::Disconnected,
|
||||
[Event::Incoming, Event::PsmConnect, Event::PsmDrop /* must be ignored */]
|
||||
.into_iter()
|
||||
.collect::<HashSet<_>>(),
|
||||
),
|
||||
(
|
||||
BareState::Incoming,
|
||||
[Event::PsmAccept, Event::PsmReject].into_iter().collect::<HashSet<_>>(),
|
||||
),
|
||||
(
|
||||
BareState::Inbound,
|
||||
[Event::Disconnected, Event::PsmDrop, Event::PsmConnect /* must be ignored */]
|
||||
.into_iter()
|
||||
.collect::<HashSet<_>>(),
|
||||
),
|
||||
(
|
||||
BareState::Outbound,
|
||||
[Event::Disconnected, Event::PsmDrop, Event::PsmConnect /* must be ignored */]
|
||||
.into_iter()
|
||||
.collect::<HashSet<_>>(),
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
// PRNG to use.
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
// Nodes that the peerset knows about.
|
||||
let mut known_nodes = HashMap::<PeerId, State>::new();
|
||||
// Nodes that we have reserved. Always a subset of `known_nodes`.
|
||||
let mut reserved_nodes = HashSet::<PeerId>::new();
|
||||
|
||||
// Bootnodes for `PeerStore` initialization.
|
||||
let bootnodes = (0..Uniform::new_inclusive(0, 4).sample(&mut rng))
|
||||
.map(|_| {
|
||||
let id = PeerId::random();
|
||||
known_nodes.insert(id, State::Disconnected);
|
||||
id
|
||||
})
|
||||
.collect();
|
||||
|
||||
let peer_store = PeerStore::new(bootnodes, None);
|
||||
let peer_store_handle = peer_store.handle();
|
||||
|
||||
let (to_notifications, mut from_controller) =
|
||||
tracing_unbounded("test_to_notifications", 10_000);
|
||||
let (protocol_handle, protocol_controller) = ProtocolController::new(
|
||||
SetId::from(0),
|
||||
ProtoSetConfig {
|
||||
reserved_nodes: {
|
||||
(0..Uniform::new_inclusive(0, 2).sample(&mut rng))
|
||||
.map(|_| {
|
||||
let id = PeerId::random();
|
||||
known_nodes.insert(id, State::Disconnected);
|
||||
reserved_nodes.insert(id);
|
||||
id
|
||||
})
|
||||
.collect()
|
||||
},
|
||||
in_peers: Uniform::new_inclusive(0, 25).sample(&mut rng),
|
||||
out_peers: Uniform::new_inclusive(0, 25).sample(&mut rng),
|
||||
reserved_only: Uniform::new_inclusive(0, 10).sample(&mut rng) == 0,
|
||||
},
|
||||
to_notifications,
|
||||
Arc::new(peer_store_handle.clone()),
|
||||
);
|
||||
|
||||
tokio::spawn(peer_store.run());
|
||||
tokio::spawn(protocol_controller.run());
|
||||
|
||||
// List of nodes the user of `peerset` assumes it's connected to. Always a subset of
|
||||
// `known_nodes`.
|
||||
let mut connected_nodes = HashSet::<PeerId>::new();
|
||||
// List of nodes the user of `peerset` called `incoming` with and that haven't been
|
||||
// accepted or rejected yet.
|
||||
let mut incoming_nodes = HashMap::<IncomingIndex, PeerId>::new();
|
||||
// Next id for incoming connections.
|
||||
let mut next_incoming_id = IncomingIndex(0);
|
||||
|
||||
// The loop below is effectively synchronous, so for `PeerStore` & `ProtocolController`
|
||||
// runners, spawned above, to advance, we use `spawn_blocking`.
|
||||
let _ = tokio::task::spawn_blocking(move || {
|
||||
// PRNG to use in `spawn_blocking` context.
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
// Perform a certain number of actions while checking that the state is consistent. If we
|
||||
// reach the end of the loop, the run has succeeded.
|
||||
// Note that with the ACKing and event postponing mechanism in `ProtocolController`
|
||||
// the test time grows quadratically with the number of iterations below.
|
||||
for _ in 0..2500 {
|
||||
// Peer we are working with.
|
||||
let mut current_peer = None;
|
||||
// Current event for state transition validation.
|
||||
let mut current_event = None;
|
||||
// Last peer state for allowed event validation.
|
||||
let mut last_state = None;
|
||||
|
||||
// Each of these weights corresponds to an action that we may perform.
|
||||
let action_weights = [150, 90, 90, 30, 30, 1, 1, 4, 4];
|
||||
|
||||
match WeightedIndex::new(&action_weights).unwrap().sample(&mut rng) {
|
||||
// If we generate 0, try to grab the next message from `ProtocolController`.
|
||||
0 => match from_controller.next().now_or_never() {
|
||||
Some(Some(Message::Connect { peer_id, .. })) => {
|
||||
log::info!("PSM: connecting to peer {}", peer_id);
|
||||
|
||||
let state = known_nodes.get_mut(&peer_id).unwrap();
|
||||
if matches!(*state, State::Incoming(_)) {
|
||||
log::info!(
|
||||
"Awaiting incoming response, ignoring obsolete Connect from PSM for peer {}",
|
||||
peer_id,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
last_state = Some(*state);
|
||||
|
||||
if *state != State::Inbound {
|
||||
*state = State::Outbound;
|
||||
}
|
||||
|
||||
if !connected_nodes.insert(peer_id) {
|
||||
log::info!("Request to connect to an already connected node {peer_id}");
|
||||
}
|
||||
|
||||
current_peer = Some(peer_id);
|
||||
current_event = Some(Event::PsmConnect);
|
||||
},
|
||||
Some(Some(Message::Drop { peer_id, .. })) => {
|
||||
log::info!("PSM: dropping peer {}", peer_id);
|
||||
|
||||
let state = known_nodes.get_mut(&peer_id).unwrap();
|
||||
if matches!(*state, State::Incoming(_)) {
|
||||
log::info!(
|
||||
"Awaiting incoming response, ignoring obsolete Drop from PSM for peer {}",
|
||||
peer_id,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
last_state = Some(*state);
|
||||
*state = State::Disconnected;
|
||||
|
||||
if !connected_nodes.remove(&peer_id) {
|
||||
log::info!("Ignoring attempt to drop a disconnected peer {}", peer_id);
|
||||
}
|
||||
|
||||
current_peer = Some(peer_id);
|
||||
current_event = Some(Event::PsmDrop);
|
||||
},
|
||||
Some(Some(Message::Accept(n))) => {
|
||||
log::info!("PSM: accepting index {}", n.0);
|
||||
|
||||
let peer_id = incoming_nodes.remove(&n).unwrap();
|
||||
|
||||
let state = known_nodes.get_mut(&peer_id).unwrap();
|
||||
match *state {
|
||||
State::Incoming(incoming_index) =>
|
||||
if n.0 < incoming_index.0 {
|
||||
log::info!(
|
||||
"Ignoring obsolete Accept for {:?} while awaiting {:?} for peer {}",
|
||||
n, incoming_index, peer_id,
|
||||
);
|
||||
continue;
|
||||
} else if n.0 > incoming_index.0 {
|
||||
panic!(
|
||||
"Received {:?} while awaiting {:?} for peer {}",
|
||||
n, incoming_index, peer_id,
|
||||
);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
last_state = Some(*state);
|
||||
*state = State::Inbound;
|
||||
|
||||
assert!(connected_nodes.insert(peer_id));
|
||||
|
||||
current_peer = Some(peer_id);
|
||||
current_event = Some(Event::PsmAccept);
|
||||
},
|
||||
Some(Some(Message::Reject(n))) => {
|
||||
log::info!("PSM: rejecting index {}", n.0);
|
||||
|
||||
let peer_id = incoming_nodes.remove(&n).unwrap();
|
||||
|
||||
let state = known_nodes.get_mut(&peer_id).unwrap();
|
||||
match *state {
|
||||
State::Incoming(incoming_index) =>
|
||||
if n.0 < incoming_index.0 {
|
||||
log::info!(
|
||||
"Ignoring obsolete Reject for {:?} while awaiting {:?} for peer {}",
|
||||
n, incoming_index, peer_id,
|
||||
);
|
||||
continue;
|
||||
} else if n.0 > incoming_index.0 {
|
||||
panic!(
|
||||
"Received {:?} while awaiting {:?} for peer {}",
|
||||
n, incoming_index, peer_id,
|
||||
);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
last_state = Some(*state);
|
||||
*state = State::Disconnected;
|
||||
|
||||
assert!(!connected_nodes.contains(&peer_id));
|
||||
|
||||
current_peer = Some(peer_id);
|
||||
current_event = Some(Event::PsmReject);
|
||||
},
|
||||
Some(None) => panic!(),
|
||||
None => {},
|
||||
},
|
||||
|
||||
// If we generate 1, discover a new node.
|
||||
1 => {
|
||||
let new_id = PeerId::random();
|
||||
known_nodes.insert(new_id, State::Disconnected);
|
||||
peer_store_handle.add_known_peer(new_id.into());
|
||||
},
|
||||
|
||||
// If we generate 2, adjust a random reputation.
|
||||
2 =>
|
||||
if let Some(id) = known_nodes.keys().choose(&mut rng) {
|
||||
let val = Uniform::new_inclusive(i32::MIN, i32::MAX).sample(&mut rng);
|
||||
let peer: pezsc_network_types::PeerId = id.into();
|
||||
peer_store_handle.report_peer(peer, ReputationChange::new(val, ""));
|
||||
},
|
||||
|
||||
// If we generate 3, disconnect from a random node.
|
||||
3 =>
|
||||
if let Some(id) = connected_nodes.iter().choose(&mut rng).cloned() {
|
||||
log::info!("Disconnected from {}", id);
|
||||
connected_nodes.remove(&id);
|
||||
|
||||
let state = known_nodes.get_mut(&id).unwrap();
|
||||
last_state = Some(*state);
|
||||
*state = State::Disconnected;
|
||||
|
||||
protocol_handle.dropped(id);
|
||||
|
||||
current_peer = Some(id);
|
||||
current_event = Some(Event::Disconnected);
|
||||
},
|
||||
|
||||
// If we generate 4, connect to a random node.
|
||||
4 => {
|
||||
if let Some(id) = known_nodes
|
||||
.keys()
|
||||
.filter(|n| {
|
||||
incoming_nodes.values().all(|m| m != *n) &&
|
||||
!connected_nodes.contains(*n)
|
||||
})
|
||||
.choose(&mut rng)
|
||||
.cloned()
|
||||
{
|
||||
log::info!("Incoming connection from {}, index {}", id, next_incoming_id.0);
|
||||
protocol_handle.incoming_connection(id, next_incoming_id);
|
||||
incoming_nodes.insert(next_incoming_id, id);
|
||||
|
||||
let state = known_nodes.get_mut(&id).unwrap();
|
||||
last_state = Some(*state);
|
||||
*state = State::Incoming(next_incoming_id);
|
||||
|
||||
next_incoming_id.0 += 1;
|
||||
|
||||
current_peer = Some(id);
|
||||
current_event = Some(Event::Incoming);
|
||||
}
|
||||
},
|
||||
|
||||
// 5 and 6 are the reserved-only mode.
|
||||
5 => {
|
||||
log::info!("Set reserved only");
|
||||
protocol_handle.set_reserved_only(true);
|
||||
},
|
||||
6 => {
|
||||
log::info!("Unset reserved only");
|
||||
protocol_handle.set_reserved_only(false);
|
||||
},
|
||||
|
||||
// 7 and 8 are about switching a random node in or out of reserved mode.
|
||||
7 => {
|
||||
if let Some(id) =
|
||||
known_nodes.keys().filter(|n| !reserved_nodes.contains(*n)).choose(&mut rng)
|
||||
{
|
||||
log::info!("Add reserved: {}", id);
|
||||
protocol_handle.add_reserved_peer(*id);
|
||||
reserved_nodes.insert(*id);
|
||||
}
|
||||
},
|
||||
8 =>
|
||||
if let Some(id) = reserved_nodes.iter().choose(&mut rng).cloned() {
|
||||
log::info!("Remove reserved: {}", id);
|
||||
reserved_nodes.remove(&id);
|
||||
protocol_handle.remove_reserved_peer(id);
|
||||
},
|
||||
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
// Validate state transitions.
|
||||
if let Some(peer_id) = current_peer {
|
||||
let event = current_event.unwrap();
|
||||
let last_state = discard_incoming_index(last_state.unwrap());
|
||||
if !allowed_events.get(&last_state).unwrap().contains(&event) {
|
||||
panic!(
|
||||
"Invalid state transition: {:?} x {:?} for peer {}",
|
||||
last_state, event, peer_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,849 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// 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 futures::prelude::*;
|
||||
|
||||
use pezsc_consensus::{ImportQueue, Link};
|
||||
use pezsc_network::{
|
||||
config::{self, FullNetworkConfiguration, MultiaddrWithPeerId, ProtocolId, TransportConfig},
|
||||
event::Event,
|
||||
peer_store::{PeerStore, PeerStoreProvider},
|
||||
service::traits::{NotificationEvent, ValidationResult},
|
||||
Multiaddr, NetworkEventStream, NetworkPeers, NetworkService, NetworkStateInfo, NetworkWorker,
|
||||
NotificationMetrics, NotificationService, PeerId,
|
||||
};
|
||||
use pezsc_network_common::role::Roles;
|
||||
use pezsc_network_light::light_client_requests::handler::LightClientRequestHandler;
|
||||
use pezsc_network_sync::{
|
||||
block_request_handler::BlockRequestHandler,
|
||||
engine::SyncingEngine,
|
||||
service::network::NetworkServiceProvider,
|
||||
state_request_handler::StateRequestHandler,
|
||||
strategy::pezkuwi::{PezkuwiSyncingStrategy, PezkuwiSyncingStrategyConfig},
|
||||
};
|
||||
use pezsp_blockchain::HeaderBackend;
|
||||
use pezsp_runtime::traits::{Block as BlockT, Zero};
|
||||
use bizinikiwi_test_runtime_client::{
|
||||
runtime::{Block as TestBlock, Hash as TestHash},
|
||||
TestClientBuilder, TestClientBuilderExt as _,
|
||||
};
|
||||
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
type TestNetworkWorker = NetworkWorker<TestBlock, TestHash>;
|
||||
type TestNetworkService = NetworkService<TestBlock, TestHash>;
|
||||
|
||||
const PROTOCOL_NAME: &str = "/foo";
|
||||
|
||||
struct TestNetwork {
|
||||
network: TestNetworkWorker,
|
||||
}
|
||||
|
||||
impl TestNetwork {
|
||||
pub fn new(network: TestNetworkWorker) -> Self {
|
||||
Self { network }
|
||||
}
|
||||
|
||||
pub fn start_network(
|
||||
self,
|
||||
) -> (Arc<TestNetworkService>, (impl Stream<Item = Event> + std::marker::Unpin)) {
|
||||
let worker = self.network;
|
||||
let service = worker.service().clone();
|
||||
let event_stream = service.event_stream("test");
|
||||
|
||||
tokio::spawn(worker.run());
|
||||
|
||||
(service, event_stream)
|
||||
}
|
||||
}
|
||||
|
||||
struct TestNetworkBuilder {
|
||||
import_queue: Option<Box<dyn ImportQueue<TestBlock>>>,
|
||||
link: Option<Box<dyn Link<TestBlock>>>,
|
||||
client: Option<Arc<bizinikiwi_test_runtime_client::TestClient>>,
|
||||
listen_addresses: Vec<Multiaddr>,
|
||||
set_config: Option<config::SetConfig>,
|
||||
chain_sync_network: Option<NetworkServiceProvider>,
|
||||
notification_protocols: Vec<config::NonDefaultSetConfig>,
|
||||
config: Option<config::NetworkConfiguration>,
|
||||
}
|
||||
|
||||
impl TestNetworkBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
import_queue: None,
|
||||
link: None,
|
||||
client: None,
|
||||
listen_addresses: Vec::new(),
|
||||
set_config: None,
|
||||
chain_sync_network: None,
|
||||
notification_protocols: Vec::new(),
|
||||
config: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_config(mut self, config: config::NetworkConfiguration) -> Self {
|
||||
self.config = Some(config);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_notification_protocol(mut self, config: config::NonDefaultSetConfig) -> Self {
|
||||
self.notification_protocols.push(config);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_listen_addresses(mut self, addresses: Vec<Multiaddr>) -> Self {
|
||||
self.listen_addresses = addresses;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_set_config(mut self, set_config: config::SetConfig) -> Self {
|
||||
self.set_config = Some(set_config);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(mut self) -> (TestNetwork, Option<Box<dyn NotificationService>>) {
|
||||
let client = self.client.as_mut().map_or(
|
||||
Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0),
|
||||
|v| v.clone(),
|
||||
);
|
||||
|
||||
let network_config = self.config.unwrap_or(config::NetworkConfiguration {
|
||||
listen_addresses: self.listen_addresses,
|
||||
transport: TransportConfig::MemoryOnly,
|
||||
..config::NetworkConfiguration::new_local()
|
||||
});
|
||||
|
||||
#[derive(Clone)]
|
||||
struct PassThroughVerifier(bool);
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<B: BlockT> pezsc_consensus::Verifier<B> for PassThroughVerifier {
|
||||
async fn verify(
|
||||
&self,
|
||||
mut block: pezsc_consensus::BlockImportParams<B>,
|
||||
) -> Result<pezsc_consensus::BlockImportParams<B>, String> {
|
||||
block.finalized = self.0;
|
||||
block.fork_choice = Some(pezsc_consensus::ForkChoiceStrategy::LongestChain);
|
||||
Ok(block)
|
||||
}
|
||||
}
|
||||
|
||||
let mut import_queue =
|
||||
self.import_queue.unwrap_or(Box::new(pezsc_consensus::BasicQueue::new(
|
||||
PassThroughVerifier(false),
|
||||
Box::new(client.clone()),
|
||||
None,
|
||||
&pezsp_core::testing::TaskExecutor::new(),
|
||||
None,
|
||||
)));
|
||||
|
||||
let protocol_id = ProtocolId::from("test-protocol-name");
|
||||
let fork_id = Some(String::from("test-fork-id"));
|
||||
let mut full_net_config = FullNetworkConfiguration::new(&network_config, None);
|
||||
|
||||
let chain_sync_network_provider =
|
||||
self.chain_sync_network.unwrap_or(NetworkServiceProvider::new());
|
||||
let chain_sync_network_handle = chain_sync_network_provider.handle();
|
||||
let mut block_relay_params =
|
||||
BlockRequestHandler::new::<
|
||||
NetworkWorker<
|
||||
bizinikiwi_test_runtime_client::runtime::Block,
|
||||
bizinikiwi_test_runtime_client::runtime::Hash,
|
||||
>,
|
||||
>(chain_sync_network_handle.clone(), &protocol_id, None, client.clone(), 50);
|
||||
tokio::spawn(Box::pin(async move {
|
||||
block_relay_params.server.run().await;
|
||||
}));
|
||||
|
||||
let state_request_protocol_config = {
|
||||
let (handler, protocol_config) = StateRequestHandler::new::<
|
||||
NetworkWorker<
|
||||
bizinikiwi_test_runtime_client::runtime::Block,
|
||||
bizinikiwi_test_runtime_client::runtime::Hash,
|
||||
>,
|
||||
>(&protocol_id, None, client.clone(), 50);
|
||||
tokio::spawn(handler.run().boxed());
|
||||
protocol_config
|
||||
};
|
||||
|
||||
let light_client_request_protocol_config = {
|
||||
let (handler, protocol_config) = LightClientRequestHandler::new::<
|
||||
NetworkWorker<
|
||||
bizinikiwi_test_runtime_client::runtime::Block,
|
||||
bizinikiwi_test_runtime_client::runtime::Hash,
|
||||
>,
|
||||
>(&protocol_id, None, client.clone());
|
||||
tokio::spawn(handler.run().boxed());
|
||||
protocol_config
|
||||
};
|
||||
|
||||
let peer_store = PeerStore::new(
|
||||
network_config
|
||||
.boot_nodes
|
||||
.iter()
|
||||
.map(|bootnode| bootnode.peer_id.into())
|
||||
.collect(),
|
||||
None,
|
||||
);
|
||||
let peer_store_handle: Arc<dyn PeerStoreProvider> = Arc::new(peer_store.handle());
|
||||
tokio::spawn(peer_store.run().boxed());
|
||||
|
||||
let syncing_config = PezkuwiSyncingStrategyConfig {
|
||||
mode: network_config.sync_mode,
|
||||
max_parallel_downloads: network_config.max_parallel_downloads,
|
||||
max_blocks_per_request: network_config.max_blocks_per_request,
|
||||
metrics_registry: None,
|
||||
state_request_protocol_name: state_request_protocol_config.name.clone(),
|
||||
block_downloader: block_relay_params.downloader,
|
||||
min_peers_to_start_warp_sync: None,
|
||||
};
|
||||
// Initialize syncing strategy.
|
||||
let syncing_strategy = Box::new(
|
||||
PezkuwiSyncingStrategy::new(syncing_config, client.clone(), None, None).unwrap(),
|
||||
);
|
||||
|
||||
let (engine, chain_sync_service, block_announce_config) = SyncingEngine::new(
|
||||
Roles::from(&config::Role::Full),
|
||||
client.clone(),
|
||||
None,
|
||||
NotificationMetrics::new(None),
|
||||
&full_net_config,
|
||||
protocol_id.clone(),
|
||||
None,
|
||||
Box::new(pezsp_consensus::block_validation::DefaultBlockAnnounceValidator),
|
||||
syncing_strategy,
|
||||
chain_sync_network_handle,
|
||||
import_queue.service(),
|
||||
Arc::clone(&peer_store_handle),
|
||||
)
|
||||
.unwrap();
|
||||
let mut link = self.link.unwrap_or(Box::new(chain_sync_service.clone()));
|
||||
|
||||
let handle = if !self.notification_protocols.is_empty() {
|
||||
for config in self.notification_protocols {
|
||||
full_net_config.add_notification_protocol(config);
|
||||
}
|
||||
None
|
||||
} else {
|
||||
let (config, handle) = config::NonDefaultSetConfig::new(
|
||||
PROTOCOL_NAME.into(),
|
||||
Vec::new(),
|
||||
1024 * 1024,
|
||||
None,
|
||||
self.set_config.unwrap_or_default(),
|
||||
);
|
||||
full_net_config.add_notification_protocol(config);
|
||||
Some(handle)
|
||||
};
|
||||
|
||||
for config in [
|
||||
block_relay_params.request_response_config,
|
||||
state_request_protocol_config,
|
||||
light_client_request_protocol_config,
|
||||
] {
|
||||
full_net_config.add_request_response_protocol(config);
|
||||
}
|
||||
|
||||
let genesis_hash =
|
||||
client.hash(Zero::zero()).ok().flatten().expect("Genesis block exists; qed");
|
||||
let worker = NetworkWorker::<
|
||||
bizinikiwi_test_runtime_client::runtime::Block,
|
||||
bizinikiwi_test_runtime_client::runtime::Hash,
|
||||
>::new(config::Params::<
|
||||
bizinikiwi_test_runtime_client::runtime::Block,
|
||||
bizinikiwi_test_runtime_client::runtime::Hash,
|
||||
NetworkWorker<_, _>,
|
||||
> {
|
||||
block_announce_config,
|
||||
role: config::Role::Full,
|
||||
executor: Box::new(|f| {
|
||||
tokio::spawn(f);
|
||||
}),
|
||||
genesis_hash,
|
||||
network_config: full_net_config,
|
||||
protocol_id,
|
||||
fork_id,
|
||||
metrics_registry: None,
|
||||
bitswap_config: None,
|
||||
notification_metrics: NotificationMetrics::new(None),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let service = worker.service().clone();
|
||||
tokio::spawn(async move {
|
||||
let _ = chain_sync_network_provider.run(service).await;
|
||||
});
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
futures::future::poll_fn(|cx| {
|
||||
import_queue.poll_actions(cx, &mut *link);
|
||||
std::task::Poll::Ready(())
|
||||
})
|
||||
.await;
|
||||
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
|
||||
}
|
||||
});
|
||||
tokio::spawn(engine.run());
|
||||
|
||||
(TestNetwork::new(worker), handle)
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds two nodes and their associated events stream.
|
||||
/// The nodes are connected together and have the `PROTOCOL_NAME` protocol registered.
|
||||
fn build_nodes_one_proto() -> (
|
||||
Arc<TestNetworkService>,
|
||||
Option<Box<dyn NotificationService>>,
|
||||
Arc<TestNetworkService>,
|
||||
Option<Box<dyn NotificationService>>,
|
||||
) {
|
||||
let listen_addr = config::build_multiaddr![Memory(rand::random::<u64>())];
|
||||
|
||||
let (network1, handle1) = TestNetworkBuilder::new()
|
||||
.with_listen_addresses(vec![listen_addr.clone()])
|
||||
.build();
|
||||
let (node1, _) = network1.start_network();
|
||||
|
||||
let (network2, handle2) = TestNetworkBuilder::new()
|
||||
.with_set_config(config::SetConfig {
|
||||
reserved_nodes: vec![MultiaddrWithPeerId {
|
||||
multiaddr: listen_addr,
|
||||
peer_id: node1.local_peer_id(),
|
||||
}],
|
||||
..Default::default()
|
||||
})
|
||||
.build();
|
||||
|
||||
let (node2, _) = network2.start_network();
|
||||
|
||||
(node1, handle1, node2, handle2)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn notifications_state_consistent() {
|
||||
// Runs two nodes and ensures that events are propagated out of the API in a consistent
|
||||
// correct order, which means no notification received on a closed substream.
|
||||
|
||||
let (node1, handle1, node2, handle2) = build_nodes_one_proto();
|
||||
let (mut handle1, mut handle2) = (handle1.unwrap(), handle2.unwrap());
|
||||
|
||||
// Write some initial notifications that shouldn't get through.
|
||||
for _ in 0..(rand::random::<u8>() % 5) {
|
||||
let _ = handle1.send_sync_notification(&node2.local_peer_id(), b"hello world".to_vec());
|
||||
}
|
||||
for _ in 0..(rand::random::<u8>() % 5) {
|
||||
let _ = handle2.send_sync_notification(&node1.local_peer_id(), b"hello world".to_vec());
|
||||
}
|
||||
|
||||
// True if we have an active substream from node1 to node2.
|
||||
let mut node1_to_node2_open = false;
|
||||
// True if we have an active substream from node2 to node1.
|
||||
let mut node2_to_node1_open = false;
|
||||
// We stop the test after a certain number of iterations.
|
||||
let mut iterations = 0;
|
||||
// Safe guard because we don't want the test to pass if no substream has been open.
|
||||
let mut something_happened = false;
|
||||
|
||||
loop {
|
||||
iterations += 1;
|
||||
if iterations >= 1_000 {
|
||||
assert!(something_happened);
|
||||
break;
|
||||
}
|
||||
|
||||
// Start by sending a notification from node1 to node2 and vice-versa. Part of the
|
||||
// test consists in ensuring that notifications get ignored if the stream isn't open.
|
||||
if rand::random::<u8>() % 5 >= 3 {
|
||||
let _ = handle1.send_sync_notification(&node2.local_peer_id(), b"hello world".to_vec());
|
||||
}
|
||||
if rand::random::<u8>() % 5 >= 3 {
|
||||
let _ = handle2.send_sync_notification(&node1.local_peer_id(), b"hello world".to_vec());
|
||||
}
|
||||
|
||||
// Also randomly disconnect the two nodes from time to time.
|
||||
if rand::random::<u8>() % 20 == 0 {
|
||||
node1.disconnect_peer(node2.local_peer_id(), PROTOCOL_NAME.into());
|
||||
}
|
||||
if rand::random::<u8>() % 20 == 0 {
|
||||
node2.disconnect_peer(node1.local_peer_id(), PROTOCOL_NAME.into());
|
||||
}
|
||||
|
||||
// Grab next event from either `events_stream1` or `events_stream2`.
|
||||
let next_event = {
|
||||
let next1 = handle1.next_event();
|
||||
let next2 = handle2.next_event();
|
||||
// We also await on a small timer, otherwise it is possible for the test to wait
|
||||
// forever while nothing at all happens on the network.
|
||||
let continue_test = futures_timer::Delay::new(Duration::from_millis(20));
|
||||
match future::select(future::select(next1, next2), continue_test).await {
|
||||
future::Either::Left((future::Either::Left((Some(ev), _)), _)) =>
|
||||
future::Either::Left(ev),
|
||||
future::Either::Left((future::Either::Right((Some(ev), _)), _)) =>
|
||||
future::Either::Right(ev),
|
||||
future::Either::Right(_) => continue,
|
||||
_ => break,
|
||||
}
|
||||
};
|
||||
|
||||
match next_event {
|
||||
future::Either::Left(NotificationEvent::ValidateInboundSubstream {
|
||||
result_tx, ..
|
||||
}) => {
|
||||
result_tx.send(ValidationResult::Accept).unwrap();
|
||||
},
|
||||
future::Either::Right(NotificationEvent::ValidateInboundSubstream {
|
||||
result_tx,
|
||||
..
|
||||
}) => {
|
||||
result_tx.send(ValidationResult::Accept).unwrap();
|
||||
},
|
||||
future::Either::Left(NotificationEvent::NotificationStreamOpened { peer, .. }) => {
|
||||
something_happened = true;
|
||||
assert!(!node1_to_node2_open);
|
||||
node1_to_node2_open = true;
|
||||
assert_eq!(peer, node2.local_peer_id());
|
||||
},
|
||||
future::Either::Right(NotificationEvent::NotificationStreamOpened { peer, .. }) => {
|
||||
something_happened = true;
|
||||
assert!(!node2_to_node1_open);
|
||||
node2_to_node1_open = true;
|
||||
assert_eq!(peer, node1.local_peer_id());
|
||||
},
|
||||
future::Either::Left(NotificationEvent::NotificationStreamClosed { peer, .. }) => {
|
||||
assert!(node1_to_node2_open);
|
||||
node1_to_node2_open = false;
|
||||
assert_eq!(peer, node2.local_peer_id());
|
||||
},
|
||||
future::Either::Right(NotificationEvent::NotificationStreamClosed { peer, .. }) => {
|
||||
assert!(node2_to_node1_open);
|
||||
node2_to_node1_open = false;
|
||||
assert_eq!(peer, node1.local_peer_id());
|
||||
},
|
||||
future::Either::Left(NotificationEvent::NotificationReceived { peer, .. }) => {
|
||||
assert!(node1_to_node2_open);
|
||||
assert_eq!(peer, node2.local_peer_id());
|
||||
if rand::random::<u8>() % 5 >= 4 {
|
||||
let _ = handle1
|
||||
.send_sync_notification(&node2.local_peer_id(), b"hello world".to_vec());
|
||||
}
|
||||
},
|
||||
future::Either::Right(NotificationEvent::NotificationReceived { peer, .. }) => {
|
||||
assert!(node2_to_node1_open);
|
||||
assert_eq!(peer, node1.local_peer_id());
|
||||
if rand::random::<u8>() % 5 >= 4 {
|
||||
let _ = handle2
|
||||
.send_sync_notification(&node1.local_peer_id(), b"hello world".to_vec());
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn lots_of_incoming_peers_works() {
|
||||
pezsp_tracing::try_init_simple();
|
||||
let listen_addr = config::build_multiaddr![Memory(rand::random::<u64>())];
|
||||
|
||||
let (main_node, handle1) = TestNetworkBuilder::new()
|
||||
.with_listen_addresses(vec![listen_addr.clone()])
|
||||
.with_set_config(config::SetConfig { in_peers: u32::MAX, ..Default::default() })
|
||||
.build();
|
||||
let mut handle1 = handle1.unwrap();
|
||||
let (main_node, _) = main_node.start_network();
|
||||
|
||||
let main_node_peer_id = main_node.local_peer_id();
|
||||
|
||||
tokio::spawn(async move {
|
||||
while let Some(event) = handle1.next_event().await {
|
||||
if let NotificationEvent::ValidateInboundSubstream { result_tx, .. } = event {
|
||||
result_tx.send(ValidationResult::Accept).unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// We spawn background tasks and push them in this `Vec`. They will all be waited upon before
|
||||
// this test ends.
|
||||
let mut background_tasks_to_wait = Vec::new();
|
||||
|
||||
for _ in 0..32 {
|
||||
let (dialing_node, handle) = TestNetworkBuilder::new()
|
||||
.with_set_config(config::SetConfig {
|
||||
reserved_nodes: vec![MultiaddrWithPeerId {
|
||||
multiaddr: listen_addr.clone(),
|
||||
peer_id: main_node_peer_id,
|
||||
}],
|
||||
..Default::default()
|
||||
})
|
||||
.build();
|
||||
let mut handle = handle.unwrap();
|
||||
let (_, _) = dialing_node.start_network();
|
||||
|
||||
background_tasks_to_wait.push(tokio::spawn(async move {
|
||||
// Create a dummy timer that will "never" fire, and that will be overwritten when we
|
||||
// actually need the timer. Using an Option would be technically cleaner, but it would
|
||||
// make the code below way more complicated.
|
||||
let mut timer = futures_timer::Delay::new(Duration::from_secs(3600 * 24 * 7)).fuse();
|
||||
|
||||
loop {
|
||||
futures::select! {
|
||||
_ = timer => {
|
||||
// Test succeeds when timer fires.
|
||||
return;
|
||||
}
|
||||
ev = handle.next_event().fuse() => match ev.unwrap() {
|
||||
NotificationEvent::ValidateInboundSubstream { result_tx, .. } => {
|
||||
result_tx.send(ValidationResult::Accept).unwrap();
|
||||
}
|
||||
NotificationEvent::NotificationStreamOpened { peer, .. } => {
|
||||
assert_eq!(peer, main_node_peer_id);
|
||||
// Test succeeds after 5 seconds. This timer is here in order to
|
||||
// detect a potential problem after opening.
|
||||
timer = futures_timer::Delay::new(Duration::from_secs(5)).fuse();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
future::join_all(background_tasks_to_wait).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn notifications_back_pressure() {
|
||||
// Node 1 floods node 2 with notifications. Random sleeps are done on node 2 to simulate the
|
||||
// node being busy. We make sure that all notifications are received.
|
||||
|
||||
const TOTAL_NOTIFS: usize = 10_000;
|
||||
|
||||
let (_node1, handle1, node2, handle2) = build_nodes_one_proto();
|
||||
let (mut handle1, mut handle2) = (handle1.unwrap(), handle2.unwrap());
|
||||
let node2_id = node2.local_peer_id();
|
||||
|
||||
let receiver = tokio::spawn(async move {
|
||||
let mut received_notifications = 0;
|
||||
|
||||
while received_notifications < TOTAL_NOTIFS {
|
||||
match handle2.next_event().await.unwrap() {
|
||||
NotificationEvent::ValidateInboundSubstream { result_tx, .. } => {
|
||||
result_tx.send(ValidationResult::Accept).unwrap();
|
||||
},
|
||||
NotificationEvent::NotificationReceived { notification, .. } => {
|
||||
assert_eq!(
|
||||
notification,
|
||||
format!("hello #{}", received_notifications).into_bytes()
|
||||
);
|
||||
received_notifications += 1;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
if rand::random::<u8>() < 2 {
|
||||
tokio::time::sleep(Duration::from_millis(rand::random::<u64>() % 750)).await;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for the `NotificationStreamOpened`.
|
||||
loop {
|
||||
match handle1.next_event().await.unwrap() {
|
||||
NotificationEvent::ValidateInboundSubstream { result_tx, .. } => {
|
||||
result_tx.send(ValidationResult::Accept).unwrap();
|
||||
},
|
||||
NotificationEvent::NotificationStreamOpened { .. } => break,
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
|
||||
// Sending!
|
||||
for num in 0..TOTAL_NOTIFS {
|
||||
handle1
|
||||
.send_async_notification(&node2_id, format!("hello #{}", num).into_bytes())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
receiver.await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fallback_name_working() {
|
||||
pezsp_tracing::try_init_simple();
|
||||
// Node 1 supports the protocols "new" and "old". Node 2 only supports "old". Checks whether
|
||||
// they can connect.
|
||||
const NEW_PROTOCOL_NAME: &str = "/new-shiny-protocol-that-isnt-PROTOCOL_NAME";
|
||||
|
||||
let listen_addr = config::build_multiaddr![Memory(rand::random::<u64>())];
|
||||
let (config, mut handle1) = config::NonDefaultSetConfig::new(
|
||||
NEW_PROTOCOL_NAME.into(),
|
||||
vec![PROTOCOL_NAME.into()],
|
||||
1024 * 1024,
|
||||
None,
|
||||
Default::default(),
|
||||
);
|
||||
let (network1, _) = TestNetworkBuilder::new()
|
||||
.with_notification_protocol(config)
|
||||
.with_config(config::NetworkConfiguration {
|
||||
listen_addresses: vec![listen_addr.clone()],
|
||||
transport: TransportConfig::MemoryOnly,
|
||||
..config::NetworkConfiguration::new_local()
|
||||
})
|
||||
.build();
|
||||
|
||||
let (node1, _) = network1.start_network();
|
||||
|
||||
let (network2, handle2) = TestNetworkBuilder::new()
|
||||
.with_set_config(config::SetConfig {
|
||||
reserved_nodes: vec![MultiaddrWithPeerId {
|
||||
multiaddr: listen_addr,
|
||||
peer_id: node1.local_peer_id(),
|
||||
}],
|
||||
..Default::default()
|
||||
})
|
||||
.build();
|
||||
let mut handle2 = handle2.unwrap();
|
||||
let _ = network2.start_network();
|
||||
|
||||
let receiver = tokio::spawn(async move {
|
||||
// Wait for the `NotificationStreamOpened`.
|
||||
loop {
|
||||
match handle2.next_event().await.unwrap() {
|
||||
NotificationEvent::ValidateInboundSubstream { result_tx, .. } => {
|
||||
result_tx.send(ValidationResult::Accept).unwrap();
|
||||
},
|
||||
NotificationEvent::NotificationStreamOpened { negotiated_fallback, .. } => {
|
||||
assert_eq!(negotiated_fallback, None);
|
||||
break;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for the `NotificationStreamOpened`.
|
||||
loop {
|
||||
match handle1.next_event().await.unwrap() {
|
||||
NotificationEvent::ValidateInboundSubstream { result_tx, .. } => {
|
||||
result_tx.send(ValidationResult::Accept).unwrap();
|
||||
},
|
||||
NotificationEvent::NotificationStreamOpened { negotiated_fallback, .. } => {
|
||||
assert_eq!(negotiated_fallback, Some(PROTOCOL_NAME.into()));
|
||||
break;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
receiver.await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic(expected = "don't match the transport")]
|
||||
async fn ensure_listen_addresses_consistent_with_transport_memory() {
|
||||
let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)];
|
||||
|
||||
let _ = TestNetworkBuilder::new()
|
||||
.with_config(config::NetworkConfiguration {
|
||||
listen_addresses: vec![listen_addr.clone()],
|
||||
transport: TransportConfig::MemoryOnly,
|
||||
..config::NetworkConfiguration::new(
|
||||
"test-node",
|
||||
"test-client",
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.build()
|
||||
.0
|
||||
.start_network();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic(expected = "don't match the transport")]
|
||||
async fn ensure_listen_addresses_consistent_with_transport_not_memory() {
|
||||
let listen_addr = config::build_multiaddr![Memory(rand::random::<u64>())];
|
||||
|
||||
let _ = TestNetworkBuilder::new()
|
||||
.with_config(config::NetworkConfiguration {
|
||||
listen_addresses: vec![listen_addr.clone()],
|
||||
..config::NetworkConfiguration::new(
|
||||
"test-node",
|
||||
"test-client",
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.build()
|
||||
.0
|
||||
.start_network();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic(expected = "don't match the transport")]
|
||||
async fn ensure_boot_node_addresses_consistent_with_transport_memory() {
|
||||
let listen_addr = config::build_multiaddr![Memory(rand::random::<u64>())];
|
||||
let boot_node = MultiaddrWithPeerId {
|
||||
multiaddr: config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)],
|
||||
peer_id: PeerId::random().into(),
|
||||
};
|
||||
|
||||
let _ = TestNetworkBuilder::new()
|
||||
.with_config(config::NetworkConfiguration {
|
||||
listen_addresses: vec![listen_addr.clone()],
|
||||
transport: TransportConfig::MemoryOnly,
|
||||
boot_nodes: vec![boot_node],
|
||||
..config::NetworkConfiguration::new(
|
||||
"test-node",
|
||||
"test-client",
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.build()
|
||||
.0
|
||||
.start_network();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic(expected = "don't match the transport")]
|
||||
async fn ensure_boot_node_addresses_consistent_with_transport_not_memory() {
|
||||
let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)];
|
||||
let boot_node = MultiaddrWithPeerId {
|
||||
multiaddr: config::build_multiaddr![Memory(rand::random::<u64>())],
|
||||
peer_id: PeerId::random().into(),
|
||||
};
|
||||
|
||||
let _ = TestNetworkBuilder::new()
|
||||
.with_config(config::NetworkConfiguration {
|
||||
listen_addresses: vec![listen_addr.clone()],
|
||||
boot_nodes: vec![boot_node],
|
||||
..config::NetworkConfiguration::new(
|
||||
"test-node",
|
||||
"test-client",
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.build()
|
||||
.0
|
||||
.start_network();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic(expected = "don't match the transport")]
|
||||
async fn ensure_reserved_node_addresses_consistent_with_transport_memory() {
|
||||
let listen_addr = config::build_multiaddr![Memory(rand::random::<u64>())];
|
||||
let reserved_node = MultiaddrWithPeerId {
|
||||
multiaddr: config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)],
|
||||
peer_id: PeerId::random().into(),
|
||||
};
|
||||
|
||||
let _ = TestNetworkBuilder::new()
|
||||
.with_config(config::NetworkConfiguration {
|
||||
listen_addresses: vec![listen_addr.clone()],
|
||||
transport: TransportConfig::MemoryOnly,
|
||||
default_peers_set: config::SetConfig {
|
||||
reserved_nodes: vec![reserved_node],
|
||||
..Default::default()
|
||||
},
|
||||
..config::NetworkConfiguration::new(
|
||||
"test-node",
|
||||
"test-client",
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.build()
|
||||
.0
|
||||
.start_network();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic(expected = "don't match the transport")]
|
||||
async fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() {
|
||||
let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)];
|
||||
let reserved_node = MultiaddrWithPeerId {
|
||||
multiaddr: config::build_multiaddr![Memory(rand::random::<u64>())],
|
||||
peer_id: PeerId::random().into(),
|
||||
};
|
||||
|
||||
let _ = TestNetworkBuilder::new()
|
||||
.with_config(config::NetworkConfiguration {
|
||||
listen_addresses: vec![listen_addr.clone()],
|
||||
default_peers_set: config::SetConfig {
|
||||
reserved_nodes: vec![reserved_node],
|
||||
..Default::default()
|
||||
},
|
||||
..config::NetworkConfiguration::new(
|
||||
"test-node",
|
||||
"test-client",
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.build()
|
||||
.0
|
||||
.start_network();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic(expected = "don't match the transport")]
|
||||
async fn ensure_public_addresses_consistent_with_transport_memory() {
|
||||
let listen_addr = config::build_multiaddr![Memory(rand::random::<u64>())];
|
||||
let public_address = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)];
|
||||
|
||||
let _ = TestNetworkBuilder::new()
|
||||
.with_config(config::NetworkConfiguration {
|
||||
listen_addresses: vec![listen_addr.clone()],
|
||||
transport: TransportConfig::MemoryOnly,
|
||||
public_addresses: vec![public_address],
|
||||
..config::NetworkConfiguration::new(
|
||||
"test-node",
|
||||
"test-client",
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.build()
|
||||
.0
|
||||
.start_network();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic(expected = "don't match the transport")]
|
||||
async fn ensure_public_addresses_consistent_with_transport_not_memory() {
|
||||
let listen_addr = config::build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(0_u16)];
|
||||
let public_address = config::build_multiaddr![Memory(rand::random::<u64>())];
|
||||
|
||||
let _ = TestNetworkBuilder::new()
|
||||
.with_config(config::NetworkConfiguration {
|
||||
listen_addresses: vec![listen_addr.clone()],
|
||||
public_addresses: vec![public_address],
|
||||
..config::NetworkConfiguration::new(
|
||||
"test-node",
|
||||
"test-client",
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.build()
|
||||
.0
|
||||
.start_network();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user