/ fedimint-core / src / module / mod.rs
mod.rs
   1  //! Fedimint supports modules to allow extending it's functionality.
   2  //! Some of the standard functionality is implemented in form of modules as
   3  //! well.
   4  //!
   5  //! The top level server-side types are:
   6  //!
   7  //! * [`fedimint_core::module::ModuleInit`]
   8  //! * [`fedimint_core::module::ServerModule`]
   9  //!
  10  //! Top level client-side types are:
  11  //!
  12  //! * `ClientModuleInit` (in `fedimint_client`)
  13  //! * `ClientModule` (in `fedimint_client`)
  14  pub mod audit;
  15  pub mod registry;
  16  
  17  use std::collections::BTreeMap;
  18  use std::fmt::{self, Debug, Formatter};
  19  use std::marker::{self, PhantomData};
  20  use std::pin::Pin;
  21  use std::sync::atomic::{AtomicU64, Ordering};
  22  use std::sync::Arc;
  23  
  24  use fedimint_logging::LOG_NET_API;
  25  use futures::Future;
  26  use jsonrpsee_core::JsonValue;
  27  use serde::{Deserialize, Serialize};
  28  use tracing::Instrument;
  29  
  30  // TODO: Make this module public and remove the wildcard `pub use` below
  31  mod version;
  32  pub use self::version::*;
  33  use crate::config::{
  34      ClientModuleConfig, ConfigGenModuleParams, DkgPeerMsg, ModuleInitParams, ServerModuleConfig,
  35      ServerModuleConsensusConfig,
  36  };
  37  use crate::core::{
  38      ClientConfig, Decoder, DecoderBuilder, Input, InputError, ModuleConsensusItem,
  39      ModuleInstanceId, ModuleKind, Output, OutputError, OutputOutcome,
  40  };
  41  use crate::db::{
  42      Committable, Database, DatabaseKey, DatabaseKeyWithNotify, DatabaseRecord, DatabaseTransaction,
  43      DatabaseVersion, ServerMigrationFn,
  44  };
  45  use crate::encoding::{Decodable, DecodeError, Encodable};
  46  use crate::fmt_utils::AbbreviateHexBytes;
  47  use crate::module::audit::Audit;
  48  use crate::net::peers::MuxPeerConnections;
  49  use crate::server::DynServerModule;
  50  use crate::task::{MaybeSend, TaskGroup};
  51  use crate::{
  52      apply, async_trait_maybe_send, maybe_add_send, maybe_add_send_sync, Amount, NumPeers, OutPoint,
  53      PeerId,
  54  };
  55  
  56  #[derive(Debug, PartialEq)]
  57  pub struct InputMeta {
  58      pub amount: TransactionItemAmount,
  59      pub pub_key: secp256k1_zkp::PublicKey,
  60  }
  61  
  62  /// Information about the amount represented by an input or output.
  63  ///
  64  /// * For **inputs** the amount is funding the transaction while the fee is
  65  ///   consuming funding
  66  /// * For **outputs** the amount and the fee consume funding
  67  #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
  68  pub struct TransactionItemAmount {
  69      pub amount: Amount,
  70      pub fee: Amount,
  71  }
  72  
  73  impl TransactionItemAmount {
  74      pub const ZERO: TransactionItemAmount = TransactionItemAmount {
  75          amount: Amount::ZERO,
  76          fee: Amount::ZERO,
  77      };
  78  }
  79  
  80  /// All requests from client to server contain these fields
  81  #[derive(Debug, Serialize, Deserialize, Clone)]
  82  pub struct ApiRequest<T> {
  83      /// Hashed user password if the API requires authentication
  84      pub auth: Option<ApiAuth>,
  85      /// Parameters required by the API
  86      pub params: T,
  87  }
  88  
  89  pub type ApiRequestErased = ApiRequest<JsonValue>;
  90  
  91  impl Default for ApiRequestErased {
  92      fn default() -> Self {
  93          Self {
  94              auth: None,
  95              params: JsonValue::Null,
  96          }
  97      }
  98  }
  99  
 100  impl ApiRequestErased {
 101      pub fn new<T: Serialize>(params: T) -> ApiRequestErased {
 102          Self {
 103              auth: None,
 104              params: serde_json::to_value(params)
 105                  .expect("parameter serialization error - this should not happen"),
 106          }
 107      }
 108  
 109      pub fn to_json(&self) -> JsonValue {
 110          serde_json::to_value(self).expect("parameter serialization error - this should not happen")
 111      }
 112  
 113      pub fn with_auth(self, auth: ApiAuth) -> Self {
 114          Self {
 115              auth: Some(auth),
 116              params: self.params,
 117          }
 118      }
 119  
 120      pub fn to_typed<T: serde::de::DeserializeOwned>(
 121          self,
 122      ) -> Result<ApiRequest<T>, serde_json::Error> {
 123          Ok(ApiRequest {
 124              auth: self.auth,
 125              params: serde_json::from_value::<T>(self.params)?,
 126          })
 127      }
 128  }
 129  
 130  /// Authentication uses the hashed user password in PHC format
 131  #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
 132  pub struct ApiAuth(pub String);
 133  
 134  impl Debug for ApiAuth {
 135      fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
 136          write!(f, "ApiAuth(****)")
 137      }
 138  }
 139  
 140  #[derive(Debug, Clone)]
 141  pub struct ApiError {
 142      pub code: i32,
 143      pub message: String,
 144  }
 145  
 146  impl ApiError {
 147      pub fn new(code: i32, message: String) -> Self {
 148          Self { code, message }
 149      }
 150  
 151      pub fn not_found(message: String) -> Self {
 152          Self::new(404, message)
 153      }
 154  
 155      pub fn bad_request(message: String) -> Self {
 156          Self::new(400, message)
 157      }
 158  
 159      pub fn unauthorized() -> Self {
 160          Self::new(401, "Invalid authorization".to_string())
 161      }
 162  
 163      pub fn server_error(message: String) -> Self {
 164          Self::new(500, message)
 165      }
 166  }
 167  
 168  /// State made available to all API endpoints for handling a request
 169  pub struct ApiEndpointContext<'dbtx> {
 170      db: Database,
 171      dbtx: DatabaseTransaction<'dbtx, Committable>,
 172      has_auth: bool,
 173      request_auth: Option<ApiAuth>,
 174  }
 175  
 176  impl<'a> ApiEndpointContext<'a> {
 177      /// `db` and `dbtx` should be isolated.
 178      pub fn new(
 179          db: Database,
 180          dbtx: DatabaseTransaction<'a, Committable>,
 181          has_auth: bool,
 182          request_auth: Option<ApiAuth>,
 183      ) -> Self {
 184          Self {
 185              db,
 186              dbtx,
 187              has_auth,
 188              request_auth,
 189          }
 190      }
 191  
 192      /// Database tx handle, will be committed
 193      pub fn dbtx<'s, 'mtx>(&'s mut self) -> DatabaseTransaction<'mtx, Committable>
 194      where
 195          'a: 'mtx,
 196          's: 'mtx,
 197      {
 198          // dbtx is already isolated.
 199          self.dbtx.to_ref()
 200      }
 201  
 202      /// Returns the auth set on the request (regardless of whether it was
 203      /// correct)
 204      pub fn request_auth(&self) -> Option<ApiAuth> {
 205          self.request_auth.clone()
 206      }
 207  
 208      /// Whether the request was authenticated as the guardian who controls this
 209      /// fedimint server
 210      pub fn has_auth(&self) -> bool {
 211          self.has_auth
 212      }
 213  
 214      pub fn db(&self) -> Database {
 215          self.db.clone()
 216      }
 217  
 218      /// Waits for key to be present in database.
 219      pub fn wait_key_exists<K>(&self, key: K) -> impl Future<Output = K::Value>
 220      where
 221          K: DatabaseKey + DatabaseRecord + DatabaseKeyWithNotify,
 222      {
 223          let db = self.db.clone();
 224          // self contains dbtx which is !Send
 225          // try removing this and see the error.
 226          async move { db.wait_key_exists(&key).await }
 227      }
 228  
 229      /// Waits for key to have a value that matches.
 230      pub fn wait_value_matches<K>(
 231          &self,
 232          key: K,
 233          matcher: impl Fn(&K::Value) -> bool + Copy,
 234      ) -> impl Future<Output = K::Value>
 235      where
 236          K: DatabaseKey + DatabaseRecord + DatabaseKeyWithNotify,
 237      {
 238          let db = self.db.clone();
 239          async move { db.wait_key_check(&key, |v| v.filter(matcher)).await.0 }
 240      }
 241  
 242      /// Attempts to commit the dbtx or returns an ApiError
 243      pub async fn commit_tx_result(self, path: &'static str) -> Result<(), ApiError> {
 244          self.dbtx.commit_tx_result().await.map_err(|_err| {
 245              tracing::warn!(
 246                  target: fedimint_logging::LOG_NET_API,
 247                  path,
 248                  "API server error when writing to database: {:?}",
 249                  _err
 250              );
 251              ApiError {
 252                  code: 500,
 253                  message: "API server error when writing to database".to_string(),
 254              }
 255          })
 256      }
 257  }
 258  
 259  #[apply(async_trait_maybe_send!)]
 260  pub trait TypedApiEndpoint {
 261      type State: Sync;
 262  
 263      /// example: /transaction
 264      const PATH: &'static str;
 265  
 266      type Param: serde::de::DeserializeOwned + Send;
 267      type Response: serde::Serialize;
 268  
 269      async fn handle<'state, 'context, 'dbtx>(
 270          state: &'state Self::State,
 271          context: &'context mut ApiEndpointContext<'dbtx>,
 272          request: Self::Param,
 273      ) -> Result<Self::Response, ApiError>
 274      where
 275          'dbtx: 'context;
 276  }
 277  
 278  #[doc(hidden)]
 279  pub mod __reexports {
 280      pub use serde_json;
 281  }
 282  
 283  /// # Example
 284  ///
 285  /// ```rust
 286  /// # use fedimint_core::module::ApiVersion;
 287  /// # use fedimint_core::module::{api_endpoint, ApiEndpoint, registry::ModuleInstanceId};
 288  /// struct State;
 289  ///
 290  /// let _: ApiEndpoint<State> = api_endpoint! {
 291  ///     "/foobar",
 292  ///     ApiVersion::new(0, 3),
 293  ///     async |state: &State, _dbtx, params: ()| -> i32 {
 294  ///         Ok(0)
 295  ///     }
 296  /// };
 297  /// ```
 298  #[macro_export]
 299  macro_rules! __api_endpoint {
 300      (
 301          $path:expr,
 302          // Api Version this endpoint was introduced in, at the current consensus level
 303          // Currently for documentation purposes only.
 304          $version_introduced:expr,
 305          async |$state:ident: &$state_ty:ty, $context:ident, $param:ident: $param_ty:ty| -> $resp_ty:ty $body:block
 306      ) => {{
 307          struct Endpoint;
 308  
 309          #[$crate::apply($crate::async_trait_maybe_send!)]
 310          impl $crate::module::TypedApiEndpoint for Endpoint {
 311              const PATH: &'static str = $path;
 312              type State = $state_ty;
 313              type Param = $param_ty;
 314              type Response = $resp_ty;
 315  
 316              async fn handle<'state, 'context, 'dbtx>(
 317                  $state: &'state Self::State,
 318                  $context: &'context mut $crate::module::ApiEndpointContext<'dbtx>,
 319                  $param: Self::Param,
 320              ) -> ::std::result::Result<Self::Response, $crate::module::ApiError> {
 321                  {
 322                      // just to enforce the correct type
 323                      const __API_VERSION: $crate::module::ApiVersion = $version_introduced;
 324                  }
 325                  $body
 326              }
 327          }
 328  
 329          $crate::module::ApiEndpoint::from_typed::<Endpoint>()
 330      }};
 331  }
 332  
 333  pub use __api_endpoint as api_endpoint;
 334  use fedimint_core::config::DkgResult;
 335  
 336  use self::registry::ModuleDecoderRegistry;
 337  
 338  type HandlerFnReturn<'a> =
 339      Pin<Box<maybe_add_send!(dyn Future<Output = Result<serde_json::Value, ApiError>> + 'a)>>;
 340  type HandlerFn<M> = Box<
 341      maybe_add_send_sync!(
 342          dyn for<'a> Fn(&'a M, ApiEndpointContext<'a>, ApiRequestErased) -> HandlerFnReturn<'a>
 343      ),
 344  >;
 345  
 346  /// Definition of an API endpoint defined by a module `M`.
 347  pub struct ApiEndpoint<M> {
 348      /// Path under which the API endpoint can be reached. It should start with a
 349      /// `/` e.g. `/transaction`. E.g. this API endpoint would be reachable
 350      /// under `module_module_instance_id_transaction` depending on the
 351      /// module name returned by `[FedertionModule::api_base_name]`.
 352      pub path: &'static str,
 353      /// Handler for the API call that takes the following arguments:
 354      ///   * Reference to the module which defined it
 355      ///   * Request parameters parsed into JSON `[Value](serde_json::Value)`
 356      pub handler: HandlerFn<M>,
 357  }
 358  
 359  /// Global request ID used for logging
 360  static REQ_ID: AtomicU64 = AtomicU64::new(0);
 361  
 362  // <()> is used to avoid specify state.
 363  impl ApiEndpoint<()> {
 364      pub fn from_typed<E: TypedApiEndpoint>() -> ApiEndpoint<E::State>
 365      where
 366          <E as TypedApiEndpoint>::Response: MaybeSend,
 367          E::Param: Debug,
 368          E::Response: Debug,
 369      {
 370          async fn handle_request<'state, 'context, 'dbtx, E>(
 371              state: &'state E::State,
 372              context: &'context mut ApiEndpointContext<'dbtx>,
 373              request: ApiRequest<E::Param>,
 374          ) -> Result<E::Response, ApiError>
 375          where
 376              'dbtx: 'context,
 377              E: TypedApiEndpoint,
 378              E::Param: Debug,
 379              E::Response: Debug,
 380          {
 381              tracing::debug!(target: LOG_NET_API, path = E::PATH, ?request, "received api request");
 382              let result = E::handle(state, context, request.params).await;
 383              if let Err(error) = &result {
 384                  tracing::warn!(target: LOG_NET_API, path = E::PATH, ?error, "api request error");
 385              } else {
 386                  tracing::debug!(target: LOG_NET_API, path = E::PATH, "api request complete");
 387              }
 388              result
 389          }
 390  
 391          ApiEndpoint {
 392              path: E::PATH,
 393              handler: Box::new(|m, mut context, request| {
 394                  Box::pin(async move {
 395                      let request = request
 396                          .to_typed()
 397                          .map_err(|e| ApiError::bad_request(e.to_string()))?;
 398  
 399                      let span = tracing::info_span!(
 400                          target: LOG_NET_API,
 401                          "api_req",
 402                          id = REQ_ID.fetch_add(1, Ordering::SeqCst),
 403                          method = E::PATH,
 404                      );
 405                      let ret = handle_request::<E>(m, &mut context, request)
 406                          .instrument(span)
 407                          .await?;
 408  
 409                      context.commit_tx_result(E::PATH).await?;
 410  
 411                      Ok(serde_json::to_value(ret).expect("encoding error"))
 412                  })
 413              }),
 414          }
 415      }
 416  }
 417  
 418  /// Operations common to Server and Client side module gen dyn newtypes
 419  ///
 420  /// Due to conflict of `impl Trait for T` for both `ServerModuleInit` and
 421  /// `ClientModuleInit`, we can't really have a `ICommonModuleInit`, so to unify
 422  /// them in `ModuleInitRegistry` we move the common functionality to be an
 423  /// interface over their dyn newtype wrappers. A bit weird, but works.
 424  #[apply(async_trait_maybe_send!)]
 425  pub trait IDynCommonModuleInit: Debug {
 426      fn decoder(&self) -> Decoder;
 427  
 428      fn module_kind(&self) -> ModuleKind;
 429  
 430      fn to_dyn_common(&self) -> DynCommonModuleInit;
 431  
 432      fn database_version(&self) -> DatabaseVersion;
 433  
 434      async fn dump_database(
 435          &self,
 436          dbtx: &mut DatabaseTransaction<'_>,
 437          prefix_names: Vec<String>,
 438      ) -> Box<dyn Iterator<Item = (String, Box<dyn erased_serde::Serialize + Send>)> + '_>;
 439  }
 440  
 441  /// Trait implemented by every `*ModuleInit` (server or client side)
 442  pub trait ModuleInit: Debug + Clone + Send + Sync + 'static {
 443      type Common: CommonModuleInit;
 444  
 445      /// This represents the module's database version that the current code is
 446      /// compatible with. It is important to increment this value whenever a
 447      /// key or a value that is persisted to the database within the module
 448      /// changes. It is also important to add the corresponding
 449      /// migration function in `get_database_migrations` which should define how
 450      /// to move from the previous database version to the current version.
 451      const DATABASE_VERSION: DatabaseVersion;
 452  
 453      fn dump_database(
 454          &self,
 455          dbtx: &mut DatabaseTransaction<'_>,
 456          prefix_names: Vec<String>,
 457      ) -> maybe_add_send!(
 458          impl Future<
 459              Output = Box<
 460                  dyn Iterator<Item = (String, Box<dyn erased_serde::Serialize + Send>)> + '_,
 461              >,
 462          >
 463      );
 464  }
 465  
 466  #[apply(async_trait_maybe_send!)]
 467  impl<T> IDynCommonModuleInit for T
 468  where
 469      T: ModuleInit,
 470  {
 471      fn decoder(&self) -> Decoder {
 472          T::Common::decoder()
 473      }
 474  
 475      fn module_kind(&self) -> ModuleKind {
 476          T::Common::KIND
 477      }
 478  
 479      fn to_dyn_common(&self) -> DynCommonModuleInit {
 480          DynCommonModuleInit::from_inner(Arc::new(self.clone()))
 481      }
 482  
 483      fn database_version(&self) -> DatabaseVersion {
 484          <Self as ModuleInit>::DATABASE_VERSION
 485      }
 486  
 487      async fn dump_database(
 488          &self,
 489          dbtx: &mut DatabaseTransaction<'_>,
 490          prefix_names: Vec<String>,
 491      ) -> Box<dyn Iterator<Item = (String, Box<dyn erased_serde::Serialize + Send>)> + '_> {
 492          <Self as ModuleInit>::dump_database(self, dbtx, prefix_names).await
 493      }
 494  }
 495  
 496  /// Interface for Module Generation
 497  ///
 498  /// This trait contains the methods responsible for the module's
 499  /// - initialization
 500  /// - config generation
 501  /// - config validation
 502  ///
 503  /// Once the module configuration is ready, the module can be instantiated via
 504  /// `[Self::init]`.
 505  #[apply(async_trait_maybe_send!)]
 506  pub trait IServerModuleInit: IDynCommonModuleInit {
 507      fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static);
 508  
 509      fn supported_api_versions(&self) -> SupportedModuleApiVersions;
 510  
 511      /// Initialize the [`DynServerModule`] instance from its config
 512      async fn init(
 513          &self,
 514          peer_num: NumPeers,
 515          cfg: ServerModuleConfig,
 516          db: Database,
 517          task_group: &TaskGroup,
 518          our_peer_id: PeerId,
 519      ) -> anyhow::Result<DynServerModule>;
 520  
 521      fn validate_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<()>;
 522  
 523      fn trusted_dealer_gen(
 524          &self,
 525          peers: &[PeerId],
 526          params: &ConfigGenModuleParams,
 527      ) -> BTreeMap<PeerId, ServerModuleConfig>;
 528  
 529      async fn distributed_gen(
 530          &self,
 531          peers: &PeerHandle,
 532          params: &ConfigGenModuleParams,
 533      ) -> DkgResult<ServerModuleConfig>;
 534  
 535      fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
 536  
 537      fn get_client_config(
 538          &self,
 539          module_instance_id: ModuleInstanceId,
 540          config: &ServerModuleConsensusConfig,
 541      ) -> anyhow::Result<ClientModuleConfig>;
 542  
 543      /// Retrieves the migrations map from the server module to be applied to the
 544      /// database before the module is initialized. The migrations map is
 545      /// indexed on the from version.
 546      fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, ServerMigrationFn>;
 547  }
 548  
 549  dyn_newtype_define!(
 550      #[derive(Clone)]
 551      pub DynCommonModuleInit(Arc<IDynCommonModuleInit>)
 552  );
 553  
 554  impl AsRef<maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)> for DynCommonModuleInit {
 555      fn as_ref(&self) -> &(maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)) {
 556          self.inner.as_ref()
 557      }
 558  }
 559  
 560  impl DynCommonModuleInit {
 561      pub fn from_inner(
 562          inner: Arc<maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)>,
 563      ) -> Self {
 564          DynCommonModuleInit { inner }
 565      }
 566  }
 567  
 568  dyn_newtype_define!(
 569      #[derive(Clone)]
 570      pub DynServerModuleInit(Arc<IServerModuleInit>)
 571  );
 572  
 573  impl AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static> for DynServerModuleInit {
 574      fn as_ref(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
 575          self.inner.as_common()
 576      }
 577  }
 578  
 579  /// Logic and constant common between server side and client side modules
 580  #[apply(async_trait_maybe_send!)]
 581  pub trait CommonModuleInit: Debug + Sized {
 582      const CONSENSUS_VERSION: ModuleConsensusVersion;
 583      const KIND: ModuleKind;
 584  
 585      type ClientConfig: ClientConfig;
 586  
 587      fn decoder() -> Decoder;
 588  }
 589  
 590  pub struct ServerModuleInitArgs<S>
 591  where
 592      S: ServerModuleInit,
 593  {
 594      cfg: ServerModuleConfig,
 595      db: Database,
 596      task_group: TaskGroup,
 597      our_peer_id: PeerId,
 598      num_peers: NumPeers,
 599      // ClientModuleInitArgs needs a bound because sometimes we need
 600      // to pass associated-types data, so let's just put it here right away
 601      _marker: marker::PhantomData<S>,
 602  }
 603  
 604  impl<S> ServerModuleInitArgs<S>
 605  where
 606      S: ServerModuleInit,
 607  {
 608      pub fn cfg(&self) -> &ServerModuleConfig {
 609          &self.cfg
 610      }
 611  
 612      pub fn db(&self) -> &Database {
 613          &self.db
 614      }
 615  
 616      pub fn num_peers(&self) -> NumPeers {
 617          self.num_peers
 618      }
 619  
 620      pub fn task_group(&self) -> &TaskGroup {
 621          &self.task_group
 622      }
 623  
 624      pub fn our_peer_id(&self) -> PeerId {
 625          self.our_peer_id
 626      }
 627  }
 628  /// Module Generation trait with associated types
 629  ///
 630  /// Needs to be implemented by module generation type
 631  ///
 632  /// For examples, take a look at one of the `MintConfigGenerator`,
 633  /// `WalletConfigGenerator`, or `LightningConfigGenerator` structs.
 634  #[apply(async_trait_maybe_send!)]
 635  pub trait ServerModuleInit: ModuleInit + Sized {
 636      type Params: ModuleInitParams;
 637  
 638      /// Version of the module consensus supported by this implementation given a
 639      /// certain [`CoreConsensusVersion`].
 640      ///
 641      /// Refer to [`ModuleConsensusVersion`] for more information about
 642      /// versioning.
 643      ///
 644      /// One module implementation ([`ServerModuleInit`] of a given
 645      /// [`ModuleKind`]) can potentially implement multiple versions of the
 646      /// consensus, and depending on the config module instance config,
 647      /// instantiate the desired one. This method should expose all the
 648      /// available versions, purely for information, setup UI and sanity
 649      /// checking purposes.
 650      fn versions(&self, core: CoreConsensusVersion) -> &[ModuleConsensusVersion];
 651  
 652      fn supported_api_versions(&self) -> SupportedModuleApiVersions;
 653  
 654      fn kind() -> ModuleKind {
 655          <Self as ModuleInit>::Common::KIND
 656      }
 657  
 658      /// Initialize the [`DynServerModule`] instance from its config
 659      async fn init(&self, args: &ServerModuleInitArgs<Self>) -> anyhow::Result<DynServerModule>;
 660  
 661      fn parse_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<Self::Params> {
 662          params.to_typed::<Self::Params>()
 663      }
 664  
 665      fn trusted_dealer_gen(
 666          &self,
 667          peers: &[PeerId],
 668          params: &ConfigGenModuleParams,
 669      ) -> BTreeMap<PeerId, ServerModuleConfig>;
 670  
 671      async fn distributed_gen(
 672          &self,
 673          peer: &PeerHandle,
 674          params: &ConfigGenModuleParams,
 675      ) -> DkgResult<ServerModuleConfig>;
 676  
 677      fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
 678  
 679      /// Converts the consensus config into the client config
 680      fn get_client_config(
 681          &self,
 682          config: &ServerModuleConsensusConfig,
 683      ) -> anyhow::Result<<<Self as ModuleInit>::Common as CommonModuleInit>::ClientConfig>;
 684  
 685      /// Retrieves the migrations map from the server module to be applied to the
 686      /// database before the module is initialized. The migrations map is
 687      /// indexed on the from version.
 688      fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, ServerMigrationFn> {
 689          BTreeMap::new()
 690      }
 691  }
 692  
 693  #[apply(async_trait_maybe_send!)]
 694  impl<T> IServerModuleInit for T
 695  where
 696      T: ServerModuleInit + 'static + Sync,
 697  {
 698      fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
 699          self
 700      }
 701  
 702      fn supported_api_versions(&self) -> SupportedModuleApiVersions {
 703          <Self as ServerModuleInit>::supported_api_versions(self)
 704      }
 705  
 706      async fn init(
 707          &self,
 708          num_peers: NumPeers,
 709          cfg: ServerModuleConfig,
 710          db: Database,
 711          task_group: &TaskGroup,
 712          our_peer_id: PeerId,
 713      ) -> anyhow::Result<DynServerModule> {
 714          <Self as ServerModuleInit>::init(
 715              self,
 716              &ServerModuleInitArgs {
 717                  num_peers,
 718                  cfg,
 719                  db,
 720                  task_group: task_group.clone(),
 721                  our_peer_id,
 722                  _marker: Default::default(),
 723              },
 724          )
 725          .await
 726      }
 727  
 728      fn validate_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<()> {
 729          <Self as ServerModuleInit>::parse_params(self, params)?;
 730          Ok(())
 731      }
 732  
 733      fn trusted_dealer_gen(
 734          &self,
 735          peers: &[PeerId],
 736          params: &ConfigGenModuleParams,
 737      ) -> BTreeMap<PeerId, ServerModuleConfig> {
 738          <Self as ServerModuleInit>::trusted_dealer_gen(self, peers, params)
 739      }
 740  
 741      async fn distributed_gen(
 742          &self,
 743          peers: &PeerHandle,
 744          params: &ConfigGenModuleParams,
 745      ) -> DkgResult<ServerModuleConfig> {
 746          <Self as ServerModuleInit>::distributed_gen(self, peers, params).await
 747      }
 748  
 749      fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()> {
 750          <Self as ServerModuleInit>::validate_config(self, identity, config)
 751      }
 752  
 753      fn get_client_config(
 754          &self,
 755          module_instance_id: ModuleInstanceId,
 756          config: &ServerModuleConsensusConfig,
 757      ) -> anyhow::Result<ClientModuleConfig> {
 758          ClientModuleConfig::from_typed(
 759              module_instance_id,
 760              <Self as ServerModuleInit>::kind(),
 761              config.version,
 762              <Self as ServerModuleInit>::get_client_config(self, config)?,
 763          )
 764      }
 765  
 766      fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, ServerMigrationFn> {
 767          <Self as ServerModuleInit>::get_database_migrations(self)
 768      }
 769  }
 770  
 771  /// Module associated types required by both client and server
 772  pub trait ModuleCommon {
 773      type ClientConfig: ClientConfig;
 774      type Input: Input;
 775      type Output: Output;
 776      type OutputOutcome: OutputOutcome;
 777      type ConsensusItem: ModuleConsensusItem;
 778      type InputError: InputError;
 779      type OutputError: OutputError;
 780  
 781      fn decoder_builder() -> DecoderBuilder {
 782          let mut decoder_builder = Decoder::builder();
 783          decoder_builder.with_decodable_type::<Self::ClientConfig>();
 784          decoder_builder.with_decodable_type::<Self::Input>();
 785          decoder_builder.with_decodable_type::<Self::Output>();
 786          decoder_builder.with_decodable_type::<Self::OutputOutcome>();
 787          decoder_builder.with_decodable_type::<Self::ConsensusItem>();
 788          decoder_builder.with_decodable_type::<Self::InputError>();
 789          decoder_builder.with_decodable_type::<Self::OutputError>();
 790  
 791          decoder_builder
 792      }
 793  
 794      fn decoder() -> Decoder {
 795          Self::decoder_builder().build()
 796      }
 797  }
 798  
 799  #[apply(async_trait_maybe_send!)]
 800  pub trait ServerModule: Debug + Sized {
 801      type Common: ModuleCommon;
 802  
 803      type Init: ServerModuleInit;
 804  
 805      fn module_kind() -> ModuleKind {
 806          // Note: All modules should define kinds as &'static str, so this doesn't
 807          // allocate
 808          <Self::Init as ModuleInit>::Common::KIND
 809      }
 810  
 811      /// Returns a decoder for the following associated types of this module:
 812      /// * `ClientConfig`
 813      /// * `Input`
 814      /// * `Output`
 815      /// * `OutputOutcome`
 816      /// * `ConsensusItem`
 817      /// * `InputError`
 818      /// * `OutputError`
 819      fn decoder() -> Decoder {
 820          Self::Common::decoder_builder().build()
 821      }
 822  
 823      /// This module's contribution to the next consensus proposal. This method
 824      /// is only guaranteed to be called once every few seconds. Consensus items
 825      /// are not meant to be latency critical; do not create them as
 826      /// a response to a processed transaction. Only use consensus items to
 827      /// establish consensus on a value that is required to verify
 828      /// transactions, like unix time, block heights and feerates, and model all
 829      /// other state changes trough transactions. The intention for this method
 830      /// is to always return all available consensus items even if they are
 831      /// redundant while process_consensus_item returns an error for the
 832      /// redundant proposals.
 833      ///
 834      /// If you think you actually do require latency critical consensus items or
 835      /// have trouble designing your module in order to avoid them please contact
 836      /// the Fedimint developers.
 837      async fn consensus_proposal<'a>(
 838          &'a self,
 839          dbtx: &mut DatabaseTransaction<'_>,
 840      ) -> Vec<<Self::Common as ModuleCommon>::ConsensusItem>;
 841  
 842      /// This function is called once for every consensus item. The function
 843      /// should return Ok if and only if the consensus item changes
 844      /// the system state. *Therefore this method should return an error in case
 845      /// of merely redundant consensus items such that they will be purged from
 846      /// the history of the federation.* This enables consensus_proposal to
 847      /// return all available consensus item without wasting disk
 848      /// space with redundant consensus items.
 849      async fn process_consensus_item<'a, 'b>(
 850          &'a self,
 851          dbtx: &mut DatabaseTransaction<'b>,
 852          consensus_item: <Self::Common as ModuleCommon>::ConsensusItem,
 853          peer_id: PeerId,
 854      ) -> anyhow::Result<()>;
 855  
 856      /// Try to spend a transaction input. On success all necessary updates will
 857      /// be part of the database transaction. On failure (e.g. double spend)
 858      /// the database transaction is rolled back and the operation will take
 859      /// no effect.
 860      async fn process_input<'a, 'b, 'c>(
 861          &'a self,
 862          dbtx: &mut DatabaseTransaction<'c>,
 863          input: &'b <Self::Common as ModuleCommon>::Input,
 864      ) -> Result<InputMeta, <Self::Common as ModuleCommon>::InputError>;
 865  
 866      /// Try to create an output (e.g. issue notes, peg-out BTC, …). On success
 867      /// all necessary updates to the database will be part of the database
 868      /// transaction. On failure (e.g. double spend) the database transaction
 869      /// is rolled back and the operation will take no effect.
 870      ///
 871      /// The supplied `out_point` identifies the operation (e.g. a peg-out or
 872      /// note issuance) and can be used to retrieve its outcome later using
 873      /// `output_status`.
 874      async fn process_output<'a, 'b>(
 875          &'a self,
 876          dbtx: &mut DatabaseTransaction<'b>,
 877          output: &'a <Self::Common as ModuleCommon>::Output,
 878          out_point: OutPoint,
 879      ) -> Result<TransactionItemAmount, <Self::Common as ModuleCommon>::OutputError>;
 880  
 881      /// Retrieve the current status of the output. Depending on the module this
 882      /// might contain data needed by the client to access funds or give an
 883      /// estimate of when funds will be available. Returns `None` if the
 884      /// output is unknown, **NOT** if it is just not ready yet.
 885      async fn output_status(
 886          &self,
 887          dbtx: &mut DatabaseTransaction<'_>,
 888          out_point: OutPoint,
 889      ) -> Option<<Self::Common as ModuleCommon>::OutputOutcome>;
 890  
 891      /// Queries the database and returns all assets and liabilities of the
 892      /// module.
 893      ///
 894      /// Summing over all modules, if liabilities > assets then an error has
 895      /// occurred in the database and consensus should halt.
 896      async fn audit(
 897          &self,
 898          dbtx: &mut DatabaseTransaction<'_>,
 899          audit: &mut Audit,
 900          module_instance_id: ModuleInstanceId,
 901      );
 902  
 903      /// Returns a list of custom API endpoints defined by the module. These are
 904      /// made available both to users as well as to other modules. They thus
 905      /// should be deterministic, only dependant on their input and the
 906      /// current epoch.
 907      fn api_endpoints(&self) -> Vec<ApiEndpoint<Self>>;
 908  }
 909  
 910  /// Creates a struct that can be used to make our module-decodable structs
 911  /// interact with `serde`-based APIs (AlephBFT, jsonrpsee). It creates a wrapper
 912  /// that holds the data as serialized
 913  // bytes internally.
 914  #[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
 915  pub struct SerdeModuleEncoding<T: Encodable + Decodable>(
 916      #[serde(with = "::fedimint_core::encoding::as_hex")] Vec<u8>,
 917      #[serde(skip)] PhantomData<T>,
 918  );
 919  
 920  impl<T> fmt::Debug for SerdeModuleEncoding<T>
 921  where
 922      T: Encodable + Decodable,
 923  {
 924      fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 925          f.write_str("SerdeModuleEncoding(")?;
 926          fmt::Debug::fmt(&AbbreviateHexBytes(&self.0), f)?;
 927          f.write_str(")")?;
 928          Ok(())
 929      }
 930  }
 931  
 932  impl<T: Encodable + Decodable> From<&T> for SerdeModuleEncoding<T> {
 933      fn from(value: &T) -> Self {
 934          let mut bytes = vec![];
 935          fedimint_core::encoding::Encodable::consensus_encode(value, &mut bytes)
 936              .expect("Writing to buffer can never fail");
 937          Self(bytes, PhantomData)
 938      }
 939  }
 940  
 941  impl<T: Encodable + Decodable + 'static> SerdeModuleEncoding<T> {
 942      pub fn try_into_inner(&self, modules: &ModuleDecoderRegistry) -> Result<T, DecodeError> {
 943          let mut reader = std::io::Cursor::new(&self.0);
 944          Decodable::consensus_decode(&mut reader, modules)
 945      }
 946  
 947      /// In cases where we know exactly which module kind we expect but don't
 948      /// have access to all decoders this function can be used instead.
 949      ///
 950      /// Note that it just assumes the decoded module instance id to be valid
 951      /// since it cannot validate against the decoder registry. The lack of
 952      /// access to a decoder registry also makes decoding structs impossible that
 953      /// themselves contain module dyn-types (e.g. a module output containing a
 954      /// fedimint transaction).
 955      pub fn try_into_inner_known_module_kind(&self, decoder: &Decoder) -> Result<T, DecodeError> {
 956          let mut reader = std::io::Cursor::new(&self.0);
 957          let module_instance =
 958              ModuleInstanceId::consensus_decode(&mut reader, &ModuleDecoderRegistry::default())?;
 959  
 960          let total_len = u64::consensus_decode(&mut reader, &ModuleDecoderRegistry::default())?;
 961  
 962          // No recursive module decoding is supported since we give an empty decoder
 963          // registry to the decode function
 964          decoder.decode_complete(&mut reader, total_len, module_instance, &Default::default())
 965      }
 966  }
 967  
 968  /// A handle passed to [`ServerModuleInit::distributed_gen`]
 969  ///
 970  /// This struct encapsulates dkg data that the module should not have a direct
 971  /// access to, and implements higher level dkg operations available to the
 972  /// module to complete its distributed initialization inside the federation.
 973  #[non_exhaustive]
 974  pub struct PeerHandle<'a> {
 975      // TODO: this whole type should be a part of a `fedimint-server` and fields here inaccessible
 976      // to outside crates, but until `ServerModule` is not in `fedimint-server` this is impossible
 977      #[doc(hidden)]
 978      pub connections: &'a MuxPeerConnections<(ModuleInstanceId, String), DkgPeerMsg>,
 979      #[doc(hidden)]
 980      pub module_instance_id: ModuleInstanceId,
 981      #[doc(hidden)]
 982      pub our_id: PeerId,
 983      #[doc(hidden)]
 984      pub peers: Vec<PeerId>,
 985  }
 986  
 987  impl<'a> PeerHandle<'a> {
 988      pub fn new(
 989          connections: &'a MuxPeerConnections<(ModuleInstanceId, String), DkgPeerMsg>,
 990          module_instance_id: ModuleInstanceId,
 991          our_id: PeerId,
 992          peers: Vec<PeerId>,
 993      ) -> Self {
 994          Self {
 995              connections,
 996              module_instance_id,
 997              our_id,
 998              peers,
 999          }
1000      }
1001  
1002      pub fn peer_ids(&self) -> &[PeerId] {
1003          self.peers.as_slice()
1004      }
1005  }