1pub mod audit;
15pub mod registry;
16
17use std::collections::BTreeMap;
18use std::fmt::{self, Debug, Formatter};
19use std::marker::{self, PhantomData};
20use std::pin::Pin;
21use std::sync::atomic::{AtomicU64, Ordering};
22use std::sync::Arc;
23
24use fedimint_logging::LOG_NET_API;
25use futures::Future;
26use jsonrpsee_core::JsonValue;
27use registry::ModuleRegistry;
28use serde::{Deserialize, Serialize};
29use tracing::Instrument;
30
31mod version;
33pub use self::version::*;
34use crate::config::{
35 ClientModuleConfig, ConfigGenModuleParams, DkgPeerMsg, ModuleInitParams, ServerModuleConfig,
36 ServerModuleConsensusConfig,
37};
38use crate::core::{
39 ClientConfig, Decoder, DecoderBuilder, Input, InputError, ModuleConsensusItem,
40 ModuleInstanceId, ModuleKind, Output, OutputError, OutputOutcome,
41};
42use crate::db::{
43 Committable, CoreMigrationFn, Database, DatabaseKey, DatabaseKeyWithNotify, DatabaseRecord,
44 DatabaseTransaction, DatabaseVersion,
45};
46use crate::encoding::{Decodable, DecodeError, Encodable};
47use crate::fmt_utils::AbbreviateHexBytes;
48use crate::module::audit::Audit;
49use crate::net::peers::MuxPeerConnections;
50use crate::server::DynServerModule;
51use crate::task::{MaybeSend, TaskGroup};
52use crate::{
53 apply, async_trait_maybe_send, maybe_add_send, maybe_add_send_sync, Amount, NumPeers, OutPoint,
54 PeerId,
55};
56
57#[derive(Debug, PartialEq, Eq)]
58pub struct InputMeta {
59 pub amount: TransactionItemAmount,
60 pub pub_key: secp256k1::PublicKey,
61}
62
63#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
69pub struct TransactionItemAmount {
70 pub amount: Amount,
71 pub fee: Amount,
72}
73
74impl TransactionItemAmount {
75 pub const ZERO: Self = Self {
76 amount: Amount::ZERO,
77 fee: Amount::ZERO,
78 };
79}
80
81#[derive(Debug, Serialize, Deserialize, Clone)]
83pub struct ApiRequest<T> {
84 pub auth: Option<ApiAuth>,
86 pub params: T,
88}
89
90pub type ApiRequestErased = ApiRequest<JsonValue>;
91
92impl Default for ApiRequestErased {
93 fn default() -> Self {
94 Self {
95 auth: None,
96 params: JsonValue::Null,
97 }
98 }
99}
100
101impl ApiRequestErased {
102 pub fn new<T: Serialize>(params: T) -> Self {
103 Self {
104 auth: None,
105 params: serde_json::to_value(params)
106 .expect("parameter serialization error - this should not happen"),
107 }
108 }
109
110 pub fn to_json(&self) -> JsonValue {
111 serde_json::to_value(self).expect("parameter serialization error - this should not happen")
112 }
113
114 pub fn with_auth(self, auth: ApiAuth) -> Self {
115 Self {
116 auth: Some(auth),
117 params: self.params,
118 }
119 }
120
121 pub fn to_typed<T: serde::de::DeserializeOwned>(
122 self,
123 ) -> Result<ApiRequest<T>, serde_json::Error> {
124 Ok(ApiRequest {
125 auth: self.auth,
126 params: serde_json::from_value::<T>(self.params)?,
127 })
128 }
129}
130
131#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
133pub struct ApiAuth(pub String);
134
135impl Debug for ApiAuth {
136 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
137 write!(f, "ApiAuth(****)")
138 }
139}
140
141#[derive(Debug, Clone)]
142pub struct ApiError {
143 pub code: i32,
144 pub message: String,
145}
146
147impl ApiError {
148 pub fn new(code: i32, message: String) -> Self {
149 Self { code, message }
150 }
151
152 pub fn not_found(message: String) -> Self {
153 Self::new(404, message)
154 }
155
156 pub fn bad_request(message: String) -> Self {
157 Self::new(400, message)
158 }
159
160 pub fn unauthorized() -> Self {
161 Self::new(401, "Invalid authorization".to_string())
162 }
163
164 pub fn server_error(message: String) -> Self {
165 Self::new(500, message)
166 }
167}
168
169pub struct ApiEndpointContext<'dbtx> {
171 db: Database,
172 dbtx: DatabaseTransaction<'dbtx, Committable>,
173 has_auth: bool,
174 request_auth: Option<ApiAuth>,
175}
176
177impl<'a> ApiEndpointContext<'a> {
178 pub fn new(
180 db: Database,
181 dbtx: DatabaseTransaction<'a, Committable>,
182 has_auth: bool,
183 request_auth: Option<ApiAuth>,
184 ) -> Self {
185 Self {
186 db,
187 dbtx,
188 has_auth,
189 request_auth,
190 }
191 }
192
193 pub fn dbtx<'s, 'mtx>(&'s mut self) -> DatabaseTransaction<'mtx, Committable>
195 where
196 'a: 'mtx,
197 's: 'mtx,
198 {
199 self.dbtx.to_ref()
201 }
202
203 pub fn request_auth(&self) -> Option<ApiAuth> {
206 self.request_auth.clone()
207 }
208
209 pub fn has_auth(&self) -> bool {
212 self.has_auth
213 }
214
215 pub fn db(&self) -> Database {
216 self.db.clone()
217 }
218
219 pub fn wait_key_exists<K>(&self, key: K) -> impl Future<Output = K::Value>
221 where
222 K: DatabaseKey + DatabaseRecord + DatabaseKeyWithNotify,
223 {
224 let db = self.db.clone();
225 async move { db.wait_key_exists(&key).await }
228 }
229
230 pub fn wait_value_matches<K>(
232 &self,
233 key: K,
234 matcher: impl Fn(&K::Value) -> bool + Copy,
235 ) -> impl Future<Output = K::Value>
236 where
237 K: DatabaseKey + DatabaseRecord + DatabaseKeyWithNotify,
238 {
239 let db = self.db.clone();
240 async move { db.wait_key_check(&key, |v| v.filter(matcher)).await.0 }
241 }
242
243 pub async fn commit_tx_result(self, path: &'static str) -> Result<(), ApiError> {
245 self.dbtx.commit_tx_result().await.map_err(|err| {
246 tracing::warn!(
247 target: fedimint_logging::LOG_NET_API,
248 path,
249 "API server error when writing to database: {:?}",
250 err
251 );
252 ApiError {
253 code: 500,
254 message: "API server error when writing to database".to_string(),
255 }
256 })
257 }
258}
259
260#[apply(async_trait_maybe_send!)]
261pub trait TypedApiEndpoint {
262 type State: Sync;
263
264 const PATH: &'static str;
266
267 type Param: serde::de::DeserializeOwned + Send;
268 type Response: serde::Serialize;
269
270 async fn handle<'state, 'context, 'dbtx>(
271 state: &'state Self::State,
272 context: &'context mut ApiEndpointContext<'dbtx>,
273 request: Self::Param,
274 ) -> Result<Self::Response, ApiError>
275 where
276 'dbtx: 'context;
277}
278
279pub use serde_json;
280
281#[macro_export]
297macro_rules! __api_endpoint {
298 (
299 $path:expr,
300 $version_introduced:expr,
303 async |$state:ident: &$state_ty:ty, $context:ident, $param:ident: $param_ty:ty| -> $resp_ty:ty $body:block
304 ) => {{
305 struct Endpoint;
306
307 #[$crate::apply($crate::async_trait_maybe_send!)]
308 impl $crate::module::TypedApiEndpoint for Endpoint {
309 const PATH: &'static str = $path;
310 type State = $state_ty;
311 type Param = $param_ty;
312 type Response = $resp_ty;
313
314 async fn handle<'state, 'context, 'dbtx>(
315 $state: &'state Self::State,
316 $context: &'context mut $crate::module::ApiEndpointContext<'dbtx>,
317 $param: Self::Param,
318 ) -> ::std::result::Result<Self::Response, $crate::module::ApiError> {
319 {
320 const __API_VERSION: $crate::module::ApiVersion = $version_introduced;
322 }
323 $body
324 }
325 }
326
327 $crate::module::ApiEndpoint::from_typed::<Endpoint>()
328 }};
329}
330
331pub use __api_endpoint as api_endpoint;
332use fedimint_core::config::DkgResult;
333
334use self::registry::ModuleDecoderRegistry;
335
336type HandlerFnReturn<'a> =
337 Pin<Box<maybe_add_send!(dyn Future<Output = Result<serde_json::Value, ApiError>> + 'a)>>;
338type HandlerFn<M> = Box<
339 maybe_add_send_sync!(
340 dyn for<'a> Fn(&'a M, ApiEndpointContext<'a>, ApiRequestErased) -> HandlerFnReturn<'a>
341 ),
342>;
343
344pub struct ApiEndpoint<M> {
346 pub path: &'static str,
351 pub handler: HandlerFn<M>,
355}
356
357static REQ_ID: AtomicU64 = AtomicU64::new(0);
359
360impl ApiEndpoint<()> {
362 pub fn from_typed<E: TypedApiEndpoint>() -> ApiEndpoint<E::State>
363 where
364 <E as TypedApiEndpoint>::Response: MaybeSend,
365 E::Param: Debug,
366 E::Response: Debug,
367 {
368 async fn handle_request<'state, 'context, 'dbtx, E>(
369 state: &'state E::State,
370 context: &'context mut ApiEndpointContext<'dbtx>,
371 request: ApiRequest<E::Param>,
372 ) -> Result<E::Response, ApiError>
373 where
374 'dbtx: 'context,
375 E: TypedApiEndpoint,
376 E::Param: Debug,
377 E::Response: Debug,
378 {
379 tracing::debug!(target: LOG_NET_API, path = E::PATH, ?request, "received api request");
380 let result = E::handle(state, context, request.params).await;
381 if let Err(error) = &result {
382 tracing::warn!(target: LOG_NET_API, path = E::PATH, ?error, "api request error");
383 } else {
384 tracing::debug!(target: LOG_NET_API, path = E::PATH, "api request complete");
385 }
386 result
387 }
388
389 ApiEndpoint {
390 path: E::PATH,
391 handler: Box::new(|m, mut context, request| {
392 Box::pin(async {
393 let request = request
394 .to_typed()
395 .map_err(|e| ApiError::bad_request(e.to_string()))?;
396
397 let span = tracing::info_span!(
398 target: LOG_NET_API,
399 "api_req",
400 id = REQ_ID.fetch_add(1, Ordering::SeqCst),
401 method = E::PATH,
402 );
403 let ret = handle_request::<E>(m, &mut context, request)
404 .instrument(span)
405 .await?;
406
407 context.commit_tx_result(E::PATH).await?;
408
409 Ok(serde_json::to_value(ret).expect("encoding error"))
410 })
411 }),
412 }
413 }
414}
415
416#[apply(async_trait_maybe_send!)]
423pub trait IDynCommonModuleInit: Debug {
424 fn decoder(&self) -> Decoder;
425
426 fn module_kind(&self) -> ModuleKind;
427
428 fn to_dyn_common(&self) -> DynCommonModuleInit;
429
430 async fn dump_database(
431 &self,
432 dbtx: &mut DatabaseTransaction<'_>,
433 prefix_names: Vec<String>,
434 ) -> Box<dyn Iterator<Item = (String, Box<dyn erased_serde::Serialize + Send>)> + '_>;
435}
436
437pub trait ModuleInit: Debug + Clone + Send + Sync + 'static {
439 type Common: CommonModuleInit;
440
441 fn dump_database(
442 &self,
443 dbtx: &mut DatabaseTransaction<'_>,
444 prefix_names: Vec<String>,
445 ) -> maybe_add_send!(
446 impl Future<
447 Output = Box<
448 dyn Iterator<Item = (String, Box<dyn erased_serde::Serialize + Send>)> + '_,
449 >,
450 >
451 );
452}
453
454#[apply(async_trait_maybe_send!)]
455impl<T> IDynCommonModuleInit for T
456where
457 T: ModuleInit,
458{
459 fn decoder(&self) -> Decoder {
460 T::Common::decoder()
461 }
462
463 fn module_kind(&self) -> ModuleKind {
464 T::Common::KIND
465 }
466
467 fn to_dyn_common(&self) -> DynCommonModuleInit {
468 DynCommonModuleInit::from_inner(Arc::new(self.clone()))
469 }
470
471 async fn dump_database(
472 &self,
473 dbtx: &mut DatabaseTransaction<'_>,
474 prefix_names: Vec<String>,
475 ) -> Box<dyn Iterator<Item = (String, Box<dyn erased_serde::Serialize + Send>)> + '_> {
476 <Self as ModuleInit>::dump_database(self, dbtx, prefix_names).await
477 }
478}
479
480#[apply(async_trait_maybe_send!)]
490pub trait IServerModuleInit: IDynCommonModuleInit {
491 fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static);
492
493 fn supported_api_versions(&self) -> SupportedModuleApiVersions;
494
495 async fn init(
497 &self,
498 peer_num: NumPeers,
499 cfg: ServerModuleConfig,
500 db: Database,
501 task_group: &TaskGroup,
502 our_peer_id: PeerId,
503 ) -> anyhow::Result<DynServerModule>;
504
505 fn validate_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<()>;
506
507 fn trusted_dealer_gen(
508 &self,
509 peers: &[PeerId],
510 params: &ConfigGenModuleParams,
511 ) -> BTreeMap<PeerId, ServerModuleConfig>;
512
513 async fn distributed_gen(
514 &self,
515 peers: &PeerHandle,
516 params: &ConfigGenModuleParams,
517 ) -> DkgResult<ServerModuleConfig>;
518
519 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
520
521 fn get_client_config(
522 &self,
523 module_instance_id: ModuleInstanceId,
524 config: &ServerModuleConsensusConfig,
525 ) -> anyhow::Result<ClientModuleConfig>;
526
527 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, CoreMigrationFn>;
531}
532
533dyn_newtype_define!(
534 #[derive(Clone)]
535 pub DynCommonModuleInit(Arc<IDynCommonModuleInit>)
536);
537
538impl AsRef<maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)> for DynCommonModuleInit {
539 fn as_ref(&self) -> &(maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)) {
540 self.inner.as_ref()
541 }
542}
543
544impl DynCommonModuleInit {
545 pub fn from_inner(
546 inner: Arc<maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)>,
547 ) -> Self {
548 Self { inner }
549 }
550}
551
552dyn_newtype_define!(
553 #[derive(Clone)]
554 pub DynServerModuleInit(Arc<IServerModuleInit>)
555);
556
557impl AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static> for DynServerModuleInit {
558 fn as_ref(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
559 self.inner.as_common()
560 }
561}
562
563#[apply(async_trait_maybe_send!)]
565pub trait CommonModuleInit: Debug + Sized {
566 const CONSENSUS_VERSION: ModuleConsensusVersion;
567 const KIND: ModuleKind;
568
569 type ClientConfig: ClientConfig;
570
571 fn decoder() -> Decoder;
572}
573
574pub struct ServerModuleInitArgs<S>
575where
576 S: ServerModuleInit,
577{
578 cfg: ServerModuleConfig,
579 db: Database,
580 task_group: TaskGroup,
581 our_peer_id: PeerId,
582 num_peers: NumPeers,
583 _marker: marker::PhantomData<S>,
586}
587
588impl<S> ServerModuleInitArgs<S>
589where
590 S: ServerModuleInit,
591{
592 pub fn cfg(&self) -> &ServerModuleConfig {
593 &self.cfg
594 }
595
596 pub fn db(&self) -> &Database {
597 &self.db
598 }
599
600 pub fn num_peers(&self) -> NumPeers {
601 self.num_peers
602 }
603
604 pub fn task_group(&self) -> &TaskGroup {
605 &self.task_group
606 }
607
608 pub fn our_peer_id(&self) -> PeerId {
609 self.our_peer_id
610 }
611}
612#[apply(async_trait_maybe_send!)]
619pub trait ServerModuleInit: ModuleInit + Sized {
620 type Params: ModuleInitParams;
621
622 fn versions(&self, core: CoreConsensusVersion) -> &[ModuleConsensusVersion];
635
636 fn supported_api_versions(&self) -> SupportedModuleApiVersions;
637
638 fn kind() -> ModuleKind {
639 <Self as ModuleInit>::Common::KIND
640 }
641
642 async fn init(&self, args: &ServerModuleInitArgs<Self>) -> anyhow::Result<DynServerModule>;
644
645 fn parse_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<Self::Params> {
646 params.to_typed::<Self::Params>()
647 }
648
649 fn trusted_dealer_gen(
650 &self,
651 peers: &[PeerId],
652 params: &ConfigGenModuleParams,
653 ) -> BTreeMap<PeerId, ServerModuleConfig>;
654
655 async fn distributed_gen(
656 &self,
657 peer: &PeerHandle,
658 params: &ConfigGenModuleParams,
659 ) -> DkgResult<ServerModuleConfig>;
660
661 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()>;
662
663 fn get_client_config(
665 &self,
666 config: &ServerModuleConsensusConfig,
667 ) -> anyhow::Result<<<Self as ModuleInit>::Common as CommonModuleInit>::ClientConfig>;
668
669 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, CoreMigrationFn> {
673 BTreeMap::new()
674 }
675}
676
677#[apply(async_trait_maybe_send!)]
678impl<T> IServerModuleInit for T
679where
680 T: ServerModuleInit + 'static + Sync,
681{
682 fn as_common(&self) -> &(dyn IDynCommonModuleInit + Send + Sync + 'static) {
683 self
684 }
685
686 fn supported_api_versions(&self) -> SupportedModuleApiVersions {
687 <Self as ServerModuleInit>::supported_api_versions(self)
688 }
689
690 async fn init(
691 &self,
692 num_peers: NumPeers,
693 cfg: ServerModuleConfig,
694 db: Database,
695 task_group: &TaskGroup,
696 our_peer_id: PeerId,
697 ) -> anyhow::Result<DynServerModule> {
698 <Self as ServerModuleInit>::init(
699 self,
700 &ServerModuleInitArgs {
701 num_peers,
702 cfg,
703 db,
704 task_group: task_group.clone(),
705 our_peer_id,
706 _marker: PhantomData,
707 },
708 )
709 .await
710 }
711
712 fn validate_params(&self, params: &ConfigGenModuleParams) -> anyhow::Result<()> {
713 <Self as ServerModuleInit>::parse_params(self, params)?;
714 Ok(())
715 }
716
717 fn trusted_dealer_gen(
718 &self,
719 peers: &[PeerId],
720 params: &ConfigGenModuleParams,
721 ) -> BTreeMap<PeerId, ServerModuleConfig> {
722 <Self as ServerModuleInit>::trusted_dealer_gen(self, peers, params)
723 }
724
725 async fn distributed_gen(
726 &self,
727 peers: &PeerHandle,
728 params: &ConfigGenModuleParams,
729 ) -> DkgResult<ServerModuleConfig> {
730 <Self as ServerModuleInit>::distributed_gen(self, peers, params).await
731 }
732
733 fn validate_config(&self, identity: &PeerId, config: ServerModuleConfig) -> anyhow::Result<()> {
734 <Self as ServerModuleInit>::validate_config(self, identity, config)
735 }
736
737 fn get_client_config(
738 &self,
739 module_instance_id: ModuleInstanceId,
740 config: &ServerModuleConsensusConfig,
741 ) -> anyhow::Result<ClientModuleConfig> {
742 ClientModuleConfig::from_typed(
743 module_instance_id,
744 <Self as ServerModuleInit>::kind(),
745 config.version,
746 <Self as ServerModuleInit>::get_client_config(self, config)?,
747 )
748 }
749
750 fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, CoreMigrationFn> {
751 <Self as ServerModuleInit>::get_database_migrations(self)
752 }
753}
754
755pub trait ModuleCommon {
757 type ClientConfig: ClientConfig;
758 type Input: Input;
759 type Output: Output;
760 type OutputOutcome: OutputOutcome;
761 type ConsensusItem: ModuleConsensusItem;
762 type InputError: InputError;
763 type OutputError: OutputError;
764
765 fn decoder_builder() -> DecoderBuilder {
766 let mut decoder_builder = Decoder::builder();
767 decoder_builder.with_decodable_type::<Self::ClientConfig>();
768 decoder_builder.with_decodable_type::<Self::Input>();
769 decoder_builder.with_decodable_type::<Self::Output>();
770 decoder_builder.with_decodable_type::<Self::OutputOutcome>();
771 decoder_builder.with_decodable_type::<Self::ConsensusItem>();
772 decoder_builder.with_decodable_type::<Self::InputError>();
773 decoder_builder.with_decodable_type::<Self::OutputError>();
774
775 decoder_builder
776 }
777
778 fn decoder() -> Decoder {
779 Self::decoder_builder().build()
780 }
781}
782
783#[apply(async_trait_maybe_send!)]
784pub trait ServerModule: Debug + Sized {
785 type Common: ModuleCommon;
786
787 type Init: ServerModuleInit;
788
789 fn module_kind() -> ModuleKind {
790 <Self::Init as ModuleInit>::Common::KIND
793 }
794
795 fn decoder() -> Decoder {
804 Self::Common::decoder_builder().build()
805 }
806
807 async fn consensus_proposal<'a>(
822 &'a self,
823 dbtx: &mut DatabaseTransaction<'_>,
824 ) -> Vec<<Self::Common as ModuleCommon>::ConsensusItem>;
825
826 async fn process_consensus_item<'a, 'b>(
834 &'a self,
835 dbtx: &mut DatabaseTransaction<'b>,
836 consensus_item: <Self::Common as ModuleCommon>::ConsensusItem,
837 peer_id: PeerId,
838 ) -> anyhow::Result<()>;
839
840 fn verify_input(
844 &self,
845 _input: &<Self::Common as ModuleCommon>::Input,
846 ) -> Result<(), <Self::Common as ModuleCommon>::InputError> {
847 Ok(())
848 }
849
850 async fn process_input<'a, 'b, 'c>(
855 &'a self,
856 dbtx: &mut DatabaseTransaction<'c>,
857 input: &'b <Self::Common as ModuleCommon>::Input,
858 ) -> Result<InputMeta, <Self::Common as ModuleCommon>::InputError>;
859
860 async fn process_output<'a, 'b>(
869 &'a self,
870 dbtx: &mut DatabaseTransaction<'b>,
871 output: &'a <Self::Common as ModuleCommon>::Output,
872 out_point: OutPoint,
873 ) -> Result<TransactionItemAmount, <Self::Common as ModuleCommon>::OutputError>;
874
875 async fn output_status(
880 &self,
881 dbtx: &mut DatabaseTransaction<'_>,
882 out_point: OutPoint,
883 ) -> Option<<Self::Common as ModuleCommon>::OutputOutcome>;
884
885 async fn audit(
891 &self,
892 dbtx: &mut DatabaseTransaction<'_>,
893 audit: &mut Audit,
894 module_instance_id: ModuleInstanceId,
895 );
896
897 fn api_endpoints(&self) -> Vec<ApiEndpoint<Self>>;
902}
903
904#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
909pub struct SerdeModuleEncoding<T: Encodable + Decodable>(
910 #[serde(with = "::fedimint_core::encoding::as_hex")] Vec<u8>,
911 #[serde(skip)] PhantomData<T>,
912);
913
914impl<T> fmt::Debug for SerdeModuleEncoding<T>
915where
916 T: Encodable + Decodable,
917{
918 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
919 f.write_str("SerdeModuleEncoding(")?;
920 fmt::Debug::fmt(&AbbreviateHexBytes(&self.0), f)?;
921 f.write_str(")")?;
922 Ok(())
923 }
924}
925
926impl<T: Encodable + Decodable> From<&T> for SerdeModuleEncoding<T> {
927 fn from(value: &T) -> Self {
928 let mut bytes = vec![];
929 fedimint_core::encoding::Encodable::consensus_encode(value, &mut bytes)
930 .expect("Writing to buffer can never fail");
931 Self(bytes, PhantomData)
932 }
933}
934
935impl<T: Encodable + Decodable + 'static> SerdeModuleEncoding<T> {
936 pub fn try_into_inner(&self, modules: &ModuleDecoderRegistry) -> Result<T, DecodeError> {
937 let mut reader = std::io::Cursor::new(&self.0);
938 Decodable::consensus_decode(&mut reader, modules)
939 }
940
941 pub fn try_into_inner_known_module_kind(&self, decoder: &Decoder) -> Result<T, DecodeError> {
950 let mut reader = std::io::Cursor::new(&self.0);
951 let module_instance =
952 ModuleInstanceId::consensus_decode(&mut reader, &ModuleDecoderRegistry::default())?;
953
954 let total_len = u64::consensus_decode(&mut reader, &ModuleDecoderRegistry::default())?;
955
956 decoder.decode_complete(
959 &mut reader,
960 total_len,
961 module_instance,
962 &ModuleRegistry::default(),
963 )
964 }
965}
966
967#[non_exhaustive]
973pub struct PeerHandle<'a> {
974 #[doc(hidden)]
977 pub connections: &'a MuxPeerConnections<(ModuleInstanceId, String), DkgPeerMsg>,
978 #[doc(hidden)]
979 pub module_instance_id: ModuleInstanceId,
980 #[doc(hidden)]
981 pub our_id: PeerId,
982 #[doc(hidden)]
983 pub peers: Vec<PeerId>,
984}
985
986impl<'a> PeerHandle<'a> {
987 pub fn new(
988 connections: &'a MuxPeerConnections<(ModuleInstanceId, String), DkgPeerMsg>,
989 module_instance_id: ModuleInstanceId,
990 our_id: PeerId,
991 peers: Vec<PeerId>,
992 ) -> Self {
993 Self {
994 connections,
995 module_instance_id,
996 our_id,
997 peers,
998 }
999 }
1000
1001 pub fn peer_ids(&self) -> &[PeerId] {
1002 self.peers.as_slice()
1003 }
1004}