hopr_chain_indexer/config.rs
1/// Configuration for the chain indexer functionality
2#[derive(Debug, Clone, smart_default::SmartDefault)]
3pub struct IndexerConfig {
4 /// The block at which the indexer should start
5 ///
6 /// It typically makes little sense to start indexing from the beginning
7 /// of the chain; all that is sufficient is to start indexing since the
8 /// relevant smart contracts were introduced into the chain.
9 ///
10 /// This value makes sure that indexing is relevant and as minimal as possible.
11 ///
12 /// Default is `0`.
13 pub start_block_number: u64,
14
15 /// Whether to use fast synchronization during indexing.
16 /// When enabled, it allows for quicker indexing of existing logs during node startup.
17 ///
18 /// Default is `true`.
19 #[default(true)]
20 pub fast_sync: bool,
21
22 /// Whether to perform logs snapshot download on startup.
23 /// When enabled, it allows for quicker indexing from scratch.
24 ///
25 /// Default is `false`.
26 #[default(false)]
27 pub enable_logs_snapshot: bool,
28
29 /// URL to download logs snapshot from.
30 /// This should point to a publicly accessible tar.xz file containing
31 /// the SQLite logs database files.
32 ///
33 /// Default is None
34 #[default(None)]
35 pub logs_snapshot_url: Option<String>,
36
37 /// Path to the data directory where databases are stored.
38 /// This is used for snapshot installation and database state checking.
39 ///
40 /// Default is empty string (must be set by application).
41 pub data_directory: String,
42}
43
44impl IndexerConfig {
45 /// Creates a new indexer configuration.
46 ///
47 /// # Arguments
48 ///
49 /// * `start_block_number` - The block number from which to start indexing
50 /// * `fast_sync` - Whether to enable fast synchronization during startup
51 /// * `enable_logs_snapshot` - Whether to enable logs snapshot download
52 /// * `logs_snapshot_url` - URL to download logs snapshot from
53 /// * `data_directory` - Path to the data directory where databases are stored
54 ///
55 /// # Returns
56 ///
57 /// A new instance of `IndexerConfig`
58 pub fn new(
59 start_block_number: u64,
60 fast_sync: bool,
61 enable_logs_snapshot: bool,
62 logs_snapshot_url: Option<String>,
63 data_directory: String,
64 ) -> Self {
65 Self {
66 start_block_number,
67 fast_sync,
68 enable_logs_snapshot,
69 logs_snapshot_url,
70 data_directory,
71 }
72 }
73
74 /// Validates the configuration and returns any validation errors.
75 ///
76 /// Performs comprehensive validation of configuration parameters including:
77 /// - URL format and protocol validation (HTTP/HTTPS/file:// supported)
78 /// - File extension validation (.tar.xz required)
79 /// - Data directory path validation
80 /// - Dependency validation (data directory required when snapshots enabled)
81 ///
82 /// # Returns
83 ///
84 /// - `Ok(())` if all validation passes
85 /// - `Err(String)` with a descriptive error message if validation fails
86 ///
87 /// # Example
88 ///
89 /// ```
90 /// use hopr_chain_indexer::IndexerConfig;
91 ///
92 /// let config = IndexerConfig::new(
93 /// 100,
94 /// true,
95 /// true,
96 /// Some("https://example.com/snapshot.tar.xz".to_string()),
97 /// "/tmp/hopr_data".to_string(),
98 /// );
99 ///
100 /// assert!(config.validate().is_ok());
101 /// ```
102 pub fn validate(&self) -> Result<(), String> {
103 // Check that url is valid if logs snapshot is enabled
104 if self.enable_logs_snapshot && self.logs_snapshot_url.is_none() {
105 return Err("Logs snapshot URL must be specified when logs snapshots are enabled".to_string());
106 }
107
108 Ok(())
109 }
110
111 /// Convenience method to check if the configuration is valid.
112 ///
113 /// This is a simple wrapper around `validate()` that returns a boolean
114 /// instead of a `Result`, making it easier to use in conditional expressions.
115 ///
116 /// # Returns
117 ///
118 /// `true` if all validation passes, `false` otherwise
119 ///
120 /// # Example
121 ///
122 /// ```
123 /// use hopr_chain_indexer::IndexerConfig;
124 ///
125 /// let config = IndexerConfig::default();
126 /// if !config.is_valid() {
127 /// // Handle invalid configuration
128 /// }
129 /// ```
130 pub fn is_valid(&self) -> bool {
131 self.validate().is_ok()
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn test_full_valid_config() {
141 let data_directory = "/tmp/hopr_test_data";
142 let logs_snapshot_url = format!("file:///tmp/snapshot.tar.xz");
143
144 let cfg = IndexerConfig::new(0, true, true, Some(logs_snapshot_url), data_directory.into());
145
146 cfg.validate().expect("Failed to validate snapshot configuration");
147 assert!(cfg.is_valid(), "Valid configuration should return true for is_valid()");
148 }
149
150 #[test]
151 fn test_disabled_snapshot_config() {
152 let cfg = IndexerConfig::new(0, true, false, Some("".to_string()), "".to_string());
153
154 assert!(
155 cfg.validate().is_ok(),
156 "Configuration should be valid when snapshots disabled"
157 );
158 }
159
160 #[test]
161 fn test_missing_snapshot_url() {
162 let cfg = IndexerConfig::new(0, true, true, None, "".to_string());
163
164 assert!(
165 cfg.validate().is_err(),
166 "Configuration should be invalid when snapshots is enabled but URL is missing"
167 );
168 }
169}