1use core::fmt;
8use std::any::{Any, TypeId};
9use std::borrow::Cow;
10use std::collections::BTreeMap;
11use std::fmt::{Debug, Display, Formatter};
12use std::io::Read;
13use std::str::FromStr;
14use std::sync::Arc;
15
16use anyhow::anyhow;
17use bitcoin::hashes::{sha256, Hash};
18use fedimint_core::encoding::{Decodable, DecodeError, DynEncodable, Encodable};
19use fedimint_core::module::registry::ModuleDecoderRegistry;
20use rand::RngCore;
21use serde::{Deserialize, Deserializer, Serialize};
22
23use crate::module::registry::ModuleRegistry;
24use crate::{
25 erased_eq_no_instance_id, module_plugin_dyn_newtype_clone_passthrough,
26 module_plugin_dyn_newtype_define, module_plugin_dyn_newtype_display_passthrough,
27 module_plugin_dyn_newtype_encode_decode, module_plugin_dyn_newtype_eq_passthrough,
28 module_plugin_static_trait_define, module_plugin_static_trait_define_config,
29};
30
31pub mod server;
32
33pub mod backup;
34
35#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, PartialOrd, Ord)]
59pub struct OperationId(pub [u8; 32]);
60
61pub struct OperationIdFullFmt<'a>(&'a OperationId);
62pub struct OperationIdShortFmt<'a>(&'a OperationId);
63
64impl OperationId {
65 pub fn new_random() -> Self {
67 let mut rng = rand::thread_rng();
68 let mut bytes = [0u8; 32];
69 rng.fill_bytes(&mut bytes);
70 Self(bytes)
71 }
72
73 pub fn from_encodable<E: Encodable>(encodable: &E) -> Self {
74 Self(encodable.consensus_hash::<sha256::Hash>().to_byte_array())
75 }
76
77 pub fn fmt_short(&self) -> OperationIdShortFmt {
78 OperationIdShortFmt(self)
79 }
80 pub fn fmt_full(&self) -> OperationIdFullFmt {
81 OperationIdFullFmt(self)
82 }
83}
84
85impl<'a> Display for OperationIdShortFmt<'a> {
86 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
87 fedimint_core::format_hex(&self.0 .0[0..4], f)?;
88 f.write_str("_")?;
89 fedimint_core::format_hex(&self.0 .0[28..], f)?;
90 Ok(())
91 }
92}
93
94impl<'a> Display for OperationIdFullFmt<'a> {
95 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
96 fedimint_core::format_hex(&self.0 .0, f)
97 }
98}
99
100impl Debug for OperationId {
101 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
102 write!(f, "OperationId({})", self.fmt_short())
103 }
104}
105
106impl FromStr for OperationId {
107 type Err = anyhow::Error;
108
109 fn from_str(s: &str) -> Result<Self, Self::Err> {
110 let bytes: [u8; 32] = hex::FromHex::from_hex(s)?;
111 Ok(Self(bytes))
112 }
113}
114
115impl Serialize for OperationId {
116 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
117 if serializer.is_human_readable() {
118 serializer.serialize_str(&self.fmt_full().to_string())
119 } else {
120 serializer.serialize_bytes(&self.0)
121 }
122 }
123}
124
125impl<'de> Deserialize<'de> for OperationId {
126 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
127 where
128 D: Deserializer<'de>,
129 {
130 if deserializer.is_human_readable() {
131 let s = String::deserialize(deserializer)?;
132 let operation_id = Self::from_str(&s)
133 .map_err(|e| serde::de::Error::custom(format!("invalid operation id: {e}")))?;
134 Ok(operation_id)
135 } else {
136 let bytes: [u8; 32] = <[u8; 32]>::deserialize(deserializer)?;
137 Ok(Self(bytes))
138 }
139 }
140}
141
142pub type ModuleInstanceId = u16;
156
157pub const MODULE_INSTANCE_ID_GLOBAL: u16 = u16::MAX;
159
160pub const LEGACY_HARDCODED_INSTANCE_ID_MINT: ModuleInstanceId = 1;
164pub const LEGACY_HARDCODED_INSTANCE_ID_WALLET: ModuleInstanceId = 2;
165
166#[derive(
172 Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Serialize, Deserialize, Encodable, Decodable,
173)]
174pub struct ModuleKind(Cow<'static, str>);
175
176impl ModuleKind {
177 pub fn clone_from_str(s: &str) -> Self {
178 Self(Cow::from(s.to_owned()))
179 }
180
181 pub const fn from_static_str(s: &'static str) -> Self {
182 Self(Cow::Borrowed(s))
183 }
184
185 pub fn as_str(&self) -> &str {
186 &self.0
187 }
188}
189
190impl fmt::Display for ModuleKind {
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 std::fmt::Display::fmt(&self.0, f)
193 }
194}
195
196impl From<&'static str> for ModuleKind {
197 fn from(val: &'static str) -> Self {
198 Self::from_static_str(val)
199 }
200}
201
202#[derive(Debug, Hash, PartialEq, Eq, Clone)]
207pub struct DynUnknown(pub Vec<u8>);
208
209impl fmt::Display for DynUnknown {
210 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
211 f.write_str(&self.0.consensus_encode_to_hex())
212 }
213}
214
215impl Encodable for DynUnknown {
222 fn consensus_encode<W: std::io::Write>(&self, w: &mut W) -> Result<usize, std::io::Error> {
223 w.write_all(&self.0[..])?;
224 Ok(self.0.len())
225 }
226}
227
228pub trait IntoDynInstance {
230 type DynType: 'static;
232
233 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType;
235}
236
237type DecodeFn = Box<
238 dyn for<'a> Fn(
239 Box<dyn Read + 'a>,
240 ModuleInstanceId,
241 &ModuleDecoderRegistry,
242 ) -> Result<Box<dyn Any>, DecodeError>
243 + Send
244 + Sync,
245>;
246
247#[derive(Default)]
248pub struct DecoderBuilder {
249 decode_fns: BTreeMap<TypeId, DecodeFn>,
250 transparent: bool,
251}
252
253impl DecoderBuilder {
254 pub fn build(self) -> Decoder {
255 Decoder {
256 decode_fns: Arc::new(self.decode_fns),
257 }
258 }
259
260 pub fn with_decodable_type<Type>(&mut self)
272 where
273 Type: IntoDynInstance + Decodable,
274 {
275 let is_transparent_decoder = self.transparent;
276 let decode_fn: DecodeFn = Box::new(
279 move |mut reader, instance, decoders: &ModuleDecoderRegistry| {
280 let decoders = if is_transparent_decoder {
284 Cow::Borrowed(decoders)
285 } else {
286 Cow::Owned(ModuleRegistry::default())
287 };
288 let typed_val = Type::consensus_decode(&mut reader, &decoders).map_err(|err| {
289 let err: anyhow::Error = err.into();
290 DecodeError::new_custom(
291 err.context(format!("while decoding Dyn type module_id={instance}")),
292 )
293 })?;
294 let dyn_val = typed_val.into_dyn(instance);
295 let any_val: Box<dyn Any> = Box::new(dyn_val);
296 Ok(any_val)
297 },
298 );
299 if self
300 .decode_fns
301 .insert(TypeId::of::<Type::DynType>(), decode_fn)
302 .is_some()
303 {
304 panic!("Tried to add multiple decoders for the same DynType");
305 }
306 }
307}
308
309#[derive(Clone, Default)]
311pub struct Decoder {
312 decode_fns: Arc<BTreeMap<TypeId, DecodeFn>>,
313}
314
315impl Decoder {
316 pub fn builder() -> DecoderBuilder {
319 DecoderBuilder::default()
320 }
321
322 #[doc(hidden)]
324 pub fn builder_system() -> DecoderBuilder {
325 DecoderBuilder {
326 transparent: true,
327 ..DecoderBuilder::default()
328 }
329 }
330
331 pub fn decode_complete<DynType: Any>(
336 &self,
337 reader: &mut dyn Read,
338 total_len: u64,
339 module_id: ModuleInstanceId,
340 decoders: &ModuleDecoderRegistry,
341 ) -> Result<DynType, DecodeError> {
342 let mut reader = reader.take(total_len);
343
344 let val = self.decode_partial(&mut reader, module_id, decoders)?;
345 let left = reader.limit();
346
347 if left != 0 {
348 return Err(fedimint_core::encoding::DecodeError::new_custom(
349 anyhow::anyhow!(
350 "Dyn type did not consume all bytes during decoding; module_id={}; expected={}; left={}; type={}",
351 module_id,
352 total_len,
353 left,
354 std::any::type_name::<DynType>(),
355 ),
356 ));
357 }
358
359 Ok(val)
360 }
361
362 pub fn decode_partial<DynType: Any>(
365 &self,
366 reader: &mut dyn Read,
367 module_id: ModuleInstanceId,
368 decoders: &ModuleDecoderRegistry,
369 ) -> Result<DynType, DecodeError> {
370 let decode_fn = self
371 .decode_fns
372 .get(&TypeId::of::<DynType>())
373 .ok_or_else(|| {
374 anyhow!(
375 "Type unknown to decoder: {}, (registered decoders={})",
376 std::any::type_name::<DynType>(),
377 self.decode_fns.len()
378 )
379 })
380 .expect("Types being decoded must be registered");
381 Ok(*decode_fn(Box::new(reader), module_id, decoders)?
382 .downcast::<DynType>()
383 .expect("Decode fn returned wrong type, can't happen due to with_decodable_type"))
384 }
385}
386
387impl Debug for Decoder {
388 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
389 write!(f, "Decoder(registered_types = {})", self.decode_fns.len())
390 }
391}
392
393pub trait IClientConfig: Debug + Display + DynEncodable {
394 fn as_any(&self) -> &(dyn Any + Send + Sync);
395 fn module_kind(&self) -> Option<ModuleKind>;
396 fn clone(&self, instance_id: ModuleInstanceId) -> DynClientConfig;
397 fn dyn_hash(&self) -> u64;
398 fn erased_eq_no_instance_id(&self, other: &DynClientConfig) -> bool;
399 fn to_json(&self) -> Option<serde_json::Value>;
400}
401
402module_plugin_static_trait_define_config! {
403 DynClientConfig, ClientConfig, IClientConfig,
404 { },
405 {
406 erased_eq_no_instance_id!(DynClientConfig);
407
408 fn to_json(&self) -> Option<serde_json::Value> {
409 Some(serde_json::to_value(self.to_owned()).expect("serialization can't fail"))
410 }
411 },
412 {
413 erased_eq_no_instance_id!(DynClientConfig);
414
415 fn to_json(&self) -> Option<serde_json::Value> {
416 None
417 }
418 }
419}
420
421module_plugin_dyn_newtype_define! {
422 pub DynClientConfig(Box<IClientConfig>)
424}
425module_plugin_dyn_newtype_encode_decode!(DynClientConfig);
426
427module_plugin_dyn_newtype_clone_passthrough!(DynClientConfig);
428
429module_plugin_dyn_newtype_eq_passthrough!(DynClientConfig);
430
431module_plugin_dyn_newtype_display_passthrough!(DynClientConfig);
432
433pub trait IInput: Debug + Display + DynEncodable {
438 fn as_any(&self) -> &(dyn Any + Send + Sync);
439 fn module_kind(&self) -> Option<ModuleKind>;
440 fn clone(&self, instance_id: ModuleInstanceId) -> DynInput;
441 fn dyn_hash(&self) -> u64;
442 fn erased_eq_no_instance_id(&self, other: &DynInput) -> bool;
443}
444
445module_plugin_static_trait_define! {
446 DynInput, Input, IInput,
447 { },
448 {
449 erased_eq_no_instance_id!(DynInput);
450 }
451}
452
453module_plugin_dyn_newtype_define! {
454 pub DynInput(Box<IInput>)
456}
457module_plugin_dyn_newtype_encode_decode!(DynInput);
458
459module_plugin_dyn_newtype_clone_passthrough!(DynInput);
460
461module_plugin_dyn_newtype_eq_passthrough!(DynInput);
462
463module_plugin_dyn_newtype_display_passthrough!(DynInput);
464
465pub trait IOutput: Debug + Display + DynEncodable {
470 fn as_any(&self) -> &(dyn Any + Send + Sync);
471 fn module_kind(&self) -> Option<ModuleKind>;
472 fn clone(&self, instance_id: ModuleInstanceId) -> DynOutput;
473 fn dyn_hash(&self) -> u64;
474 fn erased_eq_no_instance_id(&self, other: &DynOutput) -> bool;
475}
476
477module_plugin_dyn_newtype_define! {
478 pub DynOutput(Box<IOutput>)
480}
481module_plugin_static_trait_define! {
482 DynOutput, Output, IOutput,
483 { },
484 {
485 erased_eq_no_instance_id!(DynOutput);
486 }
487}
488module_plugin_dyn_newtype_encode_decode!(DynOutput);
489
490module_plugin_dyn_newtype_clone_passthrough!(DynOutput);
491
492module_plugin_dyn_newtype_eq_passthrough!(DynOutput);
493
494module_plugin_dyn_newtype_display_passthrough!(DynOutput);
495
496pub enum FinalizationError {
497 SomethingWentWrong,
498}
499
500pub trait IOutputOutcome: Debug + Display + DynEncodable {
501 fn as_any(&self) -> &(dyn Any + Send + Sync);
502 fn module_kind(&self) -> Option<ModuleKind>;
503 fn clone(&self, module_instance_id: ModuleInstanceId) -> DynOutputOutcome;
504 fn dyn_hash(&self) -> u64;
505 fn erased_eq_no_instance_id(&self, other: &DynOutputOutcome) -> bool;
506}
507
508module_plugin_dyn_newtype_define! {
509 pub DynOutputOutcome(Box<IOutputOutcome>)
511}
512module_plugin_static_trait_define! {
513 DynOutputOutcome, OutputOutcome, IOutputOutcome,
514 { },
515 {
516 erased_eq_no_instance_id!(DynOutputOutcome);
517 }
518}
519module_plugin_dyn_newtype_encode_decode!(DynOutputOutcome);
520module_plugin_dyn_newtype_clone_passthrough!(DynOutputOutcome);
521module_plugin_dyn_newtype_eq_passthrough!(DynOutputOutcome);
522module_plugin_dyn_newtype_display_passthrough!(DynOutputOutcome);
523
524pub trait IModuleConsensusItem: Debug + Display + DynEncodable {
525 fn as_any(&self) -> &(dyn Any + Send + Sync);
526 fn module_kind(&self) -> Option<ModuleKind>;
527 fn clone(&self, module_instance_id: ModuleInstanceId) -> DynModuleConsensusItem;
528 fn dyn_hash(&self) -> u64;
529
530 fn erased_eq_no_instance_id(&self, other: &DynModuleConsensusItem) -> bool;
531}
532
533module_plugin_dyn_newtype_define! {
534 pub DynModuleConsensusItem(Box<IModuleConsensusItem>)
536}
537module_plugin_static_trait_define! {
538 DynModuleConsensusItem, ModuleConsensusItem, IModuleConsensusItem,
539 { },
540 {
541 erased_eq_no_instance_id!(DynModuleConsensusItem);
542 }
543}
544module_plugin_dyn_newtype_encode_decode!(DynModuleConsensusItem);
545
546module_plugin_dyn_newtype_clone_passthrough!(DynModuleConsensusItem);
547
548module_plugin_dyn_newtype_eq_passthrough!(DynModuleConsensusItem);
549
550module_plugin_dyn_newtype_display_passthrough!(DynModuleConsensusItem);
551
552pub trait IOutputError: Debug + Display + DynEncodable {
553 fn as_any(&self) -> &(dyn Any + Send + Sync);
554 fn module_kind(&self) -> Option<ModuleKind>;
555 fn clone(&self, module_instance_id: ModuleInstanceId) -> DynOutputError;
556 fn dyn_hash(&self) -> u64;
557
558 fn erased_eq_no_instance_id(&self, other: &DynOutputError) -> bool;
559}
560
561module_plugin_dyn_newtype_define! {
562 pub DynOutputError(Box<IOutputError>)
563}
564module_plugin_static_trait_define! {
565 DynOutputError, OutputError, IOutputError,
566 { },
567 {
568 erased_eq_no_instance_id!(DynOutputError);
569 }
570}
571module_plugin_dyn_newtype_encode_decode!(DynOutputError);
572
573module_plugin_dyn_newtype_clone_passthrough!(DynOutputError);
574
575module_plugin_dyn_newtype_eq_passthrough!(DynOutputError);
576
577module_plugin_dyn_newtype_display_passthrough!(DynOutputError);
578
579pub trait IInputError: Debug + Display + DynEncodable {
580 fn as_any(&self) -> &(dyn Any + Send + Sync);
581 fn module_kind(&self) -> Option<ModuleKind>;
582 fn clone(&self, module_instance_id: ModuleInstanceId) -> DynInputError;
583 fn dyn_hash(&self) -> u64;
584
585 fn erased_eq_no_instance_id(&self, other: &DynInputError) -> bool;
586}
587
588module_plugin_dyn_newtype_define! {
589 pub DynInputError(Box<IInputError>)
590}
591module_plugin_static_trait_define! {
592 DynInputError, InputError, IInputError,
593 { },
594 {
595 erased_eq_no_instance_id!(DynInputError);
596 }
597}
598module_plugin_dyn_newtype_encode_decode!(DynInputError);
599
600module_plugin_dyn_newtype_clone_passthrough!(DynInputError);
601
602module_plugin_dyn_newtype_eq_passthrough!(DynInputError);
603
604module_plugin_dyn_newtype_display_passthrough!(DynInputError);