fedimint_server_core/
init.rs

1// TODO: remove and fix nits
2#![allow(clippy::pedantic)]
3
4use std::collections::BTreeMap;
5use std::marker;
6use std::marker::PhantomData;
7use std::sync::Arc;
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::{CoreMigrationFn, Database, DatabaseVersion};
16use fedimint_core::module::{
17    CommonModuleInit, CoreConsensusVersion, IDynCommonModuleInit, ModuleConsensusVersion,
18    ModuleInit, PeerHandle, SupportedModuleApiVersions,
19};
20use fedimint_core::task::TaskGroup;
21use fedimint_core::{apply, async_trait_maybe_send, dyn_newtype_define, NumPeers, PeerId};
22
23use crate::DynServerModule;
24
25/// Interface for Module Generation
26///
27/// This trait contains the methods responsible for the module's
28/// - initialization
29/// - config generation
30/// - config validation
31///
32/// Once the module configuration is ready, the module can be instantiated via
33/// `[Self::init]`.
34#[apply(async_trait_maybe_send!)]
35pub trait IServerModuleInit: IDynCommonModuleInit {
36    fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static);
37
38    fn supported_api_versions(&self) -> SupportedModuleApiVersions;
39
40    /// Initialize the [`DynServerModule`] instance from its config
41    async fn init(
42        &self,
43        peer_num: NumPeers,
44        cfg: ServerModuleConfig,
45        db: Database,
46        task_group: &TaskGroup,
47        our_peer_id: PeerId,
48        module_api: DynModuleApi,
49    ) -> anyhow::Result<DynServerModule>;
50
51    fn validate_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<()>;
52
53    fn trusted_dealer_gen(
54        &self,
55        peers: &[PeerId],
56        params: &ConfigGenModuleParams,
57    ) -> BTreeMap<PeerId, ServerModuleConfig>;
58
59    async fn distributed_gen(
60        &self,
61        peers: &PeerHandle,
62        params: &ConfigGenModuleParams,
63    ) -> anyhow::Result<ServerModuleConfig>;
64
65    fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
66
67    fn get_client_config(
68        &self,
69        module_instance_id: ModuleInstanceId,
70        config: &ServerModuleConsensusConfig,
71    ) -> anyhow::Result<ClientModuleConfig>;
72
73    /// Retrieves the migrations map from the server module to be applied to the
74    /// database before the module is initialized. The migrations map is
75    /// indexed on the from version.
76    fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, CoreMigrationFn>;
77}
78
79pub struct ServerModuleInitArgs<S>
80where
81    S: ServerModuleInit,
82{
83    cfg: ServerModuleConfig,
84    db: Database,
85    task_group: TaskGroup,
86    our_peer_id: PeerId,
87    num_peers: NumPeers,
88    module_api: DynModuleApi,
89    // ClientModuleInitArgs needs a bound because sometimes we need
90    // to pass associated-types data, so let's just put it here right away
91    _marker: marker::PhantomData<S>,
92}
93
94impl<S> ServerModuleInitArgs<S>
95where
96    S: ServerModuleInit,
97{
98    pub fn cfg(&self) -> &ServerModuleConfig {
99        &self.cfg
100    }
101
102    pub fn db(&self) -> &Database {
103        &self.db
104    }
105
106    pub fn num_peers(&self) -> NumPeers {
107        self.num_peers
108    }
109
110    pub fn task_group(&self) -> &TaskGroup {
111        &self.task_group
112    }
113
114    pub fn our_peer_id(&self) -> PeerId {
115        self.our_peer_id
116    }
117
118    pub fn module_api(&self) -> &DynModuleApi {
119        &self.module_api
120    }
121}
122/// Module Generation trait with associated types
123///
124/// Needs to be implemented by module generation type
125///
126/// For examples, take a look at one of the `MintConfigGenerator`,
127/// `WalletConfigGenerator`, or `LightningConfigGenerator` structs.
128#[apply(async_trait_maybe_send!)]
129pub trait ServerModuleInit: ModuleInit + Sized {
130    type Params: ModuleInitParams;
131
132    /// Version of the module consensus supported by this implementation given a
133    /// certain [`CoreConsensusVersion`].
134    ///
135    /// Refer to [`ModuleConsensusVersion`] for more information about
136    /// versioning.
137    ///
138    /// One module implementation ([`ServerModuleInit`] of a given
139    /// [`ModuleKind`]) can potentially implement multiple versions of the
140    /// consensus, and depending on the config module instance config,
141    /// instantiate the desired one. This method should expose all the
142    /// available versions, purely for information, setup UI and sanity
143    /// checking purposes.
144    fn versions(&self, core: CoreConsensusVersion) -> &[ModuleConsensusVersion];
145
146    fn supported_api_versions(&self) -> SupportedModuleApiVersions;
147
148    fn kind() -> ModuleKind {
149        <Self as ModuleInit>::Common::KIND
150    }
151
152    /// Initialize the [`DynServerModule`] instance from its config
153    async fn init(&self, args: &ServerModuleInitArgs<Self>) -> anyhow::Result<DynServerModule>;
154
155    fn parse_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<Self::Params> {
156        params.to_typed::<Self::Params>()
157    }
158
159    fn trusted_dealer_gen(
160        &self,
161        peers: &[PeerId],
162        params: &ConfigGenModuleParams,
163    ) -> BTreeMap<PeerId, ServerModuleConfig>;
164
165    async fn distributed_gen(
166        &self,
167        peer: &PeerHandle,
168        params: &ConfigGenModuleParams,
169    ) -> anyhow::Result<ServerModuleConfig>;
170
171    fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
172
173    /// Converts the consensus config into the client config
174    fn get_client_config(
175        &self,
176        config: &ServerModuleConsensusConfig,
177    ) -> anyhow::Result<<<Self as ModuleInit>::Common as CommonModuleInit>::ClientConfig>;
178
179    /// Retrieves the migrations map from the server module to be applied to the
180    /// database before the module is initialized. The migrations map is
181    /// indexed on the from version.
182    fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, CoreMigrationFn> {
183        BTreeMap::new()
184    }
185}
186
187#[apply(async_trait_maybe_send!)]
188impl<T> IServerModuleInit for T
189where
190    T: ServerModuleInit + 'static + Sync,
191{
192    fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
193        self
194    }
195
196    fn supported_api_versions(&self) -> SupportedModuleApiVersions {
197        <Self as ServerModuleInit>::supported_api_versions(self)
198    }
199
200    async fn init(
201        &self,
202        num_peers: NumPeers,
203        cfg: ServerModuleConfig,
204        db: Database,
205        task_group: &TaskGroup,
206        our_peer_id: PeerId,
207        module_api: DynModuleApi,
208    ) -> anyhow::Result<DynServerModule> {
209        <Self as ServerModuleInit>::init(
210            self,
211            &ServerModuleInitArgs {
212                num_peers,
213                cfg,
214                db,
215                task_group: task_group.clone(),
216                our_peer_id,
217                _marker: PhantomData,
218                module_api,
219            },
220        )
221        .await
222    }
223
224    fn validate_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<()> {
225        <Self as ServerModuleInit>::parse_params(self, params)?;
226        Ok(())
227    }
228
229    fn trusted_dealer_gen(
230        &self,
231        peers: &[PeerId],
232        params: &ConfigGenModuleParams,
233    ) -> BTreeMap<PeerId, ServerModuleConfig> {
234        <Self as ServerModuleInit>::trusted_dealer_gen(self, peers, params)
235    }
236
237    async fn distributed_gen(
238        &self,
239        peers: &PeerHandle,
240        params: &ConfigGenModuleParams,
241    ) -> anyhow::Result<ServerModuleConfig> {
242        <Self as ServerModuleInit>::distributed_gen(self, peers, params).await
243    }
244
245    fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()> {
246        <Self as ServerModuleInit>::validate_config(self, identity, config)
247    }
248
249    fn get_client_config(
250        &self,
251        module_instance_id: ModuleInstanceId,
252        config: &ServerModuleConsensusConfig,
253    ) -> anyhow::Result<ClientModuleConfig> {
254        ClientModuleConfig::from_typed(
255            module_instance_id,
256            <Self as ServerModuleInit>::kind(),
257            config.version,
258            <Self as ServerModuleInit>::get_client_config(self, config)?,
259        )
260    }
261
262    fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, CoreMigrationFn> {
263        <Self as ServerModuleInit>::get_database_migrations(self)
264    }
265}
266
267dyn_newtype_define!(
268    #[derive(Clone)]
269    pub DynServerModuleInit(Arc<IServerModuleInit>)
270);
271
272impl AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static> for DynServerModuleInit {
273    fn as_ref(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
274        self.inner.as_common()
275    }
276}
277
278pub type ServerModuleInitRegistry = ModuleInitRegistry<DynServerModuleInit>;
279
280pub trait ServerModuleInitRegistryExt {
281    fn to_common(&self) -> CommonModuleInitRegistry;
282}
283
284impl ServerModuleInitRegistryExt for ServerModuleInitRegistry {
285    fn to_common(&self) -> CommonModuleInitRegistry {
286        self.iter().map(|(_k, v)| v.to_dyn_common()).collect()
287    }
288}