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::task::Cancelled;
16use fedimint_core::util::SafeUrl;
17use fedimint_core::{format_hex, ModuleDecoderRegistry};
18use fedimint_logging::LOG_CORE;
19use hex::FromHex;
20use secp256k1::PublicKey;
21use serde::de::DeserializeOwned;
22use serde::ser::SerializeMap;
23use serde::{Deserialize, Deserializer, Serialize, Serializer};
24use serde_json::json;
25use thiserror::Error;
26use threshold_crypto::group::{Curve, Group, GroupEncoding};
27use threshold_crypto::{G1Projective, G2Projective};
28use tracing::warn;
29
30use crate::core::DynClientConfig;
31use crate::encoding::Decodable;
32use crate::module::{
33 CoreConsensusVersion, DynCommonModuleInit, DynServerModuleInit, IDynCommonModuleInit,
34 ModuleConsensusVersion,
35};
36use crate::{bls12_381_serde, maybe_add_send_sync, PeerId};
37
38pub const ALEPH_BFT_UNIT_BYTE_LIMIT: usize = 50_000;
41
42#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
48pub struct JsonWithKind {
49 kind: ModuleKind,
50 #[serde(flatten)]
51 value: serde_json::Value,
52}
53
54impl JsonWithKind {
55 pub fn new(kind: ModuleKind, value: serde_json::Value) -> Self {
56 Self { kind, value }
57 }
58
59 pub fn with_fixed_empty_value(self) -> Self {
80 if let serde_json::Value::Object(ref o) = self.value {
81 if o.is_empty() {
82 return Self {
83 kind: self.kind,
84 value: serde_json::Value::Null,
85 };
86 }
87 }
88
89 self
90 }
91
92 pub fn value(&self) -> &serde_json::Value {
93 &self.value
94 }
95
96 pub fn kind(&self) -> &ModuleKind {
97 &self.kind
98 }
99
100 pub fn is_kind(&self, kind: &ModuleKind) -> bool {
101 &self.kind == kind
102 }
103}
104
105#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Encodable, Decodable)]
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#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
128pub struct ClientConfig {
129 #[serde(flatten)]
130 pub global: GlobalClientConfig,
131 #[serde(deserialize_with = "de_int_key")]
132 pub modules: BTreeMap<ModuleInstanceId, ClientModuleConfig>,
133}
134
135fn de_int_key<'de, D, K, V>(deserializer: D) -> Result<BTreeMap<K, V>, D::Error>
137where
138 D: Deserializer<'de>,
139 K: Eq + Ord + FromStr,
140 K::Err: Display,
141 V: Deserialize<'de>,
142{
143 let string_map = <BTreeMap<String, V>>::deserialize(deserializer)?;
144 let map = string_map
145 .into_iter()
146 .map(|(key_str, value)| {
147 let key = K::from_str(&key_str).map_err(serde::de::Error::custom)?;
148 Ok((key, value))
149 })
150 .collect::<Result<BTreeMap<_, _>, _>>()?;
151 Ok(map)
152}
153
154fn optional_de_int_key<'de, D, K, V>(deserializer: D) -> Result<Option<BTreeMap<K, V>>, D::Error>
155where
156 D: Deserializer<'de>,
157 K: Eq + Ord + FromStr,
158 K::Err: Display,
159 V: Deserialize<'de>,
160{
161 let Some(string_map) = <Option<BTreeMap<String, V>>>::deserialize(deserializer)? else {
162 return Ok(None);
163 };
164
165 let map = string_map
166 .into_iter()
167 .map(|(key_str, value)| {
168 let key = K::from_str(&key_str).map_err(serde::de::Error::custom)?;
169 Ok((key, value))
170 })
171 .collect::<Result<BTreeMap<_, _>, _>>()?;
172
173 Ok(Some(map))
174}
175
176#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
179pub struct JsonClientConfig {
180 pub global: GlobalClientConfig,
181 pub modules: BTreeMap<ModuleInstanceId, JsonWithKind>,
182}
183
184#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
186pub struct GlobalClientConfigV0 {
187 #[serde(deserialize_with = "de_int_key")]
189 pub api_endpoints: BTreeMap<PeerId, PeerUrl>,
190 pub consensus_version: CoreConsensusVersion,
192 pub meta: BTreeMap<String, String>,
195}
196
197#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
199pub struct GlobalClientConfig {
200 #[serde(deserialize_with = "de_int_key")]
202 pub api_endpoints: BTreeMap<PeerId, PeerUrl>,
203 #[serde(default, deserialize_with = "optional_de_int_key")]
206 pub broadcast_public_keys: Option<BTreeMap<PeerId, PublicKey>>,
207 pub consensus_version: CoreConsensusVersion,
209 pub meta: BTreeMap<String, String>,
212}
213
214impl GlobalClientConfig {
215 pub fn calculate_federation_id(&self) -> FederationId {
218 FederationId(self.api_endpoints.consensus_hash())
219 }
220
221 pub fn federation_name(&self) -> Option<&str> {
223 self.meta.get(META_FEDERATION_NAME_KEY).map(|x| &**x)
224 }
225}
226
227impl ClientConfig {
228 pub fn redecode_raw(
230 self,
231 modules: &ModuleDecoderRegistry,
232 ) -> Result<Self, crate::encoding::DecodeError> {
233 Ok(Self {
234 modules: self
235 .modules
236 .into_iter()
237 .map(|(k, v)| {
238 let kind = v.kind.clone();
241 v.redecode_raw(modules)
242 .context(format!("redecode_raw: instance: {k}, kind: {kind}"))
243 .map(|v| (k, v))
244 })
245 .collect::<Result<_, _>>()?,
246 ..self
247 })
248 }
249
250 pub fn calculate_federation_id(&self) -> FederationId {
251 self.global.calculate_federation_id()
252 }
253
254 pub fn meta<V: serde::de::DeserializeOwned + 'static>(
256 &self,
257 key: &str,
258 ) -> Result<Option<V>, anyhow::Error> {
259 let Some(str_value) = self.global.meta.get(key) else {
260 return Ok(None);
261 };
262 let res = serde_json::from_str(str_value)
263 .map(Some)
264 .context(format!("Decoding meta field '{key}' failed"));
265
266 if res.is_err() && std::any::TypeId::of::<V>() == std::any::TypeId::of::<String>() {
270 let string_ret = Box::new(str_value.clone());
271 let ret = unsafe {
272 std::mem::transmute::<Box<String>, Box<V>>(string_ret)
274 };
275 Ok(Some(*ret))
276 } else {
277 res
278 }
279 }
280
281 pub fn to_json(&self) -> JsonClientConfig {
287 JsonClientConfig {
288 global: self.global.clone(),
289 modules: self
290 .modules
291 .iter()
292 .map(|(&module_instance_id, module_config)| {
293 let module_config_json = JsonWithKind {
294 kind: module_config.kind.clone(),
295 value: module_config.config
296 .clone()
297 .decoded()
298 .and_then(|dyn_cfg| dyn_cfg.to_json())
299 .unwrap_or_else(|| json!({
300 "unknown_module_hex": module_config.config.consensus_encode_to_hex()
301 })),
302 };
303 (module_instance_id, module_config_json)
304 })
305 .collect(),
306 }
307 }
308}
309
310#[derive(
316 Debug,
317 Copy,
318 Serialize,
319 Deserialize,
320 Clone,
321 Eq,
322 Hash,
323 PartialEq,
324 Encodable,
325 Decodable,
326 Ord,
327 PartialOrd,
328)]
329pub struct FederationId(pub sha256::Hash);
330
331#[derive(
332 Debug,
333 Copy,
334 Serialize,
335 Deserialize,
336 Clone,
337 Eq,
338 Hash,
339 PartialEq,
340 Encodable,
341 Decodable,
342 Ord,
343 PartialOrd,
344)]
345pub struct FederationIdPrefix([u8; 4]);
351
352impl Display for FederationIdPrefix {
353 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
354 format_hex(&self.0, f)
355 }
356}
357
358impl Display for FederationId {
359 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
360 format_hex(&self.0.to_byte_array(), f)
361 }
362}
363
364impl FromStr for FederationIdPrefix {
365 type Err = anyhow::Error;
366
367 fn from_str(s: &str) -> Result<Self, Self::Err> {
368 Ok(Self(<[u8; 4]>::from_hex(s)?))
369 }
370}
371
372impl FederationIdPrefix {
373 pub fn to_bytes(&self) -> Vec<u8> {
374 self.0.to_vec()
375 }
376}
377
378impl FederationId {
380 pub fn dummy() -> Self {
382 Self(sha256::Hash::from_byte_array([42; 32]))
383 }
384
385 pub(crate) fn from_byte_array(bytes: [u8; 32]) -> Self {
386 Self(sha256::Hash::from_byte_array(bytes))
387 }
388
389 pub fn to_prefix(&self) -> FederationIdPrefix {
390 FederationIdPrefix(self.0[..4].try_into().expect("can't fail"))
391 }
392
393 pub fn to_fake_ln_pub_key(
403 &self,
404 secp: &bitcoin::secp256k1::Secp256k1<bitcoin::secp256k1::All>,
405 ) -> anyhow::Result<bitcoin::secp256k1::PublicKey> {
406 let sk = bitcoin::secp256k1::SecretKey::from_slice(&self.0.to_byte_array())?;
407 Ok(bitcoin::secp256k1::PublicKey::from_secret_key(secp, &sk))
408 }
409}
410
411impl FromStr for FederationId {
412 type Err = anyhow::Error;
413
414 fn from_str(s: &str) -> Result<Self, Self::Err> {
415 Ok(Self::from_byte_array(<[u8; 32]>::from_hex(s)?))
416 }
417}
418
419impl ClientConfig {
420 pub fn consensus_hash(&self) -> sha256::Hash {
422 let mut engine = HashEngine::default();
423 self.consensus_encode(&mut engine)
424 .expect("Consensus hashing should never fail");
425 sha256::Hash::from_engine(engine)
426 }
427
428 pub fn get_module<T: Decodable + 'static>(&self, id: ModuleInstanceId) -> anyhow::Result<&T> {
429 self.modules.get(&id).map_or_else(
430 || Err(format_err!("Client config for module id {id} not found")),
431 |client_cfg| client_cfg.cast(),
432 )
433 }
434
435 pub fn get_module_cfg(&self, id: ModuleInstanceId) -> anyhow::Result<ClientModuleConfig> {
437 self.modules.get(&id).map_or_else(
438 || Err(format_err!("Client config for module id {id} not found")),
439 |client_cfg| Ok(client_cfg.clone()),
440 )
441 }
442
443 pub fn get_first_module_by_kind<T: Decodable + 'static>(
451 &self,
452 kind: impl Into<ModuleKind>,
453 ) -> anyhow::Result<(ModuleInstanceId, &T)> {
454 let kind: ModuleKind = kind.into();
455 let Some((id, module_cfg)) = self.modules.iter().find(|(_, v)| v.is_kind(&kind)) else {
456 anyhow::bail!("Module kind {kind} not found")
457 };
458 Ok((*id, module_cfg.cast()?))
459 }
460
461 pub fn get_first_module_by_kind_cfg(
463 &self,
464 kind: impl Into<ModuleKind>,
465 ) -> anyhow::Result<(ModuleInstanceId, ClientModuleConfig)> {
466 let kind: ModuleKind = kind.into();
467 self.modules
468 .iter()
469 .find(|(_, v)| v.is_kind(&kind))
470 .map(|(id, v)| (*id, v.clone()))
471 .ok_or_else(|| anyhow::format_err!("Module kind {kind} not found"))
472 }
473}
474
475#[derive(Clone, Debug)]
476pub struct ModuleInitRegistry<M>(BTreeMap<ModuleKind, M>);
477
478impl<M> Default for ModuleInitRegistry<M> {
479 fn default() -> Self {
480 Self(BTreeMap::new())
481 }
482}
483
484#[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
487pub struct ConfigGenModuleParams {
488 pub local: serde_json::Value,
489 pub consensus: serde_json::Value,
490}
491
492pub type ServerModuleInitRegistry = ModuleInitRegistry<DynServerModuleInit>;
493
494impl ConfigGenModuleParams {
495 pub fn new(local: serde_json::Value, consensus: serde_json::Value) -> Self {
496 Self { local, consensus }
497 }
498
499 pub fn to_typed<P: ModuleInitParams>(&self) -> anyhow::Result<P> {
502 Ok(P::from_parts(
503 Self::parse("local", self.local.clone())?,
504 Self::parse("consensus", self.consensus.clone())?,
505 ))
506 }
507
508 fn parse<P: DeserializeOwned>(name: &str, json: serde_json::Value) -> anyhow::Result<P> {
509 serde_json::from_value(json).with_context(|| format!("Schema mismatch for {name} argument"))
510 }
511
512 pub fn from_typed<P: ModuleInitParams>(p: P) -> anyhow::Result<Self> {
513 let (local, consensus) = p.to_parts();
514 Ok(Self {
515 local: serde_json::to_value(local)?,
516 consensus: serde_json::to_value(consensus)?,
517 })
518 }
519}
520
521pub type CommonModuleInitRegistry = ModuleInitRegistry<DynCommonModuleInit>;
522
523pub type ServerModuleConfigGenParamsRegistry = ModuleRegistry<ConfigGenModuleParams>;
525
526impl Eq for ServerModuleConfigGenParamsRegistry {}
527
528impl PartialEq for ServerModuleConfigGenParamsRegistry {
529 fn eq(&self, other: &Self) -> bool {
530 self.iter_modules().eq(other.iter_modules())
531 }
532}
533
534impl Serialize for ServerModuleConfigGenParamsRegistry {
535 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
536 let modules: Vec<_> = self.iter_modules().collect();
537 let mut serializer = serializer.serialize_map(Some(modules.len()))?;
538 for (id, kind, params) in modules {
539 serializer.serialize_key(&id)?;
540 serializer.serialize_value(&(kind.clone(), params.clone()))?;
541 }
542 serializer.end()
543 }
544}
545
546impl<'de> Deserialize<'de> for ServerModuleConfigGenParamsRegistry {
547 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
548 where
549 D: Deserializer<'de>,
550 {
551 let json: BTreeMap<ModuleInstanceId, (ModuleKind, ConfigGenModuleParams)> =
552 Deserialize::deserialize(deserializer)?;
553 let mut params = BTreeMap::new();
554
555 for (id, (kind, module)) in json {
556 params.insert(id, (kind, module));
557 }
558 Ok(Self::from(params))
559 }
560}
561
562impl<M> From<Vec<M>> for ModuleInitRegistry<M>
563where
564 M: AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static>,
565{
566 fn from(value: Vec<M>) -> Self {
567 Self(
568 value
569 .into_iter()
570 .map(|i| (i.as_ref().module_kind(), i))
571 .collect::<BTreeMap<_, _>>(),
572 )
573 }
574}
575
576impl<M> FromIterator<M> for ModuleInitRegistry<M>
577where
578 M: AsRef<maybe_add_send_sync!(dyn IDynCommonModuleInit + 'static)>,
579{
580 fn from_iter<T: IntoIterator<Item = M>>(iter: T) -> Self {
581 Self(
582 iter.into_iter()
583 .map(|i| (i.as_ref().module_kind(), i))
584 .collect::<BTreeMap<_, _>>(),
585 )
586 }
587}
588
589impl<M> ModuleInitRegistry<M> {
590 pub fn new() -> Self {
591 Self::default()
592 }
593
594 pub fn attach<T>(&mut self, gen: T)
595 where
596 T: Into<M> + 'static + Send + Sync,
597 M: AsRef<dyn IDynCommonModuleInit + 'static + Send + Sync>,
598 {
599 let gen: M = gen.into();
600 let kind = gen.as_ref().module_kind();
601 assert!(
602 self.0.insert(kind.clone(), gen).is_none(),
603 "Can't insert module of same kind twice: {kind}"
604 );
605 }
606
607 pub fn kinds(&self) -> BTreeSet<ModuleKind> {
608 self.0.keys().cloned().collect()
609 }
610
611 pub fn get(&self, k: &ModuleKind) -> Option<&M> {
612 self.0.get(k)
613 }
614}
615
616impl ModuleRegistry<ConfigGenModuleParams> {
617 pub fn attach_config_gen_params_by_id<T: ModuleInitParams>(
618 &mut self,
619 id: ModuleInstanceId,
620 kind: ModuleKind,
621 gen: T,
622 ) -> &mut Self {
623 let params = ConfigGenModuleParams::from_typed(gen)
624 .unwrap_or_else(|err| panic!("Invalid config gen params for {kind}: {err}"));
625 self.register_module(id, kind, params);
626 self
627 }
628
629 pub fn attach_config_gen_params<T: ModuleInitParams>(
630 &mut self,
631 kind: ModuleKind,
632 gen: T,
633 ) -> &mut Self {
634 let params = ConfigGenModuleParams::from_typed(gen)
635 .unwrap_or_else(|err| panic!("Invalid config gen params for {kind}: {err}"));
636 self.append_module(kind, params);
637 self
638 }
639}
640
641impl ServerModuleInitRegistry {
642 pub fn to_common(&self) -> CommonModuleInitRegistry {
643 ModuleInitRegistry(
644 self.0
645 .iter()
646 .map(|(k, v)| (k.clone(), v.to_dyn_common()))
647 .collect(),
648 )
649 }
650}
651
652impl<M> ModuleInitRegistry<M>
653where
654 M: AsRef<dyn IDynCommonModuleInit + Send + Sync + 'static>,
655{
656 #[deprecated(
657 note = "You probably want `available_decoders` to support missing module kinds. If you really want a strict behavior, use `decoders_strict`"
658 )]
659 pub fn decoders<'a>(
660 &self,
661 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
662 ) -> anyhow::Result<ModuleDecoderRegistry> {
663 self.decoders_strict(modules)
664 }
665
666 pub fn decoders_strict<'a>(
668 &self,
669 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
670 ) -> anyhow::Result<ModuleDecoderRegistry> {
671 let mut decoders = BTreeMap::new();
672 for (id, kind) in modules {
673 let Some(init) = self.0.get(kind) else {
674 anyhow::bail!(
675 "Detected configuration for unsupported module id: {id}, kind: {kind}"
676 )
677 };
678
679 decoders.insert(id, (kind.clone(), init.as_ref().decoder()));
680 }
681 Ok(ModuleDecoderRegistry::from(decoders))
682 }
683
684 pub fn available_decoders<'a>(
686 &self,
687 modules: impl Iterator<Item = (ModuleInstanceId, &'a ModuleKind)>,
688 ) -> anyhow::Result<ModuleDecoderRegistry> {
689 let mut decoders = BTreeMap::new();
690 for (id, kind) in modules {
691 let Some(init) = self.0.get(kind) else {
692 warn!(target: LOG_CORE, "Unsupported module id: {id}, kind: {kind}");
693 continue;
694 };
695
696 decoders.insert(id, (kind.clone(), init.as_ref().decoder()));
697 }
698 Ok(ModuleDecoderRegistry::from(decoders))
699 }
700}
701
702#[derive(Debug, Default, Clone, Serialize, Deserialize)]
704pub struct EmptyGenParams {}
705
706pub trait ModuleInitParams: serde::Serialize + serde::de::DeserializeOwned {
707 type Local: DeserializeOwned + Serialize;
709 type Consensus: DeserializeOwned + Serialize;
711
712 fn from_parts(local: Self::Local, consensus: Self::Consensus) -> Self;
714
715 fn to_parts(self) -> (Self::Local, Self::Consensus);
717}
718
719#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
720pub struct ServerModuleConsensusConfig {
721 pub kind: ModuleKind,
722 pub version: ModuleConsensusVersion,
723 #[serde(with = "::hex::serde")]
724 pub config: Vec<u8>,
725}
726
727#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Encodable, Decodable)]
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 ) -> anyhow::Result<Self> {
747 Ok(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) -> anyhow::Result<&T>
776 where
777 T: 'static,
778 {
779 self.config
780 .expect_decoded_ref()
781 .as_any()
782 .downcast_ref::<T>()
783 .context("can't convert client module config to desired type")
784 }
785}
786
787#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
791pub struct ServerModuleConfig {
792 pub local: JsonWithKind,
793 pub private: JsonWithKind,
794 pub consensus: ServerModuleConsensusConfig,
795}
796
797impl ServerModuleConfig {
798 pub fn from(
799 local: JsonWithKind,
800 private: JsonWithKind,
801 consensus: ServerModuleConsensusConfig,
802 ) -> Self {
803 Self {
804 local,
805 private,
806 consensus,
807 }
808 }
809
810 pub fn to_typed<T: TypedServerModuleConfig>(&self) -> anyhow::Result<T> {
811 let local = serde_json::from_value(self.local.value().clone())?;
812 let private = serde_json::from_value(self.private.value().clone())?;
813 let consensus = <T::Consensus>::consensus_decode(
814 &mut &self.consensus.config[..],
815 &ModuleRegistry::default(),
816 )?;
817
818 Ok(TypedServerModuleConfig::from_parts(
819 local, private, consensus,
820 ))
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) -> anyhow::Result<Self> {
833 Ok(Self::consensus_decode(
834 &mut &erased.config[..],
835 &ModuleRegistry::default(),
836 )?)
837 }
838}
839
840pub trait TypedServerModuleConfig: DeserializeOwned + Serialize {
842 type Local: DeserializeOwned + Serialize;
844 type Private: DeserializeOwned + Serialize;
847 type Consensus: TypedServerModuleConsensusConfig;
849
850 fn from_parts(local: Self::Local, private: Self::Private, consensus: Self::Consensus) -> Self;
852
853 fn to_parts(self) -> (ModuleKind, Self::Local, Self::Private, Self::Consensus);
855
856 fn to_erased(self) -> ServerModuleConfig {
858 let (kind, local, private, consensus) = self.to_parts();
859
860 ServerModuleConfig {
861 local: JsonWithKind::new(
862 kind.clone(),
863 serde_json::to_value(local).expect("serialization can't fail"),
864 ),
865 private: JsonWithKind::new(
866 kind,
867 serde_json::to_value(private).expect("serialization can't fail"),
868 ),
869 consensus: ServerModuleConsensusConfig {
870 kind: consensus.kind(),
871 version: consensus.version(),
872 config: consensus.consensus_encode_to_vec(),
873 },
874 }
875 }
876}
877
878#[derive(Serialize, Deserialize, Debug, Clone)]
880pub enum DkgPeerMsg {
881 PublicKey(secp256k1::PublicKey),
882 DistributedGen(SupportedDkgMessage),
883 Module(Vec<u8>),
884 Done,
886}
887
888pub type DkgResult<T> = Result<T, DkgError>;
890
891#[derive(Error, Debug)]
892pub enum DkgError {
894 #[error("Operation cancelled")]
896 Cancelled(#[from] Cancelled),
897 #[error("Running DKG failed due to {0}")]
899 Failed(#[from] anyhow::Error),
900 #[error("The module was not found {0}")]
901 ModuleNotFound(ModuleKind),
902 #[error("Params for modules were not found {0:?}")]
903 ParamsNotFound(BTreeSet<ModuleKind>),
904 #[error("Failed to decode module message {0:?}")]
905 ModuleDecodeError(ModuleKind),
906}
907
908pub trait ISupportedDkgMessage: Sized + Serialize + DeserializeOwned {
916 fn to_msg(self) -> SupportedDkgMessage;
917 fn from_msg(msg: SupportedDkgMessage) -> anyhow::Result<Self>;
918}
919
920#[derive(Serialize, Deserialize, Debug, Clone)]
922pub enum SupportedDkgMessage {
923 G1(DkgMessage<G1Projective>),
924 G2(DkgMessage<G2Projective>),
925}
926
927impl ISupportedDkgMessage for DkgMessage<G1Projective> {
928 fn to_msg(self) -> SupportedDkgMessage {
929 SupportedDkgMessage::G1(self)
930 }
931
932 fn from_msg(msg: SupportedDkgMessage) -> anyhow::Result<Self> {
933 match msg {
934 SupportedDkgMessage::G1(s) => Ok(s),
935 SupportedDkgMessage::G2(_) => bail!("Incorrect DkgGroup: G2"),
936 }
937 }
938}
939
940impl ISupportedDkgMessage for DkgMessage<G2Projective> {
941 fn to_msg(self) -> SupportedDkgMessage {
942 SupportedDkgMessage::G2(self)
943 }
944
945 fn from_msg(msg: SupportedDkgMessage) -> anyhow::Result<Self> {
946 match msg {
947 SupportedDkgMessage::G1(_) => bail!("Incorrect DkgGroup: G1"),
948 SupportedDkgMessage::G2(s) => Ok(s),
949 }
950 }
951}
952
953#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
954pub enum DkgMessage<G: DkgGroup> {
955 HashedCommit(Sha256),
956 Commit(#[serde(with = "serde_commit")] Vec<G>),
957 Share(
958 #[serde(with = "bls12_381_serde::scalar")] Scalar,
959 #[serde(with = "bls12_381_serde::scalar")] Scalar,
960 ),
961 Extract(#[serde(with = "serde_commit")] Vec<G>),
962}
963
964pub trait DkgGroup:
966 Group + Mul<Scalar, Output = Self> + Curve + GroupEncoding + SGroup + Unpin
967{
968}
969
970impl<T: Group + Mul<Scalar, Output = T> + Curve + GroupEncoding + SGroup + Unpin> DkgGroup for T {}
971
972mod serde_commit {
974 use serde::{Deserialize, Deserializer, Serialize, Serializer};
975
976 use crate::config::DkgGroup;
977
978 pub fn serialize<S: Serializer, G: DkgGroup>(vec: &[G], s: S) -> Result<S::Ok, S::Error> {
979 let wrap_vec: Vec<Wrap<G>> = vec.iter().copied().map(Wrap).collect();
980 wrap_vec.serialize(s)
981 }
982
983 pub fn deserialize<'d, D: Deserializer<'d>, G: DkgGroup>(d: D) -> Result<Vec<G>, D::Error> {
984 let wrap_vec = <Vec<Wrap<G>>>::deserialize(d)?;
985 Ok(wrap_vec.into_iter().map(|wrap| wrap.0).collect())
986 }
987
988 struct Wrap<G: DkgGroup>(G);
989
990 impl<G: DkgGroup> Serialize for Wrap<G> {
991 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
992 self.0.serialize2(s)
993 }
994 }
995
996 impl<'d, G: DkgGroup> Deserialize<'d> for Wrap<G> {
997 fn deserialize<D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
998 G::deserialize2(d).map(Wrap)
999 }
1000 }
1001}
1002
1003pub trait SGroup: Sized {
1004 fn serialize2<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error>;
1005 fn deserialize2<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
1006}
1007
1008impl SGroup for G2Projective {
1009 fn serialize2<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1010 bls12_381_serde::g2::serialize(&self.to_affine(), s)
1011 }
1012
1013 fn deserialize2<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
1014 bls12_381_serde::g2::deserialize(d).map(Self::from)
1015 }
1016}
1017
1018impl SGroup for G1Projective {
1019 fn serialize2<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1020 bls12_381_serde::g1::serialize(&self.to_affine(), s)
1021 }
1022
1023 fn deserialize2<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
1024 bls12_381_serde::g1::deserialize(d).map(Self::from)
1025 }
1026}
1027
1028pub const META_FEDERATION_NAME_KEY: &str = "federation_name";
1031
1032pub fn load_from_file<T: DeserializeOwned>(path: &Path) -> Result<T, anyhow::Error> {
1033 let file = std::fs::File::open(path)?;
1034 Ok(serde_json::from_reader(file)?)
1035}
1036
1037pub mod serde_binary_human_readable {
1038 use std::borrow::Cow;
1039
1040 use hex::{FromHex, ToHex};
1041 use serde::de::DeserializeOwned;
1042 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1043
1044 pub fn serialize<T: Serialize, S: Serializer>(x: &T, s: S) -> Result<S::Ok, S::Error> {
1045 if s.is_human_readable() {
1046 let bytes =
1047 bincode::serialize(x).map_err(|e| serde::ser::Error::custom(format!("{e:?}")))?;
1048 s.serialize_str(&bytes.encode_hex::<String>())
1049 } else {
1050 Serialize::serialize(x, s)
1051 }
1052 }
1053
1054 pub fn deserialize<'d, T: DeserializeOwned, D: Deserializer<'d>>(d: D) -> Result<T, D::Error> {
1055 if d.is_human_readable() {
1056 let hex_str: Cow<str> = Deserialize::deserialize(d)?;
1057 let bytes = Vec::from_hex(hex_str.as_ref()).map_err(serde::de::Error::custom)?;
1058 bincode::deserialize(&bytes).map_err(|e| serde::de::Error::custom(format!("{e:?}")))
1059 } else {
1060 Deserialize::deserialize(d)
1061 }
1062 }
1063}
1064
1065#[cfg(test)]
1066mod tests {
1067 use std::collections::BTreeMap;
1068
1069 use fedimint_core::config::{ClientConfig, GlobalClientConfig};
1070
1071 use crate::module::CoreConsensusVersion;
1072
1073 #[test]
1074 fn test_dcode_meta() {
1075 let config = ClientConfig {
1076 global: GlobalClientConfig {
1077 api_endpoints: BTreeMap::new(),
1078 broadcast_public_keys: None,
1079 consensus_version: CoreConsensusVersion { major: 0, minor: 0 },
1080 meta: vec![
1081 ("foo".to_string(), "bar".to_string()),
1082 ("baz".to_string(), "\"bam\"".to_string()),
1083 ("arr".to_string(), "[\"1\", \"2\"]".to_string()),
1084 ]
1085 .into_iter()
1086 .collect(),
1087 },
1088 modules: BTreeMap::new(),
1089 };
1090
1091 assert_eq!(
1092 config
1093 .meta::<String>("foo")
1094 .expect("parsing legacy string failed"),
1095 Some("bar".to_string())
1096 );
1097 assert_eq!(
1098 config.meta::<String>("baz").expect("parsing string failed"),
1099 Some("bam".to_string())
1100 );
1101 assert_eq!(
1102 config
1103 .meta::<Vec<String>>("arr")
1104 .expect("parsing array failed"),
1105 Some(vec!["1".to_string(), "2".to_string()])
1106 );
1107
1108 assert!(config.meta::<Vec<String>>("foo").is_err());
1109 assert!(config.meta::<Vec<String>>("baz").is_err());
1110 assert_eq!(
1111 config
1112 .meta::<String>("arr")
1113 .expect("parsing via legacy fallback failed"),
1114 Some("[\"1\", \"2\"]".to_string())
1115 );
1116 }
1117}