forest/cli_shared/cli/
config.rs

1// Copyright 2019-2025 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use crate::db::db_engine::DbConfig;
5use crate::libp2p::Libp2pConfig;
6use crate::shim::clock::ChainEpoch;
7use crate::utils::misc::env::is_env_set_and_truthy;
8use crate::{chain_sync::SyncConfig, networks::NetworkChain};
9use serde::{Deserialize, Serialize};
10use std::path::PathBuf;
11
12use super::client::Client;
13
14const FOREST_CHAIN_INDEXER_ENABLED: &str = "FOREST_CHAIN_INDEXER_ENABLED";
15
16/// Structure that defines daemon configuration when process is detached
17#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
18#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
19pub struct DaemonConfig {
20    pub user: Option<String>,
21    pub group: Option<String>,
22    pub umask: u16,
23    pub stdout: PathBuf,
24    pub stderr: PathBuf,
25    pub work_dir: PathBuf,
26    pub pid_file: Option<PathBuf>,
27}
28
29impl Default for DaemonConfig {
30    fn default() -> Self {
31        Self {
32            user: None,
33            group: None,
34            umask: 0o027,
35            stdout: "forest.out".into(),
36            stderr: "forest.err".into(),
37            work_dir: ".".into(),
38            pid_file: None,
39        }
40    }
41}
42
43/// Structure that defines events configuration
44#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
45#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
46pub struct EventsConfig {
47    #[cfg_attr(test, arbitrary(gen(|g| u32::arbitrary(g) as _)))]
48    pub max_filter_results: usize,
49    pub max_filter_height_range: ChainEpoch,
50}
51
52impl Default for EventsConfig {
53    fn default() -> Self {
54        Self {
55            max_filter_results: 10000,
56            max_filter_height_range: 2880,
57        }
58    }
59}
60
61/// Structure that defines `FEVM` configuration
62#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
63#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
64pub struct FevmConfig {
65    #[cfg_attr(test, arbitrary(gen(|g| u32::arbitrary(g) as _)))]
66    pub eth_trace_filter_max_results: usize,
67}
68
69impl Default for FevmConfig {
70    fn default() -> Self {
71        Self {
72            eth_trace_filter_max_results: 500,
73        }
74    }
75}
76
77#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
78#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
79pub struct ChainIndexerConfig {
80    /// Enable indexing Ethereum mappings
81    pub enable_indexer: bool,
82    /// Number of retention epochs for indexed entries. Set to `None` to disable garbage collection.
83    pub gc_retention_epochs: Option<u32>,
84}
85
86impl Default for ChainIndexerConfig {
87    fn default() -> Self {
88        Self {
89            enable_indexer: is_env_set_and_truthy(FOREST_CHAIN_INDEXER_ENABLED).unwrap_or(false),
90            gc_retention_epochs: None,
91        }
92    }
93}
94
95#[derive(Serialize, Deserialize, PartialEq, Default, Debug, Clone)]
96#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
97#[serde(default)]
98pub struct Config {
99    pub chain: NetworkChain,
100    pub client: Client,
101    pub parity_db: crate::db::parity_db_config::ParityDbConfig,
102    pub network: Libp2pConfig,
103    pub sync: SyncConfig,
104    pub daemon: DaemonConfig,
105    pub events: EventsConfig,
106    pub fevm: FevmConfig,
107    pub chain_indexer: ChainIndexerConfig,
108}
109
110impl Config {
111    pub fn db_config(&self) -> &DbConfig {
112        &self.parity_db
113    }
114
115    pub fn chain(&self) -> &NetworkChain {
116        &self.chain
117    }
118}
119
120#[cfg(test)]
121mod test {
122    use quickcheck_macros::quickcheck;
123
124    use super::*;
125
126    #[quickcheck]
127    fn test_config_all_params_under_section(config: Config) {
128        let serialized_config =
129            toml::to_string(&config).expect("could not serialize the configuration");
130        assert_eq!(
131            serialized_config
132                .trim_start()
133                .chars()
134                .next()
135                .expect("configuration empty"),
136            '['
137        )
138    }
139}