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,
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 #[allow(clippy::too_many_arguments)]
71 async fn init(
72 &self,
73 peer_num: NumPeers,
74 cfg: ServerModuleConfig,
75 db: Database,
76 task_group: &TaskGroup,
77 our_peer_id: PeerId,
78 module_api: DynModuleApi,
79 server_bitcoin_rpc_monitor: ServerBitcoinRpcMonitor,
80 ) -> anyhow::Result<DynServerModule>;
81
82 fn trusted_dealer_gen(
83 &self,
84 peers: &[PeerId],
85 args: &ConfigGenModuleArgs,
86 ) -> BTreeMap<PeerId, ServerModuleConfig>;
87
88 async fn distributed_gen(
89 &self,
90 peers: &(dyn PeerHandleOps + Send + Sync),
91 args: &ConfigGenModuleArgs,
92 ) -> anyhow::Result<ServerModuleConfig>;
93
94 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
95
96 fn get_client_config(
97 &self,
98 module_instance_id: ModuleInstanceId,
99 config: &ServerModuleConsensusConfig,
100 ) -> anyhow::Result<ClientModuleConfig>;
101
102 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, DynServerDbMigrationFn>;
106
107 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>>;
109
110 fn is_enabled_by_default(&self) -> bool;
112
113 fn get_documented_env_vars(&self) -> Vec<EnvVarDoc>;
115}
116
117pub trait ServerModuleShared: any::Any + Send + Sync {
120 fn new(task_group: TaskGroup) -> Self;
121}
122
123pub struct ServerModuleInitArgs<S>
124where
125 S: ServerModuleInit,
126{
127 cfg: ServerModuleConfig,
128 db: Database,
129 task_group: TaskGroup,
130 our_peer_id: PeerId,
131 num_peers: NumPeers,
132 module_api: DynModuleApi,
133 server_bitcoin_rpc_monitor: ServerBitcoinRpcMonitor,
134 _marker: marker::PhantomData<S>,
137}
138
139impl<S> ServerModuleInitArgs<S>
140where
141 S: ServerModuleInit,
142{
143 pub fn cfg(&self) -> &ServerModuleConfig {
144 &self.cfg
145 }
146
147 pub fn db(&self) -> &Database {
148 &self.db
149 }
150
151 pub fn num_peers(&self) -> NumPeers {
152 self.num_peers
153 }
154
155 pub fn task_group(&self) -> &TaskGroup {
156 &self.task_group
157 }
158
159 pub fn our_peer_id(&self) -> PeerId {
160 self.our_peer_id
161 }
162
163 pub fn module_api(&self) -> &DynModuleApi {
164 &self.module_api
165 }
166
167 pub fn server_bitcoin_rpc_monitor(&self) -> ServerBitcoinRpcMonitor {
168 self.server_bitcoin_rpc_monitor.clone()
169 }
170}
171#[apply(async_trait_maybe_send!)]
178pub trait ServerModuleInit: ModuleInit + Sized {
179 type Module: ServerModule + Send + Sync;
180
181 fn versions(&self, core: CoreConsensusVersion) -> &[ModuleConsensusVersion];
194
195 fn kind() -> ModuleKind {
196 <Self as ModuleInit>::Common::KIND
197 }
198
199 async fn init(&self, args: &ServerModuleInitArgs<Self>) -> anyhow::Result<Self::Module>;
201
202 fn trusted_dealer_gen(
203 &self,
204 peers: &[PeerId],
205 args: &ConfigGenModuleArgs,
206 ) -> BTreeMap<PeerId, ServerModuleConfig>;
207
208 async fn distributed_gen(
209 &self,
210 peers: &(dyn PeerHandleOps + Send + Sync),
211 args: &ConfigGenModuleArgs,
212 ) -> anyhow::Result<ServerModuleConfig>;
213
214 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
215
216 fn get_client_config(
218 &self,
219 config: &ServerModuleConsensusConfig,
220 ) -> anyhow::Result<<<Self as ModuleInit>::Common as CommonModuleInit>::ClientConfig>;
221
222 fn get_database_migrations(
226 &self,
227 ) -> BTreeMap<DatabaseVersion, ServerModuleDbMigrationFn<Self::Module>> {
228 BTreeMap::new()
229 }
230
231 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>> {
241 None
242 }
243
244 fn is_enabled_by_default(&self) -> bool {
247 true
248 }
249
250 fn get_documented_env_vars(&self) -> Vec<EnvVarDoc> {
255 vec![]
256 }
257}
258
259#[apply(async_trait_maybe_send!)]
260impl<T> IServerModuleInit for T
261where
262 T: ServerModuleInit + 'static + Sync,
263{
264 fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
265 self
266 }
267
268 async fn init(
269 &self,
270 num_peers: NumPeers,
271 cfg: ServerModuleConfig,
272 db: Database,
273 task_group: &TaskGroup,
274 our_peer_id: PeerId,
275 module_api: DynModuleApi,
276 server_bitcoin_rpc_monitor: ServerBitcoinRpcMonitor,
277 ) -> anyhow::Result<DynServerModule> {
278 let module = <Self as ServerModuleInit>::init(
279 self,
280 &ServerModuleInitArgs {
281 num_peers,
282 cfg,
283 db,
284 task_group: task_group.clone(),
285 our_peer_id,
286 _marker: PhantomData,
287 module_api,
288 server_bitcoin_rpc_monitor,
289 },
290 )
291 .await?;
292
293 Ok(DynServerModule::from(module))
294 }
295
296 fn trusted_dealer_gen(
297 &self,
298 peers: &[PeerId],
299 args: &ConfigGenModuleArgs,
300 ) -> BTreeMap<PeerId, ServerModuleConfig> {
301 <Self as ServerModuleInit>::trusted_dealer_gen(self, peers, args)
302 }
303
304 async fn distributed_gen(
305 &self,
306 peers: &(dyn PeerHandleOps + Send + Sync),
307 args: &ConfigGenModuleArgs,
308 ) -> anyhow::Result<ServerModuleConfig> {
309 <Self as ServerModuleInit>::distributed_gen(self, peers, args).await
310 }
311
312 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()> {
313 <Self as ServerModuleInit>::validate_config(self, identity, config)
314 }
315
316 fn get_client_config(
317 &self,
318 module_instance_id: ModuleInstanceId,
319 config: &ServerModuleConsensusConfig,
320 ) -> anyhow::Result<ClientModuleConfig> {
321 ClientModuleConfig::from_typed(
322 module_instance_id,
323 <Self as ServerModuleInit>::kind(),
324 config.version,
325 <Self as ServerModuleInit>::get_client_config(self, config)?,
326 )
327 }
328 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, DynServerDbMigrationFn> {
329 <Self as ServerModuleInit>::get_database_migrations(self)
330 .into_iter()
331 .map(|(k, f)| {
332 (k, {
333 let closure: DynServerDbMigrationFn =
334 Box::new(move |ctx: ServerDbMigrationFnContext<'_>| {
335 let map = ctx.map(ServerModuleDbMigrationContext::new);
336 Box::pin(f(map))
337 });
338 closure
339 })
340 })
341 .collect()
342 }
343
344 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>> {
345 <Self as ServerModuleInit>::used_db_prefixes(self)
346 }
347
348 fn is_enabled_by_default(&self) -> bool {
349 <Self as ServerModuleInit>::is_enabled_by_default(self)
350 }
351
352 fn get_documented_env_vars(&self) -> Vec<EnvVarDoc> {
353 <Self as ServerModuleInit>::get_documented_env_vars(self)
354 }
355}
356
357dyn_newtype_define!(
358 #[derive(Clone)]
359 pub DynServerModuleInit(Arc<IServerModuleInit>)
360);
361
362impl AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static> for DynServerModuleInit {
363 fn as_ref(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
364 self.inner.as_common()
365 }
366}
367
368pub type ServerModuleInitRegistry = ModuleInitRegistry<DynServerModuleInit>;
369
370pub trait ServerModuleInitRegistryExt {
371 fn to_common(&self) -> CommonModuleInitRegistry;
372 fn default_modules(&self) -> BTreeSet<ModuleKind>;
373}
374
375impl ServerModuleInitRegistryExt for ServerModuleInitRegistry {
376 fn to_common(&self) -> CommonModuleInitRegistry {
377 self.iter().map(|(_k, v)| v.to_dyn_common()).collect()
378 }
379
380 fn default_modules(&self) -> BTreeSet<ModuleKind> {
381 self.iter()
382 .filter(|(_kind, init)| init.is_enabled_by_default())
383 .map(|(kind, _init)| kind.clone())
384 .collect()
385 }
386}