1#![allow(clippy::pedantic)]
3
4use std::collections::{BTreeMap, BTreeSet};
5use std::marker::PhantomData;
6use std::sync::Arc;
7use std::{any, marker};
8
9use fedimint_api_client::api::DynModuleApi;
10use fedimint_core::config::{
11 ClientModuleConfig, CommonModuleInitRegistry, ConfigGenModuleParams, ModuleInitParams,
12 ModuleInitRegistry, ServerModuleConfig, ServerModuleConsensusConfig,
13};
14use fedimint_core::core::{ModuleInstanceId, ModuleKind};
15use fedimint_core::db::{Database, DatabaseVersion};
16use fedimint_core::module::{
17 CommonModuleInit, CoreConsensusVersion, IDynCommonModuleInit, ModuleConsensusVersion,
18 ModuleInit, SupportedModuleApiVersions,
19};
20use fedimint_core::task::TaskGroup;
21use fedimint_core::{NumPeers, PeerId, apply, async_trait_maybe_send, dyn_newtype_define};
22
23use crate::config::PeerHandleOps;
24use crate::migration::{
25 DynServerDbMigrationFn, ServerDbMigrationFnContext, ServerModuleDbMigrationContext,
26 ServerModuleDbMigrationFn,
27};
28use crate::{DynServerModule, ServerModule};
29
30#[apply(async_trait_maybe_send!)]
40pub trait IServerModuleInit: IDynCommonModuleInit {
41 fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static);
42
43 fn supported_api_versions(&self) -> SupportedModuleApiVersions;
44
45 #[allow(clippy::too_many_arguments)]
47 async fn init(
48 &self,
49 peer_num: NumPeers,
50 cfg: ServerModuleConfig,
51 db: Database,
52 task_group: &TaskGroup,
53 our_peer_id: PeerId,
54 module_api: DynModuleApi,
55 shared: SharedAnymap,
56 ) -> anyhow::Result<DynServerModule>;
57
58 fn validate_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<()>;
59
60 fn trusted_dealer_gen(
61 &self,
62 peers: &[PeerId],
63 params: &ConfigGenModuleParams,
64 ) -> BTreeMap<PeerId, ServerModuleConfig>;
65
66 async fn distributed_gen(
67 &self,
68 peers: &(dyn PeerHandleOps + Send + Sync),
69 params: &ConfigGenModuleParams,
70 ) -> anyhow::Result<ServerModuleConfig>;
71
72 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
73
74 fn get_client_config(
75 &self,
76 module_instance_id: ModuleInstanceId,
77 config: &ServerModuleConsensusConfig,
78 ) -> anyhow::Result<ClientModuleConfig>;
79
80 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, DynServerDbMigrationFn>;
84
85 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>>;
87}
88
89pub trait ServerModuleShared: any::Any + Send + Sync {
92 fn new(task_group: TaskGroup) -> Self;
93}
94
95type SharedAnymap = Arc<std::sync::RwLock<BTreeMap<any::TypeId, Box<dyn any::Any + Send + Sync>>>>;
96
97pub struct ServerModuleInitArgs<S>
98where
99 S: ServerModuleInit,
100{
101 cfg: ServerModuleConfig,
102 db: Database,
103 task_group: TaskGroup,
104 our_peer_id: PeerId,
105 num_peers: NumPeers,
106 module_api: DynModuleApi,
107 shared: SharedAnymap,
112 _marker: marker::PhantomData<S>,
115}
116
117impl<S> ServerModuleInitArgs<S>
118where
119 S: ServerModuleInit,
120{
121 pub fn cfg(&self) -> &ServerModuleConfig {
122 &self.cfg
123 }
124
125 pub fn db(&self) -> &Database {
126 &self.db
127 }
128
129 pub fn num_peers(&self) -> NumPeers {
130 self.num_peers
131 }
132
133 pub fn task_group(&self) -> &TaskGroup {
134 &self.task_group
135 }
136
137 pub fn our_peer_id(&self) -> PeerId {
138 self.our_peer_id
139 }
140
141 pub fn module_api(&self) -> &DynModuleApi {
142 &self.module_api
143 }
144
145 pub fn with_shared<T, R>(&self, f: impl FnOnce(&T) -> R) -> R
146 where
147 T: ServerModuleShared,
148 {
149 let type_id = any::TypeId::of::<T>();
150 let mut write = self.shared.write().expect("Locking failed");
151
152 let _ = write
153 .entry(type_id)
154 .or_insert_with(|| Box::new(<T as ServerModuleShared>::new(self.task_group.clone())));
155 drop(write);
158 let read = self.shared.read().expect("Locking failed");
159 let t: &T = read
160 .get(&type_id)
161 .expect("Must be there, just inserted")
162 .as_ref()
163 .downcast_ref()
164 .expect("Can't fail, must be of expected type");
165
166 f(t)
167 }
168
169 pub fn shared<T>(&self) -> T
170 where
171 T: ServerModuleShared + Clone,
172 {
173 self.with_shared::<T, T>(|t| t.clone())
174 }
175}
176#[apply(async_trait_maybe_send!)]
183pub trait ServerModuleInit: ModuleInit + Sized {
184 type Module: ServerModule + Send + Sync;
185 type Params: ModuleInitParams;
186
187 fn versions(&self, core: CoreConsensusVersion) -> &[ModuleConsensusVersion];
200
201 fn supported_api_versions(&self) -> SupportedModuleApiVersions;
202
203 fn kind() -> ModuleKind {
204 <Self as ModuleInit>::Common::KIND
205 }
206
207 async fn init(&self, args: &ServerModuleInitArgs<Self>) -> anyhow::Result<Self::Module>;
209
210 fn parse_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<Self::Params> {
211 params.to_typed::<Self::Params>()
212 }
213
214 fn trusted_dealer_gen(
215 &self,
216 peers: &[PeerId],
217 params: &ConfigGenModuleParams,
218 ) -> BTreeMap<PeerId, ServerModuleConfig>;
219
220 async fn distributed_gen(
221 &self,
222 peers: &(dyn PeerHandleOps + Send + Sync),
223 params: &ConfigGenModuleParams,
224 ) -> anyhow::Result<ServerModuleConfig>;
225
226 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
227
228 fn get_client_config(
230 &self,
231 config: &ServerModuleConsensusConfig,
232 ) -> anyhow::Result<<<Self as ModuleInit>::Common as CommonModuleInit>::ClientConfig>;
233
234 fn get_database_migrations(
238 &self,
239 ) -> BTreeMap<DatabaseVersion, ServerModuleDbMigrationFn<Self::Module>> {
240 BTreeMap::new()
241 }
242
243 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>> {
253 None
254 }
255}
256
257#[apply(async_trait_maybe_send!)]
258impl<T> IServerModuleInit for T
259where
260 T: ServerModuleInit + 'static + Sync,
261{
262 fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
263 self
264 }
265
266 fn supported_api_versions(&self) -> SupportedModuleApiVersions {
267 <Self as ServerModuleInit>::supported_api_versions(self)
268 }
269
270 async fn init(
271 &self,
272 num_peers: NumPeers,
273 cfg: ServerModuleConfig,
274 db: Database,
275 task_group: &TaskGroup,
276 our_peer_id: PeerId,
277 module_api: DynModuleApi,
278 shared: SharedAnymap,
279 ) -> anyhow::Result<DynServerModule> {
280 let module = <Self as ServerModuleInit>::init(
281 self,
282 &ServerModuleInitArgs {
283 num_peers,
284 cfg,
285 db,
286 task_group: task_group.clone(),
287 our_peer_id,
288 _marker: PhantomData,
289 module_api,
290 shared,
291 },
292 )
293 .await?;
294
295 Ok(DynServerModule::from(module))
296 }
297
298 fn validate_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<()> {
299 <Self as ServerModuleInit>::parse_params(self, params)?;
300 Ok(())
301 }
302
303 fn trusted_dealer_gen(
304 &self,
305 peers: &[PeerId],
306 params: &ConfigGenModuleParams,
307 ) -> BTreeMap<PeerId, ServerModuleConfig> {
308 <Self as ServerModuleInit>::trusted_dealer_gen(self, peers, params)
309 }
310
311 async fn distributed_gen(
312 &self,
313 peers: &(dyn PeerHandleOps + Send + Sync),
314 params: &ConfigGenModuleParams,
315 ) -> anyhow::Result<ServerModuleConfig> {
316 <Self as ServerModuleInit>::distributed_gen(self, peers, params).await
317 }
318
319 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()> {
320 <Self as ServerModuleInit>::validate_config(self, identity, config)
321 }
322
323 fn get_client_config(
324 &self,
325 module_instance_id: ModuleInstanceId,
326 config: &ServerModuleConsensusConfig,
327 ) -> anyhow::Result<ClientModuleConfig> {
328 ClientModuleConfig::from_typed(
329 module_instance_id,
330 <Self as ServerModuleInit>::kind(),
331 config.version,
332 <Self as ServerModuleInit>::get_client_config(self, config)?,
333 )
334 }
335 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, DynServerDbMigrationFn> {
336 <Self as ServerModuleInit>::get_database_migrations(self)
337 .into_iter()
338 .map(|(k, f)| {
339 (k, {
340 let closure: DynServerDbMigrationFn =
341 Box::new(move |ctx: ServerDbMigrationFnContext<'_>| {
342 let map = ctx.map(ServerModuleDbMigrationContext::new);
343 Box::pin(f(map))
344 });
345 closure
346 })
347 })
348 .collect()
349 }
350
351 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>> {
352 <Self as ServerModuleInit>::used_db_prefixes(self)
353 }
354}
355
356dyn_newtype_define!(
357 #[derive(Clone)]
358 pub DynServerModuleInit(Arc<IServerModuleInit>)
359);
360
361impl AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static> for DynServerModuleInit {
362 fn as_ref(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
363 self.inner.as_common()
364 }
365}
366
367pub type ServerModuleInitRegistry = ModuleInitRegistry<DynServerModuleInit>;
368
369pub trait ServerModuleInitRegistryExt {
370 fn to_common(&self) -> CommonModuleInitRegistry;
371}
372
373impl ServerModuleInitRegistryExt for ServerModuleInitRegistry {
374 fn to_common(&self) -> CommonModuleInitRegistry {
375 self.iter().map(|(_k, v)| v.to_dyn_common()).collect()
376 }
377}