1use std::collections::{BTreeMap, BTreeSet};
2use std::fmt::{Debug, Display};
3use std::hash::Hash;
4use std::ops::Mul;
5use std::path::Path;
6use std::str::FromStr;
7
8use anyhow::{bail, format_err, Context};
9use bitcoin::hashes::sha256::{Hash as Sha256, HashEngine};
10use bitcoin::hashes::{hex, sha256, Hash as BitcoinHash};
11use bls12_381::Scalar;
12use fedimint_core::core::{ModuleInstanceId, ModuleKind};
13use fedimint_core::encoding::{DynRawFallback, Encodable};
14use fedimint_core::module::registry::ModuleRegistry;
15use fedimint_core::util::SafeUrl;
16use fedimint_core::{format_hex, ModuleDecoderRegistry};
17use fedimint_logging::LOG_CORE;
18use hex::FromHex;
19use secp256k1::PublicKey;
20use serde::de::DeserializeOwned;
21use serde::ser::SerializeMap;
22use serde::{Deserialize, Deserializer, Serialize, Serializer};
23use serde_json::json;
24use threshold_crypto::group::{Curve, Group, GroupEncoding};
25use threshold_crypto::{G1Projective, G2Projective};
26use tracing::warn;
27
28use crate::core::DynClientConfig;
29use crate::encoding::Decodable;
30use crate::module::{
31 CoreConsensusVersion, DynCommonModuleInit, IDynCommonModuleInit, ModuleConsensusVersion,
32};
33use crate::{bls12_381_serde, maybe_add_send_sync, PeerId};
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 if o.is_empty() {
79 return Self {
80 kind: self.kind,
81 value: serde_json::Value::Null,
82 };
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(|(k, v)| {
235 let kind = v.kind.clone();
238 v.redecode_raw(modules)
239 .context(format!("redecode_raw: instance: {k}, kind: {kind}"))
240 .map(|v| (k, v))
241 })
242 .collect::<Result<_, _>>()?,
243 ..self
244 })
245 }
246
247 pub fn calculate_federation_id(&self) -> FederationId {
248 self.global.calculate_federation_id()
249 }
250
251 pub fn meta<V: serde::de::DeserializeOwned + 'static>(
253 &self,
254 key: &str,
255 ) -> Result<Option<V>, anyhow::Error> {
256 let Some(str_value) = self.global.meta.get(key) else {
257 return Ok(None);
258 };
259 let res = serde_json::from_str(str_value)
260 .map(Some)
261 .context(format!("Decoding meta field '{key}' failed"));
262
263 if res.is_err() && std::any::TypeId::of::<V>() == std::any::TypeId::of::<String>() {
267 let string_ret = Box::new(str_value.clone());
268 let ret = unsafe {
269 std::mem::transmute::<Box<String>, Box<V>>(string_ret)
271 };
272 Ok(Some(*ret))
273 } else {
274 res
275 }
276 }
277
278 pub fn to_json(&self) -> JsonClientConfig {
284 JsonClientConfig {
285 global: self.global.clone(),
286 modules: self
287 .modules
288 .iter()
289 .map(|(&module_instance_id, module_config)| {
290 let module_config_json = JsonWithKind {
291 kind: module_config.kind.clone(),
292 value: module_config.config
293 .clone()
294 .decoded()
295 .and_then(|dyn_cfg| dyn_cfg.to_json())
296 .unwrap_or_else(|| json!({
297 "unknown_module_hex": module_config.config.consensus_encode_to_hex()
298 })),
299 };
300 (module_instance_id, module_config_json)
301 })
302 .collect(),
303 }
304 }
305}
306
307#[derive(
313 Debug,
314 Copy,
315 Serialize,
316 Deserialize,
317 Clone,
318 Eq,
319 Hash,
320 PartialEq,
321 Encodable,
322 Decodable,
323 Ord,
324 PartialOrd,
325)]
326pub struct FederationId(pub sha256::Hash);
327
328#[derive(
329 Debug,
330 Copy,
331 Serialize,
332 Deserialize,
333 Clone,
334 Eq,
335 Hash,
336 PartialEq,
337 Encodable,
338 Decodable,
339 Ord,
340 PartialOrd,
341)]
342pub struct FederationIdPrefix([u8; 4]);
348
349impl Display for FederationIdPrefix {
350 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
351 format_hex(&self.0, f)
352 }
353}
354
355impl Display for FederationId {
356 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
357 format_hex(&self.0.to_byte_array(), f)
358 }
359}
360
361impl FromStr for FederationIdPrefix {
362 type Err = anyhow::Error;
363
364 fn from_str(s: &str) -> Result<Self, Self::Err> {
365 Ok(Self(<[u8; 4]>::from_hex(s)?))
366 }
367}
368
369impl FederationIdPrefix {
370 pub fn to_bytes(&self) -> Vec<u8> {
371 self.0.to_vec()
372 }
373}
374
375impl FederationId {
377 pub fn dummy() -> Self {
379 Self(sha256::Hash::from_byte_array([42; 32]))
380 }
381
382 pub(crate) fn from_byte_array(bytes: [u8; 32]) -> Self {
383 Self(sha256::Hash::from_byte_array(bytes))
384 }
385
386 pub fn to_prefix(&self) -> FederationIdPrefix {
387 FederationIdPrefix(self.0[..4].try_into().expect("can't fail"))
388 }
389
390 pub fn to_fake_ln_pub_key(
400 &self,
401 secp: &bitcoin::secp256k1::Secp256k1<bitcoin::secp256k1::All>,
402 ) -> anyhow::Result<bitcoin::secp256k1::PublicKey> {
403 let sk = bitcoin::secp256k1::SecretKey::from_slice(&self.0.to_byte_array())?;
404 Ok(bitcoin::secp256k1::PublicKey::from_secret_key(secp, &sk))
405 }
406}
407
408impl FromStr for FederationId {
409 type Err = anyhow::Error;
410
411 fn from_str(s: &str) -> Result<Self, Self::Err> {
412 Ok(Self::from_byte_array(<[u8; 32]>::from_hex(s)?))
413 }
414}
415
416impl ClientConfig {
417 pub fn consensus_hash(&self) -> sha256::Hash {
419 let mut engine = HashEngine::default();
420 self.consensus_encode(&mut engine)
421 .expect("Consensus hashing should never fail");
422 sha256::Hash::from_engine(engine)
423 }
424
425 pub fn get_module<T: Decodable + 'static>(&self, id: ModuleInstanceId) -> anyhow::Result<&T> {
426 self.modules.get(&id).map_or_else(
427 || Err(format_err!("Client config for module id {id} not found")),
428 |client_cfg| client_cfg.cast(),
429 )
430 }
431
432 pub fn get_module_cfg(&self, id: ModuleInstanceId) -> anyhow::Result<ClientModuleConfig> {
434 self.modules.get(&id).map_or_else(
435 || Err(format_err!("Client config for module id {id} not found")),
436 |client_cfg| Ok(client_cfg.clone()),
437 )
438 }
439
440 pub fn get_first_module_by_kind<T: Decodable + 'static>(
448 &self,
449 kind: impl Into<ModuleKind>,
450 ) -> anyhow::Result<(ModuleInstanceId, &T)> {
451 let kind: ModuleKind = kind.into();
452 let Some((id, module_cfg)) = self.modules.iter().find(|(_, v)| v.is_kind(&kind)) else {
453 anyhow::bail!("Module kind {kind} not found")
454 };
455 Ok((*id, module_cfg.cast()?))
456 }
457
458 pub fn get_first_module_by_kind_cfg(
460 &self,
461 kind: impl Into<ModuleKind>,
462 ) -> anyhow::Result<(ModuleInstanceId, ClientModuleConfig)> {
463 let kind: ModuleKind = kind.into();
464 self.modules
465 .iter()
466 .find(|(_, v)| v.is_kind(&kind))
467 .map(|(id, v)| (*id, v.clone()))
468 .ok_or_else(|| anyhow::format_err!("Module kind {kind} not found"))
469 }
470}
471
472#[derive(Clone, Debug)]
473pub struct ModuleInitRegistry<M>(BTreeMap<ModuleKind, M>);
474
475impl<M> ModuleInitRegistry<M> {
476 pub fn iter(&self) -> impl Iterator<Item = (&ModuleKind, &M)> {
477 self.0.iter()
478 }
479}
480
481impl<M> Default for ModuleInitRegistry<M> {
482 fn default() -> Self {
483 Self(BTreeMap::new())
484 }
485}
486
487#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
490pub struct ConfigGenModuleParams {
491 pub local: serde_json::Value,
492 pub consensus: serde_json::Value,
493}
494
495impl ConfigGenModuleParams {
496 pub fn new(local: serde_json::Value, consensus: serde_json::Value) -> Self {
497 Self { local, consensus }
498 }
499
500 pub fn to_typed<P: ModuleInitParams>(&self) -> anyhow::Result<P> {
503 Ok(P::from_parts(
504 Self::parse("local", self.local.clone())?,
505 Self::parse("consensus", self.consensus.clone())?,
506 ))
507 }
508
509 fn parse<P: DeserializeOwned>(name: &str, json: serde_json::Value) -> anyhow::Result<P> {
510 serde_json::from_value(json).with_context(|| format!("Schema mismatch for {name} argument"))
511 }
512
513 pub fn from_typed<P: ModuleInitParams>(p: P) -> anyhow::Result<Self> {
514 let (local, consensus) = p.to_parts();
515 Ok(Self {
516 local: serde_json::to_value(local)?,
517 consensus: serde_json::to_value(consensus)?,
518 })
519 }
520}
521
522pub type CommonModuleInitRegistry = ModuleInitRegistry<DynCommonModuleInit>;
523
524pub type ServerModuleConfigGenParamsRegistry = ModuleRegistry<ConfigGenModuleParams>;
526
527impl Eq for ServerModuleConfigGenParamsRegistry {}
528
529impl PartialEq for ServerModuleConfigGenParamsRegistry {
530 fn eq(&self, other: &Self) -> bool {
531 self.iter_modules().eq(other.iter_modules())
532 }
533}
534
535impl Serialize for ServerModuleConfigGenParamsRegistry {
536 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
537 let modules: Vec<_> = self.iter_modules().collect();
538 let mut serializer = serializer.serialize_map(Some(modules.len()))?;
539 for (id, kind, params) in modules {
540 serializer.serialize_key(&id)?;
541 serializer.serialize_value(&(kind.clone(), params.clone()))?;
542 }
543 serializer.end()
544 }
545}
546
547impl<'de> Deserialize<'de> for ServerModuleConfigGenParamsRegistry {
548 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
549 where
550 D: Deserializer<'de>,
551 {
552 let json: BTreeMap<ModuleInstanceId, (ModuleKind, ConfigGenModuleParams)> =
553 Deserialize::deserialize(deserializer)?;
554 let mut params = BTreeMap::new();
555
556 for (id, (kind, module)) in json {
557 params.insert(id, (kind, module));
558 }
559 Ok(Self::from(params))
560 }
561}
562
563impl<M> From<Vec<M>> for ModuleInitRegistry<M>
564where
565 M: AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static>,
566{
567 fn from(value: Vec<M>) -> Self {
568 Self(
569 value
570 .into_iter()
571 .map(|i| (i.as_ref().module_kind(), i))
572 .collect::<BTreeMap<_, _>>(),
573 )
574 }
575}
576
577impl<M> FromIterator<M> for ModuleInitRegistry<M>
578where
579 M: AsRef<maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)>,
580{
581 fn from_iter<T: IntoIterator<Item = M>>(iter: T) -> Self {
582 Self(
583 iter.into_iter()
584 .map(|i| (i.as_ref().module_kind(), i))
585 .collect::<BTreeMap<_, _>>(),
586 )
587 }
588}
589
590impl<M> ModuleInitRegistry<M> {
591 pub fn new() -> Self {
592 Self::default()
593 }
594
595 pub fn attach<T>(&mut self, gen: T)
596 where
597 T: Into<M> + 'static + Send + Sync,
598 M: AsRef<dyn IDynCommonModuleInit + 'static + Send + Sync>,
599 {
600 let gen: M = gen.into();
601 let kind = gen.as_ref().module_kind();
602 assert!(
603 self.0.insert(kind.clone(), gen).is_none(),
604 "Can't insert module of same kind twice: {kind}"
605 );
606 }
607
608 pub fn kinds(&self) -> BTreeSet<ModuleKind> {
609 self.0.keys().cloned().collect()
610 }
611
612 pub fn get(&self, k: &ModuleKind) -> Option<&M> {
613 self.0.get(k)
614 }
615}
616
617impl ModuleRegistry<ConfigGenModuleParams> {
618 pub fn attach_config_gen_params_by_id<T: ModuleInitParams>(
619 &mut self,
620 id: ModuleInstanceId,
621 kind: ModuleKind,
622 gen: T,
623 ) -> &mut Self {
624 let params = ConfigGenModuleParams::from_typed(gen)
625 .unwrap_or_else(|err| panic!("Invalid config gen params for {kind}: {err}"));
626 self.register_module(id, kind, params);
627 self
628 }
629
630 pub fn attach_config_gen_params<T: ModuleInitParams>(
631 &mut self,
632 kind: ModuleKind,
633 gen: T,
634 ) -> &mut Self {
635 let params = ConfigGenModuleParams::from_typed(gen)
636 .unwrap_or_else(|err| panic!("Invalid config gen params for {kind}: {err}"));
637 self.append_module(kind, params);
638 self
639 }
640}
641
642impl<M> ModuleInitRegistry<M>
643where
644 M: AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static>,
645{
646 #[deprecated(
647 note = "You probably want `available_decoders` to support missing module kinds. If you really want a strict behavior, use `decoders_strict`"
648 )]
649 pub fn decoders<'a>(
650 &self,
651 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
652 ) -> anyhow::Result<ModuleDecoderRegistry> {
653 self.decoders_strict(modules)
654 }
655
656 pub fn decoders_strict<'a>(
658 &self,
659 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
660 ) -> anyhow::Result<ModuleDecoderRegistry> {
661 let mut decoders = BTreeMap::new();
662 for (id, kind) in modules {
663 let Some(init) = self.0.get(kind) else {
664 anyhow::bail!(
665 "Detected configuration for unsupported module id: {id}, kind: {kind}"
666 )
667 };
668
669 decoders.insert(id, (kind.clone(), init.as_ref().decoder()));
670 }
671 Ok(ModuleDecoderRegistry::from(decoders))
672 }
673
674 pub fn available_decoders<'a>(
676 &self,
677 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
678 ) -> anyhow::Result<ModuleDecoderRegistry> {
679 let mut decoders = BTreeMap::new();
680 for (id, kind) in modules {
681 let Some(init) = self.0.get(kind) else {
682 warn!(target: LOG_CORE, "Unsupported module id: {id}, kind: {kind}");
683 continue;
684 };
685
686 decoders.insert(id, (kind.clone(), init.as_ref().decoder()));
687 }
688 Ok(ModuleDecoderRegistry::from(decoders))
689 }
690}
691
692#[derive(Debug, Default, Clone, Serialize, Deserialize)]
694pub struct EmptyGenParams {}
695
696pub trait ModuleInitParams: serde::Serialize + serde::de::DeserializeOwned {
697 type Local: DeserializeOwned + Serialize;
699 type Consensus: DeserializeOwned + Serialize;
701
702 fn from_parts(local: Self::Local, consensus: Self::Consensus) -> Self;
704
705 fn to_parts(self) -> (Self::Local, Self::Consensus);
707}
708
709#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
710pub struct ServerModuleConsensusConfig {
711 pub kind: ModuleKind,
712 pub version: ModuleConsensusVersion,
713 #[serde(with = "::hex::serde")]
714 pub config: Vec<u8>,
715}
716
717#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
723pub struct ClientModuleConfig {
724 pub kind: ModuleKind,
725 pub version: ModuleConsensusVersion,
726 #[serde(with = "::fedimint_core::encoding::as_hex")]
727 pub config: DynRawFallback<DynClientConfig>,
728}
729
730impl ClientModuleConfig {
731 pub fn from_typed<T: fedimint_core::core::ClientConfig>(
732 module_instance_id: ModuleInstanceId,
733 kind: ModuleKind,
734 version: ModuleConsensusVersion,
735 value: T,
736 ) -> anyhow::Result<Self> {
737 Ok(Self {
738 kind,
739 version,
740 config: fedimint_core::core::DynClientConfig::from_typed(module_instance_id, value)
741 .into(),
742 })
743 }
744
745 pub fn redecode_raw(
746 self,
747 modules: &ModuleDecoderRegistry,
748 ) -> Result<Self, crate::encoding::DecodeError> {
749 Ok(Self {
750 config: self.config.redecode_raw(modules)?,
751 ..self
752 })
753 }
754
755 pub fn is_kind(&self, kind: &ModuleKind) -> bool {
756 &self.kind == kind
757 }
758
759 pub fn kind(&self) -> &ModuleKind {
760 &self.kind
761 }
762}
763
764impl ClientModuleConfig {
765 pub fn cast<T>(&self) -> anyhow::Result<&T>
766 where
767 T: 'static,
768 {
769 self.config
770 .expect_decoded_ref()
771 .as_any()
772 .downcast_ref::<T>()
773 .context("can't convert client module config to desired type")
774 }
775}
776
777#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
781pub struct ServerModuleConfig {
782 pub local: JsonWithKind,
783 pub private: JsonWithKind,
784 pub consensus: ServerModuleConsensusConfig,
785}
786
787impl ServerModuleConfig {
788 pub fn from(
789 local: JsonWithKind,
790 private: JsonWithKind,
791 consensus: ServerModuleConsensusConfig,
792 ) -> Self {
793 Self {
794 local,
795 private,
796 consensus,
797 }
798 }
799
800 pub fn to_typed<T: TypedServerModuleConfig>(&self) -> anyhow::Result<T> {
801 let local = serde_json::from_value(self.local.value().clone())?;
802 let private = serde_json::from_value(self.private.value().clone())?;
803 let consensus = <T::Consensus>::consensus_decode_whole(
804 &self.consensus.config[..],
805 &ModuleRegistry::default(),
806 )?;
807
808 Ok(TypedServerModuleConfig::from_parts(
809 local, private, consensus,
810 ))
811 }
812}
813
814pub trait TypedServerModuleConsensusConfig:
816 DeserializeOwned + Serialize + Encodable + Decodable
817{
818 fn kind(&self) -> ModuleKind;
819
820 fn version(&self) -> ModuleConsensusVersion;
821
822 fn from_erased(erased: &ServerModuleConsensusConfig) -> anyhow::Result<Self> {
823 Ok(Self::consensus_decode_whole(
824 &erased.config[..],
825 &ModuleRegistry::default(),
826 )?)
827 }
828}
829
830pub trait TypedServerModuleConfig: DeserializeOwned + Serialize {
832 type Local: DeserializeOwned + Serialize;
834 type Private: DeserializeOwned + Serialize;
837 type Consensus: TypedServerModuleConsensusConfig;
839
840 fn from_parts(local: Self::Local, private: Self::Private, consensus: Self::Consensus) -> Self;
842
843 fn to_parts(self) -> (ModuleKind, Self::Local, Self::Private, Self::Consensus);
845
846 fn to_erased(self) -> ServerModuleConfig {
848 let (kind, local, private, consensus) = self.to_parts();
849
850 ServerModuleConfig {
851 local: JsonWithKind::new(
852 kind.clone(),
853 serde_json::to_value(local).expect("serialization can't fail"),
854 ),
855 private: JsonWithKind::new(
856 kind,
857 serde_json::to_value(private).expect("serialization can't fail"),
858 ),
859 consensus: ServerModuleConsensusConfig {
860 kind: consensus.kind(),
861 version: consensus.version(),
862 config: consensus.consensus_encode_to_vec(),
863 },
864 }
865 }
866}
867
868#[derive(Serialize, Deserialize, Debug, Clone)]
870pub enum DkgPeerMessage {
871 DistributedGen(SupportedDkgMessage),
872 Encodable(Vec<u8>),
873 Completed,
874}
875
876pub trait ISupportedDkgMessage: Sized + Serialize + DeserializeOwned {
884 fn to_msg(self) -> SupportedDkgMessage;
885 fn from_msg(msg: SupportedDkgMessage) -> anyhow::Result<Self>;
886}
887
888#[derive(Serialize, Deserialize, Debug, Clone)]
890pub enum SupportedDkgMessage {
891 G1(DkgMessage<G1Projective>),
892 G2(DkgMessage<G2Projective>),
893}
894
895impl ISupportedDkgMessage for DkgMessage<G1Projective> {
896 fn to_msg(self) -> SupportedDkgMessage {
897 SupportedDkgMessage::G1(self)
898 }
899
900 fn from_msg(msg: SupportedDkgMessage) -> anyhow::Result<Self> {
901 match msg {
902 SupportedDkgMessage::G1(s) => Ok(s),
903 SupportedDkgMessage::G2(_) => bail!("Incorrect DkgGroup: G2"),
904 }
905 }
906}
907
908impl ISupportedDkgMessage for DkgMessage<G2Projective> {
909 fn to_msg(self) -> SupportedDkgMessage {
910 SupportedDkgMessage::G2(self)
911 }
912
913 fn from_msg(msg: SupportedDkgMessage) -> anyhow::Result<Self> {
914 match msg {
915 SupportedDkgMessage::G1(_) => bail!("Incorrect DkgGroup: G1"),
916 SupportedDkgMessage::G2(s) => Ok(s),
917 }
918 }
919}
920
921#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
922pub enum DkgMessage<G: DkgGroup> {
923 HashedCommit(Sha256),
924 Commit(#[serde(with = "serde_commit")] Vec<G>),
925 Share(
926 #[serde(with = "bls12_381_serde::scalar")] Scalar,
927 #[serde(with = "bls12_381_serde::scalar")] Scalar,
928 ),
929 Extract(#[serde(with = "serde_commit")] Vec<G>),
930}
931
932pub trait DkgGroup:
934 Group + Mul<Scalar, Output = Self> + Curve + GroupEncoding + SGroup + Unpin
935{
936}
937
938impl<T: Group + Mul<Scalar, Output = T> + Curve + GroupEncoding + SGroup + Unpin> DkgGroup for T {}
939
940mod serde_commit {
942 use serde::{Deserialize, Deserializer, Serialize, Serializer};
943
944 use crate::config::DkgGroup;
945
946 pub fn serialize<S: Serializer, G: DkgGroup>(vec: &[G], s: S) -> Result<S::Ok, S::Error> {
947 let wrap_vec: Vec<Wrap<G>> = vec.iter().copied().map(Wrap).collect();
948 wrap_vec.serialize(s)
949 }
950
951 pub fn deserialize<'d, D: Deserializer<'d>, G: DkgGroup>(d: D) -> Result<Vec<G>, D::Error> {
952 let wrap_vec = <Vec<Wrap<G>>>::deserialize(d)?;
953 Ok(wrap_vec.into_iter().map(|wrap| wrap.0).collect())
954 }
955
956 struct Wrap<G: DkgGroup>(G);
957
958 impl<G: DkgGroup> Serialize for Wrap<G> {
959 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
960 self.0.serialize2(s)
961 }
962 }
963
964 impl<'d, G: DkgGroup> Deserialize<'d> for Wrap<G> {
965 fn deserialize<D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
966 G::deserialize2(d).map(Wrap)
967 }
968 }
969}
970
971pub trait SGroup: Sized {
972 fn serialize2<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error>;
973 fn deserialize2<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
974}
975
976impl SGroup for G2Projective {
977 fn serialize2<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
978 bls12_381_serde::g2::serialize(&self.to_affine(), s)
979 }
980
981 fn deserialize2<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
982 bls12_381_serde::g2::deserialize(d).map(Self::from)
983 }
984}
985
986impl SGroup for G1Projective {
987 fn serialize2<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
988 bls12_381_serde::g1::serialize(&self.to_affine(), s)
989 }
990
991 fn deserialize2<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
992 bls12_381_serde::g1::deserialize(d).map(Self::from)
993 }
994}
995
996pub const META_FEDERATION_NAME_KEY: &str = "federation_name";
999
1000pub fn load_from_file<T: DeserializeOwned>(path: &Path) -> Result<T, anyhow::Error> {
1001 let file = std::fs::File::open(path)?;
1002 Ok(serde_json::from_reader(file)?)
1003}
1004
1005pub mod serde_binary_human_readable {
1006 use std::borrow::Cow;
1007
1008 use hex::{FromHex, ToHex};
1009 use serde::de::DeserializeOwned;
1010 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1011
1012 pub fn serialize<T: Serialize, S: Serializer>(x: &T, s: S) -> Result<S::Ok, S::Error> {
1013 if s.is_human_readable() {
1014 let bytes =
1015 bincode::serialize(x).map_err(|e| serde::ser::Error::custom(format!("{e:?}")))?;
1016 s.serialize_str(&bytes.encode_hex::<String>())
1017 } else {
1018 Serialize::serialize(x, s)
1019 }
1020 }
1021
1022 pub fn deserialize<'d, T: DeserializeOwned, D: Deserializer<'d>>(d: D) -> Result<T, D::Error> {
1023 if d.is_human_readable() {
1024 let hex_str: Cow<str> = Deserialize::deserialize(d)?;
1025 let bytes = Vec::from_hex(hex_str.as_ref()).map_err(serde::de::Error::custom)?;
1026 bincode::deserialize(&bytes).map_err(|e| serde::de::Error::custom(format!("{e:?}")))
1027 } else {
1028 Deserialize::deserialize(d)
1029 }
1030 }
1031}
1032
1033#[cfg(test)]
1034mod tests {
1035 use std::collections::BTreeMap;
1036
1037 use fedimint_core::config::{ClientConfig, GlobalClientConfig};
1038
1039 use crate::module::CoreConsensusVersion;
1040
1041 #[test]
1042 fn test_dcode_meta() {
1043 let config = ClientConfig {
1044 global: GlobalClientConfig {
1045 api_endpoints: BTreeMap::new(),
1046 broadcast_public_keys: None,
1047 consensus_version: CoreConsensusVersion { major: 0, minor: 0 },
1048 meta: vec![
1049 ("foo".to_string(), "bar".to_string()),
1050 ("baz".to_string(), "\"bam\"".to_string()),
1051 ("arr".to_string(), "[\"1\", \"2\"]".to_string()),
1052 ]
1053 .into_iter()
1054 .collect(),
1055 },
1056 modules: BTreeMap::new(),
1057 };
1058
1059 assert_eq!(
1060 config
1061 .meta::<String>("foo")
1062 .expect("parsing legacy string failed"),
1063 Some("bar".to_string())
1064 );
1065 assert_eq!(
1066 config.meta::<String>("baz").expect("parsing string failed"),
1067 Some("bam".to_string())
1068 );
1069 assert_eq!(
1070 config
1071 .meta::<Vec<String>>("arr")
1072 .expect("parsing array failed"),
1073 Some(vec!["1".to_string(), "2".to_string()])
1074 );
1075
1076 assert!(config.meta::<Vec<String>>("foo").is_err());
1077 assert!(config.meta::<Vec<String>>("baz").is_err());
1078 assert_eq!(
1079 config
1080 .meta::<String>("arr")
1081 .expect("parsing via legacy fallback failed"),
1082 Some("[\"1\", \"2\"]".to_string())
1083 );
1084 }
1085}