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