hopr_lib/
config.rs

1use serde::{Deserialize, Serialize};
2use serde_with::{serde_as, DisplayFromStr};
3use validator::{Validate, ValidationError};
4
5pub use hopr_strategy::StrategyConfig;
6pub use hopr_transport::config::{
7    validate_external_host, HeartbeatConfig, HostConfig, HostType, NetworkConfig, ProtocolConfig, TransportConfig,
8};
9
10use hopr_primitive_types::prelude::*;
11use hopr_transport::config::SessionGlobalConfig;
12
13pub const DEFAULT_SAFE_TRANSACTION_SERVICE_PROVIDER: &str = "https://safe-transaction.prod.hoprtech.net/";
14pub const DEFAULT_HOST: &str = "0.0.0.0";
15pub const DEFAULT_PORT: u16 = 9091;
16
17fn validate_announced(v: &bool) -> Result<(), ValidationError> {
18    if *v {
19        Ok(())
20    } else {
21        Err(ValidationError::new(
22            "Announce option should be turned ON in 2.*, only public nodes are supported",
23        ))
24    }
25}
26
27#[inline]
28fn default_network() -> String {
29    "anvil-localhost".to_owned()
30}
31
32#[inline]
33fn just_true() -> bool {
34    true
35}
36
37#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
38#[serde(deny_unknown_fields)]
39pub struct Chain {
40    #[validate(custom(function = "validate_announced"))]
41    #[serde(default = "just_true")]
42    #[default = true]
43    pub announce: bool,
44    #[serde(default = "default_network")]
45    #[default(default_network())]
46    pub network: String,
47    #[serde(default)]
48    pub provider: Option<String>,
49    #[serde(default)]
50    pub max_rpc_requests_per_sec: Option<u32>,
51    #[serde(default)]
52    pub protocols: hopr_chain_api::config::ProtocolsConfig,
53    #[serde(default = "just_true")]
54    #[default = true]
55    pub check_unrealized_balance: bool,
56    #[serde(default = "just_true")]
57    #[default = true]
58    pub keep_logs: bool,
59    #[serde(default = "just_true")]
60    #[default = true]
61    pub fast_sync: bool,
62}
63
64#[inline]
65fn default_invalid_address() -> Address {
66    Address::default()
67}
68
69#[inline]
70fn default_safe_transaction_service_provider() -> String {
71    DEFAULT_SAFE_TRANSACTION_SERVICE_PROVIDER.to_owned()
72}
73
74#[serde_as]
75#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
76#[serde(deny_unknown_fields)]
77pub struct SafeModule {
78    #[validate(url)]
79    #[serde(default = "default_safe_transaction_service_provider")]
80    #[default(default_safe_transaction_service_provider())]
81    pub safe_transaction_service_provider: String,
82    #[serde_as(as = "DisplayFromStr")]
83    #[serde(default = "default_invalid_address")]
84    #[default(default_invalid_address())]
85    pub safe_address: Address,
86    #[serde_as(as = "DisplayFromStr")]
87    #[serde(default = "default_invalid_address")]
88    #[default(default_invalid_address())]
89    pub module_address: Address,
90}
91
92#[allow(dead_code)]
93fn validate_directory_exists(s: &str) -> Result<(), ValidationError> {
94    if std::path::Path::new(s).is_dir() {
95        Ok(())
96    } else {
97        Err(ValidationError::new("Invalid directory path specified"))
98    }
99}
100
101#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
102#[serde(deny_unknown_fields)]
103pub struct Db {
104    /// Path to the directory containing the database
105    #[serde(default)]
106    pub data: String,
107    #[serde(default = "just_true")]
108    #[default = true]
109    pub initialize: bool,
110    #[serde(default)]
111    pub force_initialize: bool,
112}
113
114#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, Validate)]
115pub struct HoprLibConfig {
116    /// Configuration related to host specifics
117    #[validate(nested)]
118    #[validate(custom(function = "validate_external_host"))]
119    #[serde(default = "default_host")]
120    #[default(default_host())]
121    pub host: HostConfig,
122    /// Configuration of the underlying database engine
123    #[validate(nested)]
124    #[serde(default)]
125    pub db: Db,
126    /// Configuration of underlying node behavior in the form strategies
127    ///
128    /// Strategies represent automatically executable behavior performed by
129    /// the node given pre-configured triggers.
130    #[validate(nested)]
131    #[serde(default = "hopr_strategy::hopr_default_strategies")]
132    #[default(hopr_strategy::hopr_default_strategies())]
133    pub strategy: StrategyConfig,
134    /// Configuration of the protocol heartbeat mechanism
135    #[validate(nested)]
136    #[serde(default)]
137    pub heartbeat: HeartbeatConfig,
138    /// Configuration of network properties
139    #[validate(nested)]
140    #[serde(default)]
141    pub network_options: NetworkConfig,
142    /// Configuration specific to transport mechanics
143    #[validate(nested)]
144    #[serde(default)]
145    pub transport: TransportConfig,
146    /// Configuration specific to protocol execution on the p2p layer
147    #[validate(nested)]
148    #[serde(default)]
149    pub protocol: ProtocolConfig,
150    /// Configuration specific to Session management.
151    #[validate(nested)]
152    #[serde(default)]
153    pub session: SessionGlobalConfig,
154    /// Blockchain-specific configuration
155    #[validate(nested)]
156    #[serde(default)]
157    pub chain: Chain,
158    /// Configuration of the `Safe` mechanism
159    #[validate(nested)]
160    #[serde(default)]
161    pub safe_module: SafeModule,
162}
163
164// NOTE: this intentionally does not validate (0.0.0.0) to force user to specify
165// their external IP.
166#[inline]
167fn default_host() -> HostConfig {
168    HostConfig {
169        address: HostType::IPv4(DEFAULT_HOST.to_owned()),
170        port: DEFAULT_PORT,
171    }
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177
178    #[test]
179    fn test_config_should_be_serializable_using_serde() -> Result<(), Box<dyn std::error::Error>> {
180        let cfg = HoprLibConfig::default();
181
182        let yaml = serde_yaml::to_string(&cfg)?;
183        let cfg_after_serde: HoprLibConfig = serde_yaml::from_str(&yaml)?;
184        assert_eq!(cfg, cfg_after_serde);
185
186        Ok(())
187    }
188}