Skip to main content

fedimint_core/module/
mod.rs

1//! Core module system traits and types.
2//!
3//! Fedimint supports modules to allow extending its functionality.
4//! Some of the standard functionality is implemented in form of modules as
5//! well. This rust module houses the core trait
6//! [`fedimint_core::module::ModuleCommon`] used by both the server and client
7//! side module traits. Specific server and client traits exist in their
8//! respective crates.
9//!
10//! The top level server-side types are:
11//!
12//! * `fedimint_server::core::ServerModuleInit`
13//! * `fedimint_server::core::ServerModule`
14//!
15//! Top level client-side types are:
16//!
17//! * `ClientModuleInit` (in `fedimint_client`)
18//! * `ClientModule` (in `fedimint_client`)
19pub mod audit;
20pub mod registry;
21
22use std::collections::{BTreeMap, BTreeSet};
23use std::error::Error;
24use std::fmt::{self, Debug, Formatter};
25use std::marker::PhantomData;
26use std::ops;
27use std::pin::Pin;
28use std::sync::Arc;
29use std::sync::atomic::{AtomicU64, Ordering};
30
31use fedimint_logging::LOG_NET_API;
32use futures::Future;
33use jsonrpsee_core::JsonValue;
34use registry::ModuleRegistry;
35use serde::{Deserialize, Serialize};
36use tracing::Instrument;
37
38// TODO: Make this module public and remove theDkgPeerMessage`pub use` below
39mod version;
40pub use self::version::*;
41use crate::core::{
42    ClientConfig, Decoder, DecoderBuilder, Input, InputError, ModuleConsensusItem,
43    ModuleInstanceId, ModuleKind, Output, OutputError, OutputOutcome,
44};
45use crate::db::{
46    Database, DatabaseError, DatabaseKey, DatabaseKeyWithNotify, DatabaseRecord,
47    DatabaseTransaction,
48};
49use crate::encoding::{Decodable, DecodeError, Encodable};
50use crate::fmt_utils::AbbreviateHexBytes;
51use crate::task::MaybeSend;
52use crate::util::FmtCompact;
53use crate::{Amount, apply, async_trait_maybe_send, maybe_add_send, maybe_add_send_sync};
54
55#[derive(Debug, PartialEq, Eq)]
56pub struct InputMeta {
57    pub amount: TransactionItemAmounts,
58    pub pub_key: secp256k1::PublicKey,
59}
60
61/// Unit of account for a given amount.
62#[derive(
63    Debug,
64    Clone,
65    Copy,
66    Eq,
67    PartialEq,
68    Hash,
69    PartialOrd,
70    Ord,
71    Deserialize,
72    Serialize,
73    Encodable,
74    Decodable,
75    Default,
76)]
77pub struct AmountUnit(u64);
78
79#[cfg(feature = "uniffi")]
80uniffi::custom_newtype!(AmountUnit, u64);
81
82impl AmountUnit {
83    /// [`AmountUnit`] with id `0` is reserved for the native Bitcoin currency.
84    /// So e.g. for a mainnet Federation it's a real Bitcoin (msats), for a
85    /// signet one it's a Signet msats, etc.
86    pub const BITCOIN: Self = Self(0);
87
88    pub fn is_bitcoin(self) -> bool {
89        self == Self::BITCOIN
90    }
91
92    pub fn new_custom(unit: u64) -> Self {
93        Self(unit)
94    }
95
96    pub const fn bitcoin() -> Self {
97        Self::BITCOIN
98    }
99}
100
101#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
102pub struct AmountWithUnit {
103    amounts: Amount,
104    unit: AmountUnit,
105}
106
107/// Multi-unit amount
108///
109/// Basically (potentially) multiple amounts, each of different unit.
110///
111/// Note: implementation must be careful not to add zero-amount
112/// entries, as these could mess up equality comparisons, etc.
113#[derive(Debug, Clone, Eq, PartialEq, Hash, Encodable, Decodable)]
114pub struct Amounts(BTreeMap<AmountUnit, Amount>);
115
116// Note: no `impl ops::DerefMut` as it could easily accidentally break the
117// invariant
118impl ops::Deref for Amounts {
119    type Target = BTreeMap<AmountUnit, Amount>;
120
121    fn deref(&self) -> &Self::Target {
122        &self.0
123    }
124}
125
126impl Amounts {
127    pub const ZERO: Self = Self(BTreeMap::new());
128
129    pub fn new_bitcoin(amount: Amount) -> Self {
130        if amount == Amount::ZERO {
131            Self(BTreeMap::from([]))
132        } else {
133            Self(BTreeMap::from([(AmountUnit::BITCOIN, amount)]))
134        }
135    }
136
137    pub fn new_bitcoin_msats(msats: u64) -> Self {
138        Self::new_bitcoin(Amount::from_msats(msats))
139    }
140
141    pub fn new_custom(unit: AmountUnit, amount: Amount) -> Self {
142        if amount == Amount::ZERO {
143            Self(BTreeMap::from([]))
144        } else {
145            Self(BTreeMap::from([(unit, amount)]))
146        }
147    }
148
149    pub fn checked_add(mut self, rhs: &Self) -> Option<Self> {
150        self.checked_add_mut(rhs)?;
151
152        Some(self)
153    }
154
155    pub fn checked_add_mut(&mut self, rhs: &Self) -> Option<&mut Self> {
156        for (unit, amount) in &rhs.0 {
157            debug_assert!(
158                *amount != Amount::ZERO,
159                "`Amounts` must not add (/remove) zero-amount entries"
160            );
161            let prev = self.0.entry(*unit).or_default();
162
163            *prev = prev.checked_add(*amount)?;
164        }
165
166        Some(self)
167    }
168
169    pub fn checked_add_bitcoin(self, amount: Amount) -> Option<Self> {
170        self.checked_add_unit(amount, AmountUnit::BITCOIN)
171    }
172
173    pub fn checked_add_unit(mut self, amount: Amount, unit: AmountUnit) -> Option<Self> {
174        if amount == Amount::ZERO {
175            return Some(self);
176        }
177
178        let prev = self.0.entry(unit).or_default();
179
180        *prev = prev.checked_add(amount)?;
181
182        Some(self)
183    }
184
185    pub fn checked_sub(&self, other: &Self) -> Option<Self> {
186        let mut result = self.clone();
187
188        for (unit, amount) in &other.0 {
189            if *amount == Amount::ZERO {
190                continue;
191            }
192
193            let prev = result.0.entry(*unit).or_default();
194
195            *prev = prev.checked_sub(*amount)?;
196
197            if *prev == Amount::ZERO {
198                result.0.remove(unit);
199            }
200        }
201
202        Some(result)
203    }
204
205    pub fn remove(&mut self, unit: &AmountUnit) -> Option<Amount> {
206        self.0.remove(unit)
207    }
208
209    pub fn get_bitcoin(&self) -> Amount {
210        self.get(&AmountUnit::BITCOIN).copied().unwrap_or_default()
211    }
212
213    pub fn expect_only_bitcoin(&self) -> Amount {
214        #[allow(clippy::option_if_let_else)] // I like it explicitly split into two cases --dpc
215        match self.get(&AmountUnit::BITCOIN) {
216            Some(amount) => {
217                assert!(
218                    self.len() == 1,
219                    "Amounts expected to contain only bitcoin and no other currencies"
220                );
221                *amount
222            }
223            None => Amount::ZERO,
224        }
225    }
226
227    pub fn iter_units(&self) -> impl Iterator<Item = AmountUnit> {
228        self.0.keys().copied()
229    }
230
231    pub fn units(&self) -> BTreeSet<AmountUnit> {
232        self.0.keys().copied().collect()
233    }
234}
235
236impl IntoIterator for Amounts {
237    type Item = (AmountUnit, Amount);
238
239    type IntoIter = <BTreeMap<AmountUnit, Amount> as IntoIterator>::IntoIter;
240
241    fn into_iter(self) -> Self::IntoIter {
242        self.0.into_iter()
243    }
244}
245
246/// Information about the amount represented by an input or output.
247///
248/// * For **inputs** the amount is funding the transaction while the fee is
249///   consuming funding
250/// * For **outputs** the amount and the fee consume funding
251#[derive(Debug, Clone, Eq, PartialEq, Hash)]
252pub struct TransactionItemAmounts {
253    pub amounts: Amounts,
254    pub fees: Amounts,
255}
256
257impl TransactionItemAmounts {
258    pub fn checked_add(self, rhs: &Self) -> Option<Self> {
259        Some(Self {
260            amounts: self.amounts.checked_add(&rhs.amounts)?,
261            fees: self.fees.checked_add(&rhs.fees)?,
262        })
263    }
264}
265
266impl TransactionItemAmounts {
267    pub const ZERO: Self = Self {
268        amounts: Amounts::ZERO,
269        fees: Amounts::ZERO,
270    };
271}
272
273/// All requests from client to server contain these fields
274#[derive(Debug, Serialize, Deserialize, Clone)]
275pub struct ApiRequest<T> {
276    /// Authentication secret for this API request, if required
277    pub auth: Option<ApiAuth>,
278    /// Parameters required by the API
279    pub params: T,
280}
281
282pub type ApiRequestErased = ApiRequest<JsonValue>;
283
284impl Default for ApiRequestErased {
285    fn default() -> Self {
286        Self {
287            auth: None,
288            params: JsonValue::Null,
289        }
290    }
291}
292
293impl ApiRequestErased {
294    pub fn new<T: Serialize>(params: T) -> Self {
295        Self {
296            auth: None,
297            params: serde_json::to_value(params)
298                .expect("parameter serialization error - this should not happen"),
299        }
300    }
301
302    pub fn to_json(&self) -> JsonValue {
303        serde_json::to_value(self).expect("parameter serialization error - this should not happen")
304    }
305
306    pub fn with_auth(self, auth: ApiAuth) -> Self {
307        Self {
308            auth: Some(auth),
309            params: self.params,
310        }
311    }
312
313    pub fn to_typed<T: serde::de::DeserializeOwned>(
314        self,
315    ) -> Result<ApiRequest<T>, serde_json::Error> {
316        Ok(ApiRequest {
317            auth: self.auth,
318            params: serde_json::from_value::<T>(self.params)?,
319        })
320    }
321}
322
323#[derive(Debug, Clone, Serialize, Deserialize)]
324pub enum ApiMethod {
325    Core(String),
326    Module(ModuleInstanceId, String),
327}
328
329impl fmt::Display for ApiMethod {
330    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
331        match self {
332            Self::Core(s) => f.write_str(s),
333            Self::Module(module_id, s) => f.write_fmt(format_args!("{module_id}-{s}")),
334        }
335    }
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize)]
339pub struct IrohApiRequest {
340    pub method: ApiMethod,
341    pub request: ApiRequestErased,
342}
343
344#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct IrohGatewayRequest {
346    /// REST API route for specifying which action to take
347    pub route: String,
348
349    /// Parameters for the request
350    pub params: Option<serde_json::Value>,
351
352    /// Password for authenticated requests to the gateway
353    pub password: Option<String>,
354}
355
356#[derive(Debug, Clone, Serialize, Deserialize)]
357pub struct IrohGatewayResponse {
358    pub status: u16,
359    pub body: serde_json::Value,
360}
361
362pub const FEDIMINT_API_ALPN: &[u8] = b"FEDIMINT_API_ALPN";
363pub const FEDIMINT_GATEWAY_ALPN: &[u8] = b"FEDIMINT_GATEWAY_ALPN";
364
365/// Authentication secret used to verify guardian admin API requests.
366///
367/// The inner value is private to prevent timing leaks via direct comparison.
368/// Use [`Self::verify`] for authentication checks.
369#[derive(Clone, Serialize, Deserialize)]
370pub struct ApiAuth(String);
371
372impl ApiAuth {
373    pub fn new(s: String) -> Self {
374        Self(s)
375    }
376
377    pub fn as_str(&self) -> &str {
378        &self.0
379    }
380
381    pub fn verify(&self, password: &str) -> bool {
382        use subtle::ConstantTimeEq as _;
383        bool::from(self.0.as_bytes().ct_eq(password.as_bytes()))
384    }
385}
386
387impl Debug for ApiAuth {
388    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
389        write!(f, "ApiAuth(****)")
390    }
391}
392
393#[derive(Debug, Clone, Serialize, Deserialize)]
394pub struct ApiError {
395    pub code: i32,
396    pub message: String,
397}
398
399impl Error for ApiError {}
400
401impl fmt::Display for ApiError {
402    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
403        f.write_fmt(format_args!("{} {}", self.code, self.message))
404    }
405}
406
407pub type ApiResult<T> = Result<T, ApiError>;
408
409impl ApiError {
410    pub fn new(code: i32, message: String) -> Self {
411        Self { code, message }
412    }
413
414    pub fn not_found(message: String) -> Self {
415        Self::new(404, message)
416    }
417
418    pub fn bad_request(message: String) -> Self {
419        Self::new(400, message)
420    }
421
422    pub fn unauthorized() -> Self {
423        Self::new(401, "Invalid authorization".to_string())
424    }
425
426    pub fn server_error(message: String) -> Self {
427        Self::new(500, message)
428    }
429}
430
431impl From<DatabaseError> for ApiError {
432    fn from(err: DatabaseError) -> Self {
433        Self {
434            code: 500,
435            message: format!("API server error when writing to database: {err}"),
436        }
437    }
438}
439
440/// State made available to all API endpoints for handling a request
441pub struct ApiEndpointContext {
442    db: Database,
443    has_auth: bool,
444}
445
446impl ApiEndpointContext {
447    /// `db` should be isolated.
448    pub fn new(db: Database, has_auth: bool) -> Self {
449        Self { db, has_auth }
450    }
451
452    /// Whether the request was authenticated as the guardian who controls this
453    /// fedimint server
454    pub fn has_auth(&self) -> bool {
455        self.has_auth
456    }
457
458    pub fn db(&self) -> Database {
459        self.db.clone()
460    }
461
462    /// Waits for key to be present in database.
463    pub fn wait_key_exists<K>(&self, key: K) -> impl Future<Output = K::Value> + use<K>
464    where
465        K: DatabaseKey + DatabaseRecord + DatabaseKeyWithNotify,
466    {
467        let db = self.db.clone();
468        // self contains dbtx which is !Send
469        // try removing this and see the error.
470        async move { db.wait_key_exists(&key).await }
471    }
472
473    /// Waits for key to have a value that matches.
474    pub fn wait_value_matches<K>(
475        &self,
476        key: K,
477        matcher: impl Fn(&K::Value) -> bool + Copy,
478    ) -> impl Future<Output = K::Value>
479    where
480        K: DatabaseKey + DatabaseRecord + DatabaseKeyWithNotify,
481    {
482        let db = self.db.clone();
483        async move { db.wait_key_check(&key, |v| v.filter(matcher)).await.0 }
484    }
485}
486
487#[apply(async_trait_maybe_send!)]
488pub trait TypedApiEndpoint {
489    type State: Sync;
490
491    /// example: /transaction
492    const PATH: &'static str;
493    const VERSION: ApiVersion;
494    type Param: serde::de::DeserializeOwned + Send;
495    type Response: serde::Serialize;
496
497    async fn handle<'state, 'context>(
498        state: &'state Self::State,
499        context: &'context mut ApiEndpointContext,
500        request: Self::Param,
501    ) -> Result<Self::Response, ApiError>;
502}
503
504pub use serde_json;
505
506/// Declares an API endpoint that does not require guardian authentication.
507///
508/// # Example
509///
510/// ```rust
511/// # use fedimint_core::module::ApiVersion;
512/// # use fedimint_core::module::{public_api_endpoint, ApiEndpoint, registry::ModuleInstanceId};
513/// struct State;
514///
515/// let _: ApiEndpoint<State> = public_api_endpoint! {
516///     "/foobar",
517///     ApiVersion::new(0, 3),
518///     async |state: &State, _dbtx, params: ()| -> i32 {
519///         Ok(0)
520///     }
521/// };
522/// ```
523#[macro_export]
524macro_rules! __public_api_endpoint {
525    (
526        $path:expr_2021,
527        // API version this endpoint was introduced in, at the current consensus level.
528        $version_introduced:expr_2021,
529        async |$state:ident: &$state_ty:ty, $context:ident, $param:ident: $param_ty:ty| -> $resp_ty:ty $body:block
530    ) => {{
531        struct Endpoint;
532
533        #[$crate::apply($crate::async_trait_maybe_send!)]
534        impl $crate::module::TypedApiEndpoint for Endpoint {
535            #[allow(deprecated)]
536            const PATH: &'static str = $path;
537            const VERSION: $crate::module::ApiVersion = $version_introduced;
538            type State = $state_ty;
539            type Param = $param_ty;
540            type Response = $resp_ty;
541
542            async fn handle<'state, 'context>(
543                $state: &'state Self::State,
544                $context: &'context mut $crate::module::ApiEndpointContext,
545                $param: Self::Param,
546            ) -> ::std::result::Result<Self::Response, $crate::module::ApiError> {
547                $body
548            }
549        }
550
551        $crate::module::ApiEndpoint::from_typed::<Endpoint>()
552    }};
553}
554
555pub use __public_api_endpoint as public_api_endpoint;
556
557/// Declares an API endpoint that verifies guardian authentication before
558/// entering the handler body.
559///
560/// An optional token argument between the context and request binds the
561/// verified [`GuardianAuthToken`](crate::net::auth::GuardianAuthToken) for
562/// handlers that pass the proof of authentication to privileged inner
563/// functions.
564#[macro_export]
565macro_rules! __admin_api_endpoint {
566    (
567        $path:expr_2021,
568        $version_introduced:expr_2021,
569        async |$state:ident: &$state_ty:ty, $context:ident, $auth:ident, $param:ident: $param_ty:ty| -> $resp_ty:ty $body:block
570    ) => {{
571        $crate::module::public_api_endpoint! {
572            $path,
573            $version_introduced,
574            async |$state: &$state_ty, $context, $param: $param_ty| -> $resp_ty {
575                // Match normal function-parameter behavior: duplicate binder
576                // names must fail to compile instead of shadowing.
577                #[allow(unused_variables)]
578                let _ = |$state: (), $context: (), $auth: (), $param: ()| {};
579                let $auth = $crate::net::auth::check_auth($context)?;
580                $body
581            }
582        }
583    }};
584    (
585        $path:expr_2021,
586        $version_introduced:expr_2021,
587        async |$state:ident: &$state_ty:ty, $context:ident, $param:ident: $param_ty:ty| -> $resp_ty:ty $body:block
588    ) => {{
589        $crate::module::public_api_endpoint! {
590            $path,
591            $version_introduced,
592            async |$state: &$state_ty, $context, $param: $param_ty| -> $resp_ty {
593                $crate::net::auth::check_auth($context)?;
594                $body
595            }
596        }
597    }};
598}
599
600pub use __admin_api_endpoint as admin_api_endpoint;
601
602use self::registry::ModuleDecoderRegistry;
603
604type HandlerFnReturn<'a> =
605    Pin<Box<maybe_add_send!(dyn Future<Output = Result<serde_json::Value, ApiError>> + 'a)>>;
606type HandlerFn<M> = Box<
607    maybe_add_send_sync!(
608        dyn for<'a> Fn(&'a M, ApiEndpointContext, ApiRequestErased) -> HandlerFnReturn<'a>
609    ),
610>;
611
612/// Definition of an API endpoint defined by a module `M`.
613pub struct ApiEndpoint<M> {
614    /// Path under which the API endpoint can be reached. It should start with a
615    /// `/` e.g. `/transaction`. E.g. this API endpoint would be reachable
616    /// under `module_module_instance_id_transaction` depending on the
617    /// module name returned by `[FedertionModule::api_base_name]`.
618    pub path: &'static str,
619    /// Handler for the API call that takes the following arguments:
620    ///   * Reference to the module which defined it
621    ///   * Request parameters parsed into JSON `[Value](serde_json::Value)`
622    pub handler: HandlerFn<M>,
623    /// API version this endpoint was introduced in.
624    pub version: ApiVersion,
625}
626
627/// Global request ID used for logging
628static REQ_ID: AtomicU64 = AtomicU64::new(0);
629
630// <()> is used to avoid specify state.
631impl ApiEndpoint<()> {
632    pub fn from_typed<E: TypedApiEndpoint>() -> ApiEndpoint<E::State>
633    where
634        <E as TypedApiEndpoint>::Response: MaybeSend,
635        E::Param: Debug,
636        E::Response: Debug,
637    {
638        async fn handle_request<'state, 'context, E>(
639            state: &'state E::State,
640            context: &'context mut ApiEndpointContext,
641            request: ApiRequest<E::Param>,
642        ) -> Result<E::Response, ApiError>
643        where
644            E: TypedApiEndpoint,
645            E::Param: Debug,
646            E::Response: Debug,
647        {
648            tracing::debug!(target: LOG_NET_API, path = E::PATH, ?request, "received api request");
649            let result = E::handle(state, context, request.params).await;
650            match &result {
651                Err(err) => {
652                    tracing::warn!(target: LOG_NET_API, path = E::PATH, err = %err.fmt_compact(), "api request error");
653                }
654                _ => {
655                    tracing::trace!(target: LOG_NET_API, path = E::PATH, "api request complete");
656                }
657            }
658            result
659        }
660
661        ApiEndpoint {
662            path: E::PATH,
663            version: E::VERSION,
664            handler: Box::new(|m, mut context, request| {
665                Box::pin(async move {
666                    let request = request
667                        .to_typed()
668                        .map_err(|e| ApiError::bad_request(e.to_string()))?;
669
670                    let span = tracing::info_span!(
671                        target: LOG_NET_API,
672                        "api_req",
673                        id = REQ_ID.fetch_add(1, Ordering::SeqCst),
674                        method = E::PATH,
675                    );
676                    let ret = handle_request::<E>(m, &mut context, request)
677                        .instrument(span)
678                        .await?;
679
680                    Ok(serde_json::to_value(ret).expect("encoding error"))
681                })
682            }),
683        }
684    }
685}
686
687/// Operations common to Server and Client side module gen dyn newtypes
688///
689/// Due to conflict of `impl Trait for T` for both `ServerModuleInit` and
690/// `ClientModuleInit`, we can't really have a `ICommonModuleInit`, so to unify
691/// them in `ModuleInitRegistry` we move the common functionality to be an
692/// interface over their dyn newtype wrappers. A bit weird, but works.
693#[apply(async_trait_maybe_send!)]
694pub trait IDynCommonModuleInit: Debug {
695    fn decoder(&self) -> Decoder;
696
697    fn module_kind(&self) -> ModuleKind;
698
699    fn to_dyn_common(&self) -> DynCommonModuleInit;
700
701    async fn dump_database(
702        &self,
703        dbtx: &mut DatabaseTransaction<'_>,
704        prefix_names: Vec<String>,
705    ) -> Box<dyn Iterator<Item = (String, Box<dyn erased_serde::Serialize + Send>)> + '_>;
706}
707
708/// Trait implemented by every `*ModuleInit` (server or client side)
709pub trait ModuleInit: Debug + Clone + Send + Sync + 'static {
710    type Common: CommonModuleInit;
711
712    fn dump_database(
713        &self,
714        dbtx: &mut DatabaseTransaction<'_>,
715        prefix_names: Vec<String>,
716    ) -> maybe_add_send!(
717        impl Future<
718            Output = Box<
719                dyn Iterator<Item = (String, Box<dyn erased_serde::Serialize + Send>)> + '_,
720            >,
721        >
722    );
723}
724
725#[apply(async_trait_maybe_send!)]
726impl<T> IDynCommonModuleInit for T
727where
728    T: ModuleInit,
729{
730    fn decoder(&self) -> Decoder {
731        T::Common::decoder()
732    }
733
734    fn module_kind(&self) -> ModuleKind {
735        T::Common::KIND
736    }
737
738    fn to_dyn_common(&self) -> DynCommonModuleInit {
739        DynCommonModuleInit::from_inner(Arc::new(self.clone()))
740    }
741
742    async fn dump_database(
743        &self,
744        dbtx: &mut DatabaseTransaction<'_>,
745        prefix_names: Vec<String>,
746    ) -> Box<dyn Iterator<Item = (String, Box<dyn erased_serde::Serialize + Send>)> + '_> {
747        <Self as ModuleInit>::dump_database(self, dbtx, prefix_names).await
748    }
749}
750
751dyn_newtype_define!(
752    #[derive(Clone)]
753    pub DynCommonModuleInit(Arc<IDynCommonModuleInit>)
754);
755
756impl AsRef<maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)> for DynCommonModuleInit {
757    fn as_ref(&self) -> &(maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)) {
758        self.inner.as_ref()
759    }
760}
761
762impl DynCommonModuleInit {
763    pub fn from_inner(
764        inner: Arc<maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)>,
765    ) -> Self {
766        Self { inner }
767    }
768}
769
770/// Logic and constant common between server side and client side modules
771#[apply(async_trait_maybe_send!)]
772pub trait CommonModuleInit: Debug + Sized {
773    const CONSENSUS_VERSION: ModuleConsensusVersion;
774    const KIND: ModuleKind;
775
776    type ClientConfig: ClientConfig;
777
778    fn decoder() -> Decoder;
779}
780
781/// Module associated types required by both client and server
782pub trait ModuleCommon {
783    type ClientConfig: ClientConfig;
784    type Input: Input;
785    type Output: Output;
786    type OutputOutcome: OutputOutcome;
787    type ConsensusItem: ModuleConsensusItem;
788    type InputError: InputError;
789    type OutputError: OutputError;
790
791    fn decoder_builder() -> DecoderBuilder {
792        let mut decoder_builder = Decoder::builder();
793        decoder_builder.with_decodable_type::<Self::ClientConfig>();
794        decoder_builder.with_decodable_type::<Self::Input>();
795        decoder_builder.with_decodable_type::<Self::Output>();
796        decoder_builder.with_decodable_type::<Self::OutputOutcome>();
797        decoder_builder.with_decodable_type::<Self::ConsensusItem>();
798        decoder_builder.with_decodable_type::<Self::InputError>();
799        decoder_builder.with_decodable_type::<Self::OutputError>();
800
801        decoder_builder
802    }
803
804    fn decoder() -> Decoder {
805        Self::decoder_builder().build()
806    }
807}
808
809/// Creates a struct that can be used to make our module-decodable structs
810/// interact with `serde`-based APIs (AlephBFT, jsonrpsee). It creates a wrapper
811/// that holds the data as serialized
812// bytes internally.
813#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
814pub struct SerdeModuleEncoding<T: Encodable + Decodable>(
815    #[serde(with = "::fedimint_core::encoding::as_hex")] Vec<u8>,
816    #[serde(skip)] PhantomData<T>,
817);
818
819/// Same as [`SerdeModuleEncoding`] but uses base64 instead of hex encoding.
820#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
821pub struct SerdeModuleEncodingBase64<T: Encodable + Decodable>(
822    #[serde(with = "::fedimint_core::encoding::as_base64")] Vec<u8>,
823    #[serde(skip)] PhantomData<T>,
824);
825
826impl<T> fmt::Debug for SerdeModuleEncoding<T>
827where
828    T: Encodable + Decodable,
829{
830    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
831        f.write_str("SerdeModuleEncoding(")?;
832        fmt::Debug::fmt(&AbbreviateHexBytes(&self.0), f)?;
833        f.write_str(")")?;
834        Ok(())
835    }
836}
837
838impl<T: Encodable + Decodable> From<&T> for SerdeModuleEncoding<T> {
839    fn from(value: &T) -> Self {
840        let mut bytes = vec![];
841        fedimint_core::encoding::Encodable::consensus_encode(value, &mut bytes)
842            .expect("Writing to buffer can never fail");
843        Self(bytes, PhantomData)
844    }
845}
846
847impl<T: Encodable + Decodable + 'static> SerdeModuleEncoding<T> {
848    pub fn try_into_inner(&self, modules: &ModuleDecoderRegistry) -> Result<T, DecodeError> {
849        Decodable::consensus_decode_whole(&self.0, modules)
850    }
851
852    /// In cases where we know exactly which module kind we expect but don't
853    /// have access to all decoders this function can be used instead.
854    ///
855    /// Note that it just assumes the decoded module instance id to be valid
856    /// since it cannot validate against the decoder registry. The lack of
857    /// access to a decoder registry also makes decoding structs impossible that
858    /// themselves contain module dyn-types (e.g. a module output containing a
859    /// fedimint transaction).
860    pub fn try_into_inner_known_module_kind(&self, decoder: &Decoder) -> Result<T, DecodeError> {
861        let mut reader = std::io::Cursor::new(&self.0);
862        let module_instance = ModuleInstanceId::consensus_decode_partial(
863            &mut reader,
864            &ModuleDecoderRegistry::default(),
865        )?;
866
867        let total_len =
868            u64::consensus_decode_partial(&mut reader, &ModuleDecoderRegistry::default())?;
869
870        // No recursive module decoding is supported since we give an empty decoder
871        // registry to the decode function
872        decoder.decode_complete(
873            &mut reader,
874            total_len,
875            module_instance,
876            &ModuleRegistry::default(),
877        )
878    }
879}
880
881impl<T: Encodable + Decodable> Encodable for SerdeModuleEncoding<T> {
882    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
883        self.0.consensus_encode(writer)
884    }
885}
886
887impl<T: Encodable + Decodable> Decodable for SerdeModuleEncoding<T> {
888    fn consensus_decode_partial_from_finite_reader<R: std::io::Read>(
889        reader: &mut R,
890        modules: &ModuleDecoderRegistry,
891    ) -> Result<Self, DecodeError> {
892        Ok(Self(
893            Vec::<u8>::consensus_decode_partial_from_finite_reader(reader, modules)?,
894            PhantomData,
895        ))
896    }
897}
898
899impl<T> fmt::Debug for SerdeModuleEncodingBase64<T>
900where
901    T: Encodable + Decodable,
902{
903    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
904        f.write_str("SerdeModuleEncoding2(")?;
905        fmt::Debug::fmt(&AbbreviateHexBytes(&self.0), f)?;
906        f.write_str(")")?;
907        Ok(())
908    }
909}
910
911impl<T: Encodable + Decodable> From<&T> for SerdeModuleEncodingBase64<T> {
912    fn from(value: &T) -> Self {
913        let mut bytes = vec![];
914        fedimint_core::encoding::Encodable::consensus_encode(value, &mut bytes)
915            .expect("Writing to buffer can never fail");
916        Self(bytes, PhantomData)
917    }
918}
919
920impl<T: Encodable + Decodable + 'static> SerdeModuleEncodingBase64<T> {
921    pub fn try_into_inner(&self, modules: &ModuleDecoderRegistry) -> Result<T, DecodeError> {
922        Decodable::consensus_decode_whole(&self.0, modules)
923    }
924
925    /// In cases where we know exactly which module kind we expect but don't
926    /// have access to all decoders this function can be used instead.
927    ///
928    /// Note that it just assumes the decoded module instance id to be valid
929    /// since it cannot validate against the decoder registry. The lack of
930    /// access to a decoder registry also makes decoding structs impossible that
931    /// themselves contain module dyn-types (e.g. a module output containing a
932    /// fedimint transaction).
933    pub fn try_into_inner_known_module_kind(&self, decoder: &Decoder) -> Result<T, DecodeError> {
934        let mut reader = std::io::Cursor::new(&self.0);
935        let module_instance = ModuleInstanceId::consensus_decode_partial(
936            &mut reader,
937            &ModuleDecoderRegistry::default(),
938        )?;
939
940        let total_len =
941            u64::consensus_decode_partial(&mut reader, &ModuleDecoderRegistry::default())?;
942
943        // No recursive module decoding is supported since we give an empty decoder
944        // registry to the decode function
945        decoder.decode_complete(
946            &mut reader,
947            total_len,
948            module_instance,
949            &ModuleRegistry::default(),
950        )
951    }
952}