mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-20 17:25:41 +00:00
add fallback request for req-response protocols (#2771)
Previously, it was only possible to retry the same request on a different protocol name that had the exact same binary payloads. Introduce a way of trying a different request on a different protocol if the first one fails with Unsupported protocol. This helps with adding new req-response versions in polkadot while preserving compatibility with unupgraded nodes. The way req-response protocols were bumped previously was that they were bundled with some other notifications protocol upgrade, like for async backing (but that is more complicated, especially if the feature does not require any changes to a notifications protocol). Will be needed for implementing https://github.com/polkadot-fellows/RFCs/pull/47 TODO: - [x] add tests - [x] add guidance docs in polkadot about req-response protocol versioning
This commit is contained in:
@@ -139,6 +139,7 @@ mod tests {
|
|||||||
use futures::{executor, future};
|
use futures::{executor, future};
|
||||||
|
|
||||||
use parity_scale_codec::Encode;
|
use parity_scale_codec::Encode;
|
||||||
|
use sc_network::ProtocolName;
|
||||||
use sp_core::testing::TaskExecutor;
|
use sp_core::testing::TaskExecutor;
|
||||||
|
|
||||||
use polkadot_node_primitives::BlockData;
|
use polkadot_node_primitives::BlockData;
|
||||||
@@ -231,7 +232,10 @@ mod tests {
|
|||||||
Some(Requests::PoVFetchingV1(outgoing)) => {outgoing}
|
Some(Requests::PoVFetchingV1(outgoing)) => {outgoing}
|
||||||
);
|
);
|
||||||
req.pending_response
|
req.pending_response
|
||||||
.send(Ok(PoVFetchingResponse::PoV(pov.clone()).encode()))
|
.send(Ok((
|
||||||
|
PoVFetchingResponse::PoV(pov.clone()).encode(),
|
||||||
|
ProtocolName::from(""),
|
||||||
|
)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
break
|
break
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ use futures::{
|
|||||||
Future, FutureExt, StreamExt,
|
Future, FutureExt, StreamExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
use sc_network as network;
|
use sc_network::{self as network, ProtocolName};
|
||||||
use sp_keyring::Sr25519Keyring;
|
use sp_keyring::Sr25519Keyring;
|
||||||
|
|
||||||
use polkadot_node_network_protocol::request_response::{v1, Recipient};
|
use polkadot_node_network_protocol::request_response::{v1, Recipient};
|
||||||
@@ -252,7 +252,7 @@ impl TestRun {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
req.pending_response
|
req.pending_response
|
||||||
.send(response.map(Encode::encode))
|
.send(response.map(|r| (r.encode(), ProtocolName::from(""))))
|
||||||
.expect("Sending response should succeed");
|
.expect("Sending response should succeed");
|
||||||
}
|
}
|
||||||
return (valid_responses == 0) && self.valid_chunks.is_empty()
|
return (valid_responses == 0) && self.valid_chunks.is_empty()
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use std::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use network::ProtocolName;
|
||||||
use polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle;
|
use polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle;
|
||||||
use polkadot_node_subsystem_util::TimeoutExt;
|
use polkadot_node_subsystem_util::TimeoutExt;
|
||||||
|
|
||||||
@@ -324,7 +325,11 @@ fn to_incoming_req(
|
|||||||
let response = rx.await;
|
let response = rx.await;
|
||||||
let payload = response.expect("Unexpected canceled request").result;
|
let payload = response.expect("Unexpected canceled request").result;
|
||||||
pending_response
|
pending_response
|
||||||
.send(payload.map_err(|_| network::RequestFailure::Refused))
|
.send(
|
||||||
|
payload
|
||||||
|
.map_err(|_| network::RequestFailure::Refused)
|
||||||
|
.map(|r| (r, ProtocolName::from(""))),
|
||||||
|
)
|
||||||
.expect("Sending response is expected to work");
|
.expect("Sending response is expected to work");
|
||||||
}
|
}
|
||||||
.boxed(),
|
.boxed(),
|
||||||
|
|||||||
@@ -22,13 +22,14 @@ use futures_timer::Delay;
|
|||||||
|
|
||||||
use parity_scale_codec::Encode;
|
use parity_scale_codec::Encode;
|
||||||
use polkadot_node_network_protocol::request_response::{
|
use polkadot_node_network_protocol::request_response::{
|
||||||
self as req_res, IncomingRequest, Recipient, ReqProtocolNames, Requests,
|
self as req_res, v1::AvailableDataFetchingRequest, IncomingRequest, Protocol, Recipient,
|
||||||
|
ReqProtocolNames, Requests,
|
||||||
};
|
};
|
||||||
use polkadot_node_subsystem_test_helpers::derive_erasure_chunks_with_proofs_and_root;
|
use polkadot_node_subsystem_test_helpers::derive_erasure_chunks_with_proofs_and_root;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use sc_network::{config::RequestResponseConfig, IfDisconnected, OutboundFailure, RequestFailure};
|
use sc_network::{IfDisconnected, OutboundFailure, ProtocolName, RequestFailure};
|
||||||
|
|
||||||
use polkadot_node_primitives::{BlockData, PoV, Proof};
|
use polkadot_node_primitives::{BlockData, PoV, Proof};
|
||||||
use polkadot_node_subsystem::messages::{
|
use polkadot_node_subsystem::messages::{
|
||||||
@@ -48,8 +49,18 @@ type VirtualOverseer = TestSubsystemContextHandle<AvailabilityRecoveryMessage>;
|
|||||||
// Deterministic genesis hash for protocol names
|
// Deterministic genesis hash for protocol names
|
||||||
const GENESIS_HASH: Hash = Hash::repeat_byte(0xff);
|
const GENESIS_HASH: Hash = Hash::repeat_byte(0xff);
|
||||||
|
|
||||||
fn test_harness_fast_path<T: Future<Output = (VirtualOverseer, RequestResponseConfig)>>(
|
fn request_receiver(
|
||||||
test: impl FnOnce(VirtualOverseer, RequestResponseConfig) -> T,
|
req_protocol_names: &ReqProtocolNames,
|
||||||
|
) -> IncomingRequestReceiver<AvailableDataFetchingRequest> {
|
||||||
|
let receiver = IncomingRequest::get_config_receiver(req_protocol_names);
|
||||||
|
// Don't close the sending end of the request protocol. Otherwise, the subsystem will terminate.
|
||||||
|
std::mem::forget(receiver.1.inbound_queue);
|
||||||
|
receiver.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_harness<T: Future<Output = VirtualOverseer>>(
|
||||||
|
subsystem: AvailabilityRecoverySubsystem,
|
||||||
|
test: impl FnOnce(VirtualOverseer) -> T,
|
||||||
) {
|
) {
|
||||||
let _ = env_logger::builder()
|
let _ = env_logger::builder()
|
||||||
.is_test(true)
|
.is_test(true)
|
||||||
@@ -60,22 +71,18 @@ fn test_harness_fast_path<T: Future<Output = (VirtualOverseer, RequestResponseCo
|
|||||||
|
|
||||||
let (context, virtual_overseer) = make_subsystem_context(pool.clone());
|
let (context, virtual_overseer) = make_subsystem_context(pool.clone());
|
||||||
|
|
||||||
let (collation_req_receiver, req_cfg) =
|
|
||||||
IncomingRequest::get_config_receiver(&ReqProtocolNames::new(&GENESIS_HASH, None));
|
|
||||||
let subsystem =
|
|
||||||
AvailabilityRecoverySubsystem::with_fast_path(collation_req_receiver, Metrics::new_dummy());
|
|
||||||
let subsystem = async {
|
let subsystem = async {
|
||||||
subsystem.run(context).await.unwrap();
|
subsystem.run(context).await.unwrap();
|
||||||
};
|
};
|
||||||
|
|
||||||
let test_fut = test(virtual_overseer, req_cfg);
|
let test_fut = test(virtual_overseer);
|
||||||
|
|
||||||
futures::pin_mut!(test_fut);
|
futures::pin_mut!(test_fut);
|
||||||
futures::pin_mut!(subsystem);
|
futures::pin_mut!(subsystem);
|
||||||
|
|
||||||
executor::block_on(future::join(
|
executor::block_on(future::join(
|
||||||
async move {
|
async move {
|
||||||
let (mut overseer, _req_cfg) = test_fut.await;
|
let mut overseer = test_fut.await;
|
||||||
overseer_signal(&mut overseer, OverseerSignal::Conclude).await;
|
overseer_signal(&mut overseer, OverseerSignal::Conclude).await;
|
||||||
},
|
},
|
||||||
subsystem,
|
subsystem,
|
||||||
@@ -83,80 +90,6 @@ fn test_harness_fast_path<T: Future<Output = (VirtualOverseer, RequestResponseCo
|
|||||||
.1
|
.1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_harness_chunks_only<T: Future<Output = (VirtualOverseer, RequestResponseConfig)>>(
|
|
||||||
test: impl FnOnce(VirtualOverseer, RequestResponseConfig) -> T,
|
|
||||||
) {
|
|
||||||
let _ = env_logger::builder()
|
|
||||||
.is_test(true)
|
|
||||||
.filter(Some("polkadot_availability_recovery"), log::LevelFilter::Trace)
|
|
||||||
.try_init();
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
|
|
||||||
let (context, virtual_overseer) = make_subsystem_context(pool.clone());
|
|
||||||
|
|
||||||
let (collation_req_receiver, req_cfg) =
|
|
||||||
IncomingRequest::get_config_receiver(&ReqProtocolNames::new(&GENESIS_HASH, None));
|
|
||||||
let subsystem = AvailabilityRecoverySubsystem::with_chunks_only(
|
|
||||||
collation_req_receiver,
|
|
||||||
Metrics::new_dummy(),
|
|
||||||
);
|
|
||||||
let subsystem = subsystem.run(context);
|
|
||||||
|
|
||||||
let test_fut = test(virtual_overseer, req_cfg);
|
|
||||||
|
|
||||||
futures::pin_mut!(test_fut);
|
|
||||||
futures::pin_mut!(subsystem);
|
|
||||||
|
|
||||||
executor::block_on(future::join(
|
|
||||||
async move {
|
|
||||||
let (mut overseer, _req_cfg) = test_fut.await;
|
|
||||||
overseer_signal(&mut overseer, OverseerSignal::Conclude).await;
|
|
||||||
},
|
|
||||||
subsystem,
|
|
||||||
))
|
|
||||||
.1
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_harness_chunks_if_pov_large<
|
|
||||||
T: Future<Output = (VirtualOverseer, RequestResponseConfig)>,
|
|
||||||
>(
|
|
||||||
test: impl FnOnce(VirtualOverseer, RequestResponseConfig) -> T,
|
|
||||||
) {
|
|
||||||
let _ = env_logger::builder()
|
|
||||||
.is_test(true)
|
|
||||||
.filter(Some("polkadot_availability_recovery"), log::LevelFilter::Trace)
|
|
||||||
.try_init();
|
|
||||||
|
|
||||||
let pool = sp_core::testing::TaskExecutor::new();
|
|
||||||
|
|
||||||
let (context, virtual_overseer) = make_subsystem_context(pool.clone());
|
|
||||||
|
|
||||||
let (collation_req_receiver, req_cfg) =
|
|
||||||
IncomingRequest::get_config_receiver(&ReqProtocolNames::new(&GENESIS_HASH, None));
|
|
||||||
let subsystem = AvailabilityRecoverySubsystem::with_chunks_if_pov_large(
|
|
||||||
collation_req_receiver,
|
|
||||||
Metrics::new_dummy(),
|
|
||||||
);
|
|
||||||
let subsystem = subsystem.run(context);
|
|
||||||
|
|
||||||
let test_fut = test(virtual_overseer, req_cfg);
|
|
||||||
|
|
||||||
futures::pin_mut!(test_fut);
|
|
||||||
futures::pin_mut!(subsystem);
|
|
||||||
|
|
||||||
executor::block_on(future::join(
|
|
||||||
async move {
|
|
||||||
let (mut overseer, _req_cfg) = test_fut.await;
|
|
||||||
overseer_signal(&mut overseer, OverseerSignal::Conclude).await;
|
|
||||||
},
|
|
||||||
subsystem,
|
|
||||||
))
|
|
||||||
.1
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
const TIMEOUT: Duration = Duration::from_millis(300);
|
const TIMEOUT: Duration = Duration::from_millis(300);
|
||||||
|
|
||||||
macro_rules! delay {
|
macro_rules! delay {
|
||||||
@@ -342,11 +275,12 @@ impl TestState {
|
|||||||
|
|
||||||
async fn test_chunk_requests(
|
async fn test_chunk_requests(
|
||||||
&self,
|
&self,
|
||||||
|
req_protocol_names: &ReqProtocolNames,
|
||||||
candidate_hash: CandidateHash,
|
candidate_hash: CandidateHash,
|
||||||
virtual_overseer: &mut VirtualOverseer,
|
virtual_overseer: &mut VirtualOverseer,
|
||||||
n: usize,
|
n: usize,
|
||||||
who_has: impl Fn(usize) -> Has,
|
who_has: impl Fn(usize) -> Has,
|
||||||
) -> Vec<oneshot::Sender<std::result::Result<Vec<u8>, RequestFailure>>> {
|
) -> Vec<oneshot::Sender<std::result::Result<(Vec<u8>, ProtocolName), RequestFailure>>> {
|
||||||
// arbitrary order.
|
// arbitrary order.
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut senders = Vec::new();
|
let mut senders = Vec::new();
|
||||||
@@ -380,7 +314,7 @@ impl TestState {
|
|||||||
|
|
||||||
let _ = req.pending_response.send(
|
let _ = req.pending_response.send(
|
||||||
available_data.map(|r|
|
available_data.map(|r|
|
||||||
req_res::v1::ChunkFetchingResponse::from(r).encode()
|
(req_res::v1::ChunkFetchingResponse::from(r).encode(), req_protocol_names.get_name(Protocol::ChunkFetchingV1))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -394,10 +328,11 @@ impl TestState {
|
|||||||
|
|
||||||
async fn test_full_data_requests(
|
async fn test_full_data_requests(
|
||||||
&self,
|
&self,
|
||||||
|
req_protocol_names: &ReqProtocolNames,
|
||||||
candidate_hash: CandidateHash,
|
candidate_hash: CandidateHash,
|
||||||
virtual_overseer: &mut VirtualOverseer,
|
virtual_overseer: &mut VirtualOverseer,
|
||||||
who_has: impl Fn(usize) -> Has,
|
who_has: impl Fn(usize) -> Has,
|
||||||
) -> Vec<oneshot::Sender<std::result::Result<Vec<u8>, RequestFailure>>> {
|
) -> Vec<oneshot::Sender<std::result::Result<(Vec<u8>, ProtocolName), RequestFailure>>> {
|
||||||
let mut senders = Vec::new();
|
let mut senders = Vec::new();
|
||||||
for _ in 0..self.validators.len() {
|
for _ in 0..self.validators.len() {
|
||||||
// Receive a request for a chunk.
|
// Receive a request for a chunk.
|
||||||
@@ -433,9 +368,10 @@ impl TestState {
|
|||||||
let done = available_data.as_ref().ok().map_or(false, |x| x.is_some());
|
let done = available_data.as_ref().ok().map_or(false, |x| x.is_some());
|
||||||
|
|
||||||
let _ = req.pending_response.send(
|
let _ = req.pending_response.send(
|
||||||
available_data.map(|r|
|
available_data.map(|r|(
|
||||||
req_res::v1::AvailableDataFetchingResponse::from(r).encode()
|
req_res::v1::AvailableDataFetchingResponse::from(r).encode(),
|
||||||
)
|
req_protocol_names.get_name(Protocol::AvailableDataFetchingV1)
|
||||||
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
if done { break }
|
if done { break }
|
||||||
@@ -532,8 +468,13 @@ impl Default for TestState {
|
|||||||
#[test]
|
#[test]
|
||||||
fn availability_is_recovered_from_chunks_if_no_group_provided() {
|
fn availability_is_recovered_from_chunks_if_no_group_provided() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_fast_path(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_fast_path(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -565,6 +506,7 @@ fn availability_is_recovered_from_chunks_if_no_group_provided() {
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.threshold(),
|
test_state.threshold(),
|
||||||
@@ -600,6 +542,7 @@ fn availability_is_recovered_from_chunks_if_no_group_provided() {
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
new_candidate.hash(),
|
new_candidate.hash(),
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.impossibility_threshold(),
|
test_state.impossibility_threshold(),
|
||||||
@@ -609,15 +552,20 @@ fn availability_is_recovered_from_chunks_if_no_group_provided() {
|
|||||||
|
|
||||||
// A request times out with `Unavailable` error.
|
// A request times out with `Unavailable` error.
|
||||||
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn availability_is_recovered_from_chunks_even_if_backing_group_supplied_if_chunks_only() {
|
fn availability_is_recovered_from_chunks_even_if_backing_group_supplied_if_chunks_only() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_chunks_only(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -649,6 +597,7 @@ fn availability_is_recovered_from_chunks_even_if_backing_group_supplied_if_chunk
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.threshold(),
|
test_state.threshold(),
|
||||||
@@ -684,6 +633,7 @@ fn availability_is_recovered_from_chunks_even_if_backing_group_supplied_if_chunk
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
new_candidate.hash(),
|
new_candidate.hash(),
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.impossibility_threshold(),
|
test_state.impossibility_threshold(),
|
||||||
@@ -693,15 +643,20 @@ fn availability_is_recovered_from_chunks_even_if_backing_group_supplied_if_chunk
|
|||||||
|
|
||||||
// A request times out with `Unavailable` error.
|
// A request times out with `Unavailable` error.
|
||||||
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bad_merkle_path_leads_to_recovery_error() {
|
fn bad_merkle_path_leads_to_recovery_error() {
|
||||||
let mut test_state = TestState::default();
|
let mut test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_fast_path(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_fast_path(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -740,6 +695,7 @@ fn bad_merkle_path_leads_to_recovery_error() {
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.impossibility_threshold(),
|
test_state.impossibility_threshold(),
|
||||||
@@ -749,15 +705,20 @@ fn bad_merkle_path_leads_to_recovery_error() {
|
|||||||
|
|
||||||
// A request times out with `Unavailable` error.
|
// A request times out with `Unavailable` error.
|
||||||
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn wrong_chunk_index_leads_to_recovery_error() {
|
fn wrong_chunk_index_leads_to_recovery_error() {
|
||||||
let mut test_state = TestState::default();
|
let mut test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_fast_path(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_fast_path(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -796,6 +757,7 @@ fn wrong_chunk_index_leads_to_recovery_error() {
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.impossibility_threshold(),
|
test_state.impossibility_threshold(),
|
||||||
@@ -805,15 +767,20 @@ fn wrong_chunk_index_leads_to_recovery_error() {
|
|||||||
|
|
||||||
// A request times out with `Unavailable` error as there are no good peers.
|
// A request times out with `Unavailable` error as there are no good peers.
|
||||||
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_erasure_coding_leads_to_invalid_error() {
|
fn invalid_erasure_coding_leads_to_invalid_error() {
|
||||||
let mut test_state = TestState::default();
|
let mut test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_fast_path(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_fast_path(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
let pov = PoV { block_data: BlockData(vec![69; 64]) };
|
let pov = PoV { block_data: BlockData(vec![69; 64]) };
|
||||||
|
|
||||||
let (bad_chunks, bad_erasure_root) = derive_erasure_chunks_with_proofs_and_root(
|
let (bad_chunks, bad_erasure_root) = derive_erasure_chunks_with_proofs_and_root(
|
||||||
@@ -859,6 +826,7 @@ fn invalid_erasure_coding_leads_to_invalid_error() {
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.threshold(),
|
test_state.threshold(),
|
||||||
@@ -868,15 +836,20 @@ fn invalid_erasure_coding_leads_to_invalid_error() {
|
|||||||
|
|
||||||
// f+1 'valid' chunks can't produce correct data.
|
// f+1 'valid' chunks can't produce correct data.
|
||||||
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Invalid);
|
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Invalid);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fast_path_backing_group_recovers() {
|
fn fast_path_backing_group_recovers() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_fast_path(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_fast_path(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -911,20 +884,30 @@ fn fast_path_backing_group_recovers() {
|
|||||||
test_state.respond_to_available_data_query(&mut virtual_overseer, false).await;
|
test_state.respond_to_available_data_query(&mut virtual_overseer, false).await;
|
||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_full_data_requests(candidate_hash, &mut virtual_overseer, who_has)
|
.test_full_data_requests(
|
||||||
|
&req_protocol_names,
|
||||||
|
candidate_hash,
|
||||||
|
&mut virtual_overseer,
|
||||||
|
who_has,
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Recovered data should match the original one.
|
// Recovered data should match the original one.
|
||||||
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn recovers_from_only_chunks_if_pov_large() {
|
fn recovers_from_only_chunks_if_pov_large() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_chunks_if_pov_large(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_chunks_if_pov_large(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -965,6 +948,7 @@ fn recovers_from_only_chunks_if_pov_large() {
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.threshold(),
|
test_state.threshold(),
|
||||||
@@ -1009,6 +993,7 @@ fn recovers_from_only_chunks_if_pov_large() {
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
new_candidate.hash(),
|
new_candidate.hash(),
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.impossibility_threshold(),
|
test_state.impossibility_threshold(),
|
||||||
@@ -1018,15 +1003,20 @@ fn recovers_from_only_chunks_if_pov_large() {
|
|||||||
|
|
||||||
// A request times out with `Unavailable` error.
|
// A request times out with `Unavailable` error.
|
||||||
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fast_path_backing_group_recovers_if_pov_small() {
|
fn fast_path_backing_group_recovers_if_pov_small() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_chunks_if_pov_large(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_chunks_if_pov_large(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -1070,20 +1060,30 @@ fn fast_path_backing_group_recovers_if_pov_small() {
|
|||||||
test_state.respond_to_available_data_query(&mut virtual_overseer, false).await;
|
test_state.respond_to_available_data_query(&mut virtual_overseer, false).await;
|
||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_full_data_requests(candidate_hash, &mut virtual_overseer, who_has)
|
.test_full_data_requests(
|
||||||
|
&req_protocol_names,
|
||||||
|
candidate_hash,
|
||||||
|
&mut virtual_overseer,
|
||||||
|
who_has,
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Recovered data should match the original one.
|
// Recovered data should match the original one.
|
||||||
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_answers_in_fast_path_causes_chunk_requests() {
|
fn no_answers_in_fast_path_causes_chunk_requests() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_fast_path(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_fast_path(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -1119,13 +1119,19 @@ fn no_answers_in_fast_path_causes_chunk_requests() {
|
|||||||
test_state.respond_to_available_data_query(&mut virtual_overseer, false).await;
|
test_state.respond_to_available_data_query(&mut virtual_overseer, false).await;
|
||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_full_data_requests(candidate_hash, &mut virtual_overseer, who_has)
|
.test_full_data_requests(
|
||||||
|
&req_protocol_names,
|
||||||
|
candidate_hash,
|
||||||
|
&mut virtual_overseer,
|
||||||
|
who_has,
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
test_state.respond_to_query_all_request(&mut virtual_overseer, |_| false).await;
|
test_state.respond_to_query_all_request(&mut virtual_overseer, |_| false).await;
|
||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.threshold(),
|
test_state.threshold(),
|
||||||
@@ -1135,15 +1141,20 @@ fn no_answers_in_fast_path_causes_chunk_requests() {
|
|||||||
|
|
||||||
// Recovered data should match the original one.
|
// Recovered data should match the original one.
|
||||||
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn task_canceled_when_receivers_dropped() {
|
fn task_canceled_when_receivers_dropped() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_chunks_only(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -1170,7 +1181,7 @@ fn task_canceled_when_receivers_dropped() {
|
|||||||
|
|
||||||
for _ in 0..test_state.validators.len() {
|
for _ in 0..test_state.validators.len() {
|
||||||
match virtual_overseer.recv().timeout(TIMEOUT).await {
|
match virtual_overseer.recv().timeout(TIMEOUT).await {
|
||||||
None => return (virtual_overseer, req_cfg),
|
None => return virtual_overseer,
|
||||||
Some(_) => continue,
|
Some(_) => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1182,8 +1193,13 @@ fn task_canceled_when_receivers_dropped() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn chunks_retry_until_all_nodes_respond() {
|
fn chunks_retry_until_all_nodes_respond() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_chunks_only(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -1215,6 +1231,7 @@ fn chunks_retry_until_all_nodes_respond() {
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.validators.len() - test_state.threshold(),
|
test_state.validators.len() - test_state.threshold(),
|
||||||
@@ -1225,6 +1242,7 @@ fn chunks_retry_until_all_nodes_respond() {
|
|||||||
// we get to go another round!
|
// we get to go another round!
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.impossibility_threshold(),
|
test_state.impossibility_threshold(),
|
||||||
@@ -1234,15 +1252,20 @@ fn chunks_retry_until_all_nodes_respond() {
|
|||||||
|
|
||||||
// Recovered data should match the original one.
|
// Recovered data should match the original one.
|
||||||
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
assert_eq!(rx.await.unwrap().unwrap_err(), RecoveryError::Unavailable);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn not_returning_requests_wont_stall_retrieval() {
|
fn not_returning_requests_wont_stall_retrieval() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_chunks_only(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -1277,13 +1300,18 @@ fn not_returning_requests_wont_stall_retrieval() {
|
|||||||
|
|
||||||
// Not returning senders won't cause the retrieval to stall:
|
// Not returning senders won't cause the retrieval to stall:
|
||||||
let _senders = test_state
|
let _senders = test_state
|
||||||
.test_chunk_requests(candidate_hash, &mut virtual_overseer, not_returning_count, |_| {
|
.test_chunk_requests(
|
||||||
Has::DoesNotReturn
|
&req_protocol_names,
|
||||||
})
|
candidate_hash,
|
||||||
|
&mut virtual_overseer,
|
||||||
|
not_returning_count,
|
||||||
|
|_| Has::DoesNotReturn,
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
// Should start over:
|
// Should start over:
|
||||||
@@ -1295,6 +1323,7 @@ fn not_returning_requests_wont_stall_retrieval() {
|
|||||||
// we get to go another round!
|
// we get to go another round!
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.threshold(),
|
test_state.threshold(),
|
||||||
@@ -1304,15 +1333,20 @@ fn not_returning_requests_wont_stall_retrieval() {
|
|||||||
|
|
||||||
// Recovered data should match the original one:
|
// Recovered data should match the original one:
|
||||||
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn all_not_returning_requests_still_recovers_on_return() {
|
fn all_not_returning_requests_still_recovers_on_return() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_chunks_only(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -1344,6 +1378,7 @@ fn all_not_returning_requests_still_recovers_on_return() {
|
|||||||
|
|
||||||
let senders = test_state
|
let senders = test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.validators.len(),
|
test_state.validators.len(),
|
||||||
@@ -1358,6 +1393,7 @@ fn all_not_returning_requests_still_recovers_on_return() {
|
|||||||
std::mem::drop(senders);
|
std::mem::drop(senders);
|
||||||
},
|
},
|
||||||
test_state.test_chunk_requests(
|
test_state.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
// Should start over:
|
// Should start over:
|
||||||
@@ -1370,6 +1406,7 @@ fn all_not_returning_requests_still_recovers_on_return() {
|
|||||||
// we get to go another round!
|
// we get to go another round!
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.threshold(),
|
test_state.threshold(),
|
||||||
@@ -1379,15 +1416,20 @@ fn all_not_returning_requests_still_recovers_on_return() {
|
|||||||
|
|
||||||
// Recovered data should match the original one:
|
// Recovered data should match the original one:
|
||||||
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn returns_early_if_we_have_the_data() {
|
fn returns_early_if_we_have_the_data() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_chunks_only(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -1414,15 +1456,20 @@ fn returns_early_if_we_have_the_data() {
|
|||||||
test_state.respond_to_available_data_query(&mut virtual_overseer, true).await;
|
test_state.respond_to_available_data_query(&mut virtual_overseer, true).await;
|
||||||
|
|
||||||
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn does_not_query_local_validator() {
|
fn does_not_query_local_validator() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_chunks_only(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -1453,6 +1500,7 @@ fn does_not_query_local_validator() {
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.validators.len(),
|
test_state.validators.len(),
|
||||||
@@ -1463,6 +1511,7 @@ fn does_not_query_local_validator() {
|
|||||||
// second round, make sure it uses the local chunk.
|
// second round, make sure it uses the local chunk.
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.threshold() - 1,
|
test_state.threshold() - 1,
|
||||||
@@ -1471,15 +1520,20 @@ fn does_not_query_local_validator() {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_local_chunk_is_ignored() {
|
fn invalid_local_chunk_is_ignored() {
|
||||||
let test_state = TestState::default();
|
let test_state = TestState::default();
|
||||||
|
let req_protocol_names = ReqProtocolNames::new(&GENESIS_HASH, None);
|
||||||
|
let subsystem = AvailabilityRecoverySubsystem::with_chunks_only(
|
||||||
|
request_receiver(&req_protocol_names),
|
||||||
|
Metrics::new_dummy(),
|
||||||
|
);
|
||||||
|
|
||||||
test_harness_chunks_only(|mut virtual_overseer, req_cfg| async move {
|
test_harness(subsystem, |mut virtual_overseer| async move {
|
||||||
overseer_signal(
|
overseer_signal(
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf(
|
||||||
@@ -1512,6 +1566,7 @@ fn invalid_local_chunk_is_ignored() {
|
|||||||
|
|
||||||
test_state
|
test_state
|
||||||
.test_chunk_requests(
|
.test_chunk_requests(
|
||||||
|
&req_protocol_names,
|
||||||
candidate_hash,
|
candidate_hash,
|
||||||
&mut virtual_overseer,
|
&mut virtual_overseer,
|
||||||
test_state.threshold() - 1,
|
test_state.threshold() - 1,
|
||||||
@@ -1520,6 +1575,6 @@ fn invalid_local_chunk_is_ignored() {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
assert_eq!(rx.await.unwrap().unwrap(), test_state.available_data);
|
||||||
(virtual_overseer, req_cfg)
|
virtual_overseer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,7 +264,8 @@ impl Network for Arc<NetworkService<Block, Hash>> {
|
|||||||
req_protocol_names: &ReqProtocolNames,
|
req_protocol_names: &ReqProtocolNames,
|
||||||
if_disconnected: IfDisconnected,
|
if_disconnected: IfDisconnected,
|
||||||
) {
|
) {
|
||||||
let (protocol, OutgoingRequest { peer, payload, pending_response }) = req.encode_request();
|
let (protocol, OutgoingRequest { peer, payload, pending_response, fallback_request }) =
|
||||||
|
req.encode_request();
|
||||||
|
|
||||||
let peer_id = match peer {
|
let peer_id = match peer {
|
||||||
Recipient::Peer(peer_id) => Some(peer_id),
|
Recipient::Peer(peer_id) => Some(peer_id),
|
||||||
@@ -315,6 +316,7 @@ impl Network for Arc<NetworkService<Block, Hash>> {
|
|||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
%peer_id,
|
%peer_id,
|
||||||
protocol = %req_protocol_names.get_name(protocol),
|
protocol = %req_protocol_names.get_name(protocol),
|
||||||
|
fallback_protocol = ?fallback_request.as_ref().map(|(_, p)| req_protocol_names.get_name(*p)),
|
||||||
?if_disconnected,
|
?if_disconnected,
|
||||||
"Starting request",
|
"Starting request",
|
||||||
);
|
);
|
||||||
@@ -324,6 +326,7 @@ impl Network for Arc<NetworkService<Block, Hash>> {
|
|||||||
peer_id,
|
peer_id,
|
||||||
req_protocol_names.get_name(protocol),
|
req_protocol_names.get_name(protocol),
|
||||||
payload,
|
payload,
|
||||||
|
fallback_request.map(|(r, p)| (r, req_protocol_names.get_name(p))),
|
||||||
pending_response,
|
pending_response,
|
||||||
if_disconnected,
|
if_disconnected,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use assert_matches::assert_matches;
|
use assert_matches::assert_matches;
|
||||||
use futures::{executor, future, Future};
|
use futures::{executor, future, Future};
|
||||||
|
use sc_network::ProtocolName;
|
||||||
use sp_core::{crypto::Pair, Encode};
|
use sp_core::{crypto::Pair, Encode};
|
||||||
use sp_keyring::Sr25519Keyring;
|
use sp_keyring::Sr25519Keyring;
|
||||||
use sp_keystore::Keystore;
|
use sp_keystore::Keystore;
|
||||||
@@ -559,11 +560,11 @@ fn act_on_advertisement_v2() {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
response_channel
|
response_channel
|
||||||
.send(Ok(request_v1::CollationFetchingResponse::Collation(
|
.send(Ok((
|
||||||
candidate_a.clone(),
|
request_v1::CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone())
|
||||||
pov.clone(),
|
.encode(),
|
||||||
)
|
ProtocolName::from(""),
|
||||||
.encode()))
|
)))
|
||||||
.expect("Sending response should succeed");
|
.expect("Sending response should succeed");
|
||||||
|
|
||||||
assert_candidate_backing_second(
|
assert_candidate_backing_second(
|
||||||
@@ -761,11 +762,11 @@ fn fetch_one_collation_at_a_time() {
|
|||||||
candidate_a.descriptor.relay_parent = test_state.relay_parent;
|
candidate_a.descriptor.relay_parent = test_state.relay_parent;
|
||||||
candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash();
|
candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash();
|
||||||
response_channel
|
response_channel
|
||||||
.send(Ok(request_v1::CollationFetchingResponse::Collation(
|
.send(Ok((
|
||||||
candidate_a.clone(),
|
request_v1::CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone())
|
||||||
pov.clone(),
|
.encode(),
|
||||||
)
|
ProtocolName::from(""),
|
||||||
.encode()))
|
)))
|
||||||
.expect("Sending response should succeed");
|
.expect("Sending response should succeed");
|
||||||
|
|
||||||
assert_candidate_backing_second(
|
assert_candidate_backing_second(
|
||||||
@@ -885,19 +886,19 @@ fn fetches_next_collation() {
|
|||||||
|
|
||||||
// First request finishes now:
|
// First request finishes now:
|
||||||
response_channel_non_exclusive
|
response_channel_non_exclusive
|
||||||
.send(Ok(request_v1::CollationFetchingResponse::Collation(
|
.send(Ok((
|
||||||
candidate_a.clone(),
|
request_v1::CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone())
|
||||||
pov.clone(),
|
.encode(),
|
||||||
)
|
ProtocolName::from(""),
|
||||||
.encode()))
|
)))
|
||||||
.expect("Sending response should succeed");
|
.expect("Sending response should succeed");
|
||||||
|
|
||||||
response_channel
|
response_channel
|
||||||
.send(Ok(request_v1::CollationFetchingResponse::Collation(
|
.send(Ok((
|
||||||
candidate_a.clone(),
|
request_v1::CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone())
|
||||||
pov.clone(),
|
.encode(),
|
||||||
)
|
ProtocolName::from(""),
|
||||||
.encode()))
|
)))
|
||||||
.expect("Sending response should succeed");
|
.expect("Sending response should succeed");
|
||||||
|
|
||||||
assert_candidate_backing_second(
|
assert_candidate_backing_second(
|
||||||
@@ -1023,11 +1024,11 @@ fn fetch_next_collation_on_invalid_collation() {
|
|||||||
candidate_a.descriptor.relay_parent = test_state.relay_parent;
|
candidate_a.descriptor.relay_parent = test_state.relay_parent;
|
||||||
candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash();
|
candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash();
|
||||||
response_channel
|
response_channel
|
||||||
.send(Ok(request_v1::CollationFetchingResponse::Collation(
|
.send(Ok((
|
||||||
candidate_a.clone(),
|
request_v1::CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone())
|
||||||
pov.clone(),
|
.encode(),
|
||||||
)
|
ProtocolName::from(""),
|
||||||
.encode()))
|
)))
|
||||||
.expect("Sending response should succeed");
|
.expect("Sending response should succeed");
|
||||||
|
|
||||||
let receipt = assert_candidate_backing_second(
|
let receipt = assert_candidate_backing_second(
|
||||||
|
|||||||
+18
-15
@@ -314,11 +314,11 @@ fn v1_advertisement_accepted_and_seconded() {
|
|||||||
let pov = PoV { block_data: BlockData(vec![1]) };
|
let pov = PoV { block_data: BlockData(vec![1]) };
|
||||||
|
|
||||||
response_channel
|
response_channel
|
||||||
.send(Ok(request_v2::CollationFetchingResponse::Collation(
|
.send(Ok((
|
||||||
candidate.clone(),
|
request_v2::CollationFetchingResponse::Collation(candidate.clone(), pov.clone())
|
||||||
pov.clone(),
|
.encode(),
|
||||||
)
|
ProtocolName::from(""),
|
||||||
.encode()))
|
)))
|
||||||
.expect("Sending response should succeed");
|
.expect("Sending response should succeed");
|
||||||
|
|
||||||
assert_candidate_backing_second(
|
assert_candidate_backing_second(
|
||||||
@@ -565,11 +565,14 @@ fn second_multiple_candidates_per_relay_parent() {
|
|||||||
let pov = PoV { block_data: BlockData(vec![1]) };
|
let pov = PoV { block_data: BlockData(vec![1]) };
|
||||||
|
|
||||||
response_channel
|
response_channel
|
||||||
.send(Ok(request_v2::CollationFetchingResponse::Collation(
|
.send(Ok((
|
||||||
candidate.clone(),
|
request_v2::CollationFetchingResponse::Collation(
|
||||||
pov.clone(),
|
candidate.clone(),
|
||||||
)
|
pov.clone(),
|
||||||
.encode()))
|
)
|
||||||
|
.encode(),
|
||||||
|
ProtocolName::from(""),
|
||||||
|
)))
|
||||||
.expect("Sending response should succeed");
|
.expect("Sending response should succeed");
|
||||||
|
|
||||||
assert_candidate_backing_second(
|
assert_candidate_backing_second(
|
||||||
@@ -717,11 +720,11 @@ fn fetched_collation_sanity_check() {
|
|||||||
let pov = PoV { block_data: BlockData(vec![1]) };
|
let pov = PoV { block_data: BlockData(vec![1]) };
|
||||||
|
|
||||||
response_channel
|
response_channel
|
||||||
.send(Ok(request_v2::CollationFetchingResponse::Collation(
|
.send(Ok((
|
||||||
candidate.clone(),
|
request_v2::CollationFetchingResponse::Collation(candidate.clone(), pov.clone())
|
||||||
pov.clone(),
|
.encode(),
|
||||||
)
|
ProtocolName::from(""),
|
||||||
.encode()))
|
)))
|
||||||
.expect("Sending response should succeed");
|
.expect("Sending response should succeed");
|
||||||
|
|
||||||
// PVD request.
|
// PVD request.
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ use futures::{
|
|||||||
use futures_timer::Delay;
|
use futures_timer::Delay;
|
||||||
use parity_scale_codec::{Decode, Encode};
|
use parity_scale_codec::{Decode, Encode};
|
||||||
|
|
||||||
use sc_network::config::RequestResponseConfig;
|
use sc_network::{config::RequestResponseConfig, ProtocolName};
|
||||||
|
|
||||||
use polkadot_node_network_protocol::{
|
use polkadot_node_network_protocol::{
|
||||||
request_response::{v1::DisputeRequest, IncomingRequest, ReqProtocolNames},
|
request_response::{v1::DisputeRequest, IncomingRequest, ReqProtocolNames},
|
||||||
@@ -832,7 +832,7 @@ async fn check_sent_requests(
|
|||||||
if confirm_receive {
|
if confirm_receive {
|
||||||
for req in reqs {
|
for req in reqs {
|
||||||
req.pending_response.send(
|
req.pending_response.send(
|
||||||
Ok(DisputeResponse::Confirmed.encode())
|
Ok((DisputeResponse::Confirmed.encode(), ProtocolName::from("")))
|
||||||
)
|
)
|
||||||
.expect("Subsystem should be listening for a response.");
|
.expect("Subsystem should be listening for a response.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,24 @@
|
|||||||
//! `trait IsRequest` .... A trait describing a particular request. It is used for gathering meta
|
//! `trait IsRequest` .... A trait describing a particular request. It is used for gathering meta
|
||||||
//! data, like what is the corresponding response type.
|
//! data, like what is the corresponding response type.
|
||||||
//!
|
//!
|
||||||
//! Versioned (v1 module): The actual requests and responses as sent over the network.
|
//! ## Versioning
|
||||||
|
//!
|
||||||
|
//! Versioning for request-response protocols can be done in multiple ways.
|
||||||
|
//!
|
||||||
|
//! If you're just changing the protocol name but the binary payloads are the same, just add a new
|
||||||
|
//! `fallback_name` to the protocol config.
|
||||||
|
//!
|
||||||
|
//! One way in which versioning has historically been achieved for req-response protocols is to
|
||||||
|
//! bundle the new req-resp version with an upgrade of a notifications protocol. The subsystem would
|
||||||
|
//! then know which request version to use based on stored data about the peer's notifications
|
||||||
|
//! protocol version.
|
||||||
|
//!
|
||||||
|
//! When bumping a notifications protocol version is not needed/desirable, you may add a new
|
||||||
|
//! req-resp protocol and set the old request as a fallback (see
|
||||||
|
//! `OutgoingRequest::new_with_fallback`). A request with the new version will be attempted and if
|
||||||
|
//! the protocol is refused by the peer, the fallback protocol request will be used.
|
||||||
|
//! Information about the actually used protocol will be returned alongside the raw response, so
|
||||||
|
//! that you know how to decode it.
|
||||||
|
|
||||||
use std::{collections::HashMap, time::Duration, u64};
|
use std::{collections::HashMap, time::Duration, u64};
|
||||||
|
|
||||||
@@ -188,11 +205,11 @@ impl Protocol {
|
|||||||
tx: Option<async_channel::Sender<network::IncomingRequest>>,
|
tx: Option<async_channel::Sender<network::IncomingRequest>>,
|
||||||
) -> RequestResponseConfig {
|
) -> RequestResponseConfig {
|
||||||
let name = req_protocol_names.get_name(self);
|
let name = req_protocol_names.get_name(self);
|
||||||
let fallback_names = self.get_fallback_names();
|
let legacy_names = self.get_legacy_name().into_iter().map(Into::into).collect();
|
||||||
match self {
|
match self {
|
||||||
Protocol::ChunkFetchingV1 => RequestResponseConfig {
|
Protocol::ChunkFetchingV1 => RequestResponseConfig {
|
||||||
name,
|
name,
|
||||||
fallback_names,
|
fallback_names: legacy_names,
|
||||||
max_request_size: 1_000,
|
max_request_size: 1_000,
|
||||||
max_response_size: POV_RESPONSE_SIZE as u64 * 3,
|
max_response_size: POV_RESPONSE_SIZE as u64 * 3,
|
||||||
// We are connected to all validators:
|
// We are connected to all validators:
|
||||||
@@ -202,7 +219,7 @@ impl Protocol {
|
|||||||
Protocol::CollationFetchingV1 | Protocol::CollationFetchingV2 =>
|
Protocol::CollationFetchingV1 | Protocol::CollationFetchingV2 =>
|
||||||
RequestResponseConfig {
|
RequestResponseConfig {
|
||||||
name,
|
name,
|
||||||
fallback_names,
|
fallback_names: legacy_names,
|
||||||
max_request_size: 1_000,
|
max_request_size: 1_000,
|
||||||
max_response_size: POV_RESPONSE_SIZE,
|
max_response_size: POV_RESPONSE_SIZE,
|
||||||
// Taken from initial implementation in collator protocol:
|
// Taken from initial implementation in collator protocol:
|
||||||
@@ -211,7 +228,7 @@ impl Protocol {
|
|||||||
},
|
},
|
||||||
Protocol::PoVFetchingV1 => RequestResponseConfig {
|
Protocol::PoVFetchingV1 => RequestResponseConfig {
|
||||||
name,
|
name,
|
||||||
fallback_names,
|
fallback_names: legacy_names,
|
||||||
max_request_size: 1_000,
|
max_request_size: 1_000,
|
||||||
max_response_size: POV_RESPONSE_SIZE,
|
max_response_size: POV_RESPONSE_SIZE,
|
||||||
request_timeout: POV_REQUEST_TIMEOUT_CONNECTED,
|
request_timeout: POV_REQUEST_TIMEOUT_CONNECTED,
|
||||||
@@ -219,7 +236,7 @@ impl Protocol {
|
|||||||
},
|
},
|
||||||
Protocol::AvailableDataFetchingV1 => RequestResponseConfig {
|
Protocol::AvailableDataFetchingV1 => RequestResponseConfig {
|
||||||
name,
|
name,
|
||||||
fallback_names,
|
fallback_names: legacy_names,
|
||||||
max_request_size: 1_000,
|
max_request_size: 1_000,
|
||||||
// Available data size is dominated by the PoV size.
|
// Available data size is dominated by the PoV size.
|
||||||
max_response_size: POV_RESPONSE_SIZE,
|
max_response_size: POV_RESPONSE_SIZE,
|
||||||
@@ -228,7 +245,7 @@ impl Protocol {
|
|||||||
},
|
},
|
||||||
Protocol::StatementFetchingV1 => RequestResponseConfig {
|
Protocol::StatementFetchingV1 => RequestResponseConfig {
|
||||||
name,
|
name,
|
||||||
fallback_names,
|
fallback_names: legacy_names,
|
||||||
max_request_size: 1_000,
|
max_request_size: 1_000,
|
||||||
// Available data size is dominated code size.
|
// Available data size is dominated code size.
|
||||||
max_response_size: STATEMENT_RESPONSE_SIZE,
|
max_response_size: STATEMENT_RESPONSE_SIZE,
|
||||||
@@ -246,7 +263,7 @@ impl Protocol {
|
|||||||
},
|
},
|
||||||
Protocol::DisputeSendingV1 => RequestResponseConfig {
|
Protocol::DisputeSendingV1 => RequestResponseConfig {
|
||||||
name,
|
name,
|
||||||
fallback_names,
|
fallback_names: legacy_names,
|
||||||
max_request_size: 1_000,
|
max_request_size: 1_000,
|
||||||
// Responses are just confirmation, in essence not even a bit. So 100 seems
|
// Responses are just confirmation, in essence not even a bit. So 100 seems
|
||||||
// plenty.
|
// plenty.
|
||||||
@@ -256,7 +273,7 @@ impl Protocol {
|
|||||||
},
|
},
|
||||||
Protocol::AttestedCandidateV2 => RequestResponseConfig {
|
Protocol::AttestedCandidateV2 => RequestResponseConfig {
|
||||||
name,
|
name,
|
||||||
fallback_names,
|
fallback_names: legacy_names,
|
||||||
max_request_size: 1_000,
|
max_request_size: 1_000,
|
||||||
max_response_size: ATTESTED_CANDIDATE_RESPONSE_SIZE,
|
max_response_size: ATTESTED_CANDIDATE_RESPONSE_SIZE,
|
||||||
request_timeout: ATTESTED_CANDIDATE_TIMEOUT,
|
request_timeout: ATTESTED_CANDIDATE_TIMEOUT,
|
||||||
@@ -328,12 +345,9 @@ impl Protocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fallback protocol names of this protocol, as understood by substrate networking.
|
|
||||||
fn get_fallback_names(self) -> Vec<ProtocolName> {
|
|
||||||
self.get_legacy_name().into_iter().map(Into::into).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Legacy protocol name associated with each peer set, if any.
|
/// Legacy protocol name associated with each peer set, if any.
|
||||||
|
/// The request will be tried on this legacy protocol name if the remote refuses to speak the
|
||||||
|
/// protocol.
|
||||||
const fn get_legacy_name(self) -> Option<&'static str> {
|
const fn get_legacy_name(self) -> Option<&'static str> {
|
||||||
match self {
|
match self {
|
||||||
Protocol::ChunkFetchingV1 => Some("/polkadot/req_chunk/1"),
|
Protocol::ChunkFetchingV1 => Some("/polkadot/req_chunk/1"),
|
||||||
@@ -360,6 +374,7 @@ pub trait IsRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Type for getting on the wire [`Protocol`] names using genesis hash & fork id.
|
/// Type for getting on the wire [`Protocol`] names using genesis hash & fork id.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ReqProtocolNames {
|
pub struct ReqProtocolNames {
|
||||||
names: HashMap<Protocol, ProtocolName>,
|
names: HashMap<Protocol, ProtocolName>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,9 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use futures::{channel::oneshot, prelude::Future};
|
use futures::{channel::oneshot, prelude::Future, FutureExt};
|
||||||
|
|
||||||
|
use network::ProtocolName;
|
||||||
use parity_scale_codec::{Decode, Encode, Error as DecodingError};
|
use parity_scale_codec::{Decode, Encode, Error as DecodingError};
|
||||||
|
|
||||||
use sc_network as network;
|
use sc_network as network;
|
||||||
@@ -49,20 +50,6 @@ pub enum Requests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Requests {
|
impl Requests {
|
||||||
/// Get the protocol this request conforms to.
|
|
||||||
pub fn get_protocol(&self) -> Protocol {
|
|
||||||
match self {
|
|
||||||
Self::ChunkFetchingV1(_) => Protocol::ChunkFetchingV1,
|
|
||||||
Self::CollationFetchingV1(_) => Protocol::CollationFetchingV1,
|
|
||||||
Self::CollationFetchingV2(_) => Protocol::CollationFetchingV2,
|
|
||||||
Self::PoVFetchingV1(_) => Protocol::PoVFetchingV1,
|
|
||||||
Self::AvailableDataFetchingV1(_) => Protocol::AvailableDataFetchingV1,
|
|
||||||
Self::StatementFetchingV1(_) => Protocol::StatementFetchingV1,
|
|
||||||
Self::DisputeSendingV1(_) => Protocol::DisputeSendingV1,
|
|
||||||
Self::AttestedCandidateV2(_) => Protocol::AttestedCandidateV2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encode the request.
|
/// Encode the request.
|
||||||
///
|
///
|
||||||
/// The corresponding protocol is returned as well, as we are now leaving typed territory.
|
/// The corresponding protocol is returned as well, as we are now leaving typed territory.
|
||||||
@@ -85,7 +72,7 @@ impl Requests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Used by the network to send us a response to a request.
|
/// Used by the network to send us a response to a request.
|
||||||
pub type ResponseSender = oneshot::Sender<Result<Vec<u8>, network::RequestFailure>>;
|
pub type ResponseSender = oneshot::Sender<Result<(Vec<u8>, ProtocolName), network::RequestFailure>>;
|
||||||
|
|
||||||
/// Any error that can occur when sending a request.
|
/// Any error that can occur when sending a request.
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
@@ -128,11 +115,13 @@ impl RequestError {
|
|||||||
/// When using `Recipient::Authority`, the addresses can be found thanks to the authority
|
/// When using `Recipient::Authority`, the addresses can be found thanks to the authority
|
||||||
/// discovery system.
|
/// discovery system.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OutgoingRequest<Req> {
|
pub struct OutgoingRequest<Req, FallbackReq = Req> {
|
||||||
/// Intended recipient of this request.
|
/// Intended recipient of this request.
|
||||||
pub peer: Recipient,
|
pub peer: Recipient,
|
||||||
/// The actual request to send over the wire.
|
/// The actual request to send over the wire.
|
||||||
pub payload: Req,
|
pub payload: Req,
|
||||||
|
/// Optional fallback request and protocol.
|
||||||
|
pub fallback_request: Option<(FallbackReq, Protocol)>,
|
||||||
/// Sender which is used by networking to get us back a response.
|
/// Sender which is used by networking to get us back a response.
|
||||||
pub pending_response: ResponseSender,
|
pub pending_response: ResponseSender,
|
||||||
}
|
}
|
||||||
@@ -149,10 +138,12 @@ pub enum Recipient {
|
|||||||
/// Responses received for an `OutgoingRequest`.
|
/// Responses received for an `OutgoingRequest`.
|
||||||
pub type OutgoingResult<Res> = Result<Res, RequestError>;
|
pub type OutgoingResult<Res> = Result<Res, RequestError>;
|
||||||
|
|
||||||
impl<Req> OutgoingRequest<Req>
|
impl<Req, FallbackReq> OutgoingRequest<Req, FallbackReq>
|
||||||
where
|
where
|
||||||
Req: IsRequest + Encode,
|
Req: IsRequest + Encode,
|
||||||
Req::Response: Decode,
|
Req::Response: Decode,
|
||||||
|
FallbackReq: IsRequest + Encode,
|
||||||
|
FallbackReq::Response: Decode,
|
||||||
{
|
{
|
||||||
/// Create a new `OutgoingRequest`.
|
/// Create a new `OutgoingRequest`.
|
||||||
///
|
///
|
||||||
@@ -163,24 +154,54 @@ where
|
|||||||
payload: Req,
|
payload: Req,
|
||||||
) -> (Self, impl Future<Output = OutgoingResult<Req::Response>>) {
|
) -> (Self, impl Future<Output = OutgoingResult<Req::Response>>) {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
let r = Self { peer, payload, pending_response: tx };
|
let r = Self { peer, payload, pending_response: tx, fallback_request: None };
|
||||||
(r, receive_response::<Req>(rx))
|
(r, receive_response::<Req>(rx.map(|r| r.map(|r| r.map(|(resp, _)| resp)))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new `OutgoingRequest` with a fallback in case the remote does not support this
|
||||||
|
/// protocol. Useful when adding a new version of a req-response protocol, to achieve
|
||||||
|
/// compatibility with the older version.
|
||||||
|
///
|
||||||
|
/// Returns a raw `Vec<u8>` response over the channel. Use the associated `ProtocolName` to know
|
||||||
|
/// which request was the successful one and appropriately decode the response.
|
||||||
|
// WARNING: This is commented for now because it's not used yet.
|
||||||
|
// If you need it, make sure to test it. You may need to enable the V1 substream upgrade
|
||||||
|
// protocol, unless libp2p was in the meantime updated to a version that fixes the problem
|
||||||
|
// described in https://github.com/libp2p/rust-libp2p/issues/5074
|
||||||
|
// pub fn new_with_fallback(
|
||||||
|
// peer: Recipient,
|
||||||
|
// payload: Req,
|
||||||
|
// fallback_request: FallbackReq,
|
||||||
|
// ) -> (Self, impl Future<Output = OutgoingResult<(Vec<u8>, ProtocolName)>>) {
|
||||||
|
// let (tx, rx) = oneshot::channel();
|
||||||
|
// let r = Self {
|
||||||
|
// peer,
|
||||||
|
// payload,
|
||||||
|
// pending_response: tx,
|
||||||
|
// fallback_request: Some((fallback_request, FallbackReq::PROTOCOL)),
|
||||||
|
// };
|
||||||
|
// (r, async { Ok(rx.await??) })
|
||||||
|
// }
|
||||||
|
|
||||||
/// Encode a request into a `Vec<u8>`.
|
/// Encode a request into a `Vec<u8>`.
|
||||||
///
|
///
|
||||||
/// As this throws away type information, we also return the `Protocol` this encoded request
|
/// As this throws away type information, we also return the `Protocol` this encoded request
|
||||||
/// adheres to.
|
/// adheres to.
|
||||||
pub fn encode_request(self) -> (Protocol, OutgoingRequest<Vec<u8>>) {
|
pub fn encode_request(self) -> (Protocol, OutgoingRequest<Vec<u8>>) {
|
||||||
let OutgoingRequest { peer, payload, pending_response } = self;
|
let OutgoingRequest { peer, payload, pending_response, fallback_request } = self;
|
||||||
let encoded = OutgoingRequest { peer, payload: payload.encode(), pending_response };
|
let encoded = OutgoingRequest {
|
||||||
|
peer,
|
||||||
|
payload: payload.encode(),
|
||||||
|
fallback_request: fallback_request.map(|(r, p)| (r.encode(), p)),
|
||||||
|
pending_response,
|
||||||
|
};
|
||||||
(Req::PROTOCOL, encoded)
|
(Req::PROTOCOL, encoded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Future for actually receiving a typed response for an `OutgoingRequest`.
|
/// Future for actually receiving a typed response for an `OutgoingRequest`.
|
||||||
async fn receive_response<Req>(
|
async fn receive_response<Req>(
|
||||||
rec: oneshot::Receiver<Result<Vec<u8>, network::RequestFailure>>,
|
rec: impl Future<Output = Result<Result<Vec<u8>, network::RequestFailure>, oneshot::Canceled>>,
|
||||||
) -> OutgoingResult<Req::Response>
|
) -> OutgoingResult<Req::Response>
|
||||||
where
|
where
|
||||||
Req: IsRequest,
|
Req: IsRequest,
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ use polkadot_primitives_test_helpers::{
|
|||||||
dummy_committed_candidate_receipt, dummy_hash, AlwaysZeroRng,
|
dummy_committed_candidate_receipt, dummy_hash, AlwaysZeroRng,
|
||||||
};
|
};
|
||||||
use sc_keystore::LocalKeystore;
|
use sc_keystore::LocalKeystore;
|
||||||
|
use sc_network::ProtocolName;
|
||||||
use sp_application_crypto::{sr25519::Pair, AppCrypto, Pair as TraitPair};
|
use sp_application_crypto::{sr25519::Pair, AppCrypto, Pair as TraitPair};
|
||||||
use sp_authority_discovery::AuthorityPair;
|
use sp_authority_discovery::AuthorityPair;
|
||||||
use sp_keyring::Sr25519Keyring;
|
use sp_keyring::Sr25519Keyring;
|
||||||
@@ -1330,7 +1331,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing(
|
|||||||
bad
|
bad
|
||||||
};
|
};
|
||||||
let response = StatementFetchingResponse::Statement(bad_candidate);
|
let response = StatementFetchingResponse::Statement(bad_candidate);
|
||||||
outgoing.pending_response.send(Ok(response.encode())).unwrap();
|
outgoing.pending_response.send(Ok((response.encode(), ProtocolName::from("")))).unwrap();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1382,7 +1383,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing(
|
|||||||
// On retry, we should have reverse order:
|
// On retry, we should have reverse order:
|
||||||
assert_eq!(outgoing.peer, Recipient::Peer(peer_c));
|
assert_eq!(outgoing.peer, Recipient::Peer(peer_c));
|
||||||
let response = StatementFetchingResponse::Statement(candidate.clone());
|
let response = StatementFetchingResponse::Statement(candidate.clone());
|
||||||
outgoing.pending_response.send(Ok(response.encode())).unwrap();
|
outgoing.pending_response.send(Ok((response.encode(), ProtocolName::from("")))).unwrap();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1869,7 +1870,7 @@ fn delay_reputation_changes() {
|
|||||||
bad
|
bad
|
||||||
};
|
};
|
||||||
let response = StatementFetchingResponse::Statement(bad_candidate);
|
let response = StatementFetchingResponse::Statement(bad_candidate);
|
||||||
outgoing.pending_response.send(Ok(response.encode())).unwrap();
|
outgoing.pending_response.send(Ok((response.encode(), ProtocolName::from("")))).unwrap();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1913,7 +1914,7 @@ fn delay_reputation_changes() {
|
|||||||
// On retry, we should have reverse order:
|
// On retry, we should have reverse order:
|
||||||
assert_eq!(outgoing.peer, Recipient::Peer(peer_c));
|
assert_eq!(outgoing.peer, Recipient::Peer(peer_c));
|
||||||
let response = StatementFetchingResponse::Statement(candidate.clone());
|
let response = StatementFetchingResponse::Statement(candidate.clone());
|
||||||
outgoing.pending_response.send(Ok(response.encode())).unwrap();
|
outgoing.pending_response.send(Ok((response.encode(), ProtocolName::from("")))).unwrap();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ use polkadot_primitives::{
|
|||||||
SessionIndex, SessionInfo, ValidatorPair,
|
SessionIndex, SessionInfo, ValidatorPair,
|
||||||
};
|
};
|
||||||
use sc_keystore::LocalKeystore;
|
use sc_keystore::LocalKeystore;
|
||||||
|
use sc_network::ProtocolName;
|
||||||
use sp_application_crypto::Pair as PairT;
|
use sp_application_crypto::Pair as PairT;
|
||||||
use sp_authority_discovery::AuthorityPair as AuthorityDiscoveryPair;
|
use sp_authority_discovery::AuthorityPair as AuthorityDiscoveryPair;
|
||||||
use sp_keyring::Sr25519Keyring;
|
use sp_keyring::Sr25519Keyring;
|
||||||
@@ -684,7 +685,7 @@ async fn handle_sent_request(
|
|||||||
persisted_validation_data,
|
persisted_validation_data,
|
||||||
statements,
|
statements,
|
||||||
};
|
};
|
||||||
outgoing.pending_response.send(Ok(res.encode())).unwrap();
|
outgoing.pending_response.send(Ok((res.encode(), ProtocolName::from("")))).unwrap();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ use polkadot_node_network_protocol::{
|
|||||||
request_response::v2 as request_v2, v2::BackedCandidateManifest,
|
request_response::v2 as request_v2, v2::BackedCandidateManifest,
|
||||||
};
|
};
|
||||||
use polkadot_primitives_test_helpers::make_candidate;
|
use polkadot_primitives_test_helpers::make_candidate;
|
||||||
use sc_network::config::{
|
use sc_network::{
|
||||||
IncomingRequest as RawIncomingRequest, OutgoingResponse as RawOutgoingResponse,
|
config::{IncomingRequest as RawIncomingRequest, OutgoingResponse as RawOutgoingResponse},
|
||||||
|
ProtocolName,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1342,7 +1343,7 @@ fn when_validator_disabled_after_sending_the_request() {
|
|||||||
persisted_validation_data: pvd,
|
persisted_validation_data: pvd,
|
||||||
statements,
|
statements,
|
||||||
};
|
};
|
||||||
outgoing.pending_response.send(Ok(res.encode())).unwrap();
|
outgoing.pending_response.send(Ok((res.encode(), ProtocolName::from("")))).unwrap();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,12 @@ fn prepare_test_inner(
|
|||||||
chunks: state.chunks.clone(),
|
chunks: state.chunks.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let network = NetworkEmulator::new(&config, &dependencies, &test_authorities);
|
let req_protocol_names = ReqProtocolNames::new(GENESIS_HASH, None);
|
||||||
|
let (collation_req_receiver, req_cfg) =
|
||||||
|
IncomingRequest::get_config_receiver(&req_protocol_names);
|
||||||
|
|
||||||
|
let network =
|
||||||
|
NetworkEmulator::new(&config, &dependencies, &test_authorities, req_protocol_names);
|
||||||
|
|
||||||
let network_bridge_tx = network_bridge::MockNetworkBridgeTx::new(
|
let network_bridge_tx = network_bridge::MockNetworkBridgeTx::new(
|
||||||
config.clone(),
|
config.clone(),
|
||||||
@@ -122,9 +127,6 @@ fn prepare_test_inner(
|
|||||||
_ => panic!("Unexpected objective"),
|
_ => panic!("Unexpected objective"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (collation_req_receiver, req_cfg) =
|
|
||||||
IncomingRequest::get_config_receiver(&ReqProtocolNames::new(GENESIS_HASH, None));
|
|
||||||
|
|
||||||
let subsystem = if use_fast_path {
|
let subsystem = if use_fast_path {
|
||||||
AvailabilityRecoverySubsystem::with_fast_path(
|
AvailabilityRecoverySubsystem::with_fast_path(
|
||||||
collation_req_receiver,
|
collation_req_receiver,
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ use polkadot_node_subsystem::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use polkadot_node_network_protocol::request_response::{
|
use polkadot_node_network_protocol::request_response::{
|
||||||
self as req_res, v1::ChunkResponse, Requests,
|
self as req_res,
|
||||||
|
v1::{AvailableDataFetchingRequest, ChunkFetchingRequest, ChunkResponse},
|
||||||
|
IsRequest, Requests,
|
||||||
};
|
};
|
||||||
use polkadot_primitives::AuthorityDiscoveryId;
|
use polkadot_primitives::AuthorityDiscoveryId;
|
||||||
|
|
||||||
@@ -144,7 +146,10 @@ impl MockNetworkBridgeTx {
|
|||||||
size = 0;
|
size = 0;
|
||||||
Err(RequestFailure::Network(OutboundFailure::ConnectionClosed))
|
Err(RequestFailure::Network(OutboundFailure::ConnectionClosed))
|
||||||
} else {
|
} else {
|
||||||
Ok(req_res::v1::ChunkFetchingResponse::from(Some(chunk)).encode())
|
Ok((
|
||||||
|
req_res::v1::ChunkFetchingResponse::from(Some(chunk)).encode(),
|
||||||
|
self.network.req_protocol_names().get_name(ChunkFetchingRequest::PROTOCOL),
|
||||||
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
let authority_discovery_id_clone = authority_discovery_id.clone();
|
let authority_discovery_id_clone = authority_discovery_id.clone();
|
||||||
@@ -212,8 +217,13 @@ impl MockNetworkBridgeTx {
|
|||||||
let response = if random_error(self.config.error) {
|
let response = if random_error(self.config.error) {
|
||||||
Err(RequestFailure::Network(OutboundFailure::ConnectionClosed))
|
Err(RequestFailure::Network(OutboundFailure::ConnectionClosed))
|
||||||
} else {
|
} else {
|
||||||
Ok(req_res::v1::AvailableDataFetchingResponse::from(Some(available_data))
|
Ok((
|
||||||
.encode())
|
req_res::v1::AvailableDataFetchingResponse::from(Some(available_data))
|
||||||
|
.encode(),
|
||||||
|
self.network
|
||||||
|
.req_protocol_names()
|
||||||
|
.get_name(AvailableDataFetchingRequest::PROTOCOL),
|
||||||
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
let future = async move {
|
let future = async move {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use super::{
|
|||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
use polkadot_node_network_protocol::request_response::ReqProtocolNames;
|
||||||
use polkadot_primitives::AuthorityDiscoveryId;
|
use polkadot_primitives::AuthorityDiscoveryId;
|
||||||
use prometheus_endpoint::U64;
|
use prometheus_endpoint::U64;
|
||||||
use rand::{seq::SliceRandom, thread_rng};
|
use rand::{seq::SliceRandom, thread_rng};
|
||||||
@@ -311,6 +312,8 @@ pub struct NetworkEmulator {
|
|||||||
stats: Vec<Arc<PeerEmulatorStats>>,
|
stats: Vec<Arc<PeerEmulatorStats>>,
|
||||||
/// Each emulated peer is a validator.
|
/// Each emulated peer is a validator.
|
||||||
validator_authority_ids: HashMap<AuthorityDiscoveryId, usize>,
|
validator_authority_ids: HashMap<AuthorityDiscoveryId, usize>,
|
||||||
|
/// Request protocol names
|
||||||
|
req_protocol_names: ReqProtocolNames,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkEmulator {
|
impl NetworkEmulator {
|
||||||
@@ -318,6 +321,7 @@ impl NetworkEmulator {
|
|||||||
config: &TestConfiguration,
|
config: &TestConfiguration,
|
||||||
dependencies: &TestEnvironmentDependencies,
|
dependencies: &TestEnvironmentDependencies,
|
||||||
authorities: &TestAuthorities,
|
authorities: &TestAuthorities,
|
||||||
|
req_protocol_names: ReqProtocolNames,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let n_peers = config.n_validators;
|
let n_peers = config.n_validators;
|
||||||
gum::info!(target: LOG_TARGET, "{}",format!("Initializing emulation for a {} peer network.", n_peers).bright_blue());
|
gum::info!(target: LOG_TARGET, "{}",format!("Initializing emulation for a {} peer network.", n_peers).bright_blue());
|
||||||
@@ -355,7 +359,12 @@ impl NetworkEmulator {
|
|||||||
|
|
||||||
gum::info!(target: LOG_TARGET, "{}",format!("Network created, connected validator count {}", connected_count).bright_black());
|
gum::info!(target: LOG_TARGET, "{}",format!("Network created, connected validator count {}", connected_count).bright_black());
|
||||||
|
|
||||||
Self { peers, stats, validator_authority_ids: validator_authority_id_mapping }
|
Self {
|
||||||
|
peers,
|
||||||
|
stats,
|
||||||
|
validator_authority_ids: validator_authority_id_mapping,
|
||||||
|
req_protocol_names,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_peer_connected(&self, peer: &AuthorityDiscoveryId) -> bool {
|
pub fn is_peer_connected(&self, peer: &AuthorityDiscoveryId) -> bool {
|
||||||
@@ -428,6 +437,11 @@ impl NetworkEmulator {
|
|||||||
// Our node always is peer 0.
|
// Our node always is peer 0.
|
||||||
self.peer_stats(0).inc_received(bytes);
|
self.peer_stats(0).inc_received(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the request protocol names
|
||||||
|
pub fn req_protocol_names(&self) -> &ReqProtocolNames {
|
||||||
|
&self.req_protocol_names
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use polkadot_node_subsystem_util::metrics::prometheus::{
|
use polkadot_node_subsystem_util::metrics::prometheus::{
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
title: Add fallback request for req-response protocols
|
||||||
|
|
||||||
|
doc:
|
||||||
|
- audience: Node Dev
|
||||||
|
description: |
|
||||||
|
Enable better req-response protocol versioning, by allowing for fallback requests on different protocols.
|
||||||
|
|
||||||
|
crates:
|
||||||
|
- name: sc_network
|
||||||
+3
-2
@@ -43,7 +43,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Response type received from network.
|
/// Response type received from network.
|
||||||
type Response = Result<Vec<u8>, RequestFailure>;
|
type Response = Result<(Vec<u8>, ProtocolName), RequestFailure>;
|
||||||
/// Used to receive a response from the network.
|
/// Used to receive a response from the network.
|
||||||
type ResponseReceiver = oneshot::Receiver<Response>;
|
type ResponseReceiver = oneshot::Receiver<Response>;
|
||||||
|
|
||||||
@@ -125,6 +125,7 @@ impl<B: Block> OnDemandJustificationsEngine<B> {
|
|||||||
peer,
|
peer,
|
||||||
self.protocol_name.clone(),
|
self.protocol_name.clone(),
|
||||||
payload,
|
payload,
|
||||||
|
None,
|
||||||
tx,
|
tx,
|
||||||
IfDisconnected::ImmediateError,
|
IfDisconnected::ImmediateError,
|
||||||
);
|
);
|
||||||
@@ -204,7 +205,7 @@ impl<B: Block> OnDemandJustificationsEngine<B> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.and_then(|encoded| {
|
.and_then(|(encoded, _)| {
|
||||||
decode_and_verify_finality_proof::<B>(
|
decode_and_verify_finality_proof::<B>(
|
||||||
&encoded[..],
|
&encoded[..],
|
||||||
req_info.block,
|
req_info.block,
|
||||||
|
|||||||
@@ -231,13 +231,20 @@ impl<B: BlockT> Behaviour<B> {
|
|||||||
pub fn send_request(
|
pub fn send_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
target: &PeerId,
|
target: &PeerId,
|
||||||
protocol: &str,
|
protocol: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
pending_response: oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
|
pending_response: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
) {
|
) {
|
||||||
self.request_responses
|
self.request_responses.send_request(
|
||||||
.send_request(target, protocol, request, pending_response, connect)
|
target,
|
||||||
|
protocol,
|
||||||
|
request,
|
||||||
|
fallback_request,
|
||||||
|
pending_response,
|
||||||
|
connect,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a shared reference to the user protocol.
|
/// Returns a shared reference to the user protocol.
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ use libp2p::{
|
|||||||
use std::{
|
use std::{
|
||||||
collections::{hash_map::Entry, HashMap},
|
collections::{hash_map::Entry, HashMap},
|
||||||
io, iter,
|
io, iter,
|
||||||
|
ops::Deref,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
@@ -172,6 +173,13 @@ pub struct OutgoingResponse {
|
|||||||
pub sent_feedback: Option<oneshot::Sender<()>>,
|
pub sent_feedback: Option<oneshot::Sender<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information stored about a pending request.
|
||||||
|
struct PendingRequest {
|
||||||
|
started_at: Instant,
|
||||||
|
response_tx: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
|
||||||
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
|
}
|
||||||
|
|
||||||
/// When sending a request, what to do on a disconnected recipient.
|
/// When sending a request, what to do on a disconnected recipient.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum IfDisconnected {
|
pub enum IfDisconnected {
|
||||||
@@ -264,8 +272,7 @@ pub struct RequestResponsesBehaviour {
|
|||||||
>,
|
>,
|
||||||
|
|
||||||
/// Pending requests, passed down to a request-response [`Behaviour`], awaiting a reply.
|
/// Pending requests, passed down to a request-response [`Behaviour`], awaiting a reply.
|
||||||
pending_requests:
|
pending_requests: HashMap<ProtocolRequestId, PendingRequest>,
|
||||||
HashMap<ProtocolRequestId, (Instant, oneshot::Sender<Result<Vec<u8>, RequestFailure>>)>,
|
|
||||||
|
|
||||||
/// Whenever an incoming request arrives, a `Future` is added to this list and will yield the
|
/// Whenever an incoming request arrives, a `Future` is added to this list and will yield the
|
||||||
/// start time and the response to send back to the remote.
|
/// start time and the response to send back to the remote.
|
||||||
@@ -348,29 +355,25 @@ impl RequestResponsesBehaviour {
|
|||||||
pub fn send_request(
|
pub fn send_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
target: &PeerId,
|
target: &PeerId,
|
||||||
protocol_name: &str,
|
protocol_name: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
pending_response: oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
|
pending_response: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
) {
|
) {
|
||||||
log::trace!(target: "sub-libp2p", "send request to {target} ({protocol_name:?}), {} bytes", request.len());
|
log::trace!(target: "sub-libp2p", "send request to {target} ({protocol_name:?}), {} bytes", request.len());
|
||||||
|
|
||||||
if let Some((protocol, _)) = self.protocols.get_mut(protocol_name) {
|
if let Some((protocol, _)) = self.protocols.get_mut(protocol_name.deref()) {
|
||||||
if protocol.is_connected(target) || connect.should_connect() {
|
Self::send_request_inner(
|
||||||
let request_id = protocol.send_request(target, request);
|
protocol,
|
||||||
let prev_req_id = self.pending_requests.insert(
|
&mut self.pending_requests,
|
||||||
(protocol_name.to_string().into(), request_id).into(),
|
target,
|
||||||
(Instant::now(), pending_response),
|
protocol_name,
|
||||||
);
|
request,
|
||||||
debug_assert!(prev_req_id.is_none(), "Expect request id to be unique.");
|
fallback_request,
|
||||||
} else if pending_response.send(Err(RequestFailure::NotConnected)).is_err() {
|
pending_response,
|
||||||
log::debug!(
|
connect,
|
||||||
target: "sub-libp2p",
|
)
|
||||||
"Not connected to peer {:?}. At the same time local \
|
|
||||||
node is no longer interested in the result.",
|
|
||||||
target,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if pending_response.send(Err(RequestFailure::UnknownProtocol)).is_err() {
|
} else if pending_response.send(Err(RequestFailure::UnknownProtocol)).is_err() {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
target: "sub-libp2p",
|
target: "sub-libp2p",
|
||||||
@@ -380,6 +383,37 @@ impl RequestResponsesBehaviour {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn send_request_inner(
|
||||||
|
behaviour: &mut Behaviour<GenericCodec>,
|
||||||
|
pending_requests: &mut HashMap<ProtocolRequestId, PendingRequest>,
|
||||||
|
target: &PeerId,
|
||||||
|
protocol_name: ProtocolName,
|
||||||
|
request: Vec<u8>,
|
||||||
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
|
pending_response: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
|
||||||
|
connect: IfDisconnected,
|
||||||
|
) {
|
||||||
|
if behaviour.is_connected(target) || connect.should_connect() {
|
||||||
|
let request_id = behaviour.send_request(target, request);
|
||||||
|
let prev_req_id = pending_requests.insert(
|
||||||
|
(protocol_name.to_string().into(), request_id).into(),
|
||||||
|
PendingRequest {
|
||||||
|
started_at: Instant::now(),
|
||||||
|
response_tx: pending_response,
|
||||||
|
fallback_request,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
debug_assert!(prev_req_id.is_none(), "Expect request id to be unique.");
|
||||||
|
} else if pending_response.send(Err(RequestFailure::NotConnected)).is_err() {
|
||||||
|
log::debug!(
|
||||||
|
target: "sub-libp2p",
|
||||||
|
"Not connected to peer {:?}. At the same time local \
|
||||||
|
node is no longer interested in the result.",
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkBehaviour for RequestResponsesBehaviour {
|
impl NetworkBehaviour for RequestResponsesBehaviour {
|
||||||
@@ -596,8 +630,10 @@ impl NetworkBehaviour for RequestResponsesBehaviour {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut fallback_requests = vec![];
|
||||||
|
|
||||||
// Poll request-responses protocols.
|
// Poll request-responses protocols.
|
||||||
for (protocol, (behaviour, resp_builder)) in &mut self.protocols {
|
for (protocol, (ref mut behaviour, ref mut resp_builder)) in &mut self.protocols {
|
||||||
'poll_protocol: while let Poll::Ready(ev) = behaviour.poll(cx, params) {
|
'poll_protocol: while let Poll::Ready(ev) = behaviour.poll(cx, params) {
|
||||||
let ev = match ev {
|
let ev = match ev {
|
||||||
// Main events we are interested in.
|
// Main events we are interested in.
|
||||||
@@ -698,17 +734,21 @@ impl NetworkBehaviour for RequestResponsesBehaviour {
|
|||||||
.pending_requests
|
.pending_requests
|
||||||
.remove(&(protocol.clone(), request_id).into())
|
.remove(&(protocol.clone(), request_id).into())
|
||||||
{
|
{
|
||||||
Some((started, pending_response)) => {
|
Some(PendingRequest { started_at, response_tx, .. }) => {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "sub-libp2p",
|
target: "sub-libp2p",
|
||||||
"received response from {peer} ({protocol:?}), {} bytes",
|
"received response from {peer} ({protocol:?}), {} bytes",
|
||||||
response.as_ref().map_or(0usize, |response| response.len()),
|
response.as_ref().map_or(0usize, |response| response.len()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let delivered = pending_response
|
let delivered = response_tx
|
||||||
.send(response.map_err(|()| RequestFailure::Refused))
|
.send(
|
||||||
|
response
|
||||||
|
.map_err(|()| RequestFailure::Refused)
|
||||||
|
.map(|resp| (resp, protocol.clone())),
|
||||||
|
)
|
||||||
.map_err(|_| RequestFailure::Obsolete);
|
.map_err(|_| RequestFailure::Obsolete);
|
||||||
(started, delivered)
|
(started_at, delivered)
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
@@ -742,8 +782,34 @@ impl NetworkBehaviour for RequestResponsesBehaviour {
|
|||||||
.pending_requests
|
.pending_requests
|
||||||
.remove(&(protocol.clone(), request_id).into())
|
.remove(&(protocol.clone(), request_id).into())
|
||||||
{
|
{
|
||||||
Some((started, pending_response)) => {
|
Some(PendingRequest {
|
||||||
if pending_response
|
started_at,
|
||||||
|
response_tx,
|
||||||
|
fallback_request,
|
||||||
|
}) => {
|
||||||
|
// Try using the fallback request if the protocol was not
|
||||||
|
// supported.
|
||||||
|
if let OutboundFailure::UnsupportedProtocols = error {
|
||||||
|
if let Some((fallback_request, fallback_protocol)) =
|
||||||
|
fallback_request
|
||||||
|
{
|
||||||
|
log::trace!(
|
||||||
|
target: "sub-libp2p",
|
||||||
|
"Request with id {:?} failed. Trying the fallback protocol. {}",
|
||||||
|
request_id,
|
||||||
|
fallback_protocol.deref()
|
||||||
|
);
|
||||||
|
fallback_requests.push((
|
||||||
|
peer,
|
||||||
|
fallback_protocol,
|
||||||
|
fallback_request,
|
||||||
|
response_tx,
|
||||||
|
));
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if response_tx
|
||||||
.send(Err(RequestFailure::Network(error.clone())))
|
.send(Err(RequestFailure::Network(error.clone())))
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
@@ -754,7 +820,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour {
|
|||||||
request_id,
|
request_id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
started
|
started_at
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
@@ -825,6 +891,25 @@ impl NetworkBehaviour for RequestResponsesBehaviour {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send out fallback requests.
|
||||||
|
for (peer, protocol, request, pending_response) in fallback_requests.drain(..) {
|
||||||
|
if let Some((behaviour, _)) = self.protocols.get_mut(&protocol) {
|
||||||
|
Self::send_request_inner(
|
||||||
|
behaviour,
|
||||||
|
&mut self.pending_requests,
|
||||||
|
&peer,
|
||||||
|
protocol,
|
||||||
|
request,
|
||||||
|
None,
|
||||||
|
pending_response,
|
||||||
|
// We can error if not connected because the
|
||||||
|
// previous attempt would have tried to establish a
|
||||||
|
// connection already or errored and we wouldn't have gotten here.
|
||||||
|
IfDisconnected::ImmediateError,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break Poll::Pending
|
break Poll::Pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -976,6 +1061,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::mock::MockPeerStore;
|
use crate::mock::MockPeerStore;
|
||||||
|
use assert_matches::assert_matches;
|
||||||
use futures::{channel::oneshot, executor::LocalPool, task::Spawn};
|
use futures::{channel::oneshot, executor::LocalPool, task::Spawn};
|
||||||
use libp2p::{
|
use libp2p::{
|
||||||
core::{
|
core::{
|
||||||
@@ -1025,7 +1111,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_request_response_works() {
|
fn basic_request_response_works() {
|
||||||
let protocol_name = "/test/req-resp/1";
|
let protocol_name = ProtocolName::from("/test/req-resp/1");
|
||||||
let mut pool = LocalPool::new();
|
let mut pool = LocalPool::new();
|
||||||
|
|
||||||
// Build swarms whose behaviour is [`RequestResponsesBehaviour`].
|
// Build swarms whose behaviour is [`RequestResponsesBehaviour`].
|
||||||
@@ -1053,7 +1139,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let protocol_config = ProtocolConfig {
|
let protocol_config = ProtocolConfig {
|
||||||
name: From::from(protocol_name),
|
name: protocol_name.clone(),
|
||||||
fallback_names: Vec::new(),
|
fallback_names: Vec::new(),
|
||||||
max_request_size: 1024,
|
max_request_size: 1024,
|
||||||
max_response_size: 1024 * 1024,
|
max_response_size: 1024 * 1024,
|
||||||
@@ -1102,8 +1188,9 @@ mod tests {
|
|||||||
let (sender, receiver) = oneshot::channel();
|
let (sender, receiver) = oneshot::channel();
|
||||||
swarm.behaviour_mut().send_request(
|
swarm.behaviour_mut().send_request(
|
||||||
&peer_id,
|
&peer_id,
|
||||||
protocol_name,
|
protocol_name.clone(),
|
||||||
b"this is a request".to_vec(),
|
b"this is a request".to_vec(),
|
||||||
|
None,
|
||||||
sender,
|
sender,
|
||||||
IfDisconnected::ImmediateError,
|
IfDisconnected::ImmediateError,
|
||||||
);
|
);
|
||||||
@@ -1118,13 +1205,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(response_receiver.unwrap().await.unwrap().unwrap(), b"this is a response");
|
assert_eq!(
|
||||||
|
response_receiver.unwrap().await.unwrap().unwrap(),
|
||||||
|
(b"this is a response".to_vec(), protocol_name)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn max_response_size_exceeded() {
|
fn max_response_size_exceeded() {
|
||||||
let protocol_name = "/test/req-resp/1";
|
let protocol_name = ProtocolName::from("/test/req-resp/1");
|
||||||
let mut pool = LocalPool::new();
|
let mut pool = LocalPool::new();
|
||||||
|
|
||||||
// Build swarms whose behaviour is [`RequestResponsesBehaviour`].
|
// Build swarms whose behaviour is [`RequestResponsesBehaviour`].
|
||||||
@@ -1150,7 +1240,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let protocol_config = ProtocolConfig {
|
let protocol_config = ProtocolConfig {
|
||||||
name: From::from(protocol_name),
|
name: protocol_name.clone(),
|
||||||
fallback_names: Vec::new(),
|
fallback_names: Vec::new(),
|
||||||
max_request_size: 1024,
|
max_request_size: 1024,
|
||||||
max_response_size: 8, // <-- important for the test
|
max_response_size: 8, // <-- important for the test
|
||||||
@@ -1201,8 +1291,9 @@ mod tests {
|
|||||||
let (sender, receiver) = oneshot::channel();
|
let (sender, receiver) = oneshot::channel();
|
||||||
swarm.behaviour_mut().send_request(
|
swarm.behaviour_mut().send_request(
|
||||||
&peer_id,
|
&peer_id,
|
||||||
protocol_name,
|
protocol_name.clone(),
|
||||||
b"this is a request".to_vec(),
|
b"this is a request".to_vec(),
|
||||||
|
None,
|
||||||
sender,
|
sender,
|
||||||
IfDisconnected::ImmediateError,
|
IfDisconnected::ImmediateError,
|
||||||
);
|
);
|
||||||
@@ -1236,14 +1327,14 @@ mod tests {
|
|||||||
/// See [`ProtocolRequestId`] for additional information.
|
/// See [`ProtocolRequestId`] for additional information.
|
||||||
#[test]
|
#[test]
|
||||||
fn request_id_collision() {
|
fn request_id_collision() {
|
||||||
let protocol_name_1 = "/test/req-resp-1/1";
|
let protocol_name_1 = ProtocolName::from("/test/req-resp-1/1");
|
||||||
let protocol_name_2 = "/test/req-resp-2/1";
|
let protocol_name_2 = ProtocolName::from("/test/req-resp-2/1");
|
||||||
let mut pool = LocalPool::new();
|
let mut pool = LocalPool::new();
|
||||||
|
|
||||||
let mut swarm_1 = {
|
let mut swarm_1 = {
|
||||||
let protocol_configs = vec![
|
let protocol_configs = vec![
|
||||||
ProtocolConfig {
|
ProtocolConfig {
|
||||||
name: From::from(protocol_name_1),
|
name: protocol_name_1.clone(),
|
||||||
fallback_names: Vec::new(),
|
fallback_names: Vec::new(),
|
||||||
max_request_size: 1024,
|
max_request_size: 1024,
|
||||||
max_response_size: 1024 * 1024,
|
max_response_size: 1024 * 1024,
|
||||||
@@ -1251,7 +1342,7 @@ mod tests {
|
|||||||
inbound_queue: None,
|
inbound_queue: None,
|
||||||
},
|
},
|
||||||
ProtocolConfig {
|
ProtocolConfig {
|
||||||
name: From::from(protocol_name_2),
|
name: protocol_name_2.clone(),
|
||||||
fallback_names: Vec::new(),
|
fallback_names: Vec::new(),
|
||||||
max_request_size: 1024,
|
max_request_size: 1024,
|
||||||
max_response_size: 1024 * 1024,
|
max_response_size: 1024 * 1024,
|
||||||
@@ -1269,7 +1360,7 @@ mod tests {
|
|||||||
|
|
||||||
let protocol_configs = vec![
|
let protocol_configs = vec![
|
||||||
ProtocolConfig {
|
ProtocolConfig {
|
||||||
name: From::from(protocol_name_1),
|
name: protocol_name_1.clone(),
|
||||||
fallback_names: Vec::new(),
|
fallback_names: Vec::new(),
|
||||||
max_request_size: 1024,
|
max_request_size: 1024,
|
||||||
max_response_size: 1024 * 1024,
|
max_response_size: 1024 * 1024,
|
||||||
@@ -1277,7 +1368,7 @@ mod tests {
|
|||||||
inbound_queue: Some(tx_1),
|
inbound_queue: Some(tx_1),
|
||||||
},
|
},
|
||||||
ProtocolConfig {
|
ProtocolConfig {
|
||||||
name: From::from(protocol_name_2),
|
name: protocol_name_2.clone(),
|
||||||
fallback_names: Vec::new(),
|
fallback_names: Vec::new(),
|
||||||
max_request_size: 1024,
|
max_request_size: 1024,
|
||||||
max_response_size: 1024 * 1024,
|
max_response_size: 1024 * 1024,
|
||||||
@@ -1359,15 +1450,17 @@ mod tests {
|
|||||||
let (sender_2, receiver_2) = oneshot::channel();
|
let (sender_2, receiver_2) = oneshot::channel();
|
||||||
swarm_1.behaviour_mut().send_request(
|
swarm_1.behaviour_mut().send_request(
|
||||||
&peer_id,
|
&peer_id,
|
||||||
protocol_name_1,
|
protocol_name_1.clone(),
|
||||||
b"this is a request".to_vec(),
|
b"this is a request".to_vec(),
|
||||||
|
None,
|
||||||
sender_1,
|
sender_1,
|
||||||
IfDisconnected::ImmediateError,
|
IfDisconnected::ImmediateError,
|
||||||
);
|
);
|
||||||
swarm_1.behaviour_mut().send_request(
|
swarm_1.behaviour_mut().send_request(
|
||||||
&peer_id,
|
&peer_id,
|
||||||
protocol_name_2,
|
protocol_name_2.clone(),
|
||||||
b"this is a request".to_vec(),
|
b"this is a request".to_vec(),
|
||||||
|
None,
|
||||||
sender_2,
|
sender_2,
|
||||||
IfDisconnected::ImmediateError,
|
IfDisconnected::ImmediateError,
|
||||||
);
|
);
|
||||||
@@ -1385,8 +1478,239 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (response_receiver_1, response_receiver_2) = response_receivers.unwrap();
|
let (response_receiver_1, response_receiver_2) = response_receivers.unwrap();
|
||||||
assert_eq!(response_receiver_1.await.unwrap().unwrap(), b"this is a response");
|
assert_eq!(
|
||||||
assert_eq!(response_receiver_2.await.unwrap().unwrap(), b"this is a response");
|
response_receiver_1.await.unwrap().unwrap(),
|
||||||
|
(b"this is a response".to_vec(), protocol_name_1)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
response_receiver_2.await.unwrap().unwrap(),
|
||||||
|
(b"this is a response".to_vec(), protocol_name_2)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn request_fallback() {
|
||||||
|
let protocol_name_1 = ProtocolName::from("/test/req-resp/2");
|
||||||
|
let protocol_name_1_fallback = ProtocolName::from("/test/req-resp/1");
|
||||||
|
let protocol_name_2 = ProtocolName::from("/test/another");
|
||||||
|
let mut pool = LocalPool::new();
|
||||||
|
|
||||||
|
let protocol_config_1 = ProtocolConfig {
|
||||||
|
name: protocol_name_1.clone(),
|
||||||
|
fallback_names: Vec::new(),
|
||||||
|
max_request_size: 1024,
|
||||||
|
max_response_size: 1024 * 1024,
|
||||||
|
request_timeout: Duration::from_secs(30),
|
||||||
|
inbound_queue: None,
|
||||||
|
};
|
||||||
|
let protocol_config_1_fallback = ProtocolConfig {
|
||||||
|
name: protocol_name_1_fallback.clone(),
|
||||||
|
fallback_names: Vec::new(),
|
||||||
|
max_request_size: 1024,
|
||||||
|
max_response_size: 1024 * 1024,
|
||||||
|
request_timeout: Duration::from_secs(30),
|
||||||
|
inbound_queue: None,
|
||||||
|
};
|
||||||
|
let protocol_config_2 = ProtocolConfig {
|
||||||
|
name: protocol_name_2.clone(),
|
||||||
|
fallback_names: Vec::new(),
|
||||||
|
max_request_size: 1024,
|
||||||
|
max_response_size: 1024 * 1024,
|
||||||
|
request_timeout: Duration::from_secs(30),
|
||||||
|
inbound_queue: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// This swarm only speaks protocol_name_1_fallback and protocol_name_2.
|
||||||
|
// It only responds to requests.
|
||||||
|
let mut older_swarm = {
|
||||||
|
let (tx_1, mut rx_1) = async_channel::bounded::<IncomingRequest>(64);
|
||||||
|
let (tx_2, mut rx_2) = async_channel::bounded::<IncomingRequest>(64);
|
||||||
|
let mut protocol_config_1_fallback = protocol_config_1_fallback.clone();
|
||||||
|
protocol_config_1_fallback.inbound_queue = Some(tx_1);
|
||||||
|
|
||||||
|
let mut protocol_config_2 = protocol_config_2.clone();
|
||||||
|
protocol_config_2.inbound_queue = Some(tx_2);
|
||||||
|
|
||||||
|
pool.spawner()
|
||||||
|
.spawn_obj(
|
||||||
|
async move {
|
||||||
|
for _ in 0..2 {
|
||||||
|
if let Some(rq) = rx_1.next().await {
|
||||||
|
let (fb_tx, fb_rx) = oneshot::channel();
|
||||||
|
assert_eq!(rq.payload, b"request on protocol /test/req-resp/1");
|
||||||
|
let _ = rq.pending_response.send(super::OutgoingResponse {
|
||||||
|
result: Ok(
|
||||||
|
b"this is a response on protocol /test/req-resp/1".to_vec()
|
||||||
|
),
|
||||||
|
reputation_changes: Vec::new(),
|
||||||
|
sent_feedback: Some(fb_tx),
|
||||||
|
});
|
||||||
|
fb_rx.await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rq) = rx_2.next().await {
|
||||||
|
let (fb_tx, fb_rx) = oneshot::channel();
|
||||||
|
assert_eq!(rq.payload, b"request on protocol /test/other");
|
||||||
|
let _ = rq.pending_response.send(super::OutgoingResponse {
|
||||||
|
result: Ok(b"this is a response on protocol /test/other".to_vec()),
|
||||||
|
reputation_changes: Vec::new(),
|
||||||
|
sent_feedback: Some(fb_tx),
|
||||||
|
});
|
||||||
|
fb_rx.await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.boxed()
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
build_swarm(vec![protocol_config_1_fallback, protocol_config_2].into_iter())
|
||||||
|
};
|
||||||
|
|
||||||
|
// This swarm speaks all protocols.
|
||||||
|
let mut new_swarm = build_swarm(
|
||||||
|
vec![
|
||||||
|
protocol_config_1.clone(),
|
||||||
|
protocol_config_1_fallback.clone(),
|
||||||
|
protocol_config_2.clone(),
|
||||||
|
]
|
||||||
|
.into_iter(),
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
let dial_addr = older_swarm.1.clone();
|
||||||
|
Swarm::dial(&mut new_swarm.0, dial_addr).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Running `older_swarm`` in the background.
|
||||||
|
pool.spawner()
|
||||||
|
.spawn_obj({
|
||||||
|
async move {
|
||||||
|
loop {
|
||||||
|
_ = older_swarm.0.select_next_some().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.boxed()
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Run the newer swarm. Attempt to make requests on all protocols.
|
||||||
|
let (mut swarm, _) = new_swarm;
|
||||||
|
let mut older_peer_id = None;
|
||||||
|
|
||||||
|
pool.run_until(async move {
|
||||||
|
let mut response_receiver = None;
|
||||||
|
// Try the new protocol with a fallback.
|
||||||
|
loop {
|
||||||
|
match swarm.select_next_some().await {
|
||||||
|
SwarmEvent::ConnectionEstablished { peer_id, .. } => {
|
||||||
|
older_peer_id = Some(peer_id);
|
||||||
|
let (sender, receiver) = oneshot::channel();
|
||||||
|
swarm.behaviour_mut().send_request(
|
||||||
|
&peer_id,
|
||||||
|
protocol_name_1.clone(),
|
||||||
|
b"request on protocol /test/req-resp/2".to_vec(),
|
||||||
|
Some((
|
||||||
|
b"request on protocol /test/req-resp/1".to_vec(),
|
||||||
|
protocol_config_1_fallback.name.clone(),
|
||||||
|
)),
|
||||||
|
sender,
|
||||||
|
IfDisconnected::ImmediateError,
|
||||||
|
);
|
||||||
|
response_receiver = Some(receiver);
|
||||||
|
},
|
||||||
|
SwarmEvent::Behaviour(Event::RequestFinished { result, .. }) => {
|
||||||
|
result.unwrap();
|
||||||
|
break
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
response_receiver.unwrap().await.unwrap().unwrap(),
|
||||||
|
(
|
||||||
|
b"this is a response on protocol /test/req-resp/1".to_vec(),
|
||||||
|
protocol_name_1_fallback.clone()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// Try the old protocol with a useless fallback.
|
||||||
|
let (sender, response_receiver) = oneshot::channel();
|
||||||
|
swarm.behaviour_mut().send_request(
|
||||||
|
older_peer_id.as_ref().unwrap(),
|
||||||
|
protocol_name_1_fallback.clone(),
|
||||||
|
b"request on protocol /test/req-resp/1".to_vec(),
|
||||||
|
Some((
|
||||||
|
b"dummy request, will fail if processed".to_vec(),
|
||||||
|
protocol_config_1_fallback.name.clone(),
|
||||||
|
)),
|
||||||
|
sender,
|
||||||
|
IfDisconnected::ImmediateError,
|
||||||
|
);
|
||||||
|
loop {
|
||||||
|
match swarm.select_next_some().await {
|
||||||
|
SwarmEvent::Behaviour(Event::RequestFinished { result, .. }) => {
|
||||||
|
result.unwrap();
|
||||||
|
break
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
response_receiver.await.unwrap().unwrap(),
|
||||||
|
(
|
||||||
|
b"this is a response on protocol /test/req-resp/1".to_vec(),
|
||||||
|
protocol_name_1_fallback.clone()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// Try the new protocol with no fallback. Should fail.
|
||||||
|
let (sender, response_receiver) = oneshot::channel();
|
||||||
|
swarm.behaviour_mut().send_request(
|
||||||
|
older_peer_id.as_ref().unwrap(),
|
||||||
|
protocol_name_1.clone(),
|
||||||
|
b"request on protocol /test/req-resp-2".to_vec(),
|
||||||
|
None,
|
||||||
|
sender,
|
||||||
|
IfDisconnected::ImmediateError,
|
||||||
|
);
|
||||||
|
loop {
|
||||||
|
match swarm.select_next_some().await {
|
||||||
|
SwarmEvent::Behaviour(Event::RequestFinished { result, .. }) => {
|
||||||
|
assert_matches!(
|
||||||
|
result.unwrap_err(),
|
||||||
|
RequestFailure::Network(OutboundFailure::UnsupportedProtocols)
|
||||||
|
);
|
||||||
|
break
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(response_receiver.await.unwrap().is_err());
|
||||||
|
// Try the other protocol with no fallback.
|
||||||
|
let (sender, response_receiver) = oneshot::channel();
|
||||||
|
swarm.behaviour_mut().send_request(
|
||||||
|
older_peer_id.as_ref().unwrap(),
|
||||||
|
protocol_name_2.clone(),
|
||||||
|
b"request on protocol /test/other".to_vec(),
|
||||||
|
None,
|
||||||
|
sender,
|
||||||
|
IfDisconnected::ImmediateError,
|
||||||
|
);
|
||||||
|
loop {
|
||||||
|
match swarm.select_next_some().await {
|
||||||
|
SwarmEvent::Behaviour(Event::RequestFinished { result, .. }) => {
|
||||||
|
result.unwrap();
|
||||||
|
break
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
response_receiver.await.unwrap().unwrap(),
|
||||||
|
(b"this is a response on protocol /test/other".to_vec(), protocol_name_2.clone())
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1048,11 +1048,12 @@ where
|
|||||||
target: PeerId,
|
target: PeerId,
|
||||||
protocol: ProtocolName,
|
protocol: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
) -> Result<Vec<u8>, RequestFailure> {
|
) -> Result<(Vec<u8>, ProtocolName), RequestFailure> {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
|
|
||||||
self.start_request(target, protocol, request, tx, connect);
|
self.start_request(target, protocol, request, fallback_request, tx, connect);
|
||||||
|
|
||||||
match rx.await {
|
match rx.await {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
@@ -1068,13 +1069,15 @@ where
|
|||||||
target: PeerId,
|
target: PeerId,
|
||||||
protocol: ProtocolName,
|
protocol: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
tx: oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
|
tx: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
) {
|
) {
|
||||||
let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::Request {
|
let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::Request {
|
||||||
target,
|
target,
|
||||||
protocol: protocol.into(),
|
protocol: protocol.into(),
|
||||||
request,
|
request,
|
||||||
|
fallback_request,
|
||||||
pending_response: tx,
|
pending_response: tx,
|
||||||
connect,
|
connect,
|
||||||
});
|
});
|
||||||
@@ -1160,7 +1163,8 @@ enum ServiceToWorkerMsg {
|
|||||||
target: PeerId,
|
target: PeerId,
|
||||||
protocol: ProtocolName,
|
protocol: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
pending_response: oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
|
pending_response: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
},
|
},
|
||||||
NetworkStatus {
|
NetworkStatus {
|
||||||
@@ -1287,13 +1291,15 @@ where
|
|||||||
target,
|
target,
|
||||||
protocol,
|
protocol,
|
||||||
request,
|
request,
|
||||||
|
fallback_request,
|
||||||
pending_response,
|
pending_response,
|
||||||
connect,
|
connect,
|
||||||
} => {
|
} => {
|
||||||
self.network_service.behaviour_mut().send_request(
|
self.network_service.behaviour_mut().send_request(
|
||||||
&target,
|
&target,
|
||||||
&protocol,
|
protocol,
|
||||||
request,
|
request,
|
||||||
|
fallback_request,
|
||||||
pending_response,
|
pending_response,
|
||||||
connect,
|
connect,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -551,8 +551,9 @@ pub trait NetworkRequest {
|
|||||||
target: PeerId,
|
target: PeerId,
|
||||||
protocol: ProtocolName,
|
protocol: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
) -> Result<Vec<u8>, RequestFailure>;
|
) -> Result<(Vec<u8>, ProtocolName), RequestFailure>;
|
||||||
|
|
||||||
/// Variation of `request` which starts a request whose response is delivered on a provided
|
/// Variation of `request` which starts a request whose response is delivered on a provided
|
||||||
/// channel.
|
/// channel.
|
||||||
@@ -569,7 +570,8 @@ pub trait NetworkRequest {
|
|||||||
target: PeerId,
|
target: PeerId,
|
||||||
protocol: ProtocolName,
|
protocol: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
tx: oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
|
tx: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -585,13 +587,20 @@ where
|
|||||||
target: PeerId,
|
target: PeerId,
|
||||||
protocol: ProtocolName,
|
protocol: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, RequestFailure>> + Send + 'async_trait>>
|
) -> Pin<
|
||||||
|
Box<
|
||||||
|
dyn Future<Output = Result<(Vec<u8>, ProtocolName), RequestFailure>>
|
||||||
|
+ Send
|
||||||
|
+ 'async_trait,
|
||||||
|
>,
|
||||||
|
>
|
||||||
where
|
where
|
||||||
'life0: 'async_trait,
|
'life0: 'async_trait,
|
||||||
Self: 'async_trait,
|
Self: 'async_trait,
|
||||||
{
|
{
|
||||||
T::request(self, target, protocol, request, connect)
|
T::request(self, target, protocol, request, fallback_request, connect)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_request(
|
fn start_request(
|
||||||
@@ -599,10 +608,11 @@ where
|
|||||||
target: PeerId,
|
target: PeerId,
|
||||||
protocol: ProtocolName,
|
protocol: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
tx: oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
|
tx: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
) {
|
) {
|
||||||
T::start_request(self, target, protocol, request, tx, connect)
|
T::start_request(self, target, protocol, request, fallback_request, tx, connect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,10 @@
|
|||||||
|
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use libp2p::PeerId;
|
use libp2p::PeerId;
|
||||||
use sc_network::request_responses::{ProtocolConfig, RequestFailure};
|
use sc_network::{
|
||||||
|
request_responses::{ProtocolConfig, RequestFailure},
|
||||||
|
ProtocolName,
|
||||||
|
};
|
||||||
use sc_network_common::sync::message::{BlockData, BlockRequest};
|
use sc_network_common::sync::message::{BlockData, BlockRequest};
|
||||||
use sp_runtime::traits::Block as BlockT;
|
use sp_runtime::traits::Block as BlockT;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -43,7 +46,7 @@ pub trait BlockDownloader<Block: BlockT>: Send + Sync {
|
|||||||
&self,
|
&self,
|
||||||
who: PeerId,
|
who: PeerId,
|
||||||
request: BlockRequest<Block>,
|
request: BlockRequest<Block>,
|
||||||
) -> Result<Result<Vec<u8>, RequestFailure>, oneshot::Canceled>;
|
) -> Result<Result<(Vec<u8>, ProtocolName), RequestFailure>, oneshot::Canceled>;
|
||||||
|
|
||||||
/// Parses the protocol specific response to retrieve the block data.
|
/// Parses the protocol specific response to retrieve the block data.
|
||||||
fn block_response_into_blocks(
|
fn block_response_into_blocks(
|
||||||
|
|||||||
@@ -570,7 +570,7 @@ impl<B: BlockT> BlockDownloader<B> for FullBlockDownloader {
|
|||||||
&self,
|
&self,
|
||||||
who: PeerId,
|
who: PeerId,
|
||||||
request: BlockRequest<B>,
|
request: BlockRequest<B>,
|
||||||
) -> Result<Result<Vec<u8>, RequestFailure>, oneshot::Canceled> {
|
) -> Result<Result<(Vec<u8>, ProtocolName), RequestFailure>, oneshot::Canceled> {
|
||||||
// Build the request protobuf.
|
// Build the request protobuf.
|
||||||
let bytes = BlockRequestSchema {
|
let bytes = BlockRequestSchema {
|
||||||
fields: request.fields.to_be_u32(),
|
fields: request.fields.to_be_u32(),
|
||||||
|
|||||||
@@ -1263,7 +1263,7 @@ where
|
|||||||
let ResponseEvent { peer_id, request, response } = response_event;
|
let ResponseEvent { peer_id, request, response } = response_event;
|
||||||
|
|
||||||
match response {
|
match response {
|
||||||
Ok(Ok(resp)) => match request {
|
Ok(Ok((resp, _))) => match request {
|
||||||
PeerRequest::Block(req) => {
|
PeerRequest::Block(req) => {
|
||||||
match self.block_downloader.block_response_into_blocks(&req, resp) {
|
match self.block_downloader.block_response_into_blocks(&req, resp) {
|
||||||
Ok(blocks) => {
|
Ok(blocks) => {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ use crate::block_relay_protocol::{BlockDownloader as BlockDownloaderT, BlockResp
|
|||||||
|
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use libp2p::PeerId;
|
use libp2p::PeerId;
|
||||||
use sc_network::RequestFailure;
|
use sc_network::{ProtocolName, RequestFailure};
|
||||||
use sc_network_common::sync::message::{BlockData, BlockRequest};
|
use sc_network_common::sync::message::{BlockData, BlockRequest};
|
||||||
use sp_runtime::traits::Block as BlockT;
|
use sp_runtime::traits::Block as BlockT;
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ mockall::mock! {
|
|||||||
&self,
|
&self,
|
||||||
who: PeerId,
|
who: PeerId,
|
||||||
request: BlockRequest<Block>,
|
request: BlockRequest<Block>,
|
||||||
) -> Result<Result<Vec<u8>, RequestFailure>, oneshot::Canceled>;
|
) -> Result<Result<(Vec<u8>, ProtocolName), RequestFailure>, oneshot::Canceled>;
|
||||||
fn block_response_into_blocks(
|
fn block_response_into_blocks(
|
||||||
&self,
|
&self,
|
||||||
request: &BlockRequest<Block>,
|
request: &BlockRequest<Block>,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use futures::{
|
|||||||
};
|
};
|
||||||
use libp2p::PeerId;
|
use libp2p::PeerId;
|
||||||
use log::error;
|
use log::error;
|
||||||
use sc_network::request_responses::RequestFailure;
|
use sc_network::{request_responses::RequestFailure, types::ProtocolName};
|
||||||
use sp_runtime::traits::Block as BlockT;
|
use sp_runtime::traits::Block as BlockT;
|
||||||
use std::task::{Context, Poll, Waker};
|
use std::task::{Context, Poll, Waker};
|
||||||
use tokio_stream::StreamMap;
|
use tokio_stream::StreamMap;
|
||||||
@@ -37,7 +37,7 @@ use tokio_stream::StreamMap;
|
|||||||
const LOG_TARGET: &'static str = "sync";
|
const LOG_TARGET: &'static str = "sync";
|
||||||
|
|
||||||
/// Response result.
|
/// Response result.
|
||||||
type ResponseResult = Result<Result<Vec<u8>, RequestFailure>, oneshot::Canceled>;
|
type ResponseResult = Result<Result<(Vec<u8>, ProtocolName), RequestFailure>, oneshot::Canceled>;
|
||||||
|
|
||||||
/// A future yielding [`ResponseResult`].
|
/// A future yielding [`ResponseResult`].
|
||||||
type ResponseFuture = BoxFuture<'static, ResponseResult>;
|
type ResponseFuture = BoxFuture<'static, ResponseResult>;
|
||||||
|
|||||||
@@ -117,14 +117,16 @@ mockall::mock! {
|
|||||||
target: PeerId,
|
target: PeerId,
|
||||||
protocol: ProtocolName,
|
protocol: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
) -> Result<Vec<u8>, RequestFailure>;
|
) -> Result<(Vec<u8>, ProtocolName), RequestFailure>;
|
||||||
fn start_request(
|
fn start_request(
|
||||||
&self,
|
&self,
|
||||||
target: PeerId,
|
target: PeerId,
|
||||||
protocol: ProtocolName,
|
protocol: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
tx: oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
fallback_request: Option<(Vec<u8>, ProtocolName)>,
|
||||||
|
tx: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ pub enum ToServiceCommand {
|
|||||||
PeerId,
|
PeerId,
|
||||||
ProtocolName,
|
ProtocolName,
|
||||||
Vec<u8>,
|
Vec<u8>,
|
||||||
oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
|
||||||
IfDisconnected,
|
IfDisconnected,
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ impl NetworkServiceHandle {
|
|||||||
who: PeerId,
|
who: PeerId,
|
||||||
protocol: ProtocolName,
|
protocol: ProtocolName,
|
||||||
request: Vec<u8>,
|
request: Vec<u8>,
|
||||||
tx: oneshot::Sender<Result<Vec<u8>, RequestFailure>>,
|
tx: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
|
||||||
connect: IfDisconnected,
|
connect: IfDisconnected,
|
||||||
) {
|
) {
|
||||||
let _ = self
|
let _ = self
|
||||||
@@ -134,7 +134,7 @@ impl NetworkServiceProvider {
|
|||||||
ToServiceCommand::ReportPeer(peer, reputation_change) =>
|
ToServiceCommand::ReportPeer(peer, reputation_change) =>
|
||||||
service.report_peer(peer, reputation_change),
|
service.report_peer(peer, reputation_change),
|
||||||
ToServiceCommand::StartRequest(peer, protocol, request, tx, connect) =>
|
ToServiceCommand::StartRequest(peer, protocol, request, tx, connect) =>
|
||||||
service.start_request(peer, protocol, request, tx, connect),
|
service.start_request(peer, protocol, request, None, tx, connect),
|
||||||
ToServiceCommand::WriteNotification(peer, protocol, message) =>
|
ToServiceCommand::WriteNotification(peer, protocol, message) =>
|
||||||
service.write_notification(peer, protocol, message),
|
service.write_notification(peer, protocol, message),
|
||||||
ToServiceCommand::SetNotificationHandshake(protocol, handshake) =>
|
ToServiceCommand::SetNotificationHandshake(protocol, handshake) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user