Skip to main content

forest/cli_shared/cli/
config.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use super::client::Client;
5use crate::db::db_engine::DbConfig;
6use crate::libp2p::Libp2pConfig;
7use crate::shim::clock::ChainEpoch;
8use crate::shim::econ::TokenAmount;
9use crate::utils::misc::env::is_env_truthy;
10use crate::{chain_sync::SyncConfig, networks::NetworkChain};
11use serde::{Deserialize, Serialize};
12use std::path::PathBuf;
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    /// Caps the events returned by event-filter queries used by the actor
48    /// events API and the Ethereum event and receipt APIs (`eth_getLogs`,
49    /// `eth_getFilterLogs`, `eth_getFilterChanges`). Set to `0` for no limit.
50    ///
51    /// The cap is a hard limit only when a query's events come from more than
52    /// one tipset. A range whose events all live in a single tipset may
53    /// exceed this value; queries scoped to a single tipset (`block_hash`,
54    /// `eth_getBlockReceipts`) bypass it entirely. `eth_getTransactionReceipt`
55    /// narrows to a single message and is also unaffected.
56    ///
57    /// Self-hosted nodes serving trusted callers can use `0` or a high value.
58    /// Public RPC operators should keep it bounded.
59    #[cfg_attr(test, arbitrary(gen(|g| u32::arbitrary(g) as _)))]
60    pub max_filter_results: usize,
61    /// Maximum block-range span (in epochs) accepted in event-filter queries.
62    pub max_filter_height_range: ChainEpoch,
63}
64
65impl Default for EventsConfig {
66    fn default() -> Self {
67        Self {
68            max_filter_results: 10000,
69            max_filter_height_range: 2880,
70        }
71    }
72}
73
74/// Structure that defines `FEVM` configuration
75#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
76#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
77pub struct FevmConfig {
78    #[cfg_attr(test, arbitrary(gen(|g| u32::arbitrary(g) as _)))]
79    pub eth_trace_filter_max_results: usize,
80}
81
82impl Default for FevmConfig {
83    fn default() -> Self {
84        Self {
85            eth_trace_filter_max_results: 500,
86        }
87    }
88}
89
90#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
91#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
92pub struct ChainIndexerConfig {
93    /// Enable indexing Ethereum mappings
94    pub enable_indexer: bool,
95    /// Number of retention epochs for indexed entries. Set to `None` to disable garbage collection.
96    pub gc_retention_epochs: Option<u32>,
97}
98
99impl Default for ChainIndexerConfig {
100    fn default() -> Self {
101        Self {
102            enable_indexer: is_env_truthy(FOREST_CHAIN_INDEXER_ENABLED),
103            gc_retention_epochs: None,
104        }
105    }
106}
107
108#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
109#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
110pub struct FeeConfig {
111    /// Indicates the default max fee for a message
112    #[serde(with = "crate::lotus_json")]
113    pub max_fee: TokenAmount,
114}
115
116impl Default for FeeConfig {
117    fn default() -> Self {
118        // The code is taken from https://github.com/filecoin-project/lotus/blob/release/v1.34.1/node/config/def.go#L39
119        Self {
120            max_fee: TokenAmount::from_atto(70_000_000_000_000_000u64), // 0.07 FIL
121        }
122    }
123}
124
125#[derive(Serialize, Deserialize, PartialEq, Default, Debug, Clone)]
126#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
127#[serde(default)]
128pub struct Config {
129    pub chain: NetworkChain,
130    pub client: Client,
131    pub parity_db: crate::db::parity_db_config::ParityDbConfig,
132    pub network: Libp2pConfig,
133    pub sync: SyncConfig,
134    pub daemon: DaemonConfig,
135    pub events: EventsConfig,
136    pub fevm: FevmConfig,
137    pub fee: FeeConfig,
138    pub chain_indexer: ChainIndexerConfig,
139}
140
141impl Config {
142    pub fn db_config(&self) -> &DbConfig {
143        &self.parity_db
144    }
145
146    pub fn chain(&self) -> &NetworkChain {
147        &self.chain
148    }
149}
150
151#[cfg(test)]
152mod test {
153    use quickcheck_macros::quickcheck;
154
155    use super::*;
156
157    #[quickcheck]
158    fn test_config_all_params_under_section(config: Config) {
159        let serialized_config =
160            toml::to_string(&config).expect("could not serialize the configuration");
161        assert_eq!(
162            serialized_config
163                .trim_start()
164                .chars()
165                .next()
166                .expect("configuration empty"),
167            '['
168        )
169    }
170}