Skip to main content

hopr_lib/
config.rs

1use std::time::Duration;
2
3use hopr_api::types::primitive::prelude::*;
4pub use hopr_transport::{
5    TagAllocatorConfig,
6    config::{
7        HoprPacketPipelineConfig, HoprProtocolConfig, HostConfig, HostType, ProbeConfig, SessionGlobalConfig,
8        TransportConfig, looks_like_domain,
9    },
10};
11use validator::{Validate, ValidationError};
12
13pub const DEFAULT_HOST: &str = "0.0.0.0";
14pub const DEFAULT_PORT: u16 = 9091;
15
16#[inline]
17fn default_invalid_address() -> Address {
18    Address::default()
19}
20
21#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_with::serde_as)]
22#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Validate)]
23#[cfg_attr(
24    feature = "serde",
25    derive(serde::Serialize, serde::Deserialize),
26    serde(deny_unknown_fields)
27)]
28pub struct SafeModule {
29    #[cfg_attr(
30        feature = "serde",
31        serde_as(as = "serde_with::DisplayFromStr"),
32        serde(default = "default_invalid_address")
33    )]
34    #[default(default_invalid_address())]
35    pub safe_address: Address,
36    #[cfg_attr(
37        feature = "serde",
38        serde_as(as = "serde_with::DisplayFromStr"),
39        serde(default = "default_invalid_address")
40    )]
41    #[default(default_invalid_address())]
42    pub module_address: Address,
43}
44
45#[allow(dead_code)]
46fn validate_directory_exists(s: &str) -> Result<(), ValidationError> {
47    if std::path::Path::new(s).is_dir() {
48        Ok(())
49    } else {
50        Err(ValidationError::new("Invalid directory path specified"))
51    }
52}
53
54#[derive(Debug, Clone, PartialEq, smart_default::SmartDefault, Validate)]
55#[cfg_attr(
56    feature = "serde",
57    derive(serde::Serialize, serde::Deserialize),
58    serde(deny_unknown_fields)
59)]
60pub struct HoprLibConfig {
61    /// Configuration related to host specifics
62    #[validate(nested)]
63    #[default(default_host())]
64    #[cfg_attr(feature = "serde", serde(default = "default_host"))]
65    pub host: HostConfig,
66    /// Determines whether the node should be advertised publicly on-chain.
67    #[cfg_attr(feature = "serde", serde(default))]
68    pub publish: bool,
69    /// Configuration of the HOPR protocol.
70    #[validate(nested)]
71    #[cfg_attr(feature = "serde", serde(default))]
72    pub protocol: HoprProtocolConfig,
73    /// Configuration of the node Safe and Module.
74    #[validate(nested)]
75    #[cfg_attr(feature = "serde", serde(default))]
76    pub safe_module: SafeModule,
77    /// Defines how often the outgoing ticket indices be saved to the persistent storage.
78    ///
79    /// If synchronization to a persistent storage does not happen and the node restarts,
80    /// the node will start from the current on-chain channel index and could as a result
81    /// be creating invalid outgoing tickets.
82    ///
83    /// Default is 15 seconds, minimum is 1 second.
84    #[default(default_out_index_sync_period())]
85    #[validate(custom(function = "validate_out_index_sync_period"))]
86    #[cfg_attr(
87        feature = "serde",
88        serde(default = "default_out_index_sync_period", with = "humantime_serde")
89    )]
90    pub out_index_sync_period: Duration,
91}
92
93const MINIMUM_OUT_SYNC_PERIOD: Duration = Duration::from_secs(1);
94
95fn validate_out_index_sync_period(lifetime: &Duration) -> Result<(), ValidationError> {
96    if lifetime < &MINIMUM_OUT_SYNC_PERIOD {
97        Err(ValidationError::new("out_index_sync_period is too low"))
98    } else {
99        Ok(())
100    }
101}
102
103fn default_out_index_sync_period() -> Duration {
104    Duration::from_secs(15)
105}
106
107// NOTE: this intentionally does not validate (0.0.0.0) to force user to specify
108// their external IP.
109#[inline]
110fn default_host() -> HostConfig {
111    HostConfig {
112        address: HostType::IPv4(DEFAULT_HOST.to_owned()),
113        port: DEFAULT_PORT,
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    #[cfg(feature = "serde")]
120    #[test]
121    fn test_config_should_be_serializable_using_serde() -> Result<(), Box<dyn std::error::Error>> {
122        let cfg = super::HoprLibConfig::default();
123
124        let yaml = serde_saphyr::to_string(&cfg)?;
125        let cfg_after_serde: super::HoprLibConfig = serde_saphyr::from_str(&yaml)?;
126        assert_eq!(cfg, cfg_after_serde);
127
128        Ok(())
129    }
130}