mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(net): add request/response message types (#176)
* feat(net): add request/response message types * chore: rustfmt
This commit is contained in:
@ -117,9 +117,9 @@ impl From<EthMessage> for ProtocolMessage {
|
|||||||
/// correlate request-response message pairs. This allows for request multiplexing.
|
/// correlate request-response message pairs. This allows for request multiplexing.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum EthMessage {
|
pub enum EthMessage {
|
||||||
// Status is required for the protocol handshake
|
/// Status is required for the protocol handshake
|
||||||
Status(Status),
|
Status(Status),
|
||||||
// The following messages are broadcast to the network
|
/// The following messages are broadcast to the network
|
||||||
NewBlockHashes(NewBlockHashes),
|
NewBlockHashes(NewBlockHashes),
|
||||||
NewBlock(Box<NewBlock>),
|
NewBlock(Box<NewBlock>),
|
||||||
Transactions(Transactions),
|
Transactions(Transactions),
|
||||||
|
|||||||
@ -3,7 +3,12 @@
|
|||||||
//! An RLPx stream is multiplexed via the prepended message-id of a framed message.
|
//! An RLPx stream is multiplexed via the prepended message-id of a framed message.
|
||||||
//! Capabilities are exchanged via the RLPx `Hello` message as pairs of `(id, version)`, <https://github.com/ethereum/devp2p/blob/master/rlpx.md#capability-messaging>
|
//! Capabilities are exchanged via the RLPx `Hello` message as pairs of `(id, version)`, <https://github.com/ethereum/devp2p/blob/master/rlpx.md#capability-messaging>
|
||||||
|
|
||||||
use reth_eth_wire::{BlockHeaders, GetBlockHeaders};
|
use futures::FutureExt;
|
||||||
|
use reth_eth_wire::{
|
||||||
|
BlockBodies, BlockHeaders, GetBlockBodies, GetBlockHeaders, GetNodeData, GetPooledTransactions,
|
||||||
|
GetReceipts, NewBlock, NewBlockHashes, NodeData, PooledTransactions, Receipts, Transactions,
|
||||||
|
};
|
||||||
|
use std::task::{ready, Context, Poll};
|
||||||
|
|
||||||
use crate::NodeId;
|
use crate::NodeId;
|
||||||
use reth_eth_wire::capability::CapabilityMessage;
|
use reth_eth_wire::capability::CapabilityMessage;
|
||||||
@ -38,9 +43,51 @@ impl From<oneshot::error::RecvError> for RequestError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents all messages that can be sent to a peer session
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PeerMessage {
|
||||||
|
/// Announce new block hashes
|
||||||
|
NewBlockHashes(NewBlockHashes),
|
||||||
|
/// Broadcast new block.
|
||||||
|
NewBlock(Box<NewBlock>),
|
||||||
|
/// Broadcast transactions.
|
||||||
|
Transactions(Transactions),
|
||||||
|
/// All `eth` request variants.
|
||||||
|
EthRequest(PeerRequest),
|
||||||
|
/// Other than eth namespace message
|
||||||
|
Other(CapabilityMessage),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// All Request variants of an [`EthMessage`]
|
||||||
|
///
|
||||||
|
/// Note: These variants come without a request ID, as it's expected that the peer session will
|
||||||
|
/// manage those
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
pub enum EthRequest {
|
||||||
|
GetBlockHeaders(GetBlockHeaders),
|
||||||
|
GetBlockBodies(GetBlockBodies),
|
||||||
|
GetPooledTransactions(GetPooledTransactions),
|
||||||
|
GetNodeData(GetNodeData),
|
||||||
|
GetReceipts(GetReceipts),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Corresponding Response variants for [`EthRequest`]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum EthResponse {
|
||||||
|
BlockHeaders(BlockHeaders),
|
||||||
|
BlockBodies(BlockBodies),
|
||||||
|
PooledTransactions(PooledTransactions),
|
||||||
|
NodeData(NodeData),
|
||||||
|
Receipts(Receipts),
|
||||||
|
}
|
||||||
|
|
||||||
/// Protocol related request messages that expect a response
|
/// Protocol related request messages that expect a response
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CapabilityRequest {
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
pub enum PeerRequest {
|
||||||
/// Request Block headers from the peer.
|
/// Request Block headers from the peer.
|
||||||
///
|
///
|
||||||
/// The response should be sent through the channel.
|
/// The response should be sent through the channel.
|
||||||
@ -48,19 +95,80 @@ pub enum CapabilityRequest {
|
|||||||
request: GetBlockHeaders,
|
request: GetBlockHeaders,
|
||||||
response: oneshot::Sender<RequestResult<BlockHeaders>>,
|
response: oneshot::Sender<RequestResult<BlockHeaders>>,
|
||||||
},
|
},
|
||||||
|
/// Request Block headers from the peer.
|
||||||
|
///
|
||||||
|
/// The response should be sent through the channel.
|
||||||
|
GetBlockBodies {
|
||||||
|
request: GetBlockHeaders,
|
||||||
|
response: oneshot::Sender<RequestResult<BlockHeaders>>,
|
||||||
|
},
|
||||||
|
/// Request pooled transactions from the peer.
|
||||||
|
///
|
||||||
|
/// The response should be sent through the channel.
|
||||||
|
GetPooledTransactions {
|
||||||
|
request: GetPooledTransactions,
|
||||||
|
response: oneshot::Sender<RequestResult<PooledTransactions>>,
|
||||||
|
},
|
||||||
|
/// Request NodeData from the peer.
|
||||||
|
///
|
||||||
|
/// The response should be sent through the channel.
|
||||||
|
GetNodeData { request: GetNodeData, response: oneshot::Sender<RequestResult<NodeData>> },
|
||||||
|
/// Request Receipts from the peer.
|
||||||
|
///
|
||||||
|
/// The response should be sent through the channel.
|
||||||
|
GetReceipts { request: GetReceipts, response: oneshot::Sender<RequestResult<Receipts>> },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The actual response object
|
/// Corresponding variant for [`PeerRequest`].
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CapabilityResponse {
|
pub enum PeerResponse {
|
||||||
GetBlockHeaders(RequestResult<BlockHeaders>),
|
BlockHeaders { response: oneshot::Receiver<RequestResult<BlockHeaders>> },
|
||||||
|
BlockBodies { response: oneshot::Receiver<RequestResult<BlockBodies>> },
|
||||||
|
PooledTransactions { response: oneshot::Receiver<RequestResult<PooledTransactions>> },
|
||||||
|
NodeData { response: oneshot::Receiver<RequestResult<NodeData>> },
|
||||||
|
Receipts { response: oneshot::Receiver<RequestResult<Receipts>> },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Cloneable connection for sending messages directly to the session of a peer.
|
// === impl PeerResponse ===
|
||||||
|
|
||||||
|
impl PeerResponse {
|
||||||
|
/// Polls the type to completion.
|
||||||
|
pub(crate) fn poll(&mut self, cx: &mut Context<'_>) -> Poll<RequestResult<EthResponse>> {
|
||||||
|
macro_rules! poll_request {
|
||||||
|
($response:ident, $item:ident, $cx:ident) => {
|
||||||
|
match ready!($response.poll_unpin($cx)) {
|
||||||
|
Ok(res) => res.map(EthResponse::$item),
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = match self {
|
||||||
|
PeerResponse::BlockHeaders { response } => {
|
||||||
|
poll_request!(response, BlockHeaders, cx)
|
||||||
|
}
|
||||||
|
PeerResponse::BlockBodies { response } => {
|
||||||
|
poll_request!(response, BlockBodies, cx)
|
||||||
|
}
|
||||||
|
PeerResponse::PooledTransactions { response } => {
|
||||||
|
poll_request!(response, PooledTransactions, cx)
|
||||||
|
}
|
||||||
|
PeerResponse::NodeData { response } => {
|
||||||
|
poll_request!(response, NodeData, cx)
|
||||||
|
}
|
||||||
|
PeerResponse::Receipts { response } => {
|
||||||
|
poll_request!(response, Receipts, cx)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Poll::Ready(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Cloneable connection for sending _requests_ directly to the session of a peer.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PeerMessageSender {
|
pub struct PeerRequestSender {
|
||||||
/// id of the remote node.
|
/// id of the remote node.
|
||||||
pub(crate) peer: NodeId,
|
pub(crate) peer: NodeId,
|
||||||
/// The Sender half connected to a session.
|
/// The Sender half connected to a session.
|
||||||
pub(crate) to_session_tx: mpsc::Sender<CapabilityMessage>,
|
pub(crate) to_session_tx: mpsc::Sender<PeerRequest>,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
//! Represents an established session.
|
//! Represents an established session.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
message::PeerRequest,
|
||||||
session::{
|
session::{
|
||||||
handle::{ActiveSessionMessage, SessionCommand},
|
handle::{ActiveSessionMessage, SessionCommand},
|
||||||
SessionId,
|
SessionId,
|
||||||
},
|
},
|
||||||
NodeId,
|
NodeId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use futures::{stream::Fuse, Sink, Stream};
|
use futures::{stream::Fuse, Sink, Stream};
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
@ -27,6 +27,8 @@ use tokio_stream::wrappers::ReceiverStream;
|
|||||||
/// node or read from connection) and emitting events back to the [`SessionHandler`].
|
/// node or read from connection) and emitting events back to the [`SessionHandler`].
|
||||||
#[pin_project]
|
#[pin_project]
|
||||||
pub(crate) struct ActiveSession {
|
pub(crate) struct ActiveSession {
|
||||||
|
/// Keeps track of request ids.
|
||||||
|
pub(crate) next_id: usize,
|
||||||
/// The underlying connection.
|
/// The underlying connection.
|
||||||
#[pin]
|
#[pin]
|
||||||
pub(crate) conn: ECIESStream<TcpStream>,
|
pub(crate) conn: ECIESStream<TcpStream>,
|
||||||
@ -43,9 +45,9 @@ pub(crate) struct ActiveSession {
|
|||||||
pub(crate) to_session: mpsc::Sender<ActiveSessionMessage>,
|
pub(crate) to_session: mpsc::Sender<ActiveSessionMessage>,
|
||||||
/// Incoming request to send to delegate to the remote peer.
|
/// Incoming request to send to delegate to the remote peer.
|
||||||
#[pin]
|
#[pin]
|
||||||
pub(crate) messages_rx: Fuse<ReceiverStream<CapabilityMessage>>,
|
pub(crate) request_tx: Fuse<ReceiverStream<PeerRequest>>,
|
||||||
/// All requests currently in progress.
|
/// All requests currently in progress.
|
||||||
pub(crate) inflight_requests: FnvHashMap<u64, ()>,
|
pub(crate) inflight_requests: FnvHashMap<usize, ()>,
|
||||||
/// Buffered messages that should be sent to the remote peer.
|
/// Buffered messages that should be sent to the remote peer.
|
||||||
pub(crate) buffered_outgoing: VecDeque<CapabilityMessage>,
|
pub(crate) buffered_outgoing: VecDeque<CapabilityMessage>,
|
||||||
}
|
}
|
||||||
@ -76,7 +78,7 @@ impl Future for ActiveSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Poll::Ready(Some(_msg)) = this.messages_rx.as_mut().poll_next(cx) {
|
while let Poll::Ready(Some(_req)) = this.request_tx.as_mut().poll_next(cx) {
|
||||||
progress = true;
|
progress = true;
|
||||||
// TODO handle request
|
// TODO handle request
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
//! Support for handling peer sessions.
|
//! Support for handling peer sessions.
|
||||||
pub use crate::message::PeerMessageSender;
|
pub use crate::message::PeerRequestSender;
|
||||||
use crate::{
|
use crate::{
|
||||||
session::{
|
session::{
|
||||||
active::ActiveSession,
|
active::ActiveSession,
|
||||||
@ -234,15 +234,16 @@ impl SessionManager {
|
|||||||
|
|
||||||
let (to_session_tx, messages_rx) = mpsc::channel(self.session_command_buffer);
|
let (to_session_tx, messages_rx) = mpsc::channel(self.session_command_buffer);
|
||||||
|
|
||||||
let messages = PeerMessageSender { peer: node_id, to_session_tx };
|
let messages = PeerRequestSender { peer: node_id, to_session_tx };
|
||||||
|
|
||||||
let session = ActiveSession {
|
let session = ActiveSession {
|
||||||
|
next_id: 0,
|
||||||
remote_node_id: node_id,
|
remote_node_id: node_id,
|
||||||
remote_capabilities: Arc::clone(&capabilities),
|
remote_capabilities: Arc::clone(&capabilities),
|
||||||
session_id,
|
session_id,
|
||||||
commands_rx: ReceiverStream::new(commands_rx),
|
commands_rx: ReceiverStream::new(commands_rx),
|
||||||
to_session: self.active_session_tx.clone(),
|
to_session: self.active_session_tx.clone(),
|
||||||
messages_rx: ReceiverStream::new(messages_rx).fuse(),
|
request_tx: ReceiverStream::new(messages_rx).fuse(),
|
||||||
inflight_requests: Default::default(),
|
inflight_requests: Default::default(),
|
||||||
conn,
|
conn,
|
||||||
buffered_outgoing: Default::default(),
|
buffered_outgoing: Default::default(),
|
||||||
@ -379,7 +380,7 @@ pub(crate) enum SessionEvent {
|
|||||||
remote_addr: SocketAddr,
|
remote_addr: SocketAddr,
|
||||||
capabilities: Arc<Capabilities>,
|
capabilities: Arc<Capabilities>,
|
||||||
status: Status,
|
status: Status,
|
||||||
messages: PeerMessageSender,
|
messages: PeerRequestSender,
|
||||||
},
|
},
|
||||||
/// A session received a valid message via RLPx.
|
/// A session received a valid message via RLPx.
|
||||||
ValidMessage {
|
ValidMessage {
|
||||||
|
|||||||
@ -3,13 +3,11 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
discovery::{Discovery, DiscoveryEvent},
|
discovery::{Discovery, DiscoveryEvent},
|
||||||
fetch::StateFetcher,
|
fetch::StateFetcher,
|
||||||
message::CapabilityResponse,
|
message::{EthResponse, PeerRequestSender, PeerResponse},
|
||||||
peers::{PeerAction, PeersManager},
|
peers::{PeerAction, PeersManager},
|
||||||
NodeId,
|
NodeId,
|
||||||
};
|
};
|
||||||
use futures::FutureExt;
|
|
||||||
|
|
||||||
use crate::message::PeerMessageSender;
|
|
||||||
use reth_eth_wire::{capability::Capabilities, Status};
|
use reth_eth_wire::{capability::Capabilities, Status};
|
||||||
use reth_interfaces::provider::BlockProvider;
|
use reth_interfaces::provider::BlockProvider;
|
||||||
use reth_primitives::{H256, U256};
|
use reth_primitives::{H256, U256};
|
||||||
@ -20,7 +18,7 @@ use std::{
|
|||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
use tokio::sync::oneshot;
|
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
/// The [`NetworkState`] keeps track of the state of all peers in the network.
|
/// The [`NetworkState`] keeps track of the state of all peers in the network.
|
||||||
@ -76,7 +74,7 @@ where
|
|||||||
_node_id: NodeId,
|
_node_id: NodeId,
|
||||||
_capabilities: Arc<Capabilities>,
|
_capabilities: Arc<Capabilities>,
|
||||||
_status: Status,
|
_status: Status,
|
||||||
_messages: PeerMessageSender,
|
_messages: PeerRequestSender,
|
||||||
) {
|
) {
|
||||||
// TODO notify fetecher as well
|
// TODO notify fetecher as well
|
||||||
}
|
}
|
||||||
@ -119,7 +117,7 @@ where
|
|||||||
fn disconnect_session(&mut self, _node: NodeId) {}
|
fn disconnect_session(&mut self, _node: NodeId) {}
|
||||||
|
|
||||||
/// Invoked when received a response from a connected peer.
|
/// Invoked when received a response from a connected peer.
|
||||||
fn on_response(&mut self, _node: NodeId, _resp: CapabilityResponse) {}
|
fn on_eth_response(&mut self, _node: NodeId, _resp: EthResponse) {}
|
||||||
|
|
||||||
/// Advances the state
|
/// Advances the state
|
||||||
pub(crate) fn poll(&mut self, cx: &mut Context<'_>) -> Poll<StateAction> {
|
pub(crate) fn poll(&mut self, cx: &mut Context<'_>) -> Poll<StateAction> {
|
||||||
@ -138,7 +136,7 @@ where
|
|||||||
// poll all connected peers for responses
|
// poll all connected peers for responses
|
||||||
for (id, peer) in self.connected_peers.iter_mut() {
|
for (id, peer) in self.connected_peers.iter_mut() {
|
||||||
if let Some(response) = peer.pending_response.as_mut() {
|
if let Some(response) = peer.pending_response.as_mut() {
|
||||||
match response.poll_unpin(cx) {
|
match response.poll(cx) {
|
||||||
Poll::Ready(Ok(resp)) => received_responses.push((*id, resp)),
|
Poll::Ready(Ok(resp)) => received_responses.push((*id, resp)),
|
||||||
Poll::Ready(Err(_)) => {
|
Poll::Ready(Err(_)) => {
|
||||||
trace!(
|
trace!(
|
||||||
@ -161,7 +159,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (id, resp) in received_responses {
|
for (id, resp) in received_responses {
|
||||||
self.on_response(id, resp);
|
self.on_eth_response(id, resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// poll peer manager
|
// poll peer manager
|
||||||
@ -185,9 +183,9 @@ pub struct ConnectedPeer {
|
|||||||
/// Best block number of the peer.
|
/// Best block number of the peer.
|
||||||
pub(crate) best_number: U256,
|
pub(crate) best_number: U256,
|
||||||
/// A communication channel directly to the session service.
|
/// A communication channel directly to the session service.
|
||||||
pub(crate) message_tx: PeerMessageSender,
|
pub(crate) message_tx: PeerRequestSender,
|
||||||
/// The response receiver for a currently active request to that peer.
|
/// The response receiver for a currently active request to that peer.
|
||||||
pub(crate) pending_response: Option<oneshot::Receiver<CapabilityResponse>>,
|
pub(crate) pending_response: Option<PeerResponse>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tracks the current state of the peer session
|
/// Tracks the current state of the peer session
|
||||||
@ -201,12 +199,12 @@ pub enum PeerSessionState {
|
|||||||
Incoming {
|
Incoming {
|
||||||
/// How long to keep this open.
|
/// How long to keep this open.
|
||||||
until: Instant,
|
until: Instant,
|
||||||
sender: PeerMessageSender,
|
sender: PeerRequestSender,
|
||||||
},
|
},
|
||||||
/// Node is connected to the peer and is ready to
|
/// Node is connected to the peer and is ready to
|
||||||
Ready {
|
Ready {
|
||||||
/// Communication channel directly to the session task
|
/// Communication channel directly to the session task
|
||||||
sender: PeerMessageSender,
|
sender: PeerRequestSender,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user