1use std::net::SocketAddr;
36
37use crate::crypto::pqc::types::{MlDsaPublicKey, MlDsaSecretKey};
38
39#[derive(Clone, Default)]
58pub struct NodeConfig {
59 pub bind_addr: Option<SocketAddr>,
61
62 pub known_peers: Vec<SocketAddr>,
65
66 pub keypair: Option<(MlDsaPublicKey, MlDsaSecretKey)>,
69}
70
71impl std::fmt::Debug for NodeConfig {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 f.debug_struct("NodeConfig")
74 .field("bind_addr", &self.bind_addr)
75 .field("known_peers", &self.known_peers)
76 .field("keypair", &self.keypair.as_ref().map(|_| "[REDACTED]"))
77 .finish()
78 }
79}
80
81impl NodeConfig {
82 pub fn new() -> Self {
84 Self::default()
85 }
86
87 pub fn builder() -> NodeConfigBuilder {
89 NodeConfigBuilder::default()
90 }
91
92 pub fn with_bind_addr(addr: SocketAddr) -> Self {
94 Self {
95 bind_addr: Some(addr),
96 ..Default::default()
97 }
98 }
99
100 pub fn with_known_peers(peers: Vec<SocketAddr>) -> Self {
102 Self {
103 known_peers: peers,
104 ..Default::default()
105 }
106 }
107
108 pub fn with_keypair(public_key: MlDsaPublicKey, secret_key: MlDsaSecretKey) -> Self {
110 Self {
111 keypair: Some((public_key, secret_key)),
112 ..Default::default()
113 }
114 }
115}
116
117#[derive(Default)]
119pub struct NodeConfigBuilder {
120 bind_addr: Option<SocketAddr>,
121 known_peers: Vec<SocketAddr>,
122 keypair: Option<(MlDsaPublicKey, MlDsaSecretKey)>,
123}
124
125impl NodeConfigBuilder {
126 pub fn bind_addr(mut self, addr: SocketAddr) -> Self {
128 self.bind_addr = Some(addr);
129 self
130 }
131
132 pub fn known_peer(mut self, addr: SocketAddr) -> Self {
134 self.known_peers.push(addr);
135 self
136 }
137
138 pub fn known_peers(mut self, addrs: impl IntoIterator<Item = SocketAddr>) -> Self {
140 self.known_peers.extend(addrs);
141 self
142 }
143
144 pub fn keypair(mut self, public_key: MlDsaPublicKey, secret_key: MlDsaSecretKey) -> Self {
146 self.keypair = Some((public_key, secret_key));
147 self
148 }
149
150 pub fn build(self) -> NodeConfig {
152 NodeConfig {
153 bind_addr: self.bind_addr,
154 known_peers: self.known_peers,
155 keypair: self.keypair,
156 }
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn test_default_config() {
166 let config = NodeConfig::default();
167 assert!(config.bind_addr.is_none());
168 assert!(config.known_peers.is_empty());
169 assert!(config.keypair.is_none());
170 }
171
172 #[test]
173 fn test_builder_with_bind_addr() {
174 let addr: SocketAddr = "0.0.0.0:9000".parse().unwrap();
175 let config = NodeConfig::builder().bind_addr(addr).build();
176 assert_eq!(config.bind_addr, Some(addr));
177 }
178
179 #[test]
180 fn test_builder_with_known_peers() {
181 let peer1: SocketAddr = "127.0.0.1:9000".parse().unwrap();
182 let peer2: SocketAddr = "127.0.0.1:9001".parse().unwrap();
183
184 let config = NodeConfig::builder()
185 .known_peer(peer1)
186 .known_peer(peer2)
187 .build();
188
189 assert_eq!(config.known_peers.len(), 2);
190 assert!(config.known_peers.contains(&peer1));
191 assert!(config.known_peers.contains(&peer2));
192 }
193
194 #[test]
195 fn test_builder_with_multiple_peers() {
196 let peers: Vec<SocketAddr> = vec![
197 "127.0.0.1:9000".parse().unwrap(),
198 "127.0.0.1:9001".parse().unwrap(),
199 ];
200
201 let config = NodeConfig::builder().known_peers(peers.clone()).build();
202
203 assert_eq!(config.known_peers, peers);
204 }
205
206 #[test]
207 fn test_with_bind_addr() {
208 let addr: SocketAddr = "0.0.0.0:9000".parse().unwrap();
209 let config = NodeConfig::with_bind_addr(addr);
210 assert_eq!(config.bind_addr, Some(addr));
211 assert!(config.known_peers.is_empty());
212 assert!(config.keypair.is_none());
213 }
214
215 #[test]
216 fn test_with_known_peers() {
217 let peers: Vec<SocketAddr> = vec![
218 "127.0.0.1:9000".parse().unwrap(),
219 "127.0.0.1:9001".parse().unwrap(),
220 ];
221
222 let config = NodeConfig::with_known_peers(peers.clone());
223 assert!(config.bind_addr.is_none());
224 assert_eq!(config.known_peers, peers);
225 assert!(config.keypair.is_none());
226 }
227
228 #[test]
229 fn test_debug_redacts_keypair() {
230 use crate::crypto::raw_public_keys::key_utils::generate_ml_dsa_keypair;
231 let (public_key, secret_key) = generate_ml_dsa_keypair().unwrap();
232 let config = NodeConfig::with_keypair(public_key, secret_key);
233 let debug_str = format!("{:?}", config);
234 assert!(debug_str.contains("[REDACTED]"));
235 assert!(!debug_str.contains(&format!("{:?}", config.keypair)));
236 }
237
238 #[test]
239 fn test_config_is_clone() {
240 let config = NodeConfig::builder()
241 .bind_addr("0.0.0.0:9000".parse().unwrap())
242 .known_peer("127.0.0.1:9001".parse().unwrap())
243 .build();
244
245 let cloned = config.clone();
246 assert_eq!(config.bind_addr, cloned.bind_addr);
247 assert_eq!(config.known_peers, cloned.known_peers);
248 }
249}