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