lighthouse/beacon_node/network/src/service.rs

210 lines
8.1 KiB
Rust
Raw Normal View History

use crate::error;
use crate::message_handler::{HandlerMessage, MessageHandler};
use crate::NetworkConfig;
use beacon_chain::{BeaconChain, BeaconChainTypes};
2019-03-20 04:09:24 +00:00
use eth2_libp2p::Service as LibP2PService;
use eth2_libp2p::Topic;
2019-03-20 04:09:24 +00:00
use eth2_libp2p::{Libp2pEvent, PeerId};
use eth2_libp2p::{PubsubMessage, RPCEvent};
2019-03-12 06:28:11 +00:00
use futures::prelude::*;
use futures::Stream;
2019-03-18 12:34:44 +00:00
use slog::{debug, info, o, trace};
use std::marker::PhantomData;
use std::sync::Arc;
2019-03-12 06:28:11 +00:00
use tokio::runtime::TaskExecutor;
use tokio::sync::{mpsc, oneshot};
2019-03-20 04:09:24 +00:00
/// Service that handles communication between internal services and the eth2_libp2p network service.
pub struct Service<T: BeaconChainTypes> {
//libp2p_service: Arc<Mutex<LibP2PService>>,
2019-04-03 05:23:09 +00:00
_libp2p_exit: oneshot::Sender<()>,
network_send: mpsc::UnboundedSender<NetworkMessage>,
_phantom: PhantomData<T>, //message_handler: MessageHandler,
//message_handler_send: Sender<HandlerMessage>
}
impl<T: BeaconChainTypes + 'static> Service<T> {
pub fn new(
beacon_chain: Arc<BeaconChain<T>>,
config: &NetworkConfig,
executor: &TaskExecutor,
log: slog::Logger,
) -> error::Result<(Arc<Self>, mpsc::UnboundedSender<NetworkMessage>)> {
// build the network channel
let (network_send, network_recv) = mpsc::unbounded_channel::<NetworkMessage>();
// launch message handler thread
let message_handler_log = log.new(o!("Service" => "MessageHandler"));
2019-03-19 12:20:39 +00:00
let message_handler_send = MessageHandler::spawn(
beacon_chain,
network_send.clone(),
executor,
message_handler_log,
)?;
// launch libp2p service
let libp2p_log = log.new(o!("Service" => "Libp2p"));
let libp2p_service = LibP2PService::new(config.clone(), libp2p_log)?;
// TODO: Spawn thread to handle libp2p messages and pass to message handler thread.
let libp2p_exit = spawn_service(
libp2p_service,
network_recv,
message_handler_send,
executor,
log,
)?;
2019-03-19 11:53:51 +00:00
let network_service = Service {
2019-04-03 05:23:09 +00:00
_libp2p_exit: libp2p_exit,
2019-03-12 06:28:11 +00:00
network_send: network_send.clone(),
_phantom: PhantomData,
2019-03-12 06:28:11 +00:00
};
2019-03-19 11:53:51 +00:00
Ok((Arc::new(network_service), network_send))
}
2019-03-12 06:28:11 +00:00
// TODO: Testing only
pub fn send_message(&mut self) {
2019-03-19 11:53:51 +00:00
self.network_send
.try_send(NetworkMessage::Send(
2019-03-19 11:53:51 +00:00
PeerId::random(),
OutgoingMessage::NotifierTest,
))
.unwrap();
2019-03-12 06:28:11 +00:00
}
}
fn spawn_service(
libp2p_service: LibP2PService,
network_recv: mpsc::UnboundedReceiver<NetworkMessage>,
message_handler_send: mpsc::UnboundedSender<HandlerMessage>,
executor: &TaskExecutor,
2019-03-12 06:28:11 +00:00
log: slog::Logger,
) -> error::Result<tokio::sync::oneshot::Sender<()>> {
let (network_exit, exit_rx) = tokio::sync::oneshot::channel();
2019-03-12 06:28:11 +00:00
// spawn on the current executor
executor.spawn(
network_service(
libp2p_service,
2019-03-12 06:28:11 +00:00
network_recv,
message_handler_send,
log.clone(),
)
// allow for manual termination
.select(exit_rx.then(|_| Ok(())))
.then(move |_| {
2019-03-18 07:22:01 +00:00
info!(log.clone(), "Network service shutdown");
2019-03-12 06:28:11 +00:00
Ok(())
}),
);
Ok(network_exit)
2019-03-12 06:28:11 +00:00
}
//TODO: Potentially handle channel errors
2019-03-12 06:28:11 +00:00
fn network_service(
mut libp2p_service: LibP2PService,
mut network_recv: mpsc::UnboundedReceiver<NetworkMessage>,
mut message_handler_send: mpsc::UnboundedSender<HandlerMessage>,
2019-03-12 06:28:11 +00:00
log: slog::Logger,
2019-03-20 04:09:24 +00:00
) -> impl futures::Future<Item = (), Error = eth2_libp2p::error::Error> {
futures::future::poll_fn(move || -> Result<_, eth2_libp2p::error::Error> {
// only end the loop once both major polls are not ready.
let mut not_ready_count = 0;
while not_ready_count < 2 {
not_ready_count = 0;
// poll the network channel
match network_recv.poll() {
Ok(Async::Ready(Some(message))) => {
match message {
// TODO: Testing message - remove
NetworkMessage::Send(peer_id, outgoing_message) => {
match outgoing_message {
OutgoingMessage::RPC(rpc_event) => {
trace!(log, "Sending RPC Event: {:?}", rpc_event);
//TODO: Make swarm private
//TODO: Implement correct peer id topic message handling
libp2p_service.swarm.send_rpc(peer_id, rpc_event);
}
OutgoingMessage::NotifierTest => {
// debug!(log, "Received message from notifier");
}
};
}
NetworkMessage::Publish { topics, message } => {
debug!(log, "Sending pubsub message"; "topics" => format!("{:?}",topics));
libp2p_service.swarm.publish(topics, *message);
}
}
}
Ok(Async::NotReady) => not_ready_count += 1,
Ok(Async::Ready(None)) => {
return Err(eth2_libp2p::error::Error::from("Network channel closed"));
}
Err(_) => {
return Err(eth2_libp2p::error::Error::from("Network channel error"));
}
}
// poll the swarm
match libp2p_service.poll() {
Ok(Async::Ready(Some(event))) => match event {
Libp2pEvent::RPC(peer_id, rpc_event) => {
trace!(log, "RPC Event: RPC message received: {:?}", rpc_event);
message_handler_send
.try_send(HandlerMessage::RPC(peer_id, rpc_event))
2019-07-16 13:26:31 +00:00
.map_err(|_| "Failed to send RPC to handler")?;
}
Libp2pEvent::PeerDialed(peer_id) => {
debug!(log, "Peer Dialed: {:?}", peer_id);
message_handler_send
.try_send(HandlerMessage::PeerDialed(peer_id))
.map_err(|_| "Failed to send PeerDialed to handler")?;
}
Libp2pEvent::PeerDisconnected(peer_id) => {
debug!(log, "Peer Disconnected: {:?}", peer_id);
message_handler_send
2019-07-16 13:26:31 +00:00
.try_send(HandlerMessage::PeerDisconnected(peer_id))
.map_err(|_| "Failed to send PeerDisconnected to handler")?;
}
Libp2pEvent::PubsubMessage {
2019-04-03 05:23:09 +00:00
source, message, ..
} => {
//TODO: Decide if we need to propagate the topic upwards. (Potentially for
//attestations)
message_handler_send
.try_send(HandlerMessage::PubsubMessage(source, message))
.map_err(|_| " failed to send pubsub message to handler")?;
}
},
Ok(Async::Ready(None)) => unreachable!("Stream never ends"),
Ok(Async::NotReady) => not_ready_count += 1,
Err(_) => not_ready_count += 1,
2019-03-12 06:28:11 +00:00
}
}
Ok(Async::NotReady)
})
}
/// Types of messages that the network service can receive.
#[derive(Debug)]
pub enum NetworkMessage {
/// Send a message to libp2p service.
//TODO: Define typing for messages across the wire
2019-03-18 12:34:44 +00:00
Send(PeerId, OutgoingMessage),
/// Publish a message to pubsub mechanism.
Publish {
topics: Vec<Topic>,
2019-04-03 05:23:09 +00:00
message: Box<PubsubMessage>,
},
2019-03-18 12:34:44 +00:00
}
/// Type of outgoing messages that can be sent through the network service.
#[derive(Debug)]
2019-03-18 12:34:44 +00:00
pub enum OutgoingMessage {
/// Send an RPC request/response.
RPC(RPCEvent),
//TODO: Remove
NotifierTest,
}