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