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, CORE_CONSENSUS_VERSION, CoreConsensusVersion, InputMeta,
18 ModuleConsensusVersion, ModuleInit, SupportedModuleApiVersions, 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 fn supported_api_versions(&self) -> SupportedModuleApiVersions {
102 SupportedModuleApiVersions::from_raw(
103 (CORE_CONSENSUS_VERSION.major, CORE_CONSENSUS_VERSION.minor),
104 (
105 MODULE_CONSENSUS_VERSION.major,
106 MODULE_CONSENSUS_VERSION.minor,
107 ),
108 &[(0, 0)],
109 )
110 }
111
112 async fn init(&self, args: &ServerModuleInitArgs<Self>) -> anyhow::Result<Self::Module> {
114 Ok(Dummy::new(args.cfg().to_typed()?))
115 }
116
117 fn trusted_dealer_gen(
119 &self,
120 peers: &[PeerId],
121 _args: &ConfigGenModuleArgs,
122 ) -> BTreeMap<PeerId, ServerModuleConfig> {
123 peers
125 .iter()
126 .map(|&peer| {
127 let config = DummyConfig {
128 private: DummyConfigPrivate,
129 consensus: DummyConfigConsensus,
130 };
131 (peer, config.to_erased())
132 })
133 .collect()
134 }
135
136 async fn distributed_gen(
138 &self,
139 _peers: &(dyn PeerHandleOps + Send + Sync),
140 _args: &ConfigGenModuleArgs,
141 ) -> anyhow::Result<ServerModuleConfig> {
142 Ok(DummyConfig {
143 private: DummyConfigPrivate,
144 consensus: DummyConfigConsensus,
145 }
146 .to_erased())
147 }
148
149 fn get_client_config(
151 &self,
152 _config: &ServerModuleConsensusConfig,
153 ) -> anyhow::Result<DummyClientConfig> {
154 Ok(DummyClientConfig)
155 }
156
157 fn validate_config(
158 &self,
159 _identity: &PeerId,
160 _config: ServerModuleConfig,
161 ) -> anyhow::Result<()> {
162 Ok(())
163 }
164
165 fn get_database_migrations(
167 &self,
168 ) -> BTreeMap<DatabaseVersion, ServerModuleDbMigrationFn<Dummy>> {
169 BTreeMap::new()
170 }
171}
172
173#[derive(Debug)]
175pub struct Dummy {
176 pub cfg: DummyConfig,
177}
178
179#[async_trait]
181impl ServerModule for Dummy {
182 type Common = DummyModuleTypes;
184 type Init = DummyInit;
185
186 async fn consensus_proposal(
187 &self,
188 _dbtx: &mut DatabaseTransaction<'_>,
189 ) -> Vec<DummyConsensusItem> {
190 Vec::new()
191 }
192
193 async fn process_consensus_item<'a, 'b>(
194 &'a self,
195 _dbtx: &mut DatabaseTransaction<'b>,
196 _consensus_item: DummyConsensusItem,
197 _peer_id: PeerId,
198 ) -> anyhow::Result<()> {
199 anyhow::bail!("The dummy module does not use consensus items");
205 }
206
207 async fn process_input<'a, 'b, 'c>(
208 &'a self,
209 dbtx: &mut DatabaseTransaction<'c>,
210 input: &'b DummyInput,
211 in_point: InPoint,
212 ) -> Result<InputMeta, DummyInputError> {
213 dbtx.insert_entry(&DummyInputAuditKey(in_point), &input.amount)
214 .await;
215
216 Ok(InputMeta {
217 amount: TransactionItemAmounts {
218 amounts: Amounts::new_bitcoin(input.amount),
219 fees: Amounts::ZERO,
220 },
221 pub_key: input.pub_key,
222 })
223 }
224
225 async fn process_output<'a, 'b>(
226 &'a self,
227 dbtx: &mut DatabaseTransaction<'b>,
228 output: &'a DummyOutput,
229 out_point: OutPoint,
230 ) -> Result<TransactionItemAmounts, DummyOutputError> {
231 dbtx.insert_entry(&DummyOutputAuditKey(out_point), &output.amount)
232 .await;
233
234 Ok(TransactionItemAmounts {
235 amounts: Amounts::new_bitcoin(output.amount),
236 fees: Amounts::ZERO,
237 })
238 }
239
240 async fn output_status(
241 &self,
242 _dbtx: &mut DatabaseTransaction<'_>,
243 _out_point: OutPoint,
244 ) -> Option<DummyOutputOutcome> {
245 None
246 }
247
248 async fn audit(
249 &self,
250 dbtx: &mut DatabaseTransaction<'_>,
251 audit: &mut Audit,
252 module_instance_id: ModuleInstanceId,
253 ) {
254 audit
256 .add_items(dbtx, module_instance_id, &DummyInputAuditPrefix, |_, v| {
257 v.msats as i64
258 })
259 .await;
260
261 audit
263 .add_items(dbtx, module_instance_id, &DummyOutputAuditPrefix, |_, v| {
264 -(v.msats as i64)
265 })
266 .await;
267 }
268
269 fn api_endpoints(&self) -> Vec<ApiEndpoint<Self>> {
270 Vec::new()
271 }
272}
273
274impl Dummy {
275 pub fn new(cfg: DummyConfig) -> Dummy {
277 Dummy { cfg }
278 }
279}