mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 21:41:12 +00:00
Get rid of Peerset compatibility layer (#14337)
* Move bootnodes from individual `SetConfig`s to `PeersetConfig` * Move `SetId` & `SetConfig` from `peerset` to `protocol_controller` * Remove unused `DropReason` * Move `Message` & `IncomingIndex` from `peerset` to `protocol_controller` * Restore running fuzz test * Get rid of `Peerset` in `fuzz` test * Spawn runners instead of manual polling in `fuzz` test * Migrate `Protocol` from `Peerset` to `PeerStore` & `ProtocolController` * Migrate `NetworkService` from `Peerset` to `PeerStore` & `ProtocolController` * Migrate `Notifications` from `Peerset` to `ProtocolController`s * Migrate `Notifications` tests from `Peerset` to `ProtocolController` * Fix compilation of `NetworkService` & `Protocol` * Fix borrowing issues in `Notifications` * Migrate `RequestResponse`from `Peerset` to `PeerStore` * rustfmt * Migrate request-response tests from `Peerset` to `PeerStore` * Migrate `reconnect_after_disconnect` test to `PeerStore` & `ProtocolController` * Fix `Notifications` tests * Remove `Peerset` completely * Fix bug with counting sync peers in `Protocol` * Eliminate indirect calls to `PeerStore` via `Protocol` * Eliminate indirect calls to `ProtocolController` via `Protocol` * Handle `Err` outcome from `remove_peers_from_reserved_set` * Add note about disconnecting sync peers in `Protocol` * minor: remove unneeded `clone()` * minor: extra comma removed * minor: use `Stream` API of `from_protocol_controllers` channel * minor: remove TODO * minor: replace `.map().flatten()` with `.flat_map()` * minor: update `ProtocolController` docs * rustfmt * Apply suggestions from code review Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com> * Extract `MockPeerStore` to `mock.rs` * Move `PeerStore` initialization to `build_network` * minor: remove unused import * minor: clarify error message * Convert `syncs_header_only_forks` test into single-threaded --------- Co-authored-by: Aaro Altonen <48052676+altonen@users.noreply.github.com>
This commit is contained in:
@@ -35,7 +35,9 @@
|
||||
//! is used to handle incoming requests.
|
||||
|
||||
use crate::{
|
||||
peer_store::BANNED_THRESHOLD, peerset::PeersetHandle, types::ProtocolName, ReputationChange,
|
||||
peer_store::{PeerStoreProvider, BANNED_THRESHOLD},
|
||||
types::ProtocolName,
|
||||
ReputationChange,
|
||||
};
|
||||
|
||||
use futures::{channel::oneshot, prelude::*};
|
||||
@@ -279,28 +281,7 @@ pub struct RequestResponsesBehaviour {
|
||||
send_feedback: HashMap<ProtocolRequestId, oneshot::Sender<()>>,
|
||||
|
||||
/// Primarily used to get a reputation of a node.
|
||||
peerset: PeersetHandle,
|
||||
|
||||
/// Pending message request, holds `MessageRequest` as a Future state to poll it
|
||||
/// until we get a response from `Peerset`
|
||||
message_request: Option<MessageRequest>,
|
||||
}
|
||||
|
||||
// This is a state of processing incoming request Message.
|
||||
// The main reason of this struct is to hold `get_peer_reputation` as a Future state.
|
||||
struct MessageRequest {
|
||||
peer: PeerId,
|
||||
request_id: RequestId,
|
||||
request: Vec<u8>,
|
||||
channel: ResponseChannel<Result<Vec<u8>, ()>>,
|
||||
protocol: ProtocolName,
|
||||
// A builder used for building responses for incoming requests. Note that we use
|
||||
// `async_channel` and not `mpsc` on purpose, because `mpsc::channel` allocates an extra
|
||||
// message slot for every cloned `Sender` and this breaks a back-pressure mechanism.
|
||||
resp_builder: Option<async_channel::Sender<IncomingRequest>>,
|
||||
// Once we get incoming request we save all params, create an async call to Peerset
|
||||
// to get the reputation of the peer.
|
||||
get_peer_reputation: Pin<Box<dyn Future<Output = Result<i32, ()>> + Send>>,
|
||||
peer_store: Box<dyn PeerStoreProvider>,
|
||||
}
|
||||
|
||||
/// Generated by the response builder and waiting to be processed.
|
||||
@@ -317,7 +298,7 @@ impl RequestResponsesBehaviour {
|
||||
/// the same protocol is passed twice.
|
||||
pub fn new(
|
||||
list: impl Iterator<Item = ProtocolConfig>,
|
||||
peerset: PeersetHandle,
|
||||
peer_store: Box<dyn PeerStoreProvider>,
|
||||
) -> Result<Self, RegisterError> {
|
||||
let mut protocols = HashMap::new();
|
||||
for protocol in list {
|
||||
@@ -354,8 +335,7 @@ impl RequestResponsesBehaviour {
|
||||
pending_responses: Default::default(),
|
||||
pending_responses_arrival_time: Default::default(),
|
||||
send_feedback: Default::default(),
|
||||
peerset,
|
||||
message_request: None,
|
||||
peer_store,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -576,96 +556,6 @@ impl NetworkBehaviour for RequestResponsesBehaviour {
|
||||
params: &mut impl PollParameters,
|
||||
) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
|
||||
'poll_all: loop {
|
||||
if let Some(message_request) = self.message_request.take() {
|
||||
// Now we can can poll `MessageRequest` until we get the reputation
|
||||
|
||||
let MessageRequest {
|
||||
peer,
|
||||
request_id,
|
||||
request,
|
||||
channel,
|
||||
protocol,
|
||||
resp_builder,
|
||||
mut get_peer_reputation,
|
||||
} = message_request;
|
||||
|
||||
let reputation = Future::poll(Pin::new(&mut get_peer_reputation), cx);
|
||||
match reputation {
|
||||
Poll::Pending => {
|
||||
// Save the state to poll it again next time.
|
||||
|
||||
self.message_request = Some(MessageRequest {
|
||||
peer,
|
||||
request_id,
|
||||
request,
|
||||
channel,
|
||||
protocol,
|
||||
resp_builder,
|
||||
get_peer_reputation,
|
||||
});
|
||||
return Poll::Pending
|
||||
},
|
||||
Poll::Ready(reputation) => {
|
||||
// Once we get the reputation we can continue processing the request.
|
||||
|
||||
let reputation = reputation.expect(
|
||||
"The channel can only be closed if the peerset no longer exists; qed",
|
||||
);
|
||||
|
||||
if reputation < BANNED_THRESHOLD {
|
||||
log::debug!(
|
||||
target: "sub-libp2p",
|
||||
"Cannot handle requests from a node with a low reputation {}: {}",
|
||||
peer,
|
||||
reputation,
|
||||
);
|
||||
continue 'poll_all
|
||||
}
|
||||
|
||||
log::trace!(target: "sub-libp2p", "request received from {peer} ({protocol:?}), {} bytes", request.len());
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
// Submit the request to the "response builder" passed by the user at
|
||||
// initialization.
|
||||
if let Some(resp_builder) = resp_builder {
|
||||
// If the response builder is too busy, silently drop `tx`. This
|
||||
// will be reported by the corresponding request-response [`Behaviour`]
|
||||
// through an `InboundFailure::Omission` event.
|
||||
// Note that we use `async_channel::bounded` and not `mpsc::channel`
|
||||
// because the latter allocates an extra slot for every cloned sender.
|
||||
let _ = resp_builder.try_send(IncomingRequest {
|
||||
peer,
|
||||
payload: request,
|
||||
pending_response: tx,
|
||||
});
|
||||
} else {
|
||||
debug_assert!(false, "Received message on outbound-only protocol.");
|
||||
}
|
||||
|
||||
self.pending_responses.push(Box::pin(async move {
|
||||
// The `tx` created above can be dropped if we are not capable of
|
||||
// processing this request, which is reflected as a
|
||||
// `InboundFailure::Omission` event.
|
||||
if let Ok(response) = rx.await {
|
||||
Some(RequestProcessingOutcome {
|
||||
peer,
|
||||
request_id,
|
||||
protocol,
|
||||
inner_channel: channel,
|
||||
response,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}));
|
||||
|
||||
// This `continue` makes sure that `pending_responses` gets polled
|
||||
// after we have added the new element.
|
||||
continue 'poll_all
|
||||
},
|
||||
}
|
||||
}
|
||||
// Poll to see if any response is ready to be sent back.
|
||||
while let Poll::Ready(Some(outcome)) = self.pending_responses.poll_next_unpin(cx) {
|
||||
let RequestProcessingOutcome {
|
||||
@@ -712,7 +602,7 @@ impl NetworkBehaviour for RequestResponsesBehaviour {
|
||||
|
||||
// Poll request-responses protocols.
|
||||
for (protocol, (behaviour, resp_builder)) in &mut self.protocols {
|
||||
while let Poll::Ready(ev) = behaviour.poll(cx, params) {
|
||||
'poll_protocol: while let Poll::Ready(ev) = behaviour.poll(cx, params) {
|
||||
let ev = match ev {
|
||||
// Main events we are interested in.
|
||||
ToSwarm::GenerateEvent(ev) => ev,
|
||||
@@ -756,23 +646,56 @@ impl NetworkBehaviour for RequestResponsesBehaviour {
|
||||
self.pending_responses_arrival_time
|
||||
.insert((protocol.clone(), request_id).into(), Instant::now());
|
||||
|
||||
let get_peer_reputation = self.peerset.clone().peer_reputation(peer);
|
||||
let get_peer_reputation = Box::pin(get_peer_reputation);
|
||||
let reputation = self.peer_store.peer_reputation(&peer);
|
||||
|
||||
// Save the Future-like state with params to poll `get_peer_reputation`
|
||||
// and to continue processing the request once we get the reputation of
|
||||
// the peer.
|
||||
self.message_request = Some(MessageRequest {
|
||||
peer,
|
||||
request_id,
|
||||
request,
|
||||
channel,
|
||||
protocol: protocol.clone(),
|
||||
resp_builder: resp_builder.clone(),
|
||||
get_peer_reputation,
|
||||
});
|
||||
if reputation < BANNED_THRESHOLD {
|
||||
log::debug!(
|
||||
target: "sub-libp2p",
|
||||
"Cannot handle requests from a node with a low reputation {}: {}",
|
||||
peer,
|
||||
reputation,
|
||||
);
|
||||
continue 'poll_protocol
|
||||
}
|
||||
|
||||
// This `continue` makes sure that `message_request` gets polled
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
// Submit the request to the "response builder" passed by the user at
|
||||
// initialization.
|
||||
if let Some(resp_builder) = resp_builder {
|
||||
// If the response builder is too busy, silently drop `tx`. This
|
||||
// will be reported by the corresponding request-response
|
||||
// [`Behaviour`] through an `InboundFailure::Omission` event.
|
||||
// Note that we use `async_channel::bounded` and not `mpsc::channel`
|
||||
// because the latter allocates an extra slot for every cloned
|
||||
// sender.
|
||||
let _ = resp_builder.try_send(IncomingRequest {
|
||||
peer,
|
||||
payload: request,
|
||||
pending_response: tx,
|
||||
});
|
||||
} else {
|
||||
debug_assert!(false, "Received message on outbound-only protocol.");
|
||||
}
|
||||
|
||||
let protocol = protocol.clone();
|
||||
|
||||
self.pending_responses.push(Box::pin(async move {
|
||||
// The `tx` created above can be dropped if we are not capable of
|
||||
// processing this request, which is reflected as a
|
||||
// `InboundFailure::Omission` event.
|
||||
rx.await.map_or(None, |response| {
|
||||
Some(RequestProcessingOutcome {
|
||||
peer,
|
||||
request_id,
|
||||
protocol,
|
||||
inner_channel: channel,
|
||||
response,
|
||||
})
|
||||
})
|
||||
}));
|
||||
|
||||
// This `continue` makes sure that `pending_responses` gets polled
|
||||
// after we have added the new element.
|
||||
continue 'poll_all
|
||||
},
|
||||
@@ -1064,7 +987,7 @@ impl Codec for GenericCodec {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::peerset::{Peerset, PeersetConfig, SetConfig};
|
||||
use crate::mock::MockPeerStore;
|
||||
use futures::{channel::oneshot, executor::LocalPool, task::Spawn};
|
||||
use libp2p::{
|
||||
core::{
|
||||
@@ -1087,7 +1010,7 @@ mod tests {
|
||||
|
||||
fn build_swarm(
|
||||
list: impl Iterator<Item = ProtocolConfig>,
|
||||
) -> (Swarm<RequestResponsesBehaviour>, Multiaddr, Peerset) {
|
||||
) -> (Swarm<RequestResponsesBehaviour>, Multiaddr) {
|
||||
let keypair = Keypair::generate_ed25519();
|
||||
|
||||
let transport = MemoryTransport::new()
|
||||
@@ -1096,19 +1019,7 @@ mod tests {
|
||||
.multiplex(libp2p::yamux::Config::default())
|
||||
.boxed();
|
||||
|
||||
let config = PeersetConfig {
|
||||
sets: vec![SetConfig {
|
||||
in_peers: u32::max_value(),
|
||||
out_peers: u32::max_value(),
|
||||
bootnodes: vec![],
|
||||
reserved_nodes: Default::default(),
|
||||
reserved_only: false,
|
||||
}],
|
||||
};
|
||||
|
||||
let (peerset, handle) = Peerset::from_config(config);
|
||||
|
||||
let behaviour = RequestResponsesBehaviour::new(list, handle).unwrap();
|
||||
let behaviour = RequestResponsesBehaviour::new(list, Box::new(MockPeerStore {})).unwrap();
|
||||
|
||||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||
let mut swarm = SwarmBuilder::with_executor(
|
||||
@@ -1121,11 +1032,7 @@ mod tests {
|
||||
let listen_addr: Multiaddr = format!("/memory/{}", rand::random::<u64>()).parse().unwrap();
|
||||
|
||||
swarm.listen_on(listen_addr.clone()).unwrap();
|
||||
(swarm, listen_addr, peerset)
|
||||
}
|
||||
|
||||
async fn loop_peerset(peerset: Peerset) {
|
||||
let _: Vec<_> = peerset.collect().await;
|
||||
(swarm, listen_addr)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1177,9 +1084,7 @@ mod tests {
|
||||
Swarm::dial(&mut swarms[0].0, dial_addr).unwrap();
|
||||
}
|
||||
|
||||
let (mut swarm, _, peerset) = swarms.remove(0);
|
||||
// Process every peerset event in the background.
|
||||
pool.spawner().spawn_obj(loop_peerset(peerset).boxed().into()).unwrap();
|
||||
let (mut swarm, _) = swarms.remove(0);
|
||||
// Running `swarm[0]` in the background.
|
||||
pool.spawner()
|
||||
.spawn_obj({
|
||||
@@ -1199,9 +1104,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
// Remove and run the remaining swarm.
|
||||
let (mut swarm, _, peerset) = swarms.remove(0);
|
||||
// Process every peerset event in the background.
|
||||
pool.spawner().spawn_obj(loop_peerset(peerset).boxed().into()).unwrap();
|
||||
let (mut swarm, _) = swarms.remove(0);
|
||||
pool.run_until(async move {
|
||||
let mut response_receiver = None;
|
||||
|
||||
@@ -1280,9 +1183,7 @@ mod tests {
|
||||
|
||||
// Running `swarm[0]` in the background until a `InboundRequest` event happens,
|
||||
// which is a hint about the test having ended.
|
||||
let (mut swarm, _, peerset) = swarms.remove(0);
|
||||
// Process every peerset event in the background.
|
||||
pool.spawner().spawn_obj(loop_peerset(peerset).boxed().into()).unwrap();
|
||||
let (mut swarm, _) = swarms.remove(0);
|
||||
pool.spawner()
|
||||
.spawn_obj({
|
||||
async move {
|
||||
@@ -1302,9 +1203,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
// Remove and run the remaining swarm.
|
||||
let (mut swarm, _, peerset) = swarms.remove(0);
|
||||
// Process every peerset event in the background.
|
||||
pool.spawner().spawn_obj(loop_peerset(peerset).boxed().into()).unwrap();
|
||||
let (mut swarm, _) = swarms.remove(0);
|
||||
pool.run_until(async move {
|
||||
let mut response_receiver = None;
|
||||
|
||||
@@ -1376,7 +1275,7 @@ mod tests {
|
||||
build_swarm(protocol_configs.into_iter()).0
|
||||
};
|
||||
|
||||
let (mut swarm_2, mut swarm_2_handler_1, mut swarm_2_handler_2, listen_add_2, peerset) = {
|
||||
let (mut swarm_2, mut swarm_2_handler_1, mut swarm_2_handler_2, listen_add_2) = {
|
||||
let (tx_1, rx_1) = async_channel::bounded(64);
|
||||
let (tx_2, rx_2) = async_channel::bounded(64);
|
||||
|
||||
@@ -1399,12 +1298,10 @@ mod tests {
|
||||
},
|
||||
];
|
||||
|
||||
let (swarm, listen_addr, peerset) = build_swarm(protocol_configs.into_iter());
|
||||
let (swarm, listen_addr) = build_swarm(protocol_configs.into_iter());
|
||||
|
||||
(swarm, rx_1, rx_2, listen_addr, peerset)
|
||||
(swarm, rx_1, rx_2, listen_addr)
|
||||
};
|
||||
// Process every peerset event in the background.
|
||||
pool.spawner().spawn_obj(loop_peerset(peerset).boxed().into()).unwrap();
|
||||
|
||||
// Ask swarm 1 to dial swarm 2. There isn't any discovery mechanism in place in this test,
|
||||
// so they wouldn't connect to each other.
|
||||
|
||||
Reference in New Issue
Block a user