forc_node/
run_opts.rs

1use std::{fmt::Display, path::PathBuf};
2
3/// Possible parameters to set while integrating with `fuel-core run`.
4#[derive(Debug, Default)]
5pub struct RunOpts {
6    pub(crate) service_name: Option<String>,
7    /// DB type, possible options are: `["in-memory", "rocksdb"]`.
8    pub(crate) db_type: DbType,
9    /// Should be used for local development only. Enabling debug mode:
10    /// - Allows GraphQL Endpoints to arbitrarily advance blocks.
11    /// - Enables debugger GraphQL Endpoints.
12    /// - Allows setting `utxo_validation` to `false`.
13    pub(crate) debug: bool,
14    /// Snapshot from which to do (re)genesis.
15    pub(crate) snapshot: PathBuf,
16    /// Peering private key from generated key-pair.
17    pub(crate) keypair: Option<String>,
18    /// Ethereum RPC endpoint.
19    pub(crate) relayer: Option<String>,
20    /// The IP address to bind the GraphQL service to.
21    pub(crate) ip: Option<std::net::IpAddr>,
22    /// The port to bind the GraphQL service to.
23    pub(crate) port: Option<u16>,
24    /// p2p network's TCP port.
25    pub(crate) peering_port: Option<u16>,
26    /// The path to the database, only relevant if the db type is not
27    /// "in-memory".
28    pub(crate) db_path: Option<PathBuf>,
29    /// Enable full utxo stateful validation.
30    pub(crate) utxo_validation: bool,
31    /// Use instant block production mode.
32    /// Newly submitted txs will immediately trigger the production of the next block.
33    pub(crate) poa_instant: bool,
34    /// Enable P2P. By default, P2P is disabled.
35    pub(crate) enable_p2p: bool,
36    /// Addresses of the bootstrap nodes
37    /// They should contain PeerId within their `Multiaddr`.
38    pub(crate) bootstrap_nodes: Option<String>,
39    /// The maximum number of headers to request in a single batch.
40    pub(crate) sync_header_batch_size: Option<u32>,
41    /// Enable the Relayer. By default, the Relayer is disabled.
42    pub(crate) enable_relayer: bool,
43    /// Ethereum contract address for the relayer. Requires conversion of EthAddress into fuel_types.
44    pub(crate) relayer_listener: Option<String>,
45    /// Number of da block that the contract is deployed at.
46    pub(crate) relayer_da_deploy_height: Option<u32>,
47    /// Number of pages or blocks containing logs that
48    /// should be downloaded in a single call to the da layer
49    pub(crate) relayer_log_page_size: Option<u32>,
50    /// The maximum number of get transaction requests to make in a single batch.
51    pub(crate) sync_block_stream_buffer_size: Option<u32>,
52}
53
54#[derive(Debug)]
55pub enum DbType {
56    InMemory,
57    RocksDb,
58}
59
60impl Default for DbType {
61    /// By default fuel-core interprets lack of explicit db-type declaration as
62    /// db-type = rocks-db.
63    fn default() -> Self {
64        Self::RocksDb
65    }
66}
67
68impl Display for DbType {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        match self {
71            DbType::InMemory => write!(f, "in-memory"),
72            DbType::RocksDb => write!(f, "rocks-db"),
73        }
74    }
75}
76
77impl RunOpts {
78    pub fn generate_params(self) -> Vec<String> {
79        let mut params = vec![];
80        if let Some(service_name) = self.service_name {
81            params.push(format!("--service-name {service_name}"));
82        }
83        if self.debug {
84            params.push("--debug".to_string());
85        }
86        if let Some(keypair) = self.keypair {
87            params.push(format!("--keypair {keypair}"));
88        }
89        if let Some(relayer) = self.relayer {
90            params.push(format!("--relayer {relayer}"));
91        }
92        if let Some(ip) = self.ip {
93            params.push(format!("--ip {ip}"));
94        }
95        if let Some(port) = self.port {
96            params.push(format!("--port {port}"));
97        }
98        if let Some(peering_port) = self.peering_port {
99            params.push(format!("--peering-port {peering_port}"));
100        }
101        if let Some(db_path) = self.db_path {
102            params.push(format!("--db-path {}", db_path.display()));
103        }
104        params.push(format!("--snapshot {}", self.snapshot.display()));
105        params.push(format!("--db-type {}", self.db_type));
106        if self.utxo_validation {
107            params.push("--utxo-validation".to_string());
108        }
109        // --poa-instant accepts `true` or `false` as param, and it is not a
110        // flag.
111        if self.poa_instant {
112            params.push("--poa-instant true".to_string());
113        } else {
114            params.push("--poa-instant false".to_string());
115        }
116        if self.enable_p2p {
117            params.push("--enable-p2p".to_string());
118        }
119        if let Some(node) = self.bootstrap_nodes {
120            params.push(format!("--bootstrap-nodes {node}"));
121        }
122        if let Some(sync_header_batch_size) = self.sync_header_batch_size {
123            params.push(format!("--sync-header-batch-size {sync_header_batch_size}"));
124        }
125        if self.enable_relayer {
126            params.push("--enable-relayer".to_string());
127        }
128        if let Some(relayer_listener) = self.relayer_listener {
129            params.push(format!(
130                "--relayer-v2-listening-contracts {}",
131                relayer_listener
132            ));
133        }
134        if let Some(da_deploy_height) = self.relayer_da_deploy_height {
135            params.push(format!("--relayer-da-deploy-height {da_deploy_height}"));
136        }
137        if let Some(log_page_size) = self.relayer_log_page_size {
138            params.push(format!("--relayer-log-page-size {log_page_size}"));
139        }
140        if let Some(sync_block) = self.sync_block_stream_buffer_size {
141            params.push(format!("--sync-block-stream-buffer-size {sync_block}"));
142        }
143        // Split run_cmd so that each arg is actually send as a separate
144        // arg. To correctly parse the args in the system level, each
145        // part of an arg should go to different indices of "argv". This
146        // means "--db-layer in-memory" needs to be interpreted as:
147        // "--db-layer", "in-memory" to be parsed correctly.
148        let params: Vec<String> = params
149            .iter()
150            .flat_map(|cmd| cmd.split_whitespace())
151            .map(|a| a.to_string())
152            .collect();
153        params
154    }
155}