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