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};
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    fn supported_api_versions(&self) -> SupportedModuleApiVersions {
91        SupportedModuleApiVersions::from_raw(
92            (CORE_CONSENSUS_VERSION.major, CORE_CONSENSUS_VERSION.minor),
93            (
94                MODULE_CONSENSUS_VERSION.major,
95                MODULE_CONSENSUS_VERSION.minor,
96            ),
97            &[(0, 0)],
98        )
99    }
100
101    /// Initialize the module
102    async fn init(&self, args: &ServerModuleInitArgs<Self>) -> anyhow::Result<Self::Module> {
103        Ok(Empty::new(args.cfg().to_typed()?))
104    }
105
106    /// Generates configs for all peers in a trusted manner for testing
107    fn trusted_dealer_gen(
108        &self,
109        peers: &[PeerId],
110        _args: &ConfigGenModuleArgs,
111    ) -> BTreeMap<PeerId, ServerModuleConfig> {
112        // Generate a config for each peer
113        peers
114            .iter()
115            .map(|&peer| {
116                let config = EmptyConfig {
117                    private: EmptyConfigPrivate,
118                    consensus: EmptyConfigConsensus {},
119                };
120                (peer, config.to_erased())
121            })
122            .collect()
123    }
124
125    /// Generates configs for all peers in an untrusted manner
126    async fn distributed_gen(
127        &self,
128        _peers: &(dyn PeerHandleOps + Send + Sync),
129        _args: &ConfigGenModuleArgs,
130    ) -> anyhow::Result<ServerModuleConfig> {
131        Ok(EmptyConfig {
132            private: EmptyConfigPrivate,
133            consensus: EmptyConfigConsensus {},
134        }
135        .to_erased())
136    }
137
138    /// Converts the consensus config into the client config
139    fn get_client_config(
140        &self,
141        config: &ServerModuleConsensusConfig,
142    ) -> anyhow::Result<EmptyClientConfig> {
143        let _config = EmptyConfigConsensus::from_erased(config)?;
144        Ok(EmptyClientConfig {})
145    }
146
147    fn validate_config(
148        &self,
149        _identity: &PeerId,
150        _config: ServerModuleConfig,
151    ) -> anyhow::Result<()> {
152        Ok(())
153    }
154
155    /// DB migrations to move from old to newer versions
156    fn get_database_migrations(
157        &self,
158    ) -> BTreeMap<DatabaseVersion, ServerModuleDbMigrationFn<Empty>> {
159        BTreeMap::new()
160    }
161}
162
163/// Empty module
164#[derive(Debug)]
165pub struct Empty {
166    pub cfg: EmptyConfig,
167}
168
169/// Implementation of consensus for the server module
170#[async_trait]
171impl ServerModule for Empty {
172    /// Define the consensus types
173    type Common = EmptyModuleTypes;
174    type Init = EmptyInit;
175
176    async fn consensus_proposal(
177        &self,
178        _dbtx: &mut DatabaseTransaction<'_>,
179    ) -> Vec<EmptyConsensusItem> {
180        Vec::new()
181    }
182
183    async fn process_consensus_item<'a, 'b>(
184        &'a self,
185        _dbtx: &mut DatabaseTransaction<'b>,
186        _consensus_item: EmptyConsensusItem,
187        _peer_id: PeerId,
188    ) -> anyhow::Result<()> {
189        // WARNING: `process_consensus_item` should return an `Err` for items that do
190        // not change any internal consensus state. Failure to do so, will result in an
191        // (potentially significantly) increased consensus history size.
192        // If you are using this code as a template,
193        // make sure to read the [`ServerModule::process_consensus_item`] documentation,
194        bail!("The empty module does not use consensus items");
195    }
196
197    async fn process_input<'a, 'b, 'c>(
198        &'a self,
199        _dbtx: &mut DatabaseTransaction<'c>,
200        _input: &'b EmptyInput,
201        _in_point: InPoint,
202    ) -> Result<InputMeta, EmptyInputError> {
203        Err(EmptyInputError::NotSupported)
204    }
205
206    async fn process_output<'a, 'b>(
207        &'a self,
208        _dbtx: &mut DatabaseTransaction<'b>,
209        _output: &'a EmptyOutput,
210        _out_point: OutPoint,
211    ) -> Result<TransactionItemAmounts, EmptyOutputError> {
212        Err(EmptyOutputError::NotSupported)
213    }
214
215    async fn output_status(
216        &self,
217        _dbtx: &mut DatabaseTransaction<'_>,
218        _out_point: OutPoint,
219    ) -> Option<EmptyOutputOutcome> {
220        None
221    }
222
223    async fn audit(
224        &self,
225        _dbtx: &mut DatabaseTransaction<'_>,
226        _audit: &mut Audit,
227        _module_instance_id: ModuleInstanceId,
228    ) {
229    }
230
231    fn api_endpoints(&self) -> Vec<ApiEndpoint<Self>> {
232        Vec::new()
233    }
234}
235
236impl Empty {
237    /// Create new module instance
238    pub fn new(cfg: EmptyConfig) -> Empty {
239        Empty { cfg }
240    }
241}