1#![allow(clippy::pedantic)]
3
4use std::collections::{BTreeMap, BTreeSet};
5use std::marker::PhantomData;
6use std::sync::Arc;
7use std::{any, marker};
8
9use bitcoin::Network;
10use fedimint_api_client::api::DynModuleApi;
11use fedimint_core::config::{
12 ClientModuleConfig, CommonModuleInitRegistry, ModuleInitRegistry, ServerModuleConfig,
13 ServerModuleConsensusConfig,
14};
15use fedimint_core::core::{ModuleInstanceId, ModuleKind};
16use fedimint_core::db::{Database, DatabaseVersion};
17use fedimint_core::module::{
18 CommonModuleInit, CoreConsensusVersion, IDynCommonModuleInit, ModuleConsensusVersion,
19 ModuleInit, SupportedModuleApiVersions,
20};
21use fedimint_core::task::TaskGroup;
22use fedimint_core::{NumPeers, PeerId, apply, async_trait_maybe_send, dyn_newtype_define};
23
24use crate::bitcoin_rpc::ServerBitcoinRpcMonitor;
25use crate::config::PeerHandleOps;
26use crate::migration::{
27 DynServerDbMigrationFn, ServerDbMigrationFnContext, ServerModuleDbMigrationContext,
28 ServerModuleDbMigrationFn,
29};
30use crate::{DynServerModule, ServerModule};
31
32pub struct EnvVarDoc {
38 pub name: &'static str,
40 pub description: &'static str,
42}
43
44#[derive(Debug, Clone, Copy)]
49pub struct ConfigGenModuleArgs {
50 pub network: Network,
52 pub disable_base_fees: bool,
54}
55
56#[apply(async_trait_maybe_send!)]
66pub trait IServerModuleInit: IDynCommonModuleInit {
67 fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static);
68
69 fn supported_api_versions(&self) -> SupportedModuleApiVersions;
70
71 #[allow(clippy::too_many_arguments)]
73 async fn init(
74 &self,
75 peer_num: NumPeers,
76 cfg: ServerModuleConfig,
77 db: Database,
78 task_group: &TaskGroup,
79 our_peer_id: PeerId,
80 module_api: DynModuleApi,
81 server_bitcoin_rpc_monitor: ServerBitcoinRpcMonitor,
82 ) -> anyhow::Result<DynServerModule>;
83
84 fn trusted_dealer_gen(
85 &self,
86 peers: &[PeerId],
87 args: &ConfigGenModuleArgs,
88 ) -> BTreeMap<PeerId, ServerModuleConfig>;
89
90 async fn distributed_gen(
91 &self,
92 peers: &(dyn PeerHandleOps + Send + Sync),
93 args: &ConfigGenModuleArgs,
94 ) -> anyhow::Result<ServerModuleConfig>;
95
96 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
97
98 fn get_client_config(
99 &self,
100 module_instance_id: ModuleInstanceId,
101 config: &ServerModuleConsensusConfig,
102 ) -> anyhow::Result<ClientModuleConfig>;
103
104 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, DynServerDbMigrationFn>;
108
109 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>>;
111
112 fn is_enabled_by_default(&self) -> bool;
114
115 fn get_documented_env_vars(&self) -> Vec<EnvVarDoc>;
117}
118
119pub trait ServerModuleShared: any::Any + Send + Sync {
122 fn new(task_group: TaskGroup) -> Self;
123}
124
125pub struct ServerModuleInitArgs<S>
126where
127 S: ServerModuleInit,
128{
129 cfg: ServerModuleConfig,
130 db: Database,
131 task_group: TaskGroup,
132 our_peer_id: PeerId,
133 num_peers: NumPeers,
134 module_api: DynModuleApi,
135 server_bitcoin_rpc_monitor: ServerBitcoinRpcMonitor,
136 _marker: marker::PhantomData<S>,
139}
140
141impl<S> ServerModuleInitArgs<S>
142where
143 S: ServerModuleInit,
144{
145 pub fn cfg(&self) -> &ServerModuleConfig {
146 &self.cfg
147 }
148
149 pub fn db(&self) -> &Database {
150 &self.db
151 }
152
153 pub fn num_peers(&self) -> NumPeers {
154 self.num_peers
155 }
156
157 pub fn task_group(&self) -> &TaskGroup {
158 &self.task_group
159 }
160
161 pub fn our_peer_id(&self) -> PeerId {
162 self.our_peer_id
163 }
164
165 pub fn module_api(&self) -> &DynModuleApi {
166 &self.module_api
167 }
168
169 pub fn server_bitcoin_rpc_monitor(&self) -> ServerBitcoinRpcMonitor {
170 self.server_bitcoin_rpc_monitor.clone()
171 }
172}
173#[apply(async_trait_maybe_send!)]
180pub trait ServerModuleInit: ModuleInit + Sized {
181 type Module: ServerModule + Send + Sync;
182
183 fn versions(&self, core: CoreConsensusVersion) -> &[ModuleConsensusVersion];
196
197 fn supported_api_versions(&self) -> SupportedModuleApiVersions;
198
199 fn kind() -> ModuleKind {
200 <Self as ModuleInit>::Common::KIND
201 }
202
203 async fn init(&self, args: &ServerModuleInitArgs<Self>) -> anyhow::Result<Self::Module>;
205
206 fn trusted_dealer_gen(
207 &self,
208 peers: &[PeerId],
209 args: &ConfigGenModuleArgs,
210 ) -> BTreeMap<PeerId, ServerModuleConfig>;
211
212 async fn distributed_gen(
213 &self,
214 peers: &(dyn PeerHandleOps + Send + Sync),
215 args: &ConfigGenModuleArgs,
216 ) -> anyhow::Result<ServerModuleConfig>;
217
218 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
219
220 fn get_client_config(
222 &self,
223 config: &ServerModuleConsensusConfig,
224 ) -> anyhow::Result<<<Self as ModuleInit>::Common as CommonModuleInit>::ClientConfig>;
225
226 fn get_database_migrations(
230 &self,
231 ) -> BTreeMap<DatabaseVersion, ServerModuleDbMigrationFn<Self::Module>> {
232 BTreeMap::new()
233 }
234
235 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>> {
245 None
246 }
247
248 fn is_enabled_by_default(&self) -> bool {
251 true
252 }
253
254 fn get_documented_env_vars(&self) -> Vec<EnvVarDoc> {
259 vec![]
260 }
261}
262
263#[apply(async_trait_maybe_send!)]
264impl<T> IServerModuleInit for T
265where
266 T: ServerModuleInit + 'static + Sync,
267{
268 fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
269 self
270 }
271
272 fn supported_api_versions(&self) -> SupportedModuleApiVersions {
273 <Self as ServerModuleInit>::supported_api_versions(self)
274 }
275
276 async fn init(
277 &self,
278 num_peers: NumPeers,
279 cfg: ServerModuleConfig,
280 db: Database,
281 task_group: &TaskGroup,
282 our_peer_id: PeerId,
283 module_api: DynModuleApi,
284 server_bitcoin_rpc_monitor: ServerBitcoinRpcMonitor,
285 ) -> anyhow::Result<DynServerModule> {
286 let module = <Self as ServerModuleInit>::init(
287 self,
288 &ServerModuleInitArgs {
289 num_peers,
290 cfg,
291 db,
292 task_group: task_group.clone(),
293 our_peer_id,
294 _marker: PhantomData,
295 module_api,
296 server_bitcoin_rpc_monitor,
297 },
298 )
299 .await?;
300
301 Ok(DynServerModule::from(module))
302 }
303
304 fn trusted_dealer_gen(
305 &self,
306 peers: &[PeerId],
307 args: &ConfigGenModuleArgs,
308 ) -> BTreeMap<PeerId, ServerModuleConfig> {
309 <Self as ServerModuleInit>::trusted_dealer_gen(self, peers, args)
310 }
311
312 async fn distributed_gen(
313 &self,
314 peers: &(dyn PeerHandleOps + Send + Sync),
315 args: &ConfigGenModuleArgs,
316 ) -> anyhow::Result<ServerModuleConfig> {
317 <Self as ServerModuleInit>::distributed_gen(self, peers, args).await
318 }
319
320 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()> {
321 <Self as ServerModuleInit>::validate_config(self, identity, config)
322 }
323
324 fn get_client_config(
325 &self,
326 module_instance_id: ModuleInstanceId,
327 config: &ServerModuleConsensusConfig,
328 ) -> anyhow::Result<ClientModuleConfig> {
329 ClientModuleConfig::from_typed(
330 module_instance_id,
331 <Self as ServerModuleInit>::kind(),
332 config.version,
333 <Self as ServerModuleInit>::get_client_config(self, config)?,
334 )
335 }
336 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, DynServerDbMigrationFn> {
337 <Self as ServerModuleInit>::get_database_migrations(self)
338 .into_iter()
339 .map(|(k, f)| {
340 (k, {
341 let closure: DynServerDbMigrationFn =
342 Box::new(move |ctx: ServerDbMigrationFnContext<'_>| {
343 let map = ctx.map(ServerModuleDbMigrationContext::new);
344 Box::pin(f(map))
345 });
346 closure
347 })
348 })
349 .collect()
350 }
351
352 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>> {
353 <Self as ServerModuleInit>::used_db_prefixes(self)
354 }
355
356 fn is_enabled_by_default(&self) -> bool {
357 <Self as ServerModuleInit>::is_enabled_by_default(self)
358 }
359
360 fn get_documented_env_vars(&self) -> Vec<EnvVarDoc> {
361 <Self as ServerModuleInit>::get_documented_env_vars(self)
362 }
363}
364
365dyn_newtype_define!(
366 #[derive(Clone)]
367 pub DynServerModuleInit(Arc<IServerModuleInit>)
368);
369
370impl AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static> for DynServerModuleInit {
371 fn as_ref(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
372 self.inner.as_common()
373 }
374}
375
376pub type ServerModuleInitRegistry = ModuleInitRegistry<DynServerModuleInit>;
377
378pub trait ServerModuleInitRegistryExt {
379 fn to_common(&self) -> CommonModuleInitRegistry;
380 fn default_modules(&self) -> BTreeSet<ModuleKind>;
381}
382
383impl ServerModuleInitRegistryExt for ServerModuleInitRegistry {
384 fn to_common(&self) -> CommonModuleInitRegistry {
385 self.iter().map(|(_k, v)| v.to_dyn_common()).collect()
386 }
387
388 fn default_modules(&self) -> BTreeSet<ModuleKind> {
389 self.iter()
390 .filter(|(_kind, init)| init.is_enabled_by_default())
391 .map(|(kind, _init)| kind.clone())
392 .collect()
393 }
394}