2019-03-25 12:02:51 +00:00
|
|
|
use crate::behaviour::{Behaviour, BehaviourEvent, PubsubMessage};
|
2019-03-12 06:28:11 +00:00
|
|
|
use crate::error;
|
2019-03-08 01:15:57 +00:00
|
|
|
use crate::multiaddr::Protocol;
|
2019-03-17 12:14:28 +00:00
|
|
|
use crate::rpc::RPCEvent;
|
2019-03-06 12:31:08 +00:00
|
|
|
use crate::NetworkConfig;
|
2020-02-19 11:12:25 +00:00
|
|
|
use crate::{NetworkGlobals, Topic, TopicHash};
|
2019-03-07 05:17:06 +00:00
|
|
|
use futures::prelude::*;
|
2019-03-12 06:28:11 +00:00
|
|
|
use futures::Stream;
|
2019-03-07 05:17:06 +00:00
|
|
|
use libp2p::core::{
|
2019-10-30 01:22:18 +00:00
|
|
|
identity::Keypair, multiaddr::Multiaddr, muxing::StreamMuxerBox, nodes::Substream,
|
2019-11-29 02:04:44 +00:00
|
|
|
transport::boxed::Boxed, ConnectedPoint,
|
2019-03-07 05:17:06 +00:00
|
|
|
};
|
2019-12-20 05:26:30 +00:00
|
|
|
use libp2p::gossipsub::MessageId;
|
2019-11-29 02:04:44 +00:00
|
|
|
use libp2p::{core, secio, swarm::NetworkBehaviour, PeerId, Swarm, Transport};
|
2019-12-06 03:13:43 +00:00
|
|
|
use slog::{crit, debug, error, info, trace, warn};
|
2019-07-01 06:38:42 +00:00
|
|
|
use std::fs::File;
|
|
|
|
use std::io::prelude::*;
|
2019-03-07 05:17:06 +00:00
|
|
|
use std::io::{Error, ErrorKind};
|
2020-02-19 11:12:25 +00:00
|
|
|
use std::sync::Arc;
|
2019-03-07 05:17:06 +00:00
|
|
|
use std::time::Duration;
|
2019-12-06 03:13:43 +00:00
|
|
|
use tokio::timer::DelayQueue;
|
2019-03-04 07:31:01 +00:00
|
|
|
|
2019-04-03 05:23:09 +00:00
|
|
|
type Libp2pStream = Boxed<(PeerId, StreamMuxerBox), Error>;
|
2019-08-10 01:44:17 +00:00
|
|
|
type Libp2pBehaviour = Behaviour<Substream<StreamMuxerBox>>;
|
2019-04-03 05:23:09 +00:00
|
|
|
|
2019-07-01 06:38:42 +00:00
|
|
|
const NETWORK_KEY_FILENAME: &str = "key";
|
2019-11-29 02:04:44 +00:00
|
|
|
/// The time in milliseconds to wait before banning a peer. This allows for any Goodbye messages to be
|
|
|
|
/// flushed and protocols to be negotiated.
|
2019-12-06 03:13:43 +00:00
|
|
|
const BAN_PEER_WAIT_TIMEOUT: u64 = 200;
|
2019-07-01 06:38:42 +00:00
|
|
|
|
2019-03-04 07:31:01 +00:00
|
|
|
/// The configuration and state of the libp2p components for the beacon node.
|
2019-08-10 01:44:17 +00:00
|
|
|
pub struct Service {
|
2019-03-07 00:43:55 +00:00
|
|
|
/// The libp2p Swarm handler.
|
2019-03-12 06:28:11 +00:00
|
|
|
//TODO: Make this private
|
2019-08-10 01:44:17 +00:00
|
|
|
pub swarm: Swarm<Libp2pStream, Libp2pBehaviour>,
|
2019-11-27 01:47:46 +00:00
|
|
|
|
2019-03-06 12:31:08 +00:00
|
|
|
/// This node's PeerId.
|
2019-08-23 05:53:53 +00:00
|
|
|
pub local_peer_id: PeerId,
|
2019-11-27 01:47:46 +00:00
|
|
|
|
2019-11-29 02:04:44 +00:00
|
|
|
/// A current list of peers to ban after a given timeout.
|
2019-12-06 03:13:43 +00:00
|
|
|
peers_to_ban: DelayQueue<PeerId>,
|
|
|
|
|
|
|
|
/// A list of timeouts after which peers become unbanned.
|
|
|
|
peer_ban_timeout: DelayQueue<PeerId>,
|
2019-11-29 02:04:44 +00:00
|
|
|
|
2019-03-12 06:28:11 +00:00
|
|
|
/// The libp2p logger handle.
|
|
|
|
pub log: slog::Logger,
|
2019-03-06 12:31:08 +00:00
|
|
|
}
|
2019-03-04 07:31:01 +00:00
|
|
|
|
2019-08-10 01:44:17 +00:00
|
|
|
impl Service {
|
2020-02-19 11:12:25 +00:00
|
|
|
pub fn new(
|
|
|
|
config: &NetworkConfig,
|
|
|
|
log: slog::Logger,
|
|
|
|
) -> error::Result<(Arc<NetworkGlobals>, Self)> {
|
2019-08-29 11:23:28 +00:00
|
|
|
trace!(log, "Libp2p Service starting");
|
2019-03-06 12:31:08 +00:00
|
|
|
|
2019-09-10 16:13:54 +00:00
|
|
|
let local_keypair = if let Some(hex_bytes) = &config.secret_key_hex {
|
|
|
|
keypair_from_hex(hex_bytes)?
|
|
|
|
} else {
|
2020-02-19 11:12:25 +00:00
|
|
|
load_private_key(config, &log)
|
2019-09-10 16:13:54 +00:00
|
|
|
};
|
|
|
|
|
2019-07-01 06:38:42 +00:00
|
|
|
// load the private key from CLI flag, disk or generate a new one
|
2019-09-10 16:13:54 +00:00
|
|
|
let local_peer_id = PeerId::from(local_keypair.public());
|
2019-08-29 11:23:28 +00:00
|
|
|
info!(log, "Libp2p Service"; "peer_id" => format!("{:?}", local_peer_id));
|
2019-03-06 12:31:08 +00:00
|
|
|
|
2020-02-19 11:12:25 +00:00
|
|
|
// set up a collection of variables accessible outside of the network crate
|
|
|
|
let network_globals = Arc::new(NetworkGlobals::new(local_peer_id.clone()));
|
|
|
|
|
2019-03-08 00:07:30 +00:00
|
|
|
let mut swarm = {
|
2019-06-25 04:51:45 +00:00
|
|
|
// Set up the transport - tcp/ws with secio and mplex/yamux
|
2019-09-10 16:13:54 +00:00
|
|
|
let transport = build_transport(local_keypair.clone());
|
2019-06-25 04:51:45 +00:00
|
|
|
// Lighthouse network behaviour
|
2020-02-19 11:12:25 +00:00
|
|
|
let behaviour = Behaviour::new(&local_keypair, config, network_globals.clone(), &log)?;
|
2019-06-25 04:51:45 +00:00
|
|
|
Swarm::new(transport, behaviour, local_peer_id.clone())
|
2019-03-08 00:07:30 +00:00
|
|
|
};
|
2019-03-06 12:31:08 +00:00
|
|
|
|
2019-06-25 08:02:11 +00:00
|
|
|
// listen on the specified address
|
|
|
|
let listen_multiaddr = {
|
|
|
|
let mut m = Multiaddr::from(config.listen_address);
|
|
|
|
m.push(Protocol::Tcp(config.libp2p_port));
|
|
|
|
m
|
|
|
|
};
|
|
|
|
|
|
|
|
match Swarm::listen_on(&mut swarm, listen_multiaddr.clone()) {
|
|
|
|
Ok(_) => {
|
|
|
|
let mut log_address = listen_multiaddr;
|
|
|
|
log_address.push(Protocol::P2p(local_peer_id.clone().into()));
|
2019-08-29 11:23:28 +00:00
|
|
|
info!(log, "Listening established"; "address" => format!("{}", log_address));
|
2019-06-25 08:02:11 +00:00
|
|
|
}
|
2019-08-23 05:53:53 +00:00
|
|
|
Err(err) => {
|
|
|
|
crit!(
|
|
|
|
log,
|
|
|
|
"Unable to listen on libp2p address";
|
|
|
|
"error" => format!("{:?}", err),
|
|
|
|
"listen_multiaddr" => format!("{}", listen_multiaddr),
|
|
|
|
);
|
|
|
|
return Err("Libp2p was unable to listen on the given listen address.".into());
|
|
|
|
}
|
2019-06-25 08:02:11 +00:00
|
|
|
};
|
2019-03-06 12:31:08 +00:00
|
|
|
|
2019-09-02 21:50:44 +00:00
|
|
|
// helper closure for dialing peers
|
2020-02-19 11:12:25 +00:00
|
|
|
let mut dial_addr = |multiaddr: &Multiaddr| {
|
2019-08-10 01:44:17 +00:00
|
|
|
match Swarm::dial_addr(&mut swarm, multiaddr.clone()) {
|
2019-08-29 11:23:28 +00:00
|
|
|
Ok(()) => debug!(log, "Dialing libp2p peer"; "address" => format!("{}", multiaddr)),
|
2019-08-10 01:44:17 +00:00
|
|
|
Err(err) => debug!(
|
|
|
|
log,
|
2019-09-02 14:34:41 +00:00
|
|
|
"Could not connect to peer"; "address" => format!("{}", multiaddr), "error" => format!("{:?}", err)
|
2019-08-10 01:44:17 +00:00
|
|
|
),
|
|
|
|
};
|
2019-09-02 21:50:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// attempt to connect to user-input libp2p nodes
|
2020-02-19 11:12:25 +00:00
|
|
|
for multiaddr in &config.libp2p_nodes {
|
2019-09-02 21:50:44 +00:00
|
|
|
dial_addr(multiaddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// attempt to connect to any specified boot-nodes
|
2020-02-19 11:12:25 +00:00
|
|
|
for bootnode_enr in &config.boot_nodes {
|
|
|
|
for multiaddr in &bootnode_enr.multiaddr() {
|
2019-09-04 22:07:57 +00:00
|
|
|
// ignore udp multiaddr if it exists
|
|
|
|
let components = multiaddr.iter().collect::<Vec<_>>();
|
|
|
|
if let Protocol::Udp(_) = components[1] {
|
|
|
|
continue;
|
|
|
|
}
|
2019-09-02 21:50:44 +00:00
|
|
|
dial_addr(multiaddr);
|
|
|
|
}
|
2019-08-10 01:44:17 +00:00
|
|
|
}
|
|
|
|
|
2019-12-20 05:26:30 +00:00
|
|
|
let mut subscribed_topics: Vec<String> = vec![];
|
2020-02-19 11:12:25 +00:00
|
|
|
for topic in config.topics.clone() {
|
2019-12-20 05:26:30 +00:00
|
|
|
let raw_topic: Topic = topic.into();
|
|
|
|
let topic_string = raw_topic.no_hash();
|
|
|
|
if swarm.subscribe(raw_topic.clone()) {
|
|
|
|
trace!(log, "Subscribed to topic"; "topic" => format!("{}", topic_string));
|
|
|
|
subscribed_topics.push(topic_string.as_str().into());
|
2019-03-19 12:20:39 +00:00
|
|
|
} else {
|
2019-12-20 05:26:30 +00:00
|
|
|
warn!(log, "Could not subscribe to topic"; "topic" => format!("{}",topic_string));
|
2019-03-19 12:20:39 +00:00
|
|
|
}
|
2019-03-13 04:37:44 +00:00
|
|
|
}
|
2019-12-20 05:26:30 +00:00
|
|
|
info!(log, "Subscribed to topics"; "topics" => format!("{:?}", subscribed_topics));
|
2019-03-13 04:37:44 +00:00
|
|
|
|
2020-02-19 11:12:25 +00:00
|
|
|
let service = Service {
|
2019-08-23 05:53:53 +00:00
|
|
|
local_peer_id,
|
2019-03-07 00:43:55 +00:00
|
|
|
swarm,
|
2019-12-06 03:13:43 +00:00
|
|
|
peers_to_ban: DelayQueue::new(),
|
|
|
|
peer_ban_timeout: DelayQueue::new(),
|
2019-03-12 06:28:11 +00:00
|
|
|
log,
|
2020-02-19 11:12:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok((network_globals, service))
|
2019-03-12 06:28:11 +00:00
|
|
|
}
|
2019-11-29 02:04:44 +00:00
|
|
|
|
2019-12-06 03:13:43 +00:00
|
|
|
/// Adds a peer to be banned for a period of time, specified by a timeout.
|
|
|
|
pub fn disconnect_and_ban_peer(&mut self, peer_id: PeerId, timeout: Duration) {
|
|
|
|
error!(self.log, "Disconnecting and banning peer"; "peer_id" => format!("{:?}", peer_id), "timeout" => format!("{:?}", timeout));
|
|
|
|
self.peers_to_ban.insert(
|
|
|
|
peer_id.clone(),
|
|
|
|
Duration::from_millis(BAN_PEER_WAIT_TIMEOUT),
|
|
|
|
);
|
|
|
|
self.peer_ban_timeout.insert(peer_id, timeout);
|
2019-11-29 02:04:44 +00:00
|
|
|
}
|
2019-03-12 06:28:11 +00:00
|
|
|
}
|
|
|
|
|
2019-08-10 01:44:17 +00:00
|
|
|
impl Stream for Service {
|
|
|
|
type Item = Libp2pEvent;
|
2019-03-12 06:28:11 +00:00
|
|
|
type Error = crate::error::Error;
|
|
|
|
|
|
|
|
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
|
|
|
loop {
|
|
|
|
match self.swarm.poll() {
|
2019-03-21 01:57:41 +00:00
|
|
|
Ok(Async::Ready(Some(event))) => match event {
|
2019-03-25 12:02:51 +00:00
|
|
|
BehaviourEvent::GossipMessage {
|
2019-09-04 16:06:39 +00:00
|
|
|
id,
|
2019-03-25 12:02:51 +00:00
|
|
|
source,
|
|
|
|
topics,
|
|
|
|
message,
|
|
|
|
} => {
|
2019-08-29 11:23:28 +00:00
|
|
|
trace!(self.log, "Gossipsub message received"; "service" => "Swarm");
|
2019-03-25 12:02:51 +00:00
|
|
|
return Ok(Async::Ready(Some(Libp2pEvent::PubsubMessage {
|
2019-09-04 16:06:39 +00:00
|
|
|
id,
|
2019-03-25 12:02:51 +00:00
|
|
|
source,
|
|
|
|
topics,
|
|
|
|
message,
|
|
|
|
})));
|
2019-03-21 01:57:41 +00:00
|
|
|
}
|
|
|
|
BehaviourEvent::RPC(peer_id, event) => {
|
|
|
|
return Ok(Async::Ready(Some(Libp2pEvent::RPC(peer_id, event))));
|
|
|
|
}
|
|
|
|
BehaviourEvent::PeerDialed(peer_id) => {
|
|
|
|
return Ok(Async::Ready(Some(Libp2pEvent::PeerDialed(peer_id))));
|
|
|
|
}
|
2019-07-16 12:32:37 +00:00
|
|
|
BehaviourEvent::PeerDisconnected(peer_id) => {
|
|
|
|
return Ok(Async::Ready(Some(Libp2pEvent::PeerDisconnected(peer_id))));
|
|
|
|
}
|
2019-11-27 01:47:46 +00:00
|
|
|
BehaviourEvent::PeerSubscribed(peer_id, topic) => {
|
|
|
|
return Ok(Async::Ready(Some(Libp2pEvent::PeerSubscribed(
|
|
|
|
peer_id, topic,
|
|
|
|
))));
|
|
|
|
}
|
2019-03-21 01:57:41 +00:00
|
|
|
},
|
2019-03-12 06:28:11 +00:00
|
|
|
Ok(Async::Ready(None)) => unreachable!("Swarm stream shouldn't end"),
|
2019-11-29 02:04:44 +00:00
|
|
|
Ok(Async::NotReady) => break,
|
2019-03-12 06:28:11 +00:00
|
|
|
_ => break,
|
|
|
|
}
|
2019-03-07 00:43:55 +00:00
|
|
|
}
|
2019-12-06 03:13:43 +00:00
|
|
|
|
|
|
|
// check if peers need to be banned
|
|
|
|
loop {
|
|
|
|
match self.peers_to_ban.poll() {
|
|
|
|
Ok(Async::Ready(Some(peer_id))) => {
|
|
|
|
let peer_id = peer_id.into_inner();
|
|
|
|
Swarm::ban_peer_id(&mut self.swarm, peer_id.clone());
|
|
|
|
// TODO: Correctly notify protocols of the disconnect
|
|
|
|
// TODO: Also remove peer from the DHT: https://github.com/sigp/lighthouse/issues/629
|
|
|
|
let dummy_connected_point = ConnectedPoint::Dialer {
|
|
|
|
address: "/ip4/0.0.0.0"
|
|
|
|
.parse::<Multiaddr>()
|
|
|
|
.expect("valid multiaddr"),
|
|
|
|
};
|
|
|
|
self.swarm
|
|
|
|
.inject_disconnected(&peer_id, dummy_connected_point);
|
|
|
|
// inform the behaviour that the peer has been banned
|
|
|
|
self.swarm.peer_banned(peer_id);
|
|
|
|
}
|
|
|
|
Ok(Async::NotReady) | Ok(Async::Ready(None)) => break,
|
|
|
|
Err(e) => {
|
|
|
|
warn!(self.log, "Peer banning queue failed"; "error" => format!("{:?}", e));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// un-ban peer if it's timeout has expired
|
|
|
|
loop {
|
|
|
|
match self.peer_ban_timeout.poll() {
|
|
|
|
Ok(Async::Ready(Some(peer_id))) => {
|
|
|
|
let peer_id = peer_id.into_inner();
|
|
|
|
debug!(self.log, "Peer has been unbanned"; "peer" => format!("{:?}", peer_id));
|
|
|
|
self.swarm.peer_unbanned(&peer_id);
|
|
|
|
Swarm::unban_peer_id(&mut self.swarm, peer_id);
|
|
|
|
}
|
|
|
|
Ok(Async::NotReady) | Ok(Async::Ready(None)) => break,
|
|
|
|
Err(e) => {
|
|
|
|
warn!(self.log, "Peer banning timeout queue failed"; "error" => format!("{:?}", e));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-12 06:28:11 +00:00
|
|
|
Ok(Async::NotReady)
|
2019-03-04 07:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-06 12:31:08 +00:00
|
|
|
|
|
|
|
/// The implementation supports TCP/IP, WebSockets over TCP/IP, secio as the encryption layer, and
|
|
|
|
/// mplex or yamux as the multiplexing layer.
|
2019-07-01 06:38:42 +00:00
|
|
|
fn build_transport(local_private_key: Keypair) -> Boxed<(PeerId, StreamMuxerBox), Error> {
|
2019-03-06 12:31:08 +00:00
|
|
|
// TODO: The Wire protocol currently doesn't specify encryption and this will need to be customised
|
|
|
|
// in the future.
|
2019-10-30 01:22:18 +00:00
|
|
|
let transport = libp2p::tcp::TcpConfig::new().nodelay(true);
|
2019-03-07 05:17:06 +00:00
|
|
|
let transport = libp2p::dns::DnsConfig::new(transport);
|
|
|
|
#[cfg(feature = "libp2p-websocket")]
|
|
|
|
let transport = {
|
|
|
|
let trans_clone = transport.clone();
|
|
|
|
transport.or_transport(websocket::WsConfig::new(trans_clone))
|
|
|
|
};
|
|
|
|
transport
|
2019-10-30 01:22:18 +00:00
|
|
|
.upgrade(core::upgrade::Version::V1)
|
|
|
|
.authenticate(secio::SecioConfig::new(local_private_key))
|
|
|
|
.multiplex(core::upgrade::SelectUpgrade::new(
|
|
|
|
libp2p::yamux::Config::default(),
|
|
|
|
libp2p::mplex::MplexConfig::new(),
|
|
|
|
))
|
|
|
|
.map(|(peer, muxer), _| (peer, core::muxing::StreamMuxerBox::new(muxer)))
|
|
|
|
.timeout(Duration::from_secs(20))
|
|
|
|
.timeout(Duration::from_secs(20))
|
2019-03-07 05:17:06 +00:00
|
|
|
.map_err(|err| Error::new(ErrorKind::Other, err))
|
|
|
|
.boxed()
|
2019-03-07 00:43:55 +00:00
|
|
|
}
|
2019-03-12 06:28:11 +00:00
|
|
|
|
|
|
|
/// Events that can be obtained from polling the Libp2p Service.
|
2019-08-10 01:44:17 +00:00
|
|
|
pub enum Libp2pEvent {
|
2019-03-21 02:15:14 +00:00
|
|
|
/// An RPC response request has been received on the swarm.
|
2019-03-19 01:47:36 +00:00
|
|
|
RPC(PeerId, RPCEvent),
|
2019-03-21 02:15:14 +00:00
|
|
|
/// Initiated the connection to a new peer.
|
2019-03-17 12:14:28 +00:00
|
|
|
PeerDialed(PeerId),
|
2019-07-16 12:32:37 +00:00
|
|
|
/// A peer has disconnected.
|
|
|
|
PeerDisconnected(PeerId),
|
2019-03-25 12:02:51 +00:00
|
|
|
/// Received pubsub message.
|
|
|
|
PubsubMessage {
|
2019-12-20 05:26:30 +00:00
|
|
|
id: MessageId,
|
2019-03-25 12:02:51 +00:00
|
|
|
source: PeerId,
|
|
|
|
topics: Vec<TopicHash>,
|
2019-08-10 01:44:17 +00:00
|
|
|
message: PubsubMessage,
|
2019-03-25 12:02:51 +00:00
|
|
|
},
|
2019-11-27 01:47:46 +00:00
|
|
|
/// Subscribed to peer for a topic hash.
|
|
|
|
PeerSubscribed(PeerId, TopicHash),
|
2019-03-12 06:28:11 +00:00
|
|
|
}
|
2019-07-01 06:38:42 +00:00
|
|
|
|
2019-09-10 16:13:54 +00:00
|
|
|
fn keypair_from_hex(hex_bytes: &str) -> error::Result<Keypair> {
|
|
|
|
let hex_bytes = if hex_bytes.starts_with("0x") {
|
|
|
|
hex_bytes[2..].to_string()
|
|
|
|
} else {
|
|
|
|
hex_bytes.to_string()
|
|
|
|
};
|
|
|
|
|
|
|
|
hex::decode(&hex_bytes)
|
|
|
|
.map_err(|e| format!("Failed to parse p2p secret key bytes: {:?}", e).into())
|
|
|
|
.and_then(keypair_from_bytes)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn keypair_from_bytes(mut bytes: Vec<u8>) -> error::Result<Keypair> {
|
|
|
|
libp2p::core::identity::secp256k1::SecretKey::from_bytes(&mut bytes)
|
|
|
|
.map(|secret| {
|
|
|
|
let keypair: libp2p::core::identity::secp256k1::Keypair = secret.into();
|
|
|
|
Keypair::Secp256k1(keypair)
|
|
|
|
})
|
|
|
|
.map_err(|e| format!("Unable to parse p2p secret key: {:?}", e).into())
|
|
|
|
}
|
|
|
|
|
2019-07-01 06:38:42 +00:00
|
|
|
/// Loads a private key from disk. If this fails, a new key is
|
|
|
|
/// generated and is then saved to disk.
|
|
|
|
///
|
|
|
|
/// Currently only secp256k1 keys are allowed, as these are the only keys supported by discv5.
|
|
|
|
fn load_private_key(config: &NetworkConfig, log: &slog::Logger) -> Keypair {
|
|
|
|
// TODO: Currently using secp256k1 keypairs - currently required for discv5
|
|
|
|
// check for key from disk
|
|
|
|
let network_key_f = config.network_dir.join(NETWORK_KEY_FILENAME);
|
|
|
|
if let Ok(mut network_key_file) = File::open(network_key_f.clone()) {
|
|
|
|
let mut key_bytes: Vec<u8> = Vec::with_capacity(36);
|
|
|
|
match network_key_file.read_to_end(&mut key_bytes) {
|
|
|
|
Err(_) => debug!(log, "Could not read network key file"),
|
|
|
|
Ok(_) => {
|
|
|
|
// only accept secp256k1 keys for now
|
|
|
|
if let Ok(secret_key) =
|
|
|
|
libp2p::core::identity::secp256k1::SecretKey::from_bytes(&mut key_bytes)
|
|
|
|
{
|
|
|
|
let kp: libp2p::core::identity::secp256k1::Keypair = secret_key.into();
|
|
|
|
debug!(log, "Loaded network key from disk.");
|
|
|
|
return Keypair::Secp256k1(kp);
|
|
|
|
} else {
|
|
|
|
debug!(log, "Network key file is not a valid secp256k1 key");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if a key could not be loaded from disk, generate a new one and save it
|
|
|
|
let local_private_key = Keypair::generate_secp256k1();
|
|
|
|
if let Keypair::Secp256k1(key) = local_private_key.clone() {
|
|
|
|
let _ = std::fs::create_dir_all(&config.network_dir);
|
|
|
|
match File::create(network_key_f.clone())
|
|
|
|
.and_then(|mut f| f.write_all(&key.secret().to_bytes()))
|
|
|
|
{
|
|
|
|
Ok(_) => {
|
|
|
|
debug!(log, "New network key generated and written to disk");
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
warn!(
|
|
|
|
log,
|
2019-08-29 11:23:28 +00:00
|
|
|
"Could not write node key to file: {:?}. error: {}", network_key_f, e
|
2019-07-01 06:38:42 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
local_private_key
|
|
|
|
}
|