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
use std::{fmt::Display, path::PathBuf};
/// Possible parameters to set while integrating with `fuel-core run`.
#[derive(Debug, Default)]
pub struct RunOpts {
pub(crate) service_name: Option<String>,
/// DB type, possible options are: `["in-memory", "rocksdb"]`.
pub(crate) db_type: DbType,
/// Should be used for local development only. Enabling debug mode:
/// - Allows GraphQL Endpoints to arbitrarily advance blocks.
/// - Enables debugger GraphQL Endpoints.
/// - Allows setting `utxo_validation` to `false`.
pub(crate) debug: bool,
/// Snapshot from which to do (re)genesis.
pub(crate) snapshot: PathBuf,
/// Peering private key from generated key-pair.
pub(crate) keypair: Option<String>,
/// Ethereum RPC endpoint.
pub(crate) relayer: Option<String>,
/// The IP address to bind the GraphQL service to.
pub(crate) ip: Option<std::net::IpAddr>,
/// The port to bind the GraphQL service to.
pub(crate) port: Option<u16>,
/// p2p network's TCP port.
pub(crate) peering_port: Option<u16>,
/// The path to the database, only relevant if the db type is not
/// "in-memory".
pub(crate) db_path: Option<PathBuf>,
/// Enable full utxo stateful validation.
pub(crate) utxo_validation: bool,
/// Use instant block production mode.
/// Newly submitted txs will immediately trigger the production of the next block.
pub(crate) poa_instant: bool,
/// Enable P2P. By default, P2P is disabled.
pub(crate) enable_p2p: bool,
/// Addresses of the bootstrap nodes
/// They should contain PeerId within their `Multiaddr`.
pub(crate) bootstrap_nodes: Option<String>,
/// The maximum number of headers to request in a single batch.
pub(crate) sync_header_batch_size: Option<u32>,
/// Enable the Relayer. By default, the Relayer is disabled.
pub(crate) enable_relayer: bool,
/// Ethereum contract address for the relayer. Requires conversion of EthAddress into fuel_types.
pub(crate) relayer_listener: Option<String>,
/// Number of da block that the contract is deployed at.
pub(crate) relayer_da_deploy_height: Option<u32>,
/// Number of pages or blocks containing logs that
/// should be downloaded in a single call to the da layer
pub(crate) relayer_log_page_size: Option<u32>,
/// The maximum number of get transaction requests to make in a single batch.
pub(crate) sync_block_stream_buffer_size: Option<u32>,
}
#[derive(Debug)]
pub enum DbType {
InMemory,
RocksDb,
}
impl Default for DbType {
/// By default fuel-core interprets lack of explicit db-type declaration as
/// db-type = rocks-db.
fn default() -> Self {
Self::RocksDb
}
}
impl Display for DbType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DbType::InMemory => write!(f, "in-memory"),
DbType::RocksDb => write!(f, "rocks-db"),
}
}
}
impl RunOpts {
pub fn generate_params(self) -> Vec<String> {
let mut params = vec![];
if let Some(service_name) = self.service_name {
params.push(format!("--service-name {service_name}"));
}
if self.debug {
params.push("--debug".to_string());
}
if let Some(keypair) = self.keypair {
params.push(format!("--keypair {keypair}"));
}
if let Some(relayer) = self.relayer {
params.push(format!("--relayer {relayer}"));
}
if let Some(ip) = self.ip {
params.push(format!("--ip {ip}"));
}
if let Some(port) = self.port {
params.push(format!("--port {port}"));
}
if let Some(peering_port) = self.peering_port {
params.push(format!("--peering-port {peering_port}"));
}
if let Some(db_path) = self.db_path {
params.push(format!("--db-path {}", db_path.display()));
}
params.push(format!("--snapshot {}", self.snapshot.display()));
params.push(format!("--db-type {}", self.db_type));
if self.utxo_validation {
params.push("--utxo-validation".to_string());
}
// --poa-instant accepts `true` or `false` as param, and it is not a
// flag.
if self.poa_instant {
params.push("--poa-instant true".to_string());
} else {
params.push("--poa-instant false".to_string());
}
if self.enable_p2p {
params.push("--enable-p2p".to_string());
}
if let Some(node) = self.bootstrap_nodes {
params.push(format!("--bootstrap-nodes {node}"));
}
if let Some(sync_header_batch_size) = self.sync_header_batch_size {
params.push(format!("--sync-header-batch-size {sync_header_batch_size}"));
}
if self.enable_relayer {
params.push("--enable-relayer".to_string());
}
if let Some(relayer_listener) = self.relayer_listener {
params.push(format!(
"--relayer-v2-listening-contracts {relayer_listener}"
));
}
if let Some(da_deploy_height) = self.relayer_da_deploy_height {
params.push(format!("--relayer-da-deploy-height {da_deploy_height}"));
}
if let Some(log_page_size) = self.relayer_log_page_size {
params.push(format!("--relayer-log-page-size {log_page_size}"));
}
if let Some(sync_block) = self.sync_block_stream_buffer_size {
params.push(format!("--sync-block-stream-buffer-size {sync_block}"));
}
// Split run_cmd so that each arg is actually send as a separate
// arg. To correctly parse the args in the system level, each
// part of an arg should go to different indices of "argv". This
// means "--db-layer in-memory" needs to be interpreted as:
// "--db-layer", "in-memory" to be parsed correctly.
let params: Vec<String> = params
.iter()
.flat_map(|cmd| cmd.split_whitespace())
.map(|a| a.to_string())
.collect();
params
}
}