1use std::collections::{BTreeMap, BTreeSet};
2use std::fmt::{Debug, Display};
3use std::hash::Hash;
4use std::path::{Path, PathBuf};
5use std::str::FromStr;
6
7use bitcoin::hashes::sha256::HashEngine;
8use bitcoin::hashes::{Hash as BitcoinHash, hex, sha256};
9use bls12_381::Scalar;
10use fedimint_core::core::{ModuleInstanceId, ModuleKind};
11use fedimint_core::encoding::{DynRawFallback, Encodable};
12use fedimint_core::module::registry::ModuleRegistry;
13use fedimint_core::util::SafeUrl;
14use fedimint_core::{ModuleDecoderRegistry, format_hex};
15use fedimint_logging::LOG_CORE;
16use hex::FromHex;
17use secp256k1::PublicKey;
18use serde::de::DeserializeOwned;
19use serde::{Deserialize, Deserializer, Serialize, Serializer};
20use serde_json::json;
21use thiserror::Error;
22use threshold_crypto::{G1Projective, G2Projective};
23use tracing::warn;
24
25use crate::core::DynClientConfig;
26use crate::encoding::{Decodable, DecodeContext as _, DecodeError};
27use crate::module::{
28 CoreConsensusVersion, DynCommonModuleInit, IDynCommonModuleInit, ModuleConsensusVersion,
29 SerdeModuleEncoding,
30};
31use crate::session_outcome::SignedSessionOutcome;
32use crate::util::FmtCompact as _;
33use crate::{PeerId, maybe_add_send_sync, secp256k1};
34
35pub const ALEPH_BFT_UNIT_BYTE_LIMIT: usize = 50_000;
38
39#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
45pub struct JsonWithKind {
46 kind: ModuleKind,
47 #[serde(flatten)]
48 value: serde_json::Value,
49}
50
51impl JsonWithKind {
52 pub fn new(kind: ModuleKind, value: serde_json::Value) -> Self {
53 Self { kind, value }
54 }
55
56 pub fn with_fixed_empty_value(self) -> Self {
77 if let serde_json::Value::Object(ref o) = self.value
78 && o.is_empty()
79 {
80 return Self {
81 kind: self.kind,
82 value: serde_json::Value::Null,
83 };
84 }
85
86 self
87 }
88
89 pub fn value(&self) -> &serde_json::Value {
90 &self.value
91 }
92
93 pub fn kind(&self) -> &ModuleKind {
94 &self.kind
95 }
96
97 pub fn is_kind(&self, kind: &ModuleKind) -> bool {
98 &self.kind == kind
99 }
100}
101
102#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
103pub struct PeerUrl {
104 pub url: SafeUrl,
106 pub name: String,
108}
109
110#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
114pub struct ClientConfigV0 {
115 #[serde(flatten)]
116 pub global: GlobalClientConfigV0,
117 #[serde(deserialize_with = "de_int_key")]
118 pub modules: BTreeMap<ModuleInstanceId, ClientModuleConfig>,
119}
120
121#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
125pub struct ClientConfig {
126 #[serde(flatten)]
127 pub global: GlobalClientConfig,
128 #[serde(deserialize_with = "de_int_key")]
129 pub modules: BTreeMap<ModuleInstanceId, ClientModuleConfig>,
130}
131
132fn de_int_key<'de, D, K, V>(deserializer: D) -> Result<BTreeMap<K, V>, D::Error>
134where
135 D: Deserializer<'de>,
136 K: Eq + Ord + FromStr,
137 K::Err: Display,
138 V: Deserialize<'de>,
139{
140 let string_map = <BTreeMap<String, V>>::deserialize(deserializer)?;
141 let map = string_map
142 .into_iter()
143 .map(|(key_str, value)| {
144 let key = K::from_str(&key_str).map_err(serde::de::Error::custom)?;
145 Ok((key, value))
146 })
147 .collect::<Result<BTreeMap<_, _>, _>>()?;
148 Ok(map)
149}
150
151fn optional_de_int_key<'de, D, K, V>(deserializer: D) -> Result<Option<BTreeMap<K, V>>, D::Error>
152where
153 D: Deserializer<'de>,
154 K: Eq + Ord + FromStr,
155 K::Err: Display,
156 V: Deserialize<'de>,
157{
158 let Some(string_map) = <Option<BTreeMap<String, V>>>::deserialize(deserializer)? else {
159 return Ok(None);
160 };
161
162 let map = string_map
163 .into_iter()
164 .map(|(key_str, value)| {
165 let key = K::from_str(&key_str).map_err(serde::de::Error::custom)?;
166 Ok((key, value))
167 })
168 .collect::<Result<BTreeMap<_, _>, _>>()?;
169
170 Ok(Some(map))
171}
172
173#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
176pub struct JsonClientConfig {
177 pub global: GlobalClientConfig,
178 pub modules: BTreeMap<ModuleInstanceId, JsonWithKind>,
179}
180
181#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
183pub struct GlobalClientConfigV0 {
184 #[serde(deserialize_with = "de_int_key")]
186 pub api_endpoints: BTreeMap<PeerId, PeerUrl>,
187 pub consensus_version: CoreConsensusVersion,
189 pub meta: BTreeMap<String, String>,
192}
193
194#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
196pub struct GlobalClientConfig {
197 #[serde(deserialize_with = "de_int_key")]
199 pub api_endpoints: BTreeMap<PeerId, PeerUrl>,
200 #[serde(default, deserialize_with = "optional_de_int_key")]
203 pub broadcast_public_keys: Option<BTreeMap<PeerId, PublicKey>>,
204 pub consensus_version: CoreConsensusVersion,
206 pub meta: BTreeMap<String, String>,
209}
210
211impl GlobalClientConfig {
212 pub fn calculate_federation_id(&self) -> FederationId {
215 FederationId(self.api_endpoints.consensus_hash())
216 }
217
218 pub fn federation_name(&self) -> Option<&str> {
220 self.meta.get(META_FEDERATION_NAME_KEY).map(|x| &**x)
221 }
222}
223
224impl ClientConfig {
225 pub fn redecode_raw(
227 self,
228 modules: &ModuleDecoderRegistry,
229 ) -> Result<Self, crate::encoding::DecodeError> {
230 Ok(Self {
231 modules: self
232 .modules
233 .into_iter()
234 .map(|(module_id, v)| {
235 let kind = v.kind.clone();
238
239 v.redecode_raw(modules)
240 .context(format!("redecode_raw: instance: {module_id}, kind: {kind}"))
241 .map(|v| (module_id, v))
242 })
243 .collect::<Result<_, _>>()?,
244 ..self
245 })
246 }
247
248 pub fn calculate_federation_id(&self) -> FederationId {
249 self.global.calculate_federation_id()
250 }
251
252 pub fn meta<V: serde::de::DeserializeOwned + 'static>(
254 &self,
255 key: &str,
256 ) -> Result<Option<V>, ModuleConfigError> {
257 let Some(str_value) = self.global.meta.get(key) else {
258 return Ok(None);
259 };
260 let res =
261 serde_json::from_str(str_value)
262 .map(Some)
263 .map_err(|source| ModuleConfigError::Meta {
264 key: key.to_owned(),
265 source,
266 });
267
268 if res.is_err() && std::any::TypeId::of::<V>() == std::any::TypeId::of::<String>() {
272 let string_ret = Box::new(str_value.clone());
273 let ret = unsafe {
274 std::mem::transmute::<Box<String>, Box<V>>(string_ret)
276 };
277 Ok(Some(*ret))
278 } else {
279 res
280 }
281 }
282
283 pub fn to_json(&self) -> JsonClientConfig {
289 JsonClientConfig {
290 global: self.global.clone(),
291 modules: self
292 .modules
293 .iter()
294 .map(|(&module_instance_id, module_config)| {
295 let module_config_json = JsonWithKind {
296 kind: module_config.kind.clone(),
297 value: module_config.config
298 .clone()
299 .decoded()
300 .and_then(|dyn_cfg| dyn_cfg.to_json())
301 .unwrap_or_else(|| json!({
302 "unknown_module_hex": module_config.config.consensus_encode_to_hex()
303 })),
304 };
305 (module_instance_id, module_config_json)
306 })
307 .collect(),
308 }
309 }
310}
311
312#[derive(
318 Debug,
319 Copy,
320 Serialize,
321 Deserialize,
322 Clone,
323 Eq,
324 Hash,
325 PartialEq,
326 Encodable,
327 Decodable,
328 Ord,
329 PartialOrd,
330)]
331pub struct FederationId(pub sha256::Hash);
332
333#[derive(
334 Debug,
335 Copy,
336 Serialize,
337 Deserialize,
338 Clone,
339 Eq,
340 Hash,
341 PartialEq,
342 Encodable,
343 Decodable,
344 Ord,
345 PartialOrd,
346)]
347pub struct FederationIdPrefix([u8; 4]);
353
354impl Display for FederationIdPrefix {
355 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
356 format_hex(&self.0, f)
357 }
358}
359
360impl Display for FederationId {
361 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
362 format_hex(&self.0.to_byte_array(), f)
363 }
364}
365
366impl FromStr for FederationIdPrefix {
367 type Err = hex::HexToArrayError;
368
369 fn from_str(s: &str) -> Result<Self, Self::Err> {
370 Ok(Self(<[u8; 4]>::from_hex(s)?))
371 }
372}
373
374impl FederationIdPrefix {
375 pub fn to_bytes(&self) -> Vec<u8> {
376 self.0.to_vec()
377 }
378}
379
380impl FederationId {
382 pub fn dummy() -> Self {
384 Self(sha256::Hash::from_byte_array([42; 32]))
385 }
386
387 pub(crate) fn from_byte_array(bytes: [u8; 32]) -> Self {
388 Self(sha256::Hash::from_byte_array(bytes))
389 }
390
391 pub fn to_prefix(&self) -> FederationIdPrefix {
392 FederationIdPrefix(self.0[..4].try_into().expect("can't fail"))
393 }
394
395 pub fn to_fake_ln_pub_key(
405 &self,
406 secp: &bitcoin::secp256k1::Secp256k1<bitcoin::secp256k1::All>,
407 ) -> Result<bitcoin::secp256k1::PublicKey, bitcoin::secp256k1::Error> {
408 let sk = bitcoin::secp256k1::SecretKey::from_slice(&self.0.to_byte_array())?;
409 Ok(bitcoin::secp256k1::PublicKey::from_secret_key(secp, &sk))
410 }
411}
412
413impl FromStr for FederationId {
414 type Err = hex::HexToArrayError;
415
416 fn from_str(s: &str) -> Result<Self, Self::Err> {
417 Ok(Self::from_byte_array(<[u8; 32]>::from_hex(s)?))
418 }
419}
420
421impl ClientConfig {
422 pub fn consensus_hash(&self) -> sha256::Hash {
424 let mut engine = HashEngine::default();
425 self.consensus_encode(&mut engine)
426 .expect("Consensus hashing should never fail");
427 sha256::Hash::from_engine(engine)
428 }
429
430 pub fn get_module<T: Decodable + 'static>(
431 &self,
432 id: ModuleInstanceId,
433 ) -> Result<&T, ModuleConfigError> {
434 self.modules.get(&id).map_or_else(
435 || Err(ModuleConfigError::ModuleNotFound { id }),
436 |client_cfg| client_cfg.cast(),
437 )
438 }
439
440 pub fn get_module_cfg(
442 &self,
443 id: ModuleInstanceId,
444 ) -> Result<ClientModuleConfig, ModuleConfigError> {
445 self.modules.get(&id).map_or_else(
446 || Err(ModuleConfigError::ModuleNotFound { id }),
447 |client_cfg| Ok(client_cfg.clone()),
448 )
449 }
450
451 pub fn get_first_module_by_kind<T: Decodable + 'static>(
459 &self,
460 kind: impl Into<ModuleKind>,
461 ) -> Result<(ModuleInstanceId, &T), ModuleConfigError> {
462 let kind: ModuleKind = kind.into();
463 let Some((id, module_cfg)) = self.modules.iter().find(|(_, v)| v.is_kind(&kind)) else {
464 return Err(ModuleConfigError::KindNotFound { kind });
465 };
466 Ok((*id, module_cfg.cast()?))
467 }
468
469 pub fn get_first_module_by_kind_cfg(
471 &self,
472 kind: impl Into<ModuleKind>,
473 ) -> Result<(ModuleInstanceId, ClientModuleConfig), ModuleConfigError> {
474 let kind: ModuleKind = kind.into();
475 self.modules
476 .iter()
477 .find(|(_, v)| v.is_kind(&kind))
478 .map(|(id, v)| (*id, v.clone()))
479 .ok_or(ModuleConfigError::KindNotFound { kind })
480 }
481}
482
483#[derive(Clone, Debug)]
484pub struct ModuleInitRegistry<M>(BTreeMap<ModuleKind, M>);
485
486const LEGACY_MODULE_ORDER: &[&str] = &["ln", "mint", "wallet", "lnv2", "meta", "unknown"];
489
490impl<M> ModuleInitRegistry<M> {
491 pub fn iter(&self) -> impl Iterator<Item = (&ModuleKind, &M)> {
492 self.0.iter()
493 }
494
495 pub fn iter_legacy_order(&self) -> Vec<(&ModuleKind, &M)> {
499 let mut ordered: Vec<(&ModuleKind, &M)> = Vec::new();
500
501 for kind_str in LEGACY_MODULE_ORDER {
503 let kind = ModuleKind::from_static_str(kind_str);
504 if let Some((k, m)) = self.0.get_key_value(&kind) {
505 ordered.push((k, m));
506 }
507 }
508
509 for (kind, module) in &self.0 {
511 if !LEGACY_MODULE_ORDER.contains(&kind.as_str()) {
512 ordered.push((kind, module));
513 }
514 }
515
516 ordered
517 }
518}
519
520impl<M> Default for ModuleInitRegistry<M> {
521 fn default() -> Self {
522 Self(BTreeMap::new())
523 }
524}
525
526pub type CommonModuleInitRegistry = ModuleInitRegistry<DynCommonModuleInit>;
527
528impl<M> From<Vec<M>> for ModuleInitRegistry<M>
529where
530 M: AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static>,
531{
532 fn from(value: Vec<M>) -> Self {
533 Self(
534 value
535 .into_iter()
536 .map(|i| (i.as_ref().module_kind(), i))
537 .collect::<BTreeMap<_, _>>(),
538 )
539 }
540}
541
542impl<M> FromIterator<M> for ModuleInitRegistry<M>
543where
544 M: AsRef<maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)>,
545{
546 fn from_iter<T: IntoIterator<Item = M>>(iter: T) -> Self {
547 Self(
548 iter.into_iter()
549 .map(|i| (i.as_ref().module_kind(), i))
550 .collect::<BTreeMap<_, _>>(),
551 )
552 }
553}
554
555impl<M> ModuleInitRegistry<M> {
556 pub fn new() -> Self {
557 Self::default()
558 }
559
560 pub fn attach<T>(&mut self, r#gen: T)
561 where
562 T: Into<M> + 'static + Send + Sync,
563 M: AsRef<dyn IDynCommonModuleInit + 'static + Send + Sync>,
564 {
565 let r#gen: M = r#gen.into();
566 let kind = r#gen.as_ref().module_kind();
567 assert!(
568 self.0.insert(kind.clone(), r#gen).is_none(),
569 "Can't insert module of same kind twice: {kind}"
570 );
571 }
572
573 pub fn kinds(&self) -> BTreeSet<ModuleKind> {
574 self.0.keys().cloned().collect()
575 }
576
577 pub fn get(&self, k: &ModuleKind) -> Option<&M> {
578 self.0.get(k)
579 }
580}
581
582impl<M> ModuleInitRegistry<M>
583where
584 M: AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static>,
585{
586 #[deprecated(
587 note = "You probably want `available_decoders` to support missing module kinds. If you really want a strict behavior, use `decoders_strict`"
588 )]
589 pub fn decoders<'a>(
590 &self,
591 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
592 ) -> Result<ModuleDecoderRegistry, ModuleConfigError> {
593 self.decoders_strict(modules)
594 }
595
596 pub fn decoders_strict<'a>(
598 &self,
599 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
600 ) -> Result<ModuleDecoderRegistry, ModuleConfigError> {
601 let mut decoders = BTreeMap::new();
602 for (id, kind) in modules {
603 let Some(init) = self.0.get(kind) else {
604 return Err(ModuleConfigError::UnsupportedModule {
605 id,
606 kind: kind.clone(),
607 });
608 };
609
610 decoders.insert(id, (kind.clone(), init.as_ref().decoder()));
611 }
612 Ok(ModuleDecoderRegistry::from(decoders))
613 }
614
615 pub fn available_decoders<'a>(
617 &self,
618 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
619 ) -> ModuleDecoderRegistry {
620 let mut decoders = BTreeMap::new();
621 for (id, kind) in modules {
622 let Some(init) = self.0.get(kind) else {
623 warn!(target: LOG_CORE, "Unsupported module id: {id}, kind: {kind}");
624 continue;
625 };
626
627 decoders.insert(id, (kind.clone(), init.as_ref().decoder()));
628 }
629 ModuleDecoderRegistry::from(decoders)
630 }
631}
632
633#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
634pub struct ServerModuleConsensusConfig {
635 pub kind: ModuleKind,
636 pub version: ModuleConsensusVersion,
637 #[serde(with = "::hex::serde")]
638 pub config: Vec<u8>,
639}
640
641#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
647pub struct ClientModuleConfig {
648 pub kind: ModuleKind,
649 pub version: ModuleConsensusVersion,
650 #[serde(with = "::fedimint_core::encoding::as_hex")]
651 pub config: DynRawFallback<DynClientConfig>,
652}
653
654impl ClientModuleConfig {
655 pub fn from_typed<T: fedimint_core::core::ClientConfig>(
656 module_instance_id: ModuleInstanceId,
657 kind: ModuleKind,
658 version: ModuleConsensusVersion,
659 value: T,
660 ) -> Self {
661 Self {
662 kind,
663 version,
664 config: fedimint_core::core::DynClientConfig::from_typed(module_instance_id, value)
665 .into(),
666 }
667 }
668
669 pub fn redecode_raw(
670 self,
671 modules: &ModuleDecoderRegistry,
672 ) -> Result<Self, crate::encoding::DecodeError> {
673 Ok(Self {
674 config: self.config.redecode_raw(modules)?,
675 ..self
676 })
677 }
678
679 pub fn is_kind(&self, kind: &ModuleKind) -> bool {
680 &self.kind == kind
681 }
682
683 pub fn kind(&self) -> &ModuleKind {
684 &self.kind
685 }
686}
687
688impl ClientModuleConfig {
689 pub fn cast<T>(&self) -> Result<&T, ModuleConfigError>
690 where
691 T: 'static,
692 {
693 match &self.config {
694 DynRawFallback::Decoded(config) => {
695 config
696 .as_any()
697 .downcast_ref::<T>()
698 .ok_or_else(|| ModuleConfigError::WrongType {
699 kind: self.kind.clone(),
700 expected: std::any::type_name::<T>(),
701 })
702 }
703 DynRawFallback::Raw {
704 module_instance_id, ..
705 } => Err(ModuleConfigError::NotDecoded {
706 id: *module_instance_id,
707 kind: self.kind.clone(),
708 }),
709 }
710 }
711}
712
713#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
717pub struct ServerModuleConfig {
718 pub private: JsonWithKind,
719 pub consensus: ServerModuleConsensusConfig,
720}
721
722impl ServerModuleConfig {
723 pub fn from(private: JsonWithKind, consensus: ServerModuleConsensusConfig) -> Self {
724 Self { private, consensus }
725 }
726
727 pub fn to_typed<T: TypedServerModuleConfig>(&self) -> Result<T, ModuleConfigError> {
728 let private = serde_json::from_value(self.private.value().clone())?;
729 let consensus = <T::Consensus>::consensus_decode_whole(
730 &self.consensus.config[..],
731 &ModuleRegistry::default(),
732 )?;
733
734 Ok(TypedServerModuleConfig::from_parts(private, consensus))
735 }
736}
737
738pub trait TypedServerModuleConsensusConfig:
740 DeserializeOwned + Serialize + Encodable + Decodable
741{
742 fn kind(&self) -> ModuleKind;
743
744 fn version(&self) -> ModuleConsensusVersion;
745
746 fn from_erased(erased: &ServerModuleConsensusConfig) -> Result<Self, ModuleConfigError> {
747 Ok(Self::consensus_decode_whole(
748 &erased.config[..],
749 &ModuleRegistry::default(),
750 )?)
751 }
752}
753
754pub trait TypedServerModuleConfig: DeserializeOwned + Serialize {
756 type Private: DeserializeOwned + Serialize;
759 type Consensus: TypedServerModuleConsensusConfig;
761
762 fn from_parts(private: Self::Private, consensus: Self::Consensus) -> Self;
764
765 fn to_parts(self) -> (ModuleKind, Self::Private, Self::Consensus);
767
768 fn to_erased(self) -> ServerModuleConfig {
770 let (kind, private, consensus) = self.to_parts();
771
772 ServerModuleConfig {
773 private: JsonWithKind::new(
774 kind,
775 serde_json::to_value(private).expect("serialization can't fail"),
776 ),
777 consensus: ServerModuleConsensusConfig {
778 kind: consensus.kind(),
779 version: consensus.version(),
780 config: consensus.consensus_encode_to_vec(),
781 },
782 }
783 }
784}
785
786#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Encodable, Decodable)]
787pub enum P2PMessage {
788 Aleph(Vec<u8>),
789 SessionSignature(secp256k1::schnorr::Signature),
790 SessionIndex(u64),
791 SignedSessionOutcome(SerdeModuleEncoding<SignedSessionOutcome>),
792 Checksum(sha256::Hash),
793 DkgG1(DkgMessageG1),
794 DkgG2(DkgMessageG2),
795 Encodable(Vec<u8>),
796 #[encodable_default]
797 Default {
798 variant: u64,
799 bytes: Vec<u8>,
800 },
801}
802
803#[derive(Debug, PartialEq, Eq, Clone, Encodable, Decodable)]
804pub enum DkgMessageG1 {
805 Hash(sha256::Hash),
806 Commitment(Vec<G1Projective>),
807 Share(Scalar),
808}
809
810#[derive(Debug, PartialEq, Eq, Clone, Encodable, Decodable)]
811pub enum DkgMessageG2 {
812 Hash(sha256::Hash),
813 Commitment(Vec<G2Projective>),
814 Share(Scalar),
815}
816
817impl Serialize for DkgMessageG1 {
820 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
821 where
822 S: Serializer,
823 {
824 self.consensus_encode_to_hex().serialize(serializer)
825 }
826}
827
828impl<'de> Deserialize<'de> for DkgMessageG1 {
829 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
830 where
831 D: Deserializer<'de>,
832 {
833 Self::consensus_decode_hex(
834 &String::deserialize(deserializer)?,
835 &ModuleDecoderRegistry::default(),
836 )
837 .map_err(|e| serde::de::Error::custom(e.fmt_compact()))
838 }
839}
840
841impl Serialize for DkgMessageG2 {
844 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
845 where
846 S: Serializer,
847 {
848 self.consensus_encode_to_hex().serialize(serializer)
849 }
850}
851
852impl<'de> Deserialize<'de> for DkgMessageG2 {
853 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
854 where
855 D: Deserializer<'de>,
856 {
857 Self::consensus_decode_hex(
858 &String::deserialize(deserializer)?,
859 &ModuleDecoderRegistry::default(),
860 )
861 .map_err(|e| serde::de::Error::custom(e.fmt_compact()))
862 }
863}
864
865pub const META_FEDERATION_NAME_KEY: &str = "federation_name";
868
869pub fn load_from_file<T: DeserializeOwned>(path: &Path) -> Result<T, ConfigFileError> {
870 let contents = std::fs::read(path).map_err(|source| ConfigFileError::Io {
871 path: path.to_owned(),
872 source,
873 })?;
874
875 serde_json::from_slice(&contents).map_err(|source| ConfigFileError::Json {
876 path: path.to_owned(),
877 source,
878 })
879}
880
881#[derive(Debug, Error)]
887#[error("The relative fee of {parts_per_million} parts per million is over the limit of {max}")]
888pub struct ExcessiveRelativeFeeError {
889 pub parts_per_million: u64,
891 pub max: u64,
893}
894
895#[derive(Debug, Error)]
897#[non_exhaustive]
898pub enum ModuleConfigError {
899 #[error("Client config for module id {id} not found")]
901 ModuleNotFound { id: ModuleInstanceId },
902 #[error("Module kind {kind} not found")]
904 KindNotFound { kind: ModuleKind },
905 #[error("Client module config of kind {kind} is not a {expected}")]
907 WrongType {
908 kind: ModuleKind,
909 expected: &'static str,
910 },
911 #[error("Client module config for module id {id} of kind {kind} has not been decoded")]
915 NotDecoded {
916 id: ModuleInstanceId,
917 kind: ModuleKind,
918 },
919 #[error("Detected configuration for unsupported module id: {id}, kind: {kind}")]
921 UnsupportedModule {
922 id: ModuleInstanceId,
923 kind: ModuleKind,
924 },
925 #[error("Decoding meta field '{key}' failed")]
927 Meta {
928 key: String,
929 #[source]
930 source: serde_json::Error,
931 },
932 #[error("Invalid JSON in module config")]
934 Json(#[from] serde_json::Error),
935 #[error("Invalid consensus encoding in module config")]
937 Decode(#[from] DecodeError),
938}
939
940#[derive(Debug, Error)]
942#[non_exhaustive]
943pub enum ConfigFileError {
944 #[error("Failed to read config file {}", path.display())]
946 Io {
947 path: PathBuf,
948 #[source]
949 source: std::io::Error,
950 },
951 #[error("Invalid JSON in config file {}", path.display())]
953 Json {
954 path: PathBuf,
955 #[source]
956 source: serde_json::Error,
957 },
958}
959
960#[cfg(test)]
961mod tests;