fedimint_core/
core.rs

1//! Fedimint Core API (common) module interface
2//!
3//! Fedimint supports externally implemented modules.
4//!
5//! This (Rust) module defines common interoperability types
6//! and functionality that is used on both client and sever side.
7use 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/// Unique identifier for one semantic, correlatable operation.
36///
37/// The concept of *operations* is used to avoid losing privacy while being as
38/// efficient as possible with regards to network requests.
39///
40/// For Fedimint transactions to be private users need to communicate with the
41/// federation using an anonymous communication network. If each API request was
42/// done in a way that it cannot be correlated to any other API request we would
43/// achieve privacy, but would reduce efficiency. E.g. on Tor we would need to
44/// open a new circuit for every request and open a new web socket connection.
45///
46/// Fortunately we do not need to do that to maintain privacy. Many API requests
47/// and transactions can be correlated by the federation anyway, in these cases
48/// it does not make any difference to re-use the same network connection. All
49/// requests, transactions, state machines that are connected from the
50/// federation's point of view anyway are grouped together as one *operation*.
51///
52/// # Choice of Operation ID
53///
54/// In cases where an operation is created by a new transaction that's being
55/// submitted the transaction's ID can be used as operation ID. If there is no
56/// transaction related to it, it should be generated randomly. Since it is a
57/// 256bit value collisions are impossible for all intents and purposes.
58#[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    /// Generate random [`OperationId`]
66    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
142/// Module instance ID
143///
144/// This value uniquely identifies a single instance of a module in a
145/// federation.
146///
147/// In case a single [`ModuleKind`] is instantiated twice (rare, but possible),
148/// each instance will have a different id.
149///
150/// Note: We have used this type differently before, assuming each `u16`
151/// uniquly identifies a type of module in question. This function will move
152/// to a `ModuleKind` type which only identifies type of a module (mint vs
153/// wallet vs ln, etc)
154// TODO: turn in a newtype
155pub type ModuleInstanceId = u16;
156
157/// Special IDs we use for global dkg
158pub const MODULE_INSTANCE_ID_GLOBAL: u16 = u16::MAX;
159
160// Note: needs to be in alphabetical order of ModuleKind of each module,
161// as this is the ordering we currently hardcoded.
162// Should be used only for pre-modularization code we still have  left
163pub const LEGACY_HARDCODED_INSTANCE_ID_MINT: ModuleInstanceId = 1;
164pub const LEGACY_HARDCODED_INSTANCE_ID_WALLET: ModuleInstanceId = 2;
165
166/// A type of a module
167///
168/// This is a short string that identifies type of a module.
169/// Authors of 3rd party modules are free to come up with a string,
170/// long enough to avoid conflicts with similar modules.
171#[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/// A type used by when decoding dyn-types, when the module is missing
203///
204/// This allows parsing and handling of dyn-types of modules which
205/// are not available.
206#[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
215// Note: confusingly, while `DynUnknown` carries a `Vec`
216// it is actually not responsible for writing out the length of the data,
217// as the higher level (`module_plugin_dyn_newtype_encode_decode`) is doing
218// it, based on how many bytes are written here. That's why `DynUnknown` does
219// not implement `Decodable` directly, and `Vec` here has len only
220// for the purpose of knowing how many bytes to carry.
221impl 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
228/// A type that has a `Dyn*`, type erased version of itself
229pub trait IntoDynInstance {
230    /// The type erased version of the type implementing this trait
231    type DynType: 'static;
232
233    /// Convert `self` into its type-erased equivalent
234    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    /// Attach decoder for a specific `Type`/`DynType` pair where `DynType =
261    /// <Type as IntoDynInstance>::DynType`.
262    ///
263    /// This allows calling `decode::<DynType>` on this decoder, returning a
264    /// `DynType` object which contains a `Type` object internally.
265    ///
266    /// **Caution**: One `Decoder` object should only contain decoders that
267    /// belong to the same [*module kind*](fedimint_core::core::ModuleKind).
268    ///
269    /// # Panics
270    /// * If multiple `Types` with the same `DynType` are added
271    pub fn with_decodable_type<Type>(&mut self)
272    where
273        Type: IntoDynInstance + Decodable,
274    {
275        let is_transparent_decoder = self.transparent;
276        // TODO: enforce that all decoders are for the same module kind (+fix docs
277        // after)
278        let decode_fn: DecodeFn = Box::new(
279            move |mut reader, instance, decoders: &ModuleDecoderRegistry| {
280                // TODO: Ideally `DynTypes` decoding couldn't ever be nested, so we could just
281                // pass empty `decoders`. But the client context uses nested `DynTypes` in
282                // `DynState`, so we special-case it with a flag.
283                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/// Consensus encoding decoder for module-specific types
310#[derive(Clone, Default)]
311pub struct Decoder {
312    decode_fns: Arc<BTreeMap<TypeId, DecodeFn>>,
313}
314
315impl Decoder {
316    /// Creates a `DecoderBuilder` to which decoders for single types can be
317    /// attached to build a `Decoder`.
318    pub fn builder() -> DecoderBuilder {
319        DecoderBuilder::default()
320    }
321
322    /// System Dyn-type, don't use.
323    #[doc(hidden)]
324    pub fn builder_system() -> DecoderBuilder {
325        DecoderBuilder {
326            transparent: true,
327            ..DecoderBuilder::default()
328        }
329    }
330
331    /// Decodes a specific `DynType` from the `reader` byte stream.
332    ///
333    /// # Panics
334    /// * If no decoder is registered for the `DynType`
335    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    /// Like [`Self::decode_complete`] but does not verify that all bytes were
363    /// consumed
364    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    /// An owned, immutable input to a [`Transaction`](fedimint_core::transaction::Transaction)
423    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
433/// Something that can be an [`DynInput`] in a
434/// [`Transaction`](fedimint_core::transaction::Transaction)
435///
436/// General purpose code should use [`DynInput`] instead
437pub 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    /// An owned, immutable input to a [`Transaction`](fedimint_core::transaction::Transaction)
455    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
465/// Something that can be an [`DynOutput`] in a
466/// [`Transaction`](fedimint_core::transaction::Transaction)
467///
468/// General purpose code should use [`DynOutput`] instead
469pub 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    /// An owned, immutable output of a [`Transaction`](fedimint_core::transaction::Transaction)
479    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    /// An owned, immutable output of a [`Transaction`](fedimint_core::transaction::Transaction) before it was finalized
510    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    /// An owned, immutable output of a [`Transaction`](fedimint_core::transaction::Transaction) before it was finalized
535    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);