discv5_cli/server/
mod.rs

1use discv5::{enr, ConfigBuilder, Discv5, ListenConfig};
2use std::{
3    convert::TryInto,
4    net::{IpAddr, SocketAddrV4, SocketAddrV6},
5    process::exit,
6    sync::Arc,
7    time::Duration,
8};
9
10/// Services
11pub mod services;
12
13/// Bootstraps server peers from a file.
14pub mod bootstrap;
15
16/// ENR creation.
17pub mod enr_build;
18
19/// Key construction for the server.
20pub mod keys;
21
22/// The [clap] cli command arguments for the server service.
23pub mod command;
24pub use command::*;
25
26/// Run the query server
27pub async fn run(server: &Server) {
28    // The number of nodes required to come to consensus before our external IP is updated.
29    let peer_update_min = server.peer_update_min;
30
31    // Build the ENR
32    let enr_key = keys::generate(server).unwrap();
33    let enr = enr_build::build(server, &enr_key).unwrap();
34
35    let connect_enr = server.enr.as_ref().map(|enr| {
36        enr.parse::<enr::Enr<enr::CombinedKey>>()
37            .expect("Invalid base64 encoded ENR")
38    });
39
40    let mut ipv4_address = None;
41    let mut ipv6_address = None;
42    for address in server.listen_addresses.split(',') {
43        match address
44            .parse::<IpAddr>()
45            .expect("Invalid listening address")
46        {
47            IpAddr::V4(ip) => ipv4_address = Some(ip),
48            IpAddr::V6(ip) => ipv6_address = Some(ip),
49        }
50    }
51
52    let listen_port = server.listen_port;
53    let listen_port_v6 = server.listen_port_v6;
54
55    let listen_config = ListenConfig::from_two_sockets(
56        ipv4_address.map(|v| SocketAddrV4::new(v, listen_port)),
57        ipv6_address.map(|v| SocketAddrV6::new(v, listen_port_v6.unwrap_or(listen_port), 0, 0)),
58    );
59
60    log::info!("Server listening on {:?}", listen_config);
61    // Build the discv5 server using a default config
62    let config = ConfigBuilder::new(listen_config)
63        .request_timeout(Duration::from_secs(3))
64        .vote_duration(Duration::from_secs(120))
65        .enr_peer_update_min(peer_update_min.try_into().unwrap())
66        .build();
67    let mut discv5 = Discv5::new(enr, enr_key, config).unwrap();
68
69    // Connect to an ENR if allowed to search for p2p connections
70    if !server.no_search {
71        if let Some(connect_enr) = connect_enr {
72            log::info!(
73                "Connecting to ENR. ip: {:?}, udp_port: {:?},  tcp_port: {:?}",
74                connect_enr.ip4(),
75                connect_enr.udp4(),
76                connect_enr.tcp4()
77            );
78            if let Err(e) = discv5.add_enr(connect_enr) {
79                log::warn!("ENR not added: {:?}", e);
80            }
81        }
82    }
83
84    // Bootstrap the server peers
85    if bootstrap::boostrap(&mut discv5, server.bootstrap.clone())
86        .await
87        .is_err()
88    {
89        log::error!("Failed to bootstrap discv5 server with bootstrap file")
90    }
91
92    // Start the discv5 server
93    discv5
94        .start()
95        .await
96        .expect("Should be able to start the server");
97
98    let server_ref = Arc::new(discv5);
99    if server.stats > 0 {
100        services::stats::run(Arc::clone(&server_ref), None, server.stats);
101    }
102
103    if server.no_search {
104        log::info!("Running without query service, press CTRL-C to exit.");
105        let _ = tokio::signal::ctrl_c().await;
106        exit(0);
107    }
108
109    // Match on the subcommand and run the appropriate service
110    match server.service {
111        ServerSubcommand::Query => {
112            log::info!("Query service running...");
113            services::query::run(server_ref, Duration::from_secs(server.break_time)).await;
114        }
115        ServerSubcommand::Events => {
116            log::info!("Events service running...");
117            services::events::run(server_ref).await;
118        }
119    }
120}