Skip to main content

ckb_app_config/configs/
network.rs

1use ckb_types::{H256, U256};
2use multiaddr::Multiaddr;
3use rand::Rng;
4use serde::{Deserialize, Serialize};
5use std::{
6    fs,
7    io::{Error, ErrorKind, Read, Write},
8    net::{IpAddr, Ipv4Addr, Ipv6Addr},
9    path::PathBuf,
10};
11use ubyte::ByteUnit;
12
13// Max data size in send buffer: 24MB (a little larger than max frame length)
14const DEFAULT_SEND_BUFFER: usize = 24 * 1024 * 1024;
15
16// Tentacle inner bound channel size, default 1024
17const DEFAULT_CHANNEL_SIZE: usize = 1024;
18
19/// Network config options.
20#[derive(Clone, Debug, Serialize, Deserialize, Default)]
21#[serde(deny_unknown_fields)]
22pub struct Config {
23    /// Only connect to whitelist peers.
24    #[serde(default)]
25    pub whitelist_only: bool,
26    /// Maximum number of allowed connected peers.
27    ///
28    /// The node will evict connections when the number exceeds this limit.
29    pub max_peers: u32,
30    /// Maximum number of outbound peers.
31    ///
32    /// When node A connects to B, B is the outbound peer of A.
33    pub max_outbound_peers: u32,
34    /// Network data storage directory path.
35    #[serde(default)]
36    pub path: PathBuf,
37    /// A list of DNS servers to discover peers.
38    #[serde(default)]
39    pub dns_seeds: Vec<String>,
40    /// Whether to probe and store local addresses.
41    #[serde(default)]
42    pub discovery_local_address: bool,
43    /// The interval between discovery announce message checking.
44    #[serde(default)]
45    pub discovery_announce_check_interval_secs: Option<u64>,
46    /// Interval between pings in seconds.
47    ///
48    /// A node pings peer regularly to see whether the connection is alive.
49    pub ping_interval_secs: u64,
50    /// The ping timeout in seconds.
51    ///
52    /// If a peer does not respond to ping before the timeout, it is evicted.
53    pub ping_timeout_secs: u64,
54    /// The interval between trials to connect more outbound peers.
55    pub connect_outbound_interval_secs: u64,
56    /// Listen addresses.
57    pub listen_addresses: Vec<Multiaddr>,
58    /// Public addresses.
59    ///
60    /// Set this if this is different from `listen_addresses`.
61    #[serde(default)]
62    pub public_addresses: Vec<Multiaddr>,
63    /// A list of peers used to boot the node discovery.
64    ///
65    /// Bootnodes are used to bootstrap the discovery when local peer storage is empty.
66    pub bootnodes: Vec<Multiaddr>,
67    /// A list of peers added in the whitelist.
68    ///
69    /// When `whitelist_only` is enabled, the node will only connect to peers in this list.
70    #[serde(default)]
71    pub whitelist_peers: Vec<Multiaddr>,
72    /// Enable UPNP when the router supports it.
73    #[serde(default)]
74    pub upnp: bool,
75    /// Enable bootnode mode.
76    ///
77    /// It is recommended to enable this when this server is intended to be used as a node in the
78    /// `bootnodes`.
79    #[serde(default)]
80    pub bootnode_mode: bool,
81    /// Supported protocols list
82    #[serde(default = "default_support_all_protocols")]
83    pub support_protocols: Vec<SupportProtocol>,
84    /// Max send buffer size in bytes.
85    pub max_send_buffer: Option<usize>,
86    /// Network use reuse port or not
87    #[serde(default = "default_reuse")]
88    pub reuse_port_on_linux: bool,
89    /// Allow ckb to upgrade tcp listening to tcp + ws listening
90    #[serde(default = "default_reuse_tcp_with_ws")]
91    pub reuse_tcp_with_ws: bool,
92    /// Disable block_relay_only connection, only use for testing.
93    #[serde(default)]
94    pub disable_block_relay_only_connection: bool,
95    /// Tentacle inner channel_size.
96    pub channel_size: Option<usize>,
97    /// A list of trusted proxies' IP addresses.
98    #[serde(default = "default_trusted_proxies")]
99    pub trusted_proxies: Vec<IpAddr>,
100    #[cfg(target_family = "wasm")]
101    #[serde(skip)]
102    pub secret_key: [u8; 32],
103    /// Chain synchronization config options.
104    #[serde(default)]
105    pub sync: SyncConfig,
106
107    /// Proxy related config options
108    #[serde(default)]
109    pub proxy: ProxyConfig,
110
111    /// Onion related config options
112    #[serde(default)]
113    pub onion: OnionConfig,
114}
115
116/// Proxy related config options
117#[derive(Clone, Debug, Serialize, Deserialize, Default)]
118pub struct ProxyConfig {
119    // like: socks5://username:password@127.0.0.1:1080
120    pub proxy_url: Option<String>,
121    // use random auth for each proxy connection
122    #[serde(default = "default_proxy_random_auth")]
123    pub proxy_random_auth: bool,
124}
125
126/// By default, let ckb to use random auth
127const fn default_proxy_random_auth() -> bool {
128    true
129}
130
131/// Onion related config options
132#[derive(Clone, Debug, Serialize, Deserialize, Default)]
133#[serde(deny_unknown_fields)]
134pub struct OnionConfig {
135    // Automatically create Tor onion service
136    pub listen_on_onion: bool,
137    // Tor server url: like: 127.0.0.1:9050
138    pub onion_server: Option<String>,
139    // The onion service will proxy incoming traffic to `p2p_listen_address`.
140    // If the CKB's peer-to-peer listen address is not set to the default 127.0.0.1
141    // with the port specified in `[network].listen_addresses` for IPv4, you should configure this field.
142    pub p2p_listen_address: Option<String>,
143    // path to store onion private key, default is ./data/network/onion_private_key
144    pub onion_private_key_path: Option<String>,
145    // tor controller url, example: 127.0.0.1:9051
146    #[serde(default = "default_tor_controller")]
147    pub tor_controller: String,
148    // tor controller hashed password
149    pub tor_password: Option<String>,
150    // The external port that the onion service will expose. Default is 8115.
151    // This is the port that will be advertised in the onion address,
152    // while traffic will be forwarded to `p2p_listen_address`.
153    #[serde(default = "default_onion_external_port")]
154    pub onion_external_port: u16,
155}
156
157/// By default, use tor controller on "127.0.0.1:9051"
158fn default_tor_controller() -> String {
159    "127.0.0.1:9051".to_string()
160}
161
162/// By default, use port 8115 for onion service
163fn default_onion_external_port() -> u16 {
164    8115
165}
166
167fn default_trusted_proxies() -> Vec<IpAddr> {
168    vec![
169        IpAddr::V4(Ipv4Addr::LOCALHOST),
170        IpAddr::V6(Ipv6Addr::LOCALHOST),
171    ]
172}
173
174/// Chain synchronization config options.
175#[derive(Clone, Debug, Serialize, Deserialize, Default)]
176#[serde(deny_unknown_fields)]
177pub struct SyncConfig {
178    /// Header map config options.
179    #[serde(default)]
180    pub header_map: HeaderMapConfig,
181    /// Block hash of assume valid target
182    #[serde(skip, default)]
183    pub assume_valid_targets: Option<Vec<H256>>,
184    /// Proof of minimum work during synchronization
185    #[serde(skip, default)]
186    pub min_chain_work: U256,
187}
188
189/// Header map config options.
190///
191/// Header map stores the block headers before fully verifying the block.
192#[derive(Clone, Debug, Serialize, Deserialize)]
193#[serde(deny_unknown_fields)]
194pub struct HeaderMapConfig {
195    /// The maximum size of data in memory
196    pub primary_limit: Option<usize>,
197    /// Disable cache if the size of data in memory less than this threshold
198    pub backend_close_threshold: Option<usize>,
199    /// The maximum amount memory limit
200    #[serde(default = "default_memory_limit")]
201    pub memory_limit: ByteUnit,
202}
203
204impl Default for HeaderMapConfig {
205    fn default() -> Self {
206        Self {
207            primary_limit: None,
208            backend_close_threshold: None,
209            memory_limit: default_memory_limit(),
210        }
211    }
212}
213
214const fn default_memory_limit() -> ByteUnit {
215    ByteUnit::Megabyte(256)
216}
217
218#[derive(Clone, Debug, Copy, Eq, PartialEq, Serialize, Deserialize, Hash)]
219#[allow(missing_docs)]
220pub enum SupportProtocol {
221    Ping,
222    Discovery,
223    Identify,
224    Feeler,
225    DisconnectMessage,
226    Sync,
227    Relay,
228    Time,
229    Alert,
230    LightClient,
231    Filter,
232    HolePunching,
233}
234
235#[allow(missing_docs)]
236pub fn default_support_all_protocols() -> Vec<SupportProtocol> {
237    vec![
238        SupportProtocol::Ping,
239        SupportProtocol::Discovery,
240        SupportProtocol::Identify,
241        SupportProtocol::Feeler,
242        SupportProtocol::DisconnectMessage,
243        SupportProtocol::Sync,
244        SupportProtocol::Relay,
245        SupportProtocol::Time,
246        SupportProtocol::Alert,
247        SupportProtocol::LightClient,
248        SupportProtocol::Filter,
249        SupportProtocol::HolePunching,
250    ]
251}
252
253/// Generate random secp256k1 key
254pub fn generate_random_key() -> [u8; 32] {
255    loop {
256        let mut key: [u8; 32] = [0; 32];
257        rand::thread_rng().fill(&mut key);
258        if secio::SecioKeyPair::secp256k1_raw_key(key).is_ok() {
259            return key;
260        }
261    }
262}
263
264/// Secret key storage
265pub fn write_secret_to_file(secret: &[u8], path: PathBuf) -> Result<(), Error> {
266    fs::OpenOptions::new()
267        .create(true)
268        .write(true)
269        .truncate(true)
270        .open(path)
271        .and_then(|mut file| {
272            file.write_all(secret)?;
273            #[cfg(unix)]
274            {
275                use std::os::unix::fs::PermissionsExt;
276                file.set_permissions(fs::Permissions::from_mode(0o400))
277            }
278            #[cfg(not(unix))]
279            {
280                let mut permissions = file.metadata()?.permissions();
281                permissions.set_readonly(true);
282                file.set_permissions(permissions)
283            }
284        })
285}
286
287/// Load secret key from path
288pub fn read_secret_key(path: PathBuf) -> Result<Option<secio::SecioKeyPair>, Error> {
289    let mut file = match fs::File::open(path.clone()) {
290        Ok(file) => file,
291        Err(_) => return Ok(None),
292    };
293    let warn = |m: bool, d: &str| {
294        if m {
295            ckb_logger::warn!(
296                "Your network secret file's permission is not {}, path: {:?}. \
297                Please fix it as soon as possible",
298                d,
299                path
300            )
301        }
302    };
303    #[cfg(unix)]
304    {
305        use std::os::unix::fs::PermissionsExt;
306        warn(
307            file.metadata()?.permissions().mode() & 0o177 != 0,
308            "less than 0o600",
309        );
310    }
311    #[cfg(not(unix))]
312    {
313        warn(!file.metadata()?.permissions().readonly(), "readonly");
314    }
315    let mut buf = Vec::new();
316    file.read_to_end(&mut buf).and_then(|_read_size| {
317        secio::SecioKeyPair::secp256k1_raw_key(&buf)
318            .map(Some)
319            .map_err(|_| Error::new(ErrorKind::InvalidData, "invalid secret key data"))
320    })
321}
322
323impl Config {
324    /// Gets the network secret key path.
325    pub fn secret_key_path(&self) -> PathBuf {
326        let mut path = self.path.clone();
327        path.push("secret_key");
328        path
329    }
330
331    /// Gets the onion network private key path.
332    pub fn onion_private_key_path(&self) -> PathBuf {
333        let mut path = self.path.clone();
334        path.push("onion_private_key");
335        path
336    }
337
338    /// Gets the peer store path.
339    pub fn peer_store_path(&self) -> PathBuf {
340        let mut path = self.path.clone();
341        path.push("peer_store");
342        path
343    }
344
345    /// Creates missing directories.
346    pub fn create_dir_if_not_exists(&self) -> Result<(), Error> {
347        if !self.path.exists() {
348            fs::create_dir(&self.path)
349        } else {
350            Ok(())
351        }
352    }
353
354    /// Gets maximum inbound peers.
355    pub fn max_inbound_peers(&self) -> u32 {
356        self.max_peers.saturating_sub(self.max_outbound_peers)
357    }
358
359    /// Gets maximum outbound peers.
360    pub fn max_outbound_peers(&self) -> u32 {
361        self.max_outbound_peers
362    }
363
364    /// Gets maximum send buffer size.
365    pub fn max_send_buffer(&self) -> usize {
366        self.max_send_buffer.unwrap_or(DEFAULT_SEND_BUFFER)
367    }
368
369    /// Gets maximum send buffer size.
370    pub fn channel_size(&self) -> usize {
371        self.channel_size.unwrap_or(DEFAULT_CHANNEL_SIZE)
372    }
373
374    /// Reads the secret key from secret key file.
375    ///
376    /// If the key file does not exists, it returns `Ok(None)`.
377    #[cfg(not(target_family = "wasm"))]
378    fn read_secret_key(&self) -> Result<Option<secio::SecioKeyPair>, Error> {
379        let path = self.secret_key_path();
380        read_secret_key(path)
381    }
382
383    /// Generates a random secret key and saves it into the file.
384    #[cfg(not(target_family = "wasm"))]
385    fn write_secret_key_to_file(&self) -> Result<(), Error> {
386        let path = self.secret_key_path();
387        let random_key_pair = generate_random_key();
388        write_secret_to_file(&random_key_pair, path)
389    }
390
391    /// Reads the private key from file or generates one if the file does not exist.
392    #[cfg(not(target_family = "wasm"))]
393    pub fn fetch_private_key(&self) -> Result<secio::SecioKeyPair, Error> {
394        match self.read_secret_key()? {
395            Some(key) => Ok(key),
396            None => {
397                self.write_secret_key_to_file()?;
398                Ok(self.read_secret_key()?.expect("key must exists"))
399            }
400        }
401    }
402
403    #[cfg(target_family = "wasm")]
404    pub fn fetch_private_key(&self) -> Result<secio::SecioKeyPair, Error> {
405        if self.secret_key == [0; 32] {
406            return Err(Error::new(
407                ErrorKind::InvalidData,
408                "invalid secret key data",
409            ));
410        } else {
411            secio::SecioKeyPair::secp256k1_raw_key(&self.secret_key)
412                .map_err(|_| Error::new(ErrorKind::InvalidData, "invalid secret key data"))
413        }
414    }
415
416    /// Gets the list of whitelist peers.
417    pub fn whitelist_peers(&self) -> Vec<Multiaddr> {
418        self.whitelist_peers.clone()
419    }
420
421    /// Gets a list of bootnodes.
422    pub fn bootnodes(&self) -> Vec<Multiaddr> {
423        self.bootnodes.clone()
424    }
425
426    /// Checks whether the outbound peer service should be enabled.
427    pub fn outbound_peer_service_enabled(&self) -> bool {
428        self.connect_outbound_interval_secs > 0
429    }
430
431    /// Checks whether the DNS seeding service should be enabled.
432    pub fn dns_seeding_service_enabled(&self) -> bool {
433        !self.dns_seeds.is_empty()
434    }
435}
436
437/// By default, using reuse port can make any outbound connection of the node become a potential
438/// listen address, which will help the robustness of our network
439const fn default_reuse() -> bool {
440    true
441}
442
443/// By default, allow ckb to upgrade tcp listening to tcp + ws listening
444const fn default_reuse_tcp_with_ws() -> bool {
445    true
446}