embedded_td/config/
mod.rs

1//! Config of tendermint
2
3mod log_level;
4pub use log_level::*;
5
6mod fast_sync;
7pub use fast_sync::*;
8
9mod db_backend;
10pub use db_backend::*;
11
12mod p2p;
13pub use p2p::*;
14
15mod mempool;
16pub use mempool::*;
17
18mod state_sync;
19pub use state_sync::*;
20
21mod consensus;
22pub use consensus::*;
23
24mod tx_index;
25pub use tx_index::*;
26
27mod prometheus;
28pub use prometheus::*;
29
30use crate::{defined, model};
31
32/// Config for tendermint
33#[derive(Debug, Clone)]
34pub struct Config {
35    /// Log level
36    pub log_level: LogLevel,
37
38    /// Readable name of this node. Default is a random name.
39    pub moniker: String,
40
41    /// Backend storage, default is goleveldb
42    pub db_backend: DbBackend,
43
44    /// Format for output log,
45    pub log_format: LogFormat,
46
47    /// TCP or UNIX socket address for Tendermint to listen on for
48    /// connections from an external PrivValidator process
49    pub priv_validator_laddr: String,
50
51    /// If true, query the ABCI app on connecting to a new peer
52    /// so the app can decide if we should keep the connection or not
53    pub filter_peers: bool,
54
55    /// pprof listen addr. Useful to debug tendermint.
56    pub pprof_laddr: String,
57
58    /// Data dis
59    pub data_dir: String,
60
61    /// P2P config
62    pub p2p: P2PConfig,
63
64    /// Mempool config
65    pub mempool: MempoolConfig,
66
67    /// State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine
68    /// snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in
69    /// the network to take and serve state machine snapshots. State sync is not attempted if the node
70    /// has any local state (LastBlockHeight > 0). The node will have a truncated block history,
71    /// starting from the height of the snapshot.
72    pub state_sync: Option<StateSyncConfig>,
73
74    /// Version of fast sync.
75    pub fast_sync: Option<FastSyncVersion>,
76
77    /// Consensus config
78    pub consensus: ConsensusConfig,
79
80    /// What indexer to use for transactions
81    ///
82    /// The application will set which txs to index. In some cases a node operator will be able
83    /// to decide which txs to index based on configuration set in the application.
84    ///
85    /// Options:
86    ///   1) "null"
87    ///   2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
88    ///   3) "psql" - the indexer services backed by PostgreSQL.
89    /// When "kv" or "psql" is chosen "tx.height" and "tx.hash" will always be indexed.
90    pub tx_index: TxIndexConfig,
91
92    /// When true, Prometheus metrics are served under /metrics on
93    /// PrometheusListenAddr.
94    /// Check out the documentation for the list of available metrics.
95    pub prometheus: Option<PrometheusConfig>,
96}
97
98impl Default for Config {
99    fn default() -> Self {
100        let moniker = String::from("aa");
101
102        Self {
103            moniker,
104            log_format: Default::default(),
105            db_backend: Default::default(),
106            log_level: Default::default(),
107            priv_validator_laddr: Default::default(),
108            filter_peers: false,
109            pprof_laddr: Default::default(),
110            p2p: Default::default(),
111            mempool: Default::default(),
112            state_sync: None,
113            fast_sync: Some(FastSyncVersion::default()),
114            consensus: Default::default(),
115            tx_index: Default::default(),
116            prometheus: None,
117            data_dir: String::new(),
118        }
119    }
120}
121
122impl Config {
123    pub fn new(data_dir: &str) -> Self {
124        Self {
125            data_dir: String::from(data_dir),
126            ..Default::default()
127        }
128    }
129}
130
131macro_rules! define_to_str_for_enum {
132    ($e:ident, $( $key:ident => $value:expr ),*) => {
133        impl $e {
134            pub fn to_str(&self) -> &'static str {
135                match self {
136                    $( Self::$key => $value, )*
137                }
138            }
139        }
140    };
141}
142
143pub(crate) use define_to_str_for_enum;
144
145macro_rules! define_build_mode_setter {
146    ($name:ident, str) => {
147        pub fn $name(self, $name: &str) -> Self {
148            let mut this = self;
149            this.$name = String::from($name);
150            this
151        }
152    };
153    ($name:ident, $type:ty) => {
154        pub fn $name(self, $name: $type) -> Self {
155            let mut this = self;
156            this.$name = $name;
157            this
158        }
159    };
160    ($name:ident, $type:ty, option, $enable: ident) => {
161        pub fn $enable(self, $name: $type) -> Self {
162            let mut this = self;
163            this.$name = Some($name);
164            this
165        }
166    };
167}
168
169pub(crate) use define_build_mode_setter;
170
171impl Config {
172    define_build_mode_setter!(log_level, LogLevel);
173
174    define_build_mode_setter!(moniker, str);
175
176    define_build_mode_setter!(db_backend, DbBackend);
177
178    define_build_mode_setter!(log_format, LogFormat);
179
180    define_build_mode_setter!(priv_validator_laddr, str);
181
182    define_build_mode_setter!(filter_peers, bool);
183
184    define_build_mode_setter!(p2p, P2PConfig);
185
186    define_build_mode_setter!(mempool, MempoolConfig);
187
188    define_build_mode_setter!(state_sync, StateSyncConfig, option, enable_state_sync);
189
190    define_build_mode_setter!(fast_sync, FastSyncVersion, option, enable_fast_sync);
191
192    define_build_mode_setter!(consensus, ConsensusConfig);
193
194    define_build_mode_setter!(tx_index, TxIndexConfig);
195
196    define_build_mode_setter!(prometheus, PrometheusConfig, option, enabel_prometheus);
197}
198
199impl Config {
200    pub(crate) fn into_model(self, base_dir: &str) -> model::Config {
201        let db_dir = if self.data_dir.is_empty() {
202            format!("{}/{}", base_dir, defined::DATA_DIR)
203        } else {
204            self.data_dir
205        };
206
207        let rpc = {
208            let laddr = format!("unix://{}/{}", base_dir, defined::RPC_UNIX_SOCKET_FILE);
209
210            model::Rpc {
211                laddr,
212                cors_allowed_origins: Default::default(),
213                cors_allowed_headers: Default::default(),
214                cors_allowed_methods: Default::default(),
215                grpc_laddr: Default::default(),
216                unsafe_opt: true,
217                max_open_connections: 900,
218                max_subscription_clients: 100,
219                max_subscriptions_per_client: 5,
220                experimental_subscription_buffer_size: 200,
221                experimental_websocket_write_buffer_size: 200,
222                experimental_close_on_slow_client: false,
223                timeout_broadcast_tx_commit: String::from("10s"),
224                max_body_bytes: 1000000,
225                max_header_bytes: 1048576,
226                tls_key_file: Default::default(),
227                tls_cert_file: Default::default(),
228                pprof_laddr: self.pprof_laddr,
229                grpc_max_open_connections: 900,
230            }
231        };
232
233        let p2p = {
234            let addr_book_file = format!("{}/{}", base_dir, defined::ADDR_BOOK_FILE);
235            let persistent_peers_max_dial_period = format!(
236                "{}s",
237                self.p2p.persistent_peers_max_dial_period.whole_seconds()
238            );
239            let flush_throttle_timeout =
240                format!("{}ms", self.p2p.flush_throttle_timeout.whole_milliseconds());
241            let handshake_timeout = format!("{}s", self.p2p.handshake_timeout.whole_seconds());
242            let dial_timeout = format!("{}s", self.p2p.dial_timeout.whole_seconds());
243
244            model::P2P {
245                laddr: self.p2p.laddr,
246                external_address: self.p2p.external_address,
247                seeds: self.p2p.seeds.join(","),
248                persistent_peers: self.p2p.persistent_peers.join(","),
249                upnp: self.p2p.upnp,
250                addr_book_file,
251                addr_book_strict: !self.p2p.local_net,
252                max_num_inbound_peers: self.p2p.max_num_inbound_peers,
253                max_num_outbound_peers: self.p2p.max_num_outbound_peers,
254                unconditional_peer_ids: self.p2p.unconditional_peer_ids.join(","),
255                persistent_peers_max_dial_period,
256                flush_throttle_timeout,
257                max_packet_msg_payload_size: self.p2p.max_packet_msg_payload_size,
258                send_rate: self.p2p.send_rate,
259                recv_rate: self.p2p.recv_rate,
260                pex: self.p2p.pex,
261                seed_mode: self.p2p.seed_mode,
262                private_peer_ids: self.p2p.private_peer_ids.join(","),
263                allow_duplicate_ip: self.p2p.allow_duplicate_ip,
264                handshake_timeout,
265                dial_timeout,
266            }
267        };
268
269        let mempool = {
270            let ttl_duration = format!("{}s", self.mempool.ttl_duration.whole_seconds());
271
272            model::Mempool {
273                version: String::from(self.mempool.version.to_str()),
274                wal_dir: Default::default(),
275                size: self.mempool.size,
276                max_tx_bytes: self.mempool.max_tx_bytes,
277                cache_size: self.mempool.cache_size,
278                keep_invalid_txs_in_cache: self.mempool.keep_invalid_txs_in_cache,
279                max_txs_bytes: self.mempool.max_txs_bytes,
280                max_batch_bytes: 0,
281                ttl_duration,
282                ttl_num_blocks: self.mempool.ttl_num_blocks,
283                recheck: self.mempool.recheck,
284                broadcast: self.mempool.broadcast,
285            }
286        };
287
288        let statesync = {
289            let (enable, state_sync) = if let Some(state_sync) = self.state_sync {
290                (true, state_sync)
291            } else {
292                (false, Default::default())
293            };
294
295            let trust_period = format!("{}s", state_sync.trust_period.whole_seconds());
296
297            let discovery_time = format!("{}s", state_sync.discovery_time.whole_seconds());
298
299            let chunk_request_timeout =
300                format!("{}s", state_sync.chunk_request_timeout.whole_seconds());
301
302            model::StateSync {
303                enable,
304                rpc_servers: state_sync.rpc_servers.join(","),
305                trust_hash: state_sync.trust_hash,
306                trust_height: state_sync.trust_height,
307                trust_period,
308                discovery_time,
309                temp_dir: Default::default(),
310                chunk_request_timeout,
311                chunk_fetchers: format!("{}", state_sync.chunk_fetchers),
312            }
313        };
314
315        let (fast_sync, fastsync) = {
316            let fast_sync = self.fast_sync.is_some();
317
318            let version = if let Some(v) = self.fast_sync {
319                String::from(v.to_str())
320            } else {
321                String::from("v0")
322            };
323
324            (fast_sync, model::FastSync { version })
325        };
326
327        let consensus = {
328            let wal_file = format!("{}/{}", db_dir, defined::WAL_FILE);
329
330            model::Consensus {
331                wal_file,
332                timeout_propose: utils::build_duration_ms(self.consensus.timeout_propose),
333                timeout_propose_delta: utils::build_duration_ms(
334                    self.consensus.timeout_propose_delta,
335                ),
336                timeout_prevote: utils::build_duration_ms(self.consensus.timeout_prevote),
337                timeout_prevote_delta: utils::build_duration_ms(
338                    self.consensus.timeout_prevote_delta,
339                ),
340                timeout_precommit: utils::build_duration_ms(self.consensus.timeout_precommit),
341                timeout_precommit_delta: utils::build_duration_ms(
342                    self.consensus.timeout_precommit_delta,
343                ),
344                timeout_commit: utils::build_duration_ms(self.consensus.timeout_commit),
345                double_sign_check_height: self.consensus.double_sign_check_height,
346                skip_timeout_commit: self.consensus.skip_timeout_commit,
347                create_empty_blocks: self.consensus.create_empty_blocks,
348                create_empty_blocks_interval: utils::build_duration_ms(
349                    self.consensus.create_empty_blocks_interval,
350                ),
351                peer_gossip_sleep_duration: utils::build_duration_ms(
352                    self.consensus.peer_gossip_sleep_duration,
353                ),
354                peer_query_maj23_sleep_duration: utils::build_duration_ms(
355                    self.consensus.peer_query_maj23_sleep_duration,
356                ),
357                discard_abci_responses: self.consensus.discard_abci_responses,
358            }
359        };
360
361        let tx_index = {
362            let indexer = self.tx_index.to_str();
363
364            let pgsql_conn = if let TxIndexConfig::Psql(c) = self.tx_index {
365                c
366            } else {
367                Default::default()
368            };
369
370            model::TxIndex {
371                indexer: String::from(indexer),
372                pgsql_conn,
373            }
374        };
375
376        let prometheus = {
377            let (enable, prometheus) = if let Some(p) = self.prometheus {
378                (true, p)
379            } else {
380                (false, Default::default())
381            };
382
383            model::Instrumentation {
384                prometheus: enable,
385                prometheus_listen_addr: prometheus.prometheus_listen_addr,
386                max_open_connections: prometheus.max_open_connections,
387                namespace: prometheus.namespace,
388            }
389        };
390
391        let proxy_app = format!("unix://{}/{}", base_dir, defined::APP_UNIX_SOCKET_FILE);
392        log::debug!("proxy_app socket file is : {}", proxy_app);
393
394        let genesis_file = format!("{}/{}", db_dir, defined::GENESIS_FILE);
395
396        let priv_validator_key_file = format!("{}/{}", base_dir, defined::VALIDATOR_KEY_FILE);
397
398        let priv_validator_state_file = format!("{}/{}", db_dir, defined::VALIDATOR_STATE_FILE);
399
400        let node_key_file = format!("{}/{}", base_dir, defined::NODE_KEY_FILE);
401
402        model::Config {
403            proxy_app,
404            moniker: self.moniker,
405            fast_sync,
406            db_backend: String::from(self.db_backend.to_str()),
407            db_dir,
408            log_level: String::from(self.log_level.to_str()),
409            log_format: String::from(self.log_format.to_str()),
410            genesis_file,
411            priv_validator_key_file,
412            priv_validator_state_file,
413            priv_validator_laddr: self.priv_validator_laddr,
414            node_key_file,
415            abci: String::from("socket"),
416            filter_peers: self.filter_peers,
417            rpc,
418            p2p,
419            mempool,
420            statesync,
421            fastsync,
422            consensus,
423            tx_index,
424            instrumentation: prometheus,
425        }
426    }
427}
428
429mod utils {
430    use time::Duration;
431
432    /*     pub fn build_duration_s(d: Duration) -> String { */
433    /*     format!("{}s", d.whole_seconds()) */
434    /* } */
435    /*  */
436    pub fn build_duration_ms(d: Duration) -> String {
437        format!("{}ms", d.whole_milliseconds())
438    }
439}