fedimint_empty_server/
lib.rs

1#![deny(clippy::pedantic)]
2#![allow(clippy::module_name_repetitions)]
3#![allow(clippy::must_use_candidate)]
4
5use std::collections::BTreeMap;
6
7use anyhow::bail;
8use async_trait::async_trait;
9use fedimint_core::config::{
10    ConfigGenModuleParams, ServerModuleConfig, ServerModuleConsensusConfig,
11    TypedServerModuleConfig, TypedServerModuleConsensusConfig,
12};
13use fedimint_core::core::ModuleInstanceId;
14use fedimint_core::db::{DatabaseTransaction, DatabaseVersion};
15use fedimint_core::module::audit::Audit;
16use fedimint_core::module::{
17    ApiEndpoint, CORE_CONSENSUS_VERSION, CoreConsensusVersion, InputMeta, ModuleConsensusVersion,
18    ModuleInit, SupportedModuleApiVersions, TransactionItemAmount,
19};
20use fedimint_core::{InPoint, OutPoint, PeerId, push_db_pair_items};
21use fedimint_empty_common::config::{
22    EmptyClientConfig, EmptyConfig, EmptyConfigConsensus, EmptyConfigPrivate, EmptyGenParams,
23};
24use fedimint_empty_common::{
25    EmptyCommonInit, EmptyConsensusItem, EmptyInput, EmptyInputError, EmptyModuleTypes,
26    EmptyOutput, EmptyOutputError, EmptyOutputOutcome, MODULE_CONSENSUS_VERSION,
27};
28use fedimint_server_core::config::PeerHandleOps;
29use fedimint_server_core::migration::ServerModuleDbMigrationFn;
30use fedimint_server_core::{ServerModule, ServerModuleInit, ServerModuleInitArgs};
31use futures::StreamExt;
32use strum::IntoEnumIterator;
33
34use crate::db::{DbKeyPrefix, EmptyExampleKeyPrefix};
35
36pub mod db;
37
38/// Generates the module
39#[derive(Debug, Clone)]
40pub struct EmptyInit;
41
42// TODO: Boilerplate-code
43impl ModuleInit for EmptyInit {
44    type Common = EmptyCommonInit;
45
46    /// Dumps all database items for debugging
47    async fn dump_database(
48        &self,
49        dbtx: &mut DatabaseTransaction<'_>,
50        prefix_names: Vec<String>,
51    ) -> Box<dyn Iterator<Item = (String, Box<dyn erased_serde::Serialize + Send>)> + '_> {
52        // TODO: Boilerplate-code
53        let mut items: BTreeMap<String, Box<dyn erased_serde::Serialize + Send>> = BTreeMap::new();
54        let filtered_prefixes = DbKeyPrefix::iter().filter(|f| {
55            prefix_names.is_empty() || prefix_names.contains(&f.to_string().to_lowercase())
56        });
57
58        for table in filtered_prefixes {
59            match table {
60                DbKeyPrefix::Example => {
61                    push_db_pair_items!(
62                        dbtx,
63                        EmptyExampleKeyPrefix,
64                        EmptyExampleKey,
65                        Vec<u8>,
66                        items,
67                        "Empty Example"
68                    );
69                }
70            }
71        }
72
73        Box::new(items.into_iter())
74    }
75}
76
77/// Implementation of server module non-consensus functions
78#[async_trait]
79impl ServerModuleInit for EmptyInit {
80    type Module = Empty;
81    type Params = EmptyGenParams;
82
83    /// Returns the version of this module
84    fn versions(&self, _core: CoreConsensusVersion) -> &[ModuleConsensusVersion] {
85        &[MODULE_CONSENSUS_VERSION]
86    }
87
88    fn supported_api_versions(&self) -> SupportedModuleApiVersions {
89        SupportedModuleApiVersions::from_raw(
90            (CORE_CONSENSUS_VERSION.major, CORE_CONSENSUS_VERSION.minor),
91            (
92                MODULE_CONSENSUS_VERSION.major,
93                MODULE_CONSENSUS_VERSION.minor,
94            ),
95            &[(0, 0)],
96        )
97    }
98
99    /// Initialize the module
100    async fn init(&self, args: &ServerModuleInitArgs<Self>) -> anyhow::Result<Self::Module> {
101        Ok(Empty::new(args.cfg().to_typed()?))
102    }
103
104    /// Generates configs for all peers in a trusted manner for testing
105    fn trusted_dealer_gen(
106        &self,
107        peers: &[PeerId],
108        params: &ConfigGenModuleParams,
109    ) -> BTreeMap<PeerId, ServerModuleConfig> {
110        let _params = self.parse_params(params).unwrap();
111        // Generate a config for each peer
112        peers
113            .iter()
114            .map(|&peer| {
115                let config = EmptyConfig {
116                    private: EmptyConfigPrivate,
117                    consensus: EmptyConfigConsensus {},
118                };
119                (peer, config.to_erased())
120            })
121            .collect()
122    }
123
124    /// Generates configs for all peers in an untrusted manner
125    async fn distributed_gen(
126        &self,
127        _peers: &(dyn PeerHandleOps + Send + Sync),
128        params: &ConfigGenModuleParams,
129    ) -> anyhow::Result<ServerModuleConfig> {
130        let _params = self.parse_params(params).unwrap();
131
132        Ok(EmptyConfig {
133            private: EmptyConfigPrivate,
134            consensus: EmptyConfigConsensus {},
135        }
136        .to_erased())
137    }
138
139    /// Converts the consensus config into the client config
140    fn get_client_config(
141        &self,
142        config: &ServerModuleConsensusConfig,
143    ) -> anyhow::Result<EmptyClientConfig> {
144        let _config = EmptyConfigConsensus::from_erased(config)?;
145        Ok(EmptyClientConfig {})
146    }
147
148    fn validate_config(
149        &self,
150        _identity: &PeerId,
151        _config: ServerModuleConfig,
152    ) -> anyhow::Result<()> {
153        Ok(())
154    }
155
156    /// DB migrations to move from old to newer versions
157    fn get_database_migrations(
158        &self,
159    ) -> BTreeMap<DatabaseVersion, ServerModuleDbMigrationFn<Empty>> {
160        BTreeMap::new()
161    }
162}
163
164/// Empty module
165#[derive(Debug)]
166pub struct Empty {
167    pub cfg: EmptyConfig,
168}
169
170/// Implementation of consensus for the server module
171#[async_trait]
172impl ServerModule for Empty {
173    /// Define the consensus types
174    type Common = EmptyModuleTypes;
175    type Init = EmptyInit;
176
177    async fn consensus_proposal(
178        &self,
179        _dbtx: &mut DatabaseTransaction<'_>,
180    ) -> Vec<EmptyConsensusItem> {
181        Vec::new()
182    }
183
184    async fn process_consensus_item<'a, 'b>(
185        &'a self,
186        _dbtx: &mut DatabaseTransaction<'b>,
187        _consensus_item: EmptyConsensusItem,
188        _peer_id: PeerId,
189    ) -> anyhow::Result<()> {
190        // WARNING: `process_consensus_item` should return an `Err` for items that do
191        // not change any internal consensus state. Failure to do so, will result in an
192        // (potentially significantly) increased consensus history size.
193        // If you are using this code as a template,
194        // make sure to read the [`ServerModule::process_consensus_item`] documentation,
195        bail!("The empty module does not use consensus items");
196    }
197
198    async fn process_input<'a, 'b, 'c>(
199        &'a self,
200        _dbtx: &mut DatabaseTransaction<'c>,
201        _input: &'b EmptyInput,
202        _in_point: InPoint,
203    ) -> Result<InputMeta, EmptyInputError> {
204        Err(EmptyInputError::NotSupported)
205    }
206
207    async fn process_output<'a, 'b>(
208        &'a self,
209        _dbtx: &mut DatabaseTransaction<'b>,
210        _output: &'a EmptyOutput,
211        _out_point: OutPoint,
212    ) -> Result<TransactionItemAmount, EmptyOutputError> {
213        Err(EmptyOutputError::NotSupported)
214    }
215
216    async fn output_status(
217        &self,
218        _dbtx: &mut DatabaseTransaction<'_>,
219        _out_point: OutPoint,
220    ) -> Option<EmptyOutputOutcome> {
221        None
222    }
223
224    async fn audit(
225        &self,
226        _dbtx: &mut DatabaseTransaction<'_>,
227        _audit: &mut Audit,
228        _module_instance_id: ModuleInstanceId,
229    ) {
230    }
231
232    fn api_endpoints(&self) -> Vec<ApiEndpoint<Self>> {
233        Vec::new()
234    }
235}
236
237impl Empty {
238    /// Create new module instance
239    pub fn new(cfg: EmptyConfig) -> Empty {
240        Empty { cfg }
241    }
242}