diem_config/
utils.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4// Copyright 2021 Conflux Foundation. All rights reserved.
5// Conflux is free software and distributed under GNU General Public License.
6// See http://www.gnu.org/licenses/
7
8use crate::config::NodeConfig;
9use diem_types::{
10    account_address::AccountAddress,
11    network_address::{NetworkAddress, Protocol},
12    transaction::{authenticator::AuthenticationKey, Transaction},
13};
14use if_addrs::get_if_addrs;
15use std::net::{TcpListener, TcpStream};
16
17pub fn default_validator_owner_auth_key_from_name(
18    name: &[u8],
19) -> AuthenticationKey {
20    let salt = "validator_owner::";
21    let mut name_in_bytes = salt.as_bytes().to_vec();
22    name_in_bytes.extend_from_slice(name);
23    let hash = diem_crypto::HashValue::sha3_256_of(&name_in_bytes);
24    AuthenticationKey::new(*hash.as_ref())
25}
26
27pub fn validator_owner_account_from_name(name: &[u8]) -> AccountAddress {
28    default_validator_owner_auth_key_from_name(name).derived_address()
29}
30
31/// Return an ephemeral, available port. On unix systems, the port returned will
32/// be in the TIME_WAIT state ensuring that the OS won't hand out this port for
33/// some grace period. Callers should be able to bind to this port given they
34/// use SO_REUSEADDR.
35pub fn get_available_port() -> u16 {
36    const MAX_PORT_RETRIES: u32 = 1000;
37
38    for _ in 0..MAX_PORT_RETRIES {
39        if let Ok(port) = get_ephemeral_port() {
40            return port;
41        }
42    }
43
44    panic!("Error: could not find an available port");
45}
46
47fn get_ephemeral_port() -> ::std::io::Result<u16> {
48    // Request a random available port from the OS
49    let listener = TcpListener::bind(("localhost", 0))?;
50    let addr = listener.local_addr()?;
51
52    // Create and accept a connection (which we'll promptly drop) in order to
53    // force the port into the TIME_WAIT state, ensuring that the port will
54    // be reserved from some limited amount of time (roughly 60s on some
55    // Linux systems)
56    let _sender = TcpStream::connect(addr)?;
57    let _incoming = listener.accept()?;
58
59    Ok(addr.port())
60}
61
62/// Extracts one local non-loopback IP address, if one exists. Otherwise returns
63/// None.
64pub fn get_local_ip() -> Option<NetworkAddress> {
65    get_if_addrs().ok().and_then(|if_addrs| {
66        if_addrs
67            .iter()
68            .find(|if_addr| !if_addr.is_loopback())
69            .map(|if_addr| NetworkAddress::from(Protocol::from(if_addr.ip())))
70    })
71}
72
73pub fn get_available_port_in_multiaddr(is_ipv4: bool) -> NetworkAddress {
74    let ip_proto = if is_ipv4 {
75        Protocol::Ip4("0.0.0.0".parse().unwrap())
76    } else {
77        Protocol::Ip6("::1".parse().unwrap())
78    };
79    NetworkAddress::from(ip_proto).push(Protocol::Tcp(get_available_port()))
80}
81
82pub fn get_genesis_txn(config: &NodeConfig) -> Option<&Transaction> {
83    config.execution.genesis.as_ref()
84}