1#![deny(clippy::pedantic)]
2#![allow(clippy::cast_possible_wrap)]
3#![allow(clippy::missing_errors_doc)]
4#![allow(clippy::module_name_repetitions)]
5#![allow(clippy::must_use_candidate)]
6
7use std::collections::BTreeMap;
8
9use async_trait::async_trait;
10use fedimint_core::config::{
11 ServerModuleConfig, ServerModuleConsensusConfig, TypedServerModuleConfig,
12};
13use fedimint_core::core::ModuleInstanceId;
14use fedimint_core::db::{DatabaseTransaction, DatabaseVersion, IDatabaseTransactionOpsCoreTyped};
15use fedimint_core::module::audit::Audit;
16use fedimint_core::module::{
17 Amounts, ApiEndpoint, CoreConsensusVersion, InputMeta, ModuleConsensusVersion, ModuleInit,
18 TransactionItemAmounts,
19};
20use fedimint_core::{Amount, InPoint, OutPoint, PeerId, push_db_pair_items};
21pub use fedimint_dummy_common as common;
22use fedimint_dummy_common::config::{
23 DummyClientConfig, DummyConfig, DummyConfigConsensus, DummyConfigPrivate,
24};
25use fedimint_dummy_common::{
26 DummyCommonInit, DummyConsensusItem, DummyInput, DummyInputError, DummyModuleTypes,
27 DummyOutput, DummyOutputError, DummyOutputOutcome, 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::{
38 DbKeyPrefix, DummyInputAuditKey, DummyInputAuditPrefix, DummyOutputAuditKey,
39 DummyOutputAuditPrefix,
40};
41
42pub mod db;
43
44#[derive(Debug, Clone)]
46pub struct DummyInit;
47
48impl ModuleInit for DummyInit {
49 type Common = DummyCommonInit;
50
51 async fn dump_database(
53 &self,
54 dbtx: &mut DatabaseTransaction<'_>,
55 prefix_names: Vec<String>,
56 ) -> Box<dyn Iterator<Item = (String, Box<dyn erased_serde::Serialize + Send>)> + '_> {
57 let mut items: BTreeMap<String, Box<dyn erased_serde::Serialize + Send>> = BTreeMap::new();
58 let filtered_prefixes = DbKeyPrefix::iter().filter(|f| {
59 prefix_names.is_empty() || prefix_names.contains(&f.to_string().to_lowercase())
60 });
61
62 for table in filtered_prefixes {
63 match table {
64 DbKeyPrefix::InputAudit => {
65 push_db_pair_items!(
66 dbtx,
67 DummyInputAuditPrefix,
68 DummyInputAuditKey,
69 Amount,
70 items,
71 "Dummy Input Audit"
72 );
73 }
74 DbKeyPrefix::OutputAudit => {
75 push_db_pair_items!(
76 dbtx,
77 DummyOutputAuditPrefix,
78 DummyOutputAuditKey,
79 Amount,
80 items,
81 "Dummy Output Audit"
82 );
83 }
84 }
85 }
86
87 Box::new(items.into_iter())
88 }
89}
90
91#[async_trait]
93impl ServerModuleInit for DummyInit {
94 type Module = Dummy;
95
96 fn versions(&self, _core: CoreConsensusVersion) -> &[ModuleConsensusVersion] {
98 &[MODULE_CONSENSUS_VERSION]
99 }
100
101 async fn init(&self, args: &ServerModuleInitArgs<Self>) -> anyhow::Result<Self::Module> {
103 Ok(Dummy::new(args.cfg().to_typed()?))
104 }
105
106 fn trusted_dealer_gen(
108 &self,
109 peers: &[PeerId],
110 _args: &ConfigGenModuleArgs,
111 ) -> BTreeMap<PeerId, ServerModuleConfig> {
112 peers
114 .iter()
115 .map(|&peer| {
116 let config = DummyConfig {
117 private: DummyConfigPrivate,
118 consensus: DummyConfigConsensus,
119 };
120 (peer, config.to_erased())
121 })
122 .collect()
123 }
124
125 async fn distributed_gen(
127 &self,
128 _peers: &(dyn PeerHandleOps + Send + Sync),
129 _args: &ConfigGenModuleArgs,
130 ) -> anyhow::Result<ServerModuleConfig> {
131 Ok(DummyConfig {
132 private: DummyConfigPrivate,
133 consensus: DummyConfigConsensus,
134 }
135 .to_erased())
136 }
137
138 fn get_client_config(
140 &self,
141 _config: &ServerModuleConsensusConfig,
142 ) -> anyhow::Result<DummyClientConfig> {
143 Ok(DummyClientConfig)
144 }
145
146 fn validate_config(
147 &self,
148 _identity: &PeerId,
149 _config: ServerModuleConfig,
150 ) -> anyhow::Result<()> {
151 Ok(())
152 }
153
154 fn get_database_migrations(
156 &self,
157 ) -> BTreeMap<DatabaseVersion, ServerModuleDbMigrationFn<Dummy>> {
158 BTreeMap::new()
159 }
160}
161
162#[derive(Debug)]
164pub struct Dummy {
165 pub cfg: DummyConfig,
166}
167
168#[async_trait]
170impl ServerModule for Dummy {
171 type Common = DummyModuleTypes;
173 type Init = DummyInit;
174
175 async fn consensus_proposal(
176 &self,
177 _dbtx: &mut DatabaseTransaction<'_>,
178 ) -> Vec<DummyConsensusItem> {
179 Vec::new()
180 }
181
182 async fn process_consensus_item<'a, 'b>(
183 &'a self,
184 _dbtx: &mut DatabaseTransaction<'b>,
185 _consensus_item: DummyConsensusItem,
186 _peer_id: PeerId,
187 ) -> anyhow::Result<()> {
188 anyhow::bail!("The dummy 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 DummyInput,
200 in_point: InPoint,
201 ) -> Result<InputMeta, DummyInputError> {
202 dbtx.insert_entry(&DummyInputAuditKey(in_point), &input.amount)
203 .await;
204
205 Ok(InputMeta {
206 amount: TransactionItemAmounts {
207 amounts: Amounts::new_bitcoin(input.amount),
208 fees: Amounts::ZERO,
209 },
210 pub_key: input.pub_key,
211 })
212 }
213
214 async fn process_output<'a, 'b>(
215 &'a self,
216 dbtx: &mut DatabaseTransaction<'b>,
217 output: &'a DummyOutput,
218 out_point: OutPoint,
219 ) -> Result<TransactionItemAmounts, DummyOutputError> {
220 dbtx.insert_entry(&DummyOutputAuditKey(out_point), &output.amount)
221 .await;
222
223 Ok(TransactionItemAmounts {
224 amounts: Amounts::new_bitcoin(output.amount),
225 fees: Amounts::ZERO,
226 })
227 }
228
229 async fn output_status(
230 &self,
231 _dbtx: &mut DatabaseTransaction<'_>,
232 _out_point: OutPoint,
233 ) -> Option<DummyOutputOutcome> {
234 None
235 }
236
237 async fn audit(
238 &self,
239 dbtx: &mut DatabaseTransaction<'_>,
240 audit: &mut Audit,
241 module_instance_id: ModuleInstanceId,
242 ) {
243 audit
245 .add_items(dbtx, module_instance_id, &DummyInputAuditPrefix, |_, v| {
246 v.msats as i64
247 })
248 .await;
249
250 audit
252 .add_items(dbtx, module_instance_id, &DummyOutputAuditPrefix, |_, v| {
253 -(v.msats as i64)
254 })
255 .await;
256 }
257
258 fn api_endpoints(&self) -> Vec<ApiEndpoint<Self>> {
259 Vec::new()
260 }
261}
262
263impl Dummy {
264 pub fn new(cfg: DummyConfig) -> Dummy {
266 Dummy { cfg }
267 }
268}