Skip to main content

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