1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
use commonware_cryptography::{PublicKey, Scheme};
use governor::Quota;
use prometheus_client::registry::Registry;
use std::{
net::SocketAddr,
num::NonZeroU32,
sync::{Arc, Mutex},
time::Duration,
};
/// Known peer and its accompanying address that will be dialed on startup.
pub type Bootstrapper = (PublicKey, SocketAddr);
/// Configuration for the peer-to-peer instance.
///
/// # Warning
/// It is recommended to synchronize this configuration across peers in the network (with the
/// exection of `crypto`, `registry`, `address`, `bootstrappers`, `allow_private_ips`, and `mailbox_size`).
/// If this is not sycnhronized, connections could be unnecessarily dropped, messages could be parsed incorrectly,
/// and/or peers will rate limit each other during normal operation.
#[derive(Clone)]
pub struct Config<C: Scheme> {
/// Cryptographic primitives.
pub crypto: C,
/// Registry for prometheus metrics.
pub registry: Arc<Mutex<Registry>>,
/// Dialable address of the peer.
pub address: SocketAddr,
/// Peers dialed on startup.
pub bootstrappers: Vec<Bootstrapper>,
/// Whether or not to allow connections with private IP addresses.
pub allow_private_ips: bool,
/// Message backlog allowed for internal actors.
///
/// When there are more messages in the mailbox than this value, any actor
/// sending a message will be blocked until the mailbox is processed.
pub mailbox_size: usize,
/// Maximum size used for all messages sent over the wire.
///
/// We use this to prevent malicious peers from sending us large messages
/// that would consume all of our memory.
///
/// If a message is larger than this size, it will be chunked into parts
/// of this size or smaller.
///
/// If this value is not synchronized across all connected peers,
/// chunks will be parsed incorrectly (any non-terminal chunk must be of ~this
/// size).
pub max_frame_length: usize,
/// Duration after which to close the connection if the handshake is not completed.
pub handshake_timeout: Duration,
/// Duration after which to close the connection if no message is read.
pub read_timeout: Duration,
/// Duration after which to close the connection if a message cannot be written.
pub write_timeout: Duration,
/// Whether or not to disable Nagle's algorithm.
///
/// The algorithm combines a series of small network packets into a single packet
/// before sending to reduce overhead of sending multiple small packets which might not
/// be efficient on slow, congested networks. However, to do so the algorithm introduces
/// a slight delay as it waits to accumulate more data. Latency-sensitive networks should
/// consider disabling it to send the packets as soon as possible to reduce latency.
///
/// Note: Make sure that your compile target has and allows this configuration otherwise
/// panics or unexpected behaviours are possible.
pub tcp_nodelay: Option<bool>,
/// Quota for connection attempts per peer (incoming or outgoing).
pub allowed_connection_rate_per_peer: Quota,
/// Quota for incoming connections across all peers.
pub allowed_incoming_connection_rate: Quota,
/// Frequency to attempt to dial known addresses.
pub dial_frequency: Duration,
/// Quota for peers to dial.
pub dial_rate: Quota,
/// Number of peer sets to track.
///
/// We will attempt to maintain connections to peers stored
/// across all peer sets, not just the most recent. This allows
/// us to continue serving requests to peers that have recently
/// been evicted and/or to communicate with peers in a future
/// set (if we, for example, are trying to do a reshare of a threshold
/// key).
pub tracked_peer_sets: usize,
/// Frequency we gossip about known peers.
///
/// If there is no other network activity, this message is used as a ping
/// and should be sent more often than the read_timeout.
pub gossip_bit_vec_frequency: Duration,
/// Quota for bit vector messages a peer can send us.
pub allowed_bit_vec_rate: Quota,
/// Maximum number of peers we will send or consider valid when receiving in a single messsage.
///
/// This is used to prevent malicious peers from sending us a large number of peers at one time (each
/// of which requires a signature verification).
pub peer_gossip_max_count: usize,
/// Quota for peers messages a peer can send us.
pub allowed_peers_rate: Quota,
}
impl<C: Scheme> Config<C> {
/// Generates a configuration with reasonable defaults for usage in production.
pub fn recommended(
crypto: C,
registry: Arc<Mutex<Registry>>,
address: SocketAddr,
bootstrappers: Vec<Bootstrapper>,
) -> Self {
Self {
crypto,
registry,
address,
bootstrappers,
allow_private_ips: false,
mailbox_size: 1_000,
max_frame_length: 1024 * 1024, // 1 MB
handshake_timeout: Duration::from_secs(5),
read_timeout: Duration::from_secs(60),
write_timeout: Duration::from_secs(30),
tcp_nodelay: None,
allowed_connection_rate_per_peer: Quota::per_minute(NonZeroU32::new(1).unwrap()),
allowed_incoming_connection_rate: Quota::per_second(NonZeroU32::new(256).unwrap()),
dial_frequency: Duration::from_secs(60),
dial_rate: Quota::per_minute(NonZeroU32::new(30).unwrap()),
tracked_peer_sets: 4,
gossip_bit_vec_frequency: Duration::from_secs(50),
allowed_bit_vec_rate: Quota::per_second(NonZeroU32::new(2).unwrap()),
peer_gossip_max_count: 32,
allowed_peers_rate: Quota::per_second(NonZeroU32::new(2).unwrap()),
}
}
/// Generates a configuration that minimizes peer discovery latency. This
/// can be useful when running local demos.
///
/// # Warning
/// It is not recommended to use this configuration in production.
pub fn aggressive(
crypto: C,
registry: Arc<Mutex<Registry>>,
address: SocketAddr,
bootstrappers: Vec<Bootstrapper>,
) -> Self {
Self {
crypto,
registry,
address,
bootstrappers,
allow_private_ips: true,
mailbox_size: 1_000,
max_frame_length: 1024 * 1024, // 1 MB
handshake_timeout: Duration::from_secs(5),
read_timeout: Duration::from_secs(10), // should be greater than gossip_bit_vec_frequency
write_timeout: Duration::from_secs(10),
tcp_nodelay: None,
allowed_connection_rate_per_peer: Quota::per_second(NonZeroU32::new(1).unwrap()),
allowed_incoming_connection_rate: Quota::per_second(NonZeroU32::new(256).unwrap()),
dial_frequency: Duration::from_secs(5),
dial_rate: Quota::per_second(NonZeroU32::new(30).unwrap()),
tracked_peer_sets: 4,
gossip_bit_vec_frequency: Duration::from_secs(5),
allowed_bit_vec_rate: Quota::per_second(NonZeroU32::new(5).unwrap()),
peer_gossip_max_count: 32,
allowed_peers_rate: Quota::per_second(NonZeroU32::new(5).unwrap()),
}
}
}