1#[cfg(feature = "uniffi")]
2use std::collections::HashMap;
3use std::collections::{BTreeMap, BTreeSet};
4use std::fmt::{Debug, Display};
5use std::hash::Hash;
6use std::path::{Path, PathBuf};
7use std::str::FromStr;
8
9use anyhow::Context;
10use bitcoin::hashes::sha256::HashEngine;
11use bitcoin::hashes::{Hash as BitcoinHash, hex, sha256};
12use bls12_381::Scalar;
13use fedimint_core::core::{ModuleInstanceId, ModuleKind};
14use fedimint_core::encoding::{DynRawFallback, Encodable};
15use fedimint_core::module::registry::ModuleRegistry;
16use fedimint_core::util::SafeUrl;
17use fedimint_core::{ModuleDecoderRegistry, format_hex};
18use fedimint_logging::LOG_CORE;
19use hex::FromHex;
20use secp256k1::PublicKey;
21use serde::de::DeserializeOwned;
22use serde::{Deserialize, Deserializer, Serialize, Serializer};
23use serde_json::json;
24use thiserror::Error;
25use threshold_crypto::{G1Projective, G2Projective};
26use tracing::warn;
27
28use crate::core::DynClientConfig;
29use crate::encoding::{Decodable, DecodeError};
30use crate::module::{
31 CoreConsensusVersion, DynCommonModuleInit, IDynCommonModuleInit, ModuleConsensusVersion,
32 SerdeModuleEncoding,
33};
34use crate::session_outcome::SignedSessionOutcome;
35use crate::{PeerId, maybe_add_send_sync, secp256k1};
36
37pub const ALEPH_BFT_UNIT_BYTE_LIMIT: usize = 50_000;
40
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
47pub struct JsonWithKind {
48 kind: ModuleKind,
49 #[serde(flatten)]
50 value: serde_json::Value,
51}
52
53impl JsonWithKind {
54 pub fn new(kind: ModuleKind, value: serde_json::Value) -> Self {
55 Self { kind, value }
56 }
57
58 pub fn with_fixed_empty_value(self) -> Self {
79 if let serde_json::Value::Object(ref o) = self.value
80 && o.is_empty()
81 {
82 return Self {
83 kind: self.kind,
84 value: serde_json::Value::Null,
85 };
86 }
87
88 self
89 }
90
91 pub fn value(&self) -> &serde_json::Value {
92 &self.value
93 }
94
95 pub fn kind(&self) -> &ModuleKind {
96 &self.kind
97 }
98
99 pub fn is_kind(&self, kind: &ModuleKind) -> bool {
100 &self.kind == kind
101 }
102}
103
104#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
105#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
106pub struct PeerUrl {
107 pub url: SafeUrl,
109 pub name: String,
111}
112
113#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
117pub struct ClientConfigV0 {
118 #[serde(flatten)]
119 pub global: GlobalClientConfigV0,
120 #[serde(deserialize_with = "de_int_key")]
121 pub modules: BTreeMap<ModuleInstanceId, ClientModuleConfig>,
122}
123
124#[cfg(feature = "uniffi")]
129type ClientModulesMap = BTreeMap<ModuleInstanceId, ClientModuleConfig>;
130
131#[cfg(feature = "uniffi")]
132uniffi::custom_type!(ClientModulesMap, HashMap<ModuleInstanceId, ClientModuleConfig>, {
133 remote,
134 lower: |m| m.into_iter().collect(),
135 try_lift: |h| Ok(h.into_iter().collect()),
136});
137
138#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
142#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
143pub struct ClientConfig {
144 #[serde(flatten)]
145 pub global: GlobalClientConfig,
146 #[serde(deserialize_with = "de_int_key")]
147 pub modules: BTreeMap<ModuleInstanceId, ClientModuleConfig>,
148}
149
150#[cfg(feature = "uniffi")]
151uniffi::custom_type!(PublicKey, String, {
152 remote,
153 lower: |pk| pk.to_string(),
154 try_lift: |s| PublicKey::from_str(&s).map_err(|e| anyhow::anyhow!(e)),
155});
156
157fn de_int_key<'de, D, K, V>(deserializer: D) -> Result<BTreeMap<K, V>, D::Error>
159where
160 D: Deserializer<'de>,
161 K: Eq + Ord + FromStr,
162 K::Err: Display,
163 V: Deserialize<'de>,
164{
165 let string_map = <BTreeMap<String, V>>::deserialize(deserializer)?;
166 let map = string_map
167 .into_iter()
168 .map(|(key_str, value)| {
169 let key = K::from_str(&key_str).map_err(serde::de::Error::custom)?;
170 Ok((key, value))
171 })
172 .collect::<Result<BTreeMap<_, _>, _>>()?;
173 Ok(map)
174}
175
176fn optional_de_int_key<'de, D, K, V>(deserializer: D) -> Result<Option<BTreeMap<K, V>>, D::Error>
177where
178 D: Deserializer<'de>,
179 K: Eq + Ord + FromStr,
180 K::Err: Display,
181 V: Deserialize<'de>,
182{
183 let Some(string_map) = <Option<BTreeMap<String, V>>>::deserialize(deserializer)? else {
184 return Ok(None);
185 };
186
187 let map = string_map
188 .into_iter()
189 .map(|(key_str, value)| {
190 let key = K::from_str(&key_str).map_err(serde::de::Error::custom)?;
191 Ok((key, value))
192 })
193 .collect::<Result<BTreeMap<_, _>, _>>()?;
194
195 Ok(Some(map))
196}
197
198#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
201pub struct JsonClientConfig {
202 pub global: GlobalClientConfig,
203 pub modules: BTreeMap<ModuleInstanceId, JsonWithKind>,
204}
205
206#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
208pub struct GlobalClientConfigV0 {
209 #[serde(deserialize_with = "de_int_key")]
211 pub api_endpoints: BTreeMap<PeerId, PeerUrl>,
212 pub consensus_version: CoreConsensusVersion,
214 pub meta: BTreeMap<String, String>,
217}
218
219#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
221#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
222pub struct GlobalClientConfig {
223 #[serde(deserialize_with = "de_int_key")]
225 pub api_endpoints: BTreeMap<PeerId, PeerUrl>,
226 #[serde(default, deserialize_with = "optional_de_int_key")]
229 pub broadcast_public_keys: Option<BTreeMap<PeerId, PublicKey>>,
230 pub consensus_version: CoreConsensusVersion,
232 pub meta: BTreeMap<String, String>,
235}
236
237#[cfg(feature = "uniffi")]
242type ApiEndpointsMap = BTreeMap<PeerId, PeerUrl>;
243#[cfg(feature = "uniffi")]
244type BroadcastPublicKeysMap = BTreeMap<PeerId, PublicKey>;
245#[cfg(feature = "uniffi")]
246type MetaMap = BTreeMap<String, String>;
247
248#[cfg(feature = "uniffi")]
249uniffi::custom_type!(ApiEndpointsMap, HashMap<PeerId, PeerUrl>, {
250 remote,
251 lower: |m| m.into_iter().collect(),
252 try_lift: |h| Ok(h.into_iter().collect()),
253});
254
255#[cfg(feature = "uniffi")]
256uniffi::custom_type!(BroadcastPublicKeysMap, HashMap<PeerId, PublicKey>, {
257 remote,
258 lower: |m| m.into_iter().collect(),
259 try_lift: |h| Ok(h.into_iter().collect()),
260});
261
262#[cfg(feature = "uniffi")]
263uniffi::custom_type!(MetaMap, HashMap<String, String>, {
264 remote,
265 lower: |m| m.into_iter().collect(),
266 try_lift: |h| Ok(h.into_iter().collect()),
267});
268
269impl GlobalClientConfig {
270 pub fn calculate_federation_id(&self) -> FederationId {
273 FederationId(self.api_endpoints.consensus_hash())
274 }
275
276 pub fn federation_name(&self) -> Option<&str> {
278 self.meta.get(META_FEDERATION_NAME_KEY).map(|x| &**x)
279 }
280}
281
282impl ClientConfig {
283 pub fn redecode_raw(
285 self,
286 modules: &ModuleDecoderRegistry,
287 ) -> Result<Self, crate::encoding::DecodeError> {
288 Ok(Self {
289 modules: self
290 .modules
291 .into_iter()
292 .map(|(module_id, v)| {
293 let kind = v.kind.clone();
296
297 v.redecode_raw(modules)
298 .context(format!("redecode_raw: instance: {module_id}, kind: {kind}"))
299 .map(|v| (module_id, v))
300 })
301 .collect::<Result<_, _>>()?,
302 ..self
303 })
304 }
305
306 pub fn calculate_federation_id(&self) -> FederationId {
307 self.global.calculate_federation_id()
308 }
309
310 pub fn meta<V: serde::de::DeserializeOwned + 'static>(
312 &self,
313 key: &str,
314 ) -> Result<Option<V>, ModuleConfigError> {
315 let Some(str_value) = self.global.meta.get(key) else {
316 return Ok(None);
317 };
318 let res =
319 serde_json::from_str(str_value)
320 .map(Some)
321 .map_err(|source| ModuleConfigError::Meta {
322 key: key.to_owned(),
323 source,
324 });
325
326 if res.is_err() && std::any::TypeId::of::<V>() == std::any::TypeId::of::<String>() {
330 let string_ret = Box::new(str_value.clone());
331 let ret = unsafe {
332 std::mem::transmute::<Box<String>, Box<V>>(string_ret)
334 };
335 Ok(Some(*ret))
336 } else {
337 res
338 }
339 }
340
341 pub fn to_json(&self) -> JsonClientConfig {
347 JsonClientConfig {
348 global: self.global.clone(),
349 modules: self
350 .modules
351 .iter()
352 .map(|(&module_instance_id, module_config)| {
353 let module_config_json = JsonWithKind {
354 kind: module_config.kind.clone(),
355 value: module_config.config
356 .clone()
357 .decoded()
358 .and_then(|dyn_cfg| dyn_cfg.to_json())
359 .unwrap_or_else(|| json!({
360 "unknown_module_hex": module_config.config.consensus_encode_to_hex()
361 })),
362 };
363 (module_instance_id, module_config_json)
364 })
365 .collect(),
366 }
367 }
368}
369
370#[derive(
376 Debug,
377 Copy,
378 Serialize,
379 Deserialize,
380 Clone,
381 Eq,
382 Hash,
383 PartialEq,
384 Encodable,
385 Decodable,
386 Ord,
387 PartialOrd,
388)]
389pub struct FederationId(pub sha256::Hash);
390
391#[cfg(feature = "uniffi")]
392uniffi::custom_type!(FederationId, String, {
393 lower: |obj| obj.to_string(),
394 try_lift: |bytes| {
395 let obj: FederationId = bytes.parse().map_err(|e| anyhow::anyhow!("Failed to parse FederationId from string: {e}"))?;
396 Ok(obj)
397 },
398});
399
400#[derive(
401 Debug,
402 Copy,
403 Serialize,
404 Deserialize,
405 Clone,
406 Eq,
407 Hash,
408 PartialEq,
409 Encodable,
410 Decodable,
411 Ord,
412 PartialOrd,
413)]
414pub struct FederationIdPrefix([u8; 4]);
420
421impl Display for FederationIdPrefix {
422 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
423 format_hex(&self.0, f)
424 }
425}
426
427impl Display for FederationId {
428 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
429 format_hex(&self.0.to_byte_array(), f)
430 }
431}
432
433impl FromStr for FederationIdPrefix {
434 type Err = hex::HexToArrayError;
435
436 fn from_str(s: &str) -> Result<Self, Self::Err> {
437 Ok(Self(<[u8; 4]>::from_hex(s)?))
438 }
439}
440
441impl FederationIdPrefix {
442 pub fn to_bytes(&self) -> Vec<u8> {
443 self.0.to_vec()
444 }
445}
446
447impl FederationId {
449 pub fn dummy() -> Self {
451 Self(sha256::Hash::from_byte_array([42; 32]))
452 }
453
454 pub(crate) fn from_byte_array(bytes: [u8; 32]) -> Self {
455 Self(sha256::Hash::from_byte_array(bytes))
456 }
457
458 pub fn to_prefix(&self) -> FederationIdPrefix {
459 FederationIdPrefix(self.0[..4].try_into().expect("can't fail"))
460 }
461
462 pub fn to_fake_ln_pub_key(
472 &self,
473 secp: &bitcoin::secp256k1::Secp256k1<bitcoin::secp256k1::All>,
474 ) -> Result<bitcoin::secp256k1::PublicKey, bitcoin::secp256k1::Error> {
475 let sk = bitcoin::secp256k1::SecretKey::from_slice(&self.0.to_byte_array())?;
476 Ok(bitcoin::secp256k1::PublicKey::from_secret_key(secp, &sk))
477 }
478}
479
480impl FromStr for FederationId {
481 type Err = hex::HexToArrayError;
482
483 fn from_str(s: &str) -> Result<Self, Self::Err> {
484 Ok(Self::from_byte_array(<[u8; 32]>::from_hex(s)?))
485 }
486}
487
488impl ClientConfig {
489 pub fn consensus_hash(&self) -> sha256::Hash {
491 let mut engine = HashEngine::default();
492 self.consensus_encode(&mut engine)
493 .expect("Consensus hashing should never fail");
494 sha256::Hash::from_engine(engine)
495 }
496
497 pub fn get_module<T: Decodable + 'static>(
498 &self,
499 id: ModuleInstanceId,
500 ) -> Result<&T, ModuleConfigError> {
501 self.modules.get(&id).map_or_else(
502 || Err(ModuleConfigError::ModuleNotFound { id }),
503 |client_cfg| client_cfg.cast(),
504 )
505 }
506
507 pub fn get_module_cfg(
509 &self,
510 id: ModuleInstanceId,
511 ) -> Result<ClientModuleConfig, ModuleConfigError> {
512 self.modules.get(&id).map_or_else(
513 || Err(ModuleConfigError::ModuleNotFound { id }),
514 |client_cfg| Ok(client_cfg.clone()),
515 )
516 }
517
518 pub fn get_first_module_by_kind<T: Decodable + 'static>(
526 &self,
527 kind: impl Into<ModuleKind>,
528 ) -> Result<(ModuleInstanceId, &T), ModuleConfigError> {
529 let kind: ModuleKind = kind.into();
530 let Some((id, module_cfg)) = self.modules.iter().find(|(_, v)| v.is_kind(&kind)) else {
531 return Err(ModuleConfigError::KindNotFound { kind });
532 };
533 Ok((*id, module_cfg.cast()?))
534 }
535
536 pub fn get_first_module_by_kind_cfg(
538 &self,
539 kind: impl Into<ModuleKind>,
540 ) -> Result<(ModuleInstanceId, ClientModuleConfig), ModuleConfigError> {
541 let kind: ModuleKind = kind.into();
542 self.modules
543 .iter()
544 .find(|(_, v)| v.is_kind(&kind))
545 .map(|(id, v)| (*id, v.clone()))
546 .ok_or(ModuleConfigError::KindNotFound { kind })
547 }
548}
549
550#[derive(Clone, Debug)]
551pub struct ModuleInitRegistry<M>(BTreeMap<ModuleKind, M>);
552
553const LEGACY_MODULE_ORDER: &[&str] = &["ln", "mint", "wallet", "lnv2", "meta", "unknown"];
556
557impl<M> ModuleInitRegistry<M> {
558 pub fn iter(&self) -> impl Iterator<Item = (&ModuleKind, &M)> {
559 self.0.iter()
560 }
561
562 pub fn iter_legacy_order(&self) -> Vec<(&ModuleKind, &M)> {
566 let mut ordered: Vec<(&ModuleKind, &M)> = Vec::new();
567
568 for kind_str in LEGACY_MODULE_ORDER {
570 let kind = ModuleKind::from_static_str(kind_str);
571 if let Some((k, m)) = self.0.get_key_value(&kind) {
572 ordered.push((k, m));
573 }
574 }
575
576 for (kind, module) in &self.0 {
578 if !LEGACY_MODULE_ORDER.contains(&kind.as_str()) {
579 ordered.push((kind, module));
580 }
581 }
582
583 ordered
584 }
585}
586
587impl<M> Default for ModuleInitRegistry<M> {
588 fn default() -> Self {
589 Self(BTreeMap::new())
590 }
591}
592
593pub type CommonModuleInitRegistry = ModuleInitRegistry<DynCommonModuleInit>;
594
595impl<M> From<Vec<M>> for ModuleInitRegistry<M>
596where
597 M: AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static>,
598{
599 fn from(value: Vec<M>) -> Self {
600 Self(
601 value
602 .into_iter()
603 .map(|i| (i.as_ref().module_kind(), i))
604 .collect::<BTreeMap<_, _>>(),
605 )
606 }
607}
608
609impl<M> FromIterator<M> for ModuleInitRegistry<M>
610where
611 M: AsRef<maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)>,
612{
613 fn from_iter<T: IntoIterator<Item = M>>(iter: T) -> Self {
614 Self(
615 iter.into_iter()
616 .map(|i| (i.as_ref().module_kind(), i))
617 .collect::<BTreeMap<_, _>>(),
618 )
619 }
620}
621
622impl<M> ModuleInitRegistry<M> {
623 pub fn new() -> Self {
624 Self::default()
625 }
626
627 pub fn attach<T>(&mut self, r#gen: T)
628 where
629 T: Into<M> + 'static + Send + Sync,
630 M: AsRef<dyn IDynCommonModuleInit + 'static + Send + Sync>,
631 {
632 let r#gen: M = r#gen.into();
633 let kind = r#gen.as_ref().module_kind();
634 assert!(
635 self.0.insert(kind.clone(), r#gen).is_none(),
636 "Can't insert module of same kind twice: {kind}"
637 );
638 }
639
640 pub fn kinds(&self) -> BTreeSet<ModuleKind> {
641 self.0.keys().cloned().collect()
642 }
643
644 pub fn get(&self, k: &ModuleKind) -> Option<&M> {
645 self.0.get(k)
646 }
647}
648
649impl<M> ModuleInitRegistry<M>
650where
651 M: AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static>,
652{
653 #[deprecated(
654 note = "You probably want `available_decoders` to support missing module kinds. If you really want a strict behavior, use `decoders_strict`"
655 )]
656 pub fn decoders<'a>(
657 &self,
658 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
659 ) -> Result<ModuleDecoderRegistry, ModuleConfigError> {
660 self.decoders_strict(modules)
661 }
662
663 pub fn decoders_strict<'a>(
665 &self,
666 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
667 ) -> Result<ModuleDecoderRegistry, ModuleConfigError> {
668 let mut decoders = BTreeMap::new();
669 for (id, kind) in modules {
670 let Some(init) = self.0.get(kind) else {
671 return Err(ModuleConfigError::UnsupportedModule {
672 id,
673 kind: kind.clone(),
674 });
675 };
676
677 decoders.insert(id, (kind.clone(), init.as_ref().decoder()));
678 }
679 Ok(ModuleDecoderRegistry::from(decoders))
680 }
681
682 pub fn available_decoders<'a>(
684 &self,
685 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
686 ) -> ModuleDecoderRegistry {
687 let mut decoders = BTreeMap::new();
688 for (id, kind) in modules {
689 let Some(init) = self.0.get(kind) else {
690 warn!(target: LOG_CORE, "Unsupported module id: {id}, kind: {kind}");
691 continue;
692 };
693
694 decoders.insert(id, (kind.clone(), init.as_ref().decoder()));
695 }
696 ModuleDecoderRegistry::from(decoders)
697 }
698}
699
700#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
701pub struct ServerModuleConsensusConfig {
702 pub kind: ModuleKind,
703 pub version: ModuleConsensusVersion,
704 #[serde(with = "::hex::serde")]
705 pub config: Vec<u8>,
706}
707
708#[cfg(feature = "uniffi")]
715type ClientModuleConfigRaw = DynRawFallback<DynClientConfig>;
716
717#[cfg(feature = "uniffi")]
718uniffi::custom_type!(ClientModuleConfigRaw, String, {
719 lower: |v| v.consensus_encode_to_hex(),
720 try_lift: |s| {
721 ClientModuleConfigRaw::consensus_decode_hex(&s, &ModuleDecoderRegistry::default())
722 .map_err(|e| anyhow::anyhow!("Failed to decode client module config: {e}"))
723 },
724});
725
726#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
732#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
733pub struct ClientModuleConfig {
734 pub kind: ModuleKind,
735 pub version: ModuleConsensusVersion,
736 #[serde(with = "::fedimint_core::encoding::as_hex")]
737 pub config: DynRawFallback<DynClientConfig>,
738}
739
740impl ClientModuleConfig {
741 pub fn from_typed<T: fedimint_core::core::ClientConfig>(
742 module_instance_id: ModuleInstanceId,
743 kind: ModuleKind,
744 version: ModuleConsensusVersion,
745 value: T,
746 ) -> Self {
747 Self {
748 kind,
749 version,
750 config: fedimint_core::core::DynClientConfig::from_typed(module_instance_id, value)
751 .into(),
752 }
753 }
754
755 pub fn redecode_raw(
756 self,
757 modules: &ModuleDecoderRegistry,
758 ) -> Result<Self, crate::encoding::DecodeError> {
759 Ok(Self {
760 config: self.config.redecode_raw(modules)?,
761 ..self
762 })
763 }
764
765 pub fn is_kind(&self, kind: &ModuleKind) -> bool {
766 &self.kind == kind
767 }
768
769 pub fn kind(&self) -> &ModuleKind {
770 &self.kind
771 }
772}
773
774impl ClientModuleConfig {
775 pub fn cast<T>(&self) -> Result<&T, ModuleConfigError>
776 where
777 T: 'static,
778 {
779 match &self.config {
780 DynRawFallback::Decoded(config) => {
781 config
782 .as_any()
783 .downcast_ref::<T>()
784 .ok_or_else(|| ModuleConfigError::WrongType {
785 kind: self.kind.clone(),
786 expected: std::any::type_name::<T>(),
787 })
788 }
789 DynRawFallback::Raw {
790 module_instance_id, ..
791 } => Err(ModuleConfigError::NotDecoded {
792 id: *module_instance_id,
793 kind: self.kind.clone(),
794 }),
795 }
796 }
797}
798
799#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
803pub struct ServerModuleConfig {
804 pub private: JsonWithKind,
805 pub consensus: ServerModuleConsensusConfig,
806}
807
808impl ServerModuleConfig {
809 pub fn from(private: JsonWithKind, consensus: ServerModuleConsensusConfig) -> Self {
810 Self { private, consensus }
811 }
812
813 pub fn to_typed<T: TypedServerModuleConfig>(&self) -> Result<T, ModuleConfigError> {
814 let private = serde_json::from_value(self.private.value().clone())?;
815 let consensus = <T::Consensus>::consensus_decode_whole(
816 &self.consensus.config[..],
817 &ModuleRegistry::default(),
818 )?;
819
820 Ok(TypedServerModuleConfig::from_parts(private, consensus))
821 }
822}
823
824pub trait TypedServerModuleConsensusConfig:
826 DeserializeOwned + Serialize + Encodable + Decodable
827{
828 fn kind(&self) -> ModuleKind;
829
830 fn version(&self) -> ModuleConsensusVersion;
831
832 fn from_erased(erased: &ServerModuleConsensusConfig) -> Result<Self, ModuleConfigError> {
833 Ok(Self::consensus_decode_whole(
834 &erased.config[..],
835 &ModuleRegistry::default(),
836 )?)
837 }
838}
839
840pub trait TypedServerModuleConfig: DeserializeOwned + Serialize {
842 type Private: DeserializeOwned + Serialize;
845 type Consensus: TypedServerModuleConsensusConfig;
847
848 fn from_parts(private: Self::Private, consensus: Self::Consensus) -> Self;
850
851 fn to_parts(self) -> (ModuleKind, Self::Private, Self::Consensus);
853
854 fn to_erased(self) -> ServerModuleConfig {
856 let (kind, private, consensus) = self.to_parts();
857
858 ServerModuleConfig {
859 private: JsonWithKind::new(
860 kind,
861 serde_json::to_value(private).expect("serialization can't fail"),
862 ),
863 consensus: ServerModuleConsensusConfig {
864 kind: consensus.kind(),
865 version: consensus.version(),
866 config: consensus.consensus_encode_to_vec(),
867 },
868 }
869 }
870}
871
872#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Encodable, Decodable)]
873pub enum P2PMessage {
874 Aleph(Vec<u8>),
875 SessionSignature(secp256k1::schnorr::Signature),
876 SessionIndex(u64),
877 SignedSessionOutcome(SerdeModuleEncoding<SignedSessionOutcome>),
878 Checksum(sha256::Hash),
879 DkgG1(DkgMessageG1),
880 DkgG2(DkgMessageG2),
881 Encodable(Vec<u8>),
882 #[encodable_default]
883 Default {
884 variant: u64,
885 bytes: Vec<u8>,
886 },
887}
888
889#[derive(Debug, PartialEq, Eq, Clone, Encodable, Decodable)]
890pub enum DkgMessageG1 {
891 Hash(sha256::Hash),
892 Commitment(Vec<G1Projective>),
893 Share(Scalar),
894}
895
896#[derive(Debug, PartialEq, Eq, Clone, Encodable, Decodable)]
897pub enum DkgMessageG2 {
898 Hash(sha256::Hash),
899 Commitment(Vec<G2Projective>),
900 Share(Scalar),
901}
902
903impl Serialize for DkgMessageG1 {
906 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
907 where
908 S: Serializer,
909 {
910 self.consensus_encode_to_hex().serialize(serializer)
911 }
912}
913
914impl<'de> Deserialize<'de> for DkgMessageG1 {
915 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
916 where
917 D: Deserializer<'de>,
918 {
919 Self::consensus_decode_hex(
920 &String::deserialize(deserializer)?,
921 &ModuleDecoderRegistry::default(),
922 )
923 .map_err(serde::de::Error::custom)
924 }
925}
926
927impl Serialize for DkgMessageG2 {
930 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
931 where
932 S: Serializer,
933 {
934 self.consensus_encode_to_hex().serialize(serializer)
935 }
936}
937
938impl<'de> Deserialize<'de> for DkgMessageG2 {
939 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
940 where
941 D: Deserializer<'de>,
942 {
943 Self::consensus_decode_hex(
944 &String::deserialize(deserializer)?,
945 &ModuleDecoderRegistry::default(),
946 )
947 .map_err(serde::de::Error::custom)
948 }
949}
950
951pub const META_FEDERATION_NAME_KEY: &str = "federation_name";
954
955pub fn load_from_file<T: DeserializeOwned>(path: &Path) -> Result<T, ConfigFileError> {
956 let contents = std::fs::read(path).map_err(|source| ConfigFileError::Io {
957 path: path.to_owned(),
958 source,
959 })?;
960
961 serde_json::from_slice(&contents).map_err(|source| ConfigFileError::Json {
962 path: path.to_owned(),
963 source,
964 })
965}
966
967#[derive(Debug, Error)]
969#[non_exhaustive]
970pub enum ModuleConfigError {
971 #[error("Client config for module id {id} not found")]
973 ModuleNotFound { id: ModuleInstanceId },
974 #[error("Module kind {kind} not found")]
976 KindNotFound { kind: ModuleKind },
977 #[error("Client module config of kind {kind} is not a {expected}")]
979 WrongType {
980 kind: ModuleKind,
981 expected: &'static str,
982 },
983 #[error("Client module config for module id {id} of kind {kind} has not been decoded")]
987 NotDecoded {
988 id: ModuleInstanceId,
989 kind: ModuleKind,
990 },
991 #[error("Detected configuration for unsupported module id: {id}, kind: {kind}")]
993 UnsupportedModule {
994 id: ModuleInstanceId,
995 kind: ModuleKind,
996 },
997 #[error("Decoding meta field '{key}' failed")]
999 Meta {
1000 key: String,
1001 #[source]
1002 source: serde_json::Error,
1003 },
1004 #[error("Invalid JSON in module config")]
1006 Json(#[from] serde_json::Error),
1007 #[error("Invalid consensus encoding in module config")]
1009 Decode(#[from] DecodeError),
1010}
1011
1012#[derive(Debug, Error)]
1014#[non_exhaustive]
1015pub enum ConfigFileError {
1016 #[error("Failed to read config file {}", path.display())]
1018 Io {
1019 path: PathBuf,
1020 #[source]
1021 source: std::io::Error,
1022 },
1023 #[error("Invalid JSON in config file {}", path.display())]
1025 Json {
1026 path: PathBuf,
1027 #[source]
1028 source: serde_json::Error,
1029 },
1030}
1031
1032#[cfg(test)]
1033mod tests;