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::bitcoin_rpc::ServerBitcoinRpcMonitor;
24use crate::config::PeerHandleOps;
25use crate::migration::{
26 DynServerDbMigrationFn, ServerDbMigrationFnContext, ServerModuleDbMigrationContext,
27 ServerModuleDbMigrationFn,
28};
29use crate::{DynServerModule, ServerModule};
30
31#[apply(async_trait_maybe_send!)]
41pub trait IServerModuleInit: IDynCommonModuleInit {
42 fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static);
43
44 fn supported_api_versions(&self) -> SupportedModuleApiVersions;
45
46 #[allow(clippy::too_many_arguments)]
48 async fn init(
49 &self,
50 peer_num: NumPeers,
51 cfg: ServerModuleConfig,
52 db: Database,
53 task_group: &TaskGroup,
54 our_peer_id: PeerId,
55 module_api: DynModuleApi,
56 server_bitcoin_rpc_monitor: ServerBitcoinRpcMonitor,
57 ) -> anyhow::Result<DynServerModule>;
58
59 fn validate_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<()>;
60
61 fn trusted_dealer_gen(
62 &self,
63 peers: &[PeerId],
64 params: &ConfigGenModuleParams,
65 disable_base_fees: bool,
66 ) -> BTreeMap<PeerId, ServerModuleConfig>;
67
68 async fn distributed_gen(
69 &self,
70 peers: &(dyn PeerHandleOps + Send + Sync),
71 params: &ConfigGenModuleParams,
72 disable_base_fees: bool,
73 ) -> anyhow::Result<ServerModuleConfig>;
74
75 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
76
77 fn get_client_config(
78 &self,
79 module_instance_id: ModuleInstanceId,
80 config: &ServerModuleConsensusConfig,
81 ) -> anyhow::Result<ClientModuleConfig>;
82
83 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, DynServerDbMigrationFn>;
87
88 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>>;
90}
91
92pub trait ServerModuleShared: any::Any + Send + Sync {
95 fn new(task_group: TaskGroup) -> Self;
96}
97
98pub struct ServerModuleInitArgs<S>
99where
100 S: ServerModuleInit,
101{
102 cfg: ServerModuleConfig,
103 db: Database,
104 task_group: TaskGroup,
105 our_peer_id: PeerId,
106 num_peers: NumPeers,
107 module_api: DynModuleApi,
108 server_bitcoin_rpc_monitor: ServerBitcoinRpcMonitor,
109 _marker: marker::PhantomData<S>,
112}
113
114impl<S> ServerModuleInitArgs<S>
115where
116 S: ServerModuleInit,
117{
118 pub fn cfg(&self) -> &ServerModuleConfig {
119 &self.cfg
120 }
121
122 pub fn db(&self) -> &Database {
123 &self.db
124 }
125
126 pub fn num_peers(&self) -> NumPeers {
127 self.num_peers
128 }
129
130 pub fn task_group(&self) -> &TaskGroup {
131 &self.task_group
132 }
133
134 pub fn our_peer_id(&self) -> PeerId {
135 self.our_peer_id
136 }
137
138 pub fn module_api(&self) -> &DynModuleApi {
139 &self.module_api
140 }
141
142 pub fn server_bitcoin_rpc_monitor(&self) -> ServerBitcoinRpcMonitor {
143 self.server_bitcoin_rpc_monitor.clone()
144 }
145}
146#[apply(async_trait_maybe_send!)]
153pub trait ServerModuleInit: ModuleInit + Sized {
154 type Module: ServerModule + Send + Sync;
155 type Params: ModuleInitParams;
156
157 fn versions(&self, core: CoreConsensusVersion) -> &[ModuleConsensusVersion];
170
171 fn supported_api_versions(&self) -> SupportedModuleApiVersions;
172
173 fn kind() -> ModuleKind {
174 <Self as ModuleInit>::Common::KIND
175 }
176
177 async fn init(&self, args: &ServerModuleInitArgs<Self>) -> anyhow::Result<Self::Module>;
179
180 fn parse_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<Self::Params> {
181 params.to_typed::<Self::Params>()
182 }
183
184 fn trusted_dealer_gen(
185 &self,
186 peers: &[PeerId],
187 params: &ConfigGenModuleParams,
188 disable_base_fees: bool,
189 ) -> BTreeMap<PeerId, ServerModuleConfig>;
190
191 async fn distributed_gen(
192 &self,
193 peers: &(dyn PeerHandleOps + Send + Sync),
194 params: &ConfigGenModuleParams,
195 disable_base_fees: bool,
196 ) -> anyhow::Result<ServerModuleConfig>;
197
198 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
199
200 fn get_client_config(
202 &self,
203 config: &ServerModuleConsensusConfig,
204 ) -> anyhow::Result<<<Self as ModuleInit>::Common as CommonModuleInit>::ClientConfig>;
205
206 fn get_database_migrations(
210 &self,
211 ) -> BTreeMap<DatabaseVersion, ServerModuleDbMigrationFn<Self::Module>> {
212 BTreeMap::new()
213 }
214
215 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>> {
225 None
226 }
227}
228
229#[apply(async_trait_maybe_send!)]
230impl<T> IServerModuleInit for T
231where
232 T: ServerModuleInit + 'static + Sync,
233{
234 fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
235 self
236 }
237
238 fn supported_api_versions(&self) -> SupportedModuleApiVersions {
239 <Self as ServerModuleInit>::supported_api_versions(self)
240 }
241
242 async fn init(
243 &self,
244 num_peers: NumPeers,
245 cfg: ServerModuleConfig,
246 db: Database,
247 task_group: &TaskGroup,
248 our_peer_id: PeerId,
249 module_api: DynModuleApi,
250 server_bitcoin_rpc_monitor: ServerBitcoinRpcMonitor,
251 ) -> anyhow::Result<DynServerModule> {
252 let module = <Self as ServerModuleInit>::init(
253 self,
254 &ServerModuleInitArgs {
255 num_peers,
256 cfg,
257 db,
258 task_group: task_group.clone(),
259 our_peer_id,
260 _marker: PhantomData,
261 module_api,
262 server_bitcoin_rpc_monitor,
263 },
264 )
265 .await?;
266
267 Ok(DynServerModule::from(module))
268 }
269
270 fn validate_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<()> {
271 <Self as ServerModuleInit>::parse_params(self, params)?;
272 Ok(())
273 }
274
275 fn trusted_dealer_gen(
276 &self,
277 peers: &[PeerId],
278 params: &ConfigGenModuleParams,
279 disable_base_fees: bool,
280 ) -> BTreeMap<PeerId, ServerModuleConfig> {
281 <Self as ServerModuleInit>::trusted_dealer_gen(self, peers, params, disable_base_fees)
282 }
283
284 async fn distributed_gen(
285 &self,
286 peers: &(dyn PeerHandleOps + Send + Sync),
287 params: &ConfigGenModuleParams,
288 disable_base_fees: bool,
289 ) -> anyhow::Result<ServerModuleConfig> {
290 <Self as ServerModuleInit>::distributed_gen(self, peers, params, disable_base_fees).await
291 }
292
293 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()> {
294 <Self as ServerModuleInit>::validate_config(self, identity, config)
295 }
296
297 fn get_client_config(
298 &self,
299 module_instance_id: ModuleInstanceId,
300 config: &ServerModuleConsensusConfig,
301 ) -> anyhow::Result<ClientModuleConfig> {
302 ClientModuleConfig::from_typed(
303 module_instance_id,
304 <Self as ServerModuleInit>::kind(),
305 config.version,
306 <Self as ServerModuleInit>::get_client_config(self, config)?,
307 )
308 }
309 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, DynServerDbMigrationFn> {
310 <Self as ServerModuleInit>::get_database_migrations(self)
311 .into_iter()
312 .map(|(k, f)| {
313 (k, {
314 let closure: DynServerDbMigrationFn =
315 Box::new(move |ctx: ServerDbMigrationFnContext<'_>| {
316 let map = ctx.map(ServerModuleDbMigrationContext::new);
317 Box::pin(f(map))
318 });
319 closure
320 })
321 })
322 .collect()
323 }
324
325 fn used_db_prefixes(&self) -> Option<BTreeSet<u8>> {
326 <Self as ServerModuleInit>::used_db_prefixes(self)
327 }
328}
329
330dyn_newtype_define!(
331 #[derive(Clone)]
332 pub DynServerModuleInit(Arc<IServerModuleInit>)
333);
334
335impl AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static> for DynServerModuleInit {
336 fn as_ref(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
337 self.inner.as_common()
338 }
339}
340
341pub type ServerModuleInitRegistry = ModuleInitRegistry<DynServerModuleInit>;
342
343pub trait ServerModuleInitRegistryExt {
344 fn to_common(&self) -> CommonModuleInitRegistry;
345}
346
347impl ServerModuleInitRegistryExt for ServerModuleInitRegistry {
348 fn to_common(&self) -> CommonModuleInitRegistry {
349 self.iter().map(|(_k, v)| v.to_dyn_common()).collect()
350 }
351}