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