core.rs
1 //! Fedimint Core API (common) module interface 2 //! 3 //! Fedimint supports externally implemented modules. 4 //! 5 //! This (Rust) module defines common interoperability types 6 //! and functionality that is used on both client and sever side. 7 use core::fmt; 8 use std::any::{Any, TypeId}; 9 use std::borrow::Cow; 10 use std::collections::BTreeMap; 11 use std::fmt::{Debug, Display, Formatter}; 12 use std::io::Read; 13 use std::str::FromStr; 14 use std::sync::Arc; 15 use std::{cmp, marker}; 16 17 use anyhow::anyhow; 18 use bitcoin_hashes::{sha256, Hash}; 19 use fedimint_core::encoding::{Decodable, DecodeError, DynEncodable, Encodable}; 20 use fedimint_core::module::registry::ModuleDecoderRegistry; 21 use rand::RngCore; 22 use serde::{Deserialize, Deserializer, Serialize}; 23 24 use crate::{ 25 erased_eq_no_instance_id, module_plugin_dyn_newtype_clone_passthrough, 26 module_plugin_dyn_newtype_define, module_plugin_dyn_newtype_display_passthrough, 27 module_plugin_dyn_newtype_encode_decode, module_plugin_dyn_newtype_eq_passthrough, 28 module_plugin_static_trait_define, module_plugin_static_trait_define_config, 29 }; 30 31 pub mod server; 32 33 pub mod backup; 34 35 /// Unique identifier for one semantic, correlatable operation. 36 /// 37 /// The concept of *operations* is used to avoid losing privacy while being as 38 /// efficient as possible with regards to network requests. 39 /// 40 /// For Fedimint transactions to be private users need to communicate with the 41 /// federation using an anonymous communication network. If each API request was 42 /// done in a way that it cannot be correlated to any other API request we would 43 /// achieve privacy, but would reduce efficiency. E.g. on Tor we would need to 44 /// open a new circuit for every request and open a new web socket connection. 45 /// 46 /// Fortunately we do not need to do that to maintain privacy. Many API requests 47 /// and transactions can be correlated by the federation anyway, in these cases 48 /// it does not make any difference to re-use the same network connection. All 49 /// requests, transactions, state machines that are connected from the 50 /// federation's point of view anyway are grouped together as one *operation*. 51 /// 52 /// # Choice of Operation ID 53 /// 54 /// In cases where an operation is created by a new transaction that's being 55 /// submitted the transaction's ID can be used as operation ID. If there is no 56 /// transaction related to it, it should be generated randomly. Since it is a 57 /// 256bit value collisions are impossible for all intents and purposes. 58 #[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, PartialOrd, Ord)] 59 pub struct OperationId(pub [u8; 32]); 60 61 impl OperationId { 62 /// Generate random [`OperationId`] 63 pub fn new_random() -> Self { 64 let mut rng = rand::thread_rng(); 65 let mut bytes = [0u8; 32]; 66 rng.fill_bytes(&mut bytes); 67 Self(bytes) 68 } 69 70 pub fn from_encodable<E: Encodable>(encodable: E) -> OperationId { 71 Self(encodable.consensus_hash::<sha256::Hash>().to_byte_array()) 72 } 73 } 74 75 impl Display for OperationId { 76 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 77 bitcoin29::hashes::hex::format_hex(&self.0, f) 78 } 79 } 80 81 impl Debug for OperationId { 82 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 83 write!(f, "OperationId({self})") 84 } 85 } 86 87 impl FromStr for OperationId { 88 type Err = anyhow::Error; 89 90 fn from_str(s: &str) -> Result<Self, Self::Err> { 91 let bytes: [u8; 32] = hex::FromHex::from_hex(s)?; 92 Ok(OperationId(bytes)) 93 } 94 } 95 96 impl Serialize for OperationId { 97 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 98 if serializer.is_human_readable() { 99 serializer.serialize_str(&self.to_string()) 100 } else { 101 serializer.serialize_bytes(&self.0) 102 } 103 } 104 } 105 106 impl<'de> Deserialize<'de> for OperationId { 107 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 108 where 109 D: Deserializer<'de>, 110 { 111 if deserializer.is_human_readable() { 112 let s = String::deserialize(deserializer)?; 113 let operation_id = OperationId::from_str(&s) 114 .map_err(|e| serde::de::Error::custom(format!("invalid operation id: {e}")))?; 115 Ok(operation_id) 116 } else { 117 let bytes: [u8; 32] = <[u8; 32]>::deserialize(deserializer)?; 118 Ok(OperationId(bytes)) 119 } 120 } 121 } 122 123 /// Module instance ID 124 /// 125 /// This value uniquely identifies a single instance of a module in a 126 /// federation. 127 /// 128 /// In case a single [`ModuleKind`] is instantiated twice (rare, but possible), 129 /// each instance will have a different id. 130 /// 131 /// Note: We have used this type differently before, assuming each `u16` 132 /// uniquly identifies a type of module in question. This function will move 133 /// to a `ModuleKind` type which only identifies type of a module (mint vs 134 /// wallet vs ln, etc) 135 // TODO: turn in a newtype 136 pub type ModuleInstanceId = u16; 137 138 /// Special IDs we use for global dkg 139 pub const MODULE_INSTANCE_ID_GLOBAL: u16 = u16::MAX; 140 141 // Note: needs to be in alphabetical order of ModuleKind of each module, 142 // as this is the ordering we currently hardcoded. 143 // Should be used only for pre-modularization code we still have left 144 pub const LEGACY_HARDCODED_INSTANCE_ID_LN: ModuleInstanceId = 0; 145 pub const LEGACY_HARDCODED_INSTANCE_ID_MINT: ModuleInstanceId = 1; 146 pub const LEGACY_HARDCODED_INSTANCE_ID_WALLET: ModuleInstanceId = 2; 147 148 /// A type of a module 149 /// 150 /// This is a short string that identifies type of a module. 151 /// Authors of 3rd party modules are free to come up with a string, 152 /// long enough to avoid conflicts with similar modules. 153 #[derive( 154 Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Serialize, Deserialize, Encodable, Decodable, 155 )] 156 pub struct ModuleKind(Cow<'static, str>); 157 158 impl ModuleKind { 159 pub fn clone_from_str(s: &str) -> Self { 160 Self(Cow::from(s.to_owned())) 161 } 162 163 pub const fn from_static_str(s: &'static str) -> Self { 164 Self(Cow::Borrowed(s)) 165 } 166 167 pub fn as_str(&self) -> &str { 168 &self.0 169 } 170 } 171 172 impl fmt::Display for ModuleKind { 173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 174 std::fmt::Display::fmt(&self.0, f) 175 } 176 } 177 178 impl From<&'static str> for ModuleKind { 179 fn from(val: &'static str) -> Self { 180 ModuleKind::from_static_str(val) 181 } 182 } 183 184 /// A type used by when decoding dyn-types, when the module is missing 185 /// 186 /// This allows parsing and handling of dyn-types of modules which 187 /// are not available. 188 #[derive(Encodable, Decodable, Debug, Hash, PartialEq, Clone)] 189 pub struct DynUnknown(pub Vec<u8>); 190 191 impl fmt::Display for DynUnknown { 192 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 193 f.write_str(&self.0.consensus_encode_to_hex()) 194 } 195 } 196 197 /// A type that has a `Dyn*`, type erased version of itself 198 /// 199 /// Use [`IntoDynNever`] in places where a given type will never 200 /// actually be created, but something is needed to appease the 201 /// type system. 202 pub trait IntoDynInstance { 203 /// The type erased version of the type implementing this trait 204 type DynType: 'static; 205 206 /// Convert `self` into its type-erased equivalent 207 fn into_dyn(self, instance_id: ModuleInstanceId) -> Self::DynType; 208 } 209 210 enum Never {} 211 212 /// Type that can be used as type-system placeholder for [`IntoDynInstance`] 213 pub struct IntoDynNever<T> { 214 _phantom: marker::PhantomData<T>, 215 // you can't make that 216 _never: Never, 217 } 218 219 impl<T> cmp::PartialEq for IntoDynNever<T> { 220 fn eq(&self, _: &Self) -> bool { 221 unreachable!() 222 } 223 } 224 225 impl<T> cmp::Eq for IntoDynNever<T> {} 226 227 impl<T> fmt::Debug for IntoDynNever<T> { 228 fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result { 229 unreachable!() 230 } 231 } 232 233 impl<T> Clone for IntoDynNever<T> { 234 fn clone(&self) -> Self { 235 unreachable!() 236 } 237 } 238 239 impl<T> Encodable for IntoDynNever<T> { 240 fn consensus_encode<W: std::io::Write>(&self, _: &mut W) -> Result<usize, std::io::Error> { 241 unreachable!() 242 } 243 } 244 245 impl<T> Decodable for IntoDynNever<T> { 246 fn consensus_decode<R: std::io::Read>( 247 _: &mut R, 248 _: &ModuleDecoderRegistry, 249 ) -> Result<Self, DecodeError> { 250 unreachable!() 251 } 252 } 253 254 impl<T> IntoDynInstance for IntoDynNever<T> 255 where 256 T: 'static, 257 { 258 type DynType = T; 259 260 fn into_dyn(self, _instance_id: ModuleInstanceId) -> Self::DynType { 261 unreachable!() 262 } 263 } 264 265 type DecodeFn = Box< 266 dyn for<'a> Fn( 267 Box<dyn Read + 'a>, 268 ModuleInstanceId, 269 &ModuleDecoderRegistry, 270 ) -> Result<Box<dyn Any>, DecodeError> 271 + Send 272 + Sync, 273 >; 274 275 #[derive(Default)] 276 pub struct DecoderBuilder { 277 decode_fns: BTreeMap<TypeId, DecodeFn>, 278 transparent: bool, 279 } 280 281 impl DecoderBuilder { 282 pub fn build(self) -> Decoder { 283 Decoder { 284 decode_fns: Arc::new(self.decode_fns), 285 } 286 } 287 288 /// Attach decoder for a specific `Type`/`DynType` pair where `DynType = 289 /// <Type as IntoDynInstance>::DynType`. 290 /// 291 /// This allows calling `decode::<DynType>` on this decoder, returning a 292 /// `DynType` object which contains a `Type` object internally. 293 /// 294 /// **Caution**: One `Decoder` object should only contain decoders that 295 /// belong to the same [*module kind*](fedimint_core::core::ModuleKind). 296 /// 297 /// # Panics 298 /// * If multiple `Types` with the same `DynType` are added 299 pub fn with_decodable_type<Type>(&mut self) 300 where 301 Type: IntoDynInstance + Decodable, 302 { 303 let is_transparent_decoder = self.transparent; 304 // TODO: enforce that all decoders are for the same module kind (+fix docs 305 // after) 306 let decode_fn: DecodeFn = Box::new( 307 move |mut reader, instance, decoders: &ModuleDecoderRegistry| { 308 // TODO: Ideally `DynTypes` decoding couldn't ever be nested, so we could just 309 // pass empty `decoders`. But the client context uses nested `DynTypes` in 310 // `DynState`, so we special-case it with a flag. 311 let decoders = if is_transparent_decoder { 312 Cow::Borrowed(decoders) 313 } else { 314 Cow::Owned(Default::default()) 315 }; 316 let typed_val = Type::consensus_decode(&mut reader, &decoders).map_err(|err| { 317 let err: anyhow::Error = err.into(); 318 DecodeError::new_custom( 319 err.context(format!("while decoding Dyn type module_id={instance}")), 320 ) 321 })?; 322 let dyn_val = typed_val.into_dyn(instance); 323 let any_val: Box<dyn Any> = Box::new(dyn_val); 324 Ok(any_val) 325 }, 326 ); 327 if self 328 .decode_fns 329 .insert(TypeId::of::<Type::DynType>(), decode_fn) 330 .is_some() 331 { 332 panic!("Tried to add multiple decoders for the same DynType"); 333 } 334 } 335 } 336 337 /// Decoder for module associated types 338 #[derive(Clone, Default)] 339 pub struct Decoder { 340 decode_fns: Arc<BTreeMap<TypeId, DecodeFn>>, 341 } 342 343 impl Decoder { 344 /// Creates a `DecoderBuilder` to which decoders for single types can be 345 /// attached to build a `Decoder`. 346 pub fn builder() -> DecoderBuilder { 347 DecoderBuilder::default() 348 } 349 350 /// System Dyn-type, don't use. 351 #[doc(hidden)] 352 pub fn builder_system() -> DecoderBuilder { 353 DecoderBuilder { 354 transparent: true, 355 ..DecoderBuilder::default() 356 } 357 } 358 359 /// Decodes a specific `DynType` from the `reader` byte stream. 360 /// 361 /// # Panics 362 /// * If no decoder is registered for the `DynType` 363 pub fn decode_complete<DynType: Any>( 364 &self, 365 reader: &mut dyn Read, 366 total_len: u64, 367 module_id: ModuleInstanceId, 368 decoders: &ModuleDecoderRegistry, 369 ) -> Result<DynType, DecodeError> { 370 let mut reader = reader.take(total_len); 371 372 let val = self.decode_partial(&mut reader, module_id, decoders)?; 373 let left = reader.limit(); 374 375 if left != 0 { 376 return Err(fedimint_core::encoding::DecodeError::new_custom( 377 anyhow::anyhow!( 378 "Dyn type did not consume all bytes during decoding; module_id={}; expected={}; left={}; type={}", 379 module_id, 380 total_len, 381 left, 382 std::any::type_name::<DynType>(), 383 ), 384 )); 385 } 386 387 Ok(val) 388 } 389 390 /// Like [`Self::decode_complete`] but does not verify that all bytes were 391 /// consumed 392 pub fn decode_partial<DynType: Any>( 393 &self, 394 reader: &mut dyn Read, 395 module_id: ModuleInstanceId, 396 decoders: &ModuleDecoderRegistry, 397 ) -> Result<DynType, DecodeError> { 398 let decode_fn = self 399 .decode_fns 400 .get(&TypeId::of::<DynType>()) 401 .ok_or_else(|| { 402 anyhow!( 403 "Type unknown to decoder: {}, (registered decoders={})", 404 std::any::type_name::<DynType>(), 405 self.decode_fns.len() 406 ) 407 }) 408 .expect("Types being decoded must be registered"); 409 Ok(*decode_fn(Box::new(reader), module_id, decoders)? 410 .downcast::<DynType>() 411 .expect("Decode fn returned wrong type, can't happen due to with_decodable_type")) 412 } 413 } 414 415 impl Debug for Decoder { 416 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 417 write!(f, "Decoder(registered_types = {})", self.decode_fns.len()) 418 } 419 } 420 421 pub trait IClientConfig: Debug + Display + DynEncodable { 422 fn as_any(&self) -> &(dyn Any + Send + Sync); 423 fn clone(&self, instance_id: ModuleInstanceId) -> DynClientConfig; 424 fn dyn_hash(&self) -> u64; 425 fn erased_eq_no_instance_id(&self, other: &DynClientConfig) -> bool; 426 fn to_json(&self) -> Option<serde_json::Value>; 427 } 428 429 module_plugin_static_trait_define_config! { 430 DynClientConfig, ClientConfig, IClientConfig, 431 { }, 432 { 433 erased_eq_no_instance_id!(DynClientConfig); 434 435 fn to_json(&self) -> Option<serde_json::Value> { 436 Some(serde_json::to_value(self.to_owned()).expect("serialization can't fail")) 437 } 438 }, 439 { 440 erased_eq_no_instance_id!(DynClientConfig); 441 442 fn to_json(&self) -> Option<serde_json::Value> { 443 None 444 } 445 } 446 } 447 448 module_plugin_dyn_newtype_define! { 449 /// An owned, immutable input to a [`Transaction`](fedimint_core::transaction::Transaction) 450 pub DynClientConfig(Box<IClientConfig>) 451 } 452 module_plugin_dyn_newtype_encode_decode!(DynClientConfig); 453 454 module_plugin_dyn_newtype_clone_passthrough!(DynClientConfig); 455 456 module_plugin_dyn_newtype_eq_passthrough!(DynClientConfig); 457 458 module_plugin_dyn_newtype_display_passthrough!(DynClientConfig); 459 460 /// Something that can be an [`DynInput`] in a 461 /// [`Transaction`](fedimint_core::transaction::Transaction) 462 /// 463 /// General purpose code should use [`DynInput`] instead 464 pub trait IInput: Debug + Display + DynEncodable { 465 fn as_any(&self) -> &(dyn Any + Send + Sync); 466 fn clone(&self, instance_id: ModuleInstanceId) -> DynInput; 467 fn dyn_hash(&self) -> u64; 468 fn erased_eq_no_instance_id(&self, other: &DynInput) -> bool; 469 } 470 471 module_plugin_static_trait_define! { 472 DynInput, Input, IInput, 473 { }, 474 { 475 erased_eq_no_instance_id!(DynInput); 476 } 477 } 478 479 module_plugin_dyn_newtype_define! { 480 /// An owned, immutable input to a [`Transaction`](fedimint_core::transaction::Transaction) 481 pub DynInput(Box<IInput>) 482 } 483 module_plugin_dyn_newtype_encode_decode!(DynInput); 484 485 module_plugin_dyn_newtype_clone_passthrough!(DynInput); 486 487 module_plugin_dyn_newtype_eq_passthrough!(DynInput); 488 489 module_plugin_dyn_newtype_display_passthrough!(DynInput); 490 491 /// Something that can be an [`DynOutput`] in a 492 /// [`Transaction`](fedimint_core::transaction::Transaction) 493 /// 494 /// General purpose code should use [`DynOutput`] instead 495 pub trait IOutput: Debug + Display + DynEncodable { 496 fn as_any(&self) -> &(dyn Any + Send + Sync); 497 fn clone(&self, instance_id: ModuleInstanceId) -> DynOutput; 498 fn dyn_hash(&self) -> u64; 499 fn erased_eq_no_instance_id(&self, other: &DynOutput) -> bool; 500 } 501 502 module_plugin_dyn_newtype_define! { 503 /// An owned, immutable output of a [`Transaction`](fedimint_core::transaction::Transaction) 504 pub DynOutput(Box<IOutput>) 505 } 506 module_plugin_static_trait_define! { 507 DynOutput, Output, IOutput, 508 { }, 509 { 510 erased_eq_no_instance_id!(DynOutput); 511 } 512 } 513 module_plugin_dyn_newtype_encode_decode!(DynOutput); 514 515 module_plugin_dyn_newtype_clone_passthrough!(DynOutput); 516 517 module_plugin_dyn_newtype_eq_passthrough!(DynOutput); 518 519 module_plugin_dyn_newtype_display_passthrough!(DynOutput); 520 521 pub enum FinalizationError { 522 SomethingWentWrong, 523 } 524 525 pub trait IOutputOutcome: Debug + Display + DynEncodable { 526 fn as_any(&self) -> &(dyn Any + Send + Sync); 527 fn clone(&self, module_instance_id: ModuleInstanceId) -> DynOutputOutcome; 528 fn dyn_hash(&self) -> u64; 529 fn erased_eq_no_instance_id(&self, other: &DynOutputOutcome) -> bool; 530 } 531 532 module_plugin_dyn_newtype_define! { 533 /// An owned, immutable output of a [`Transaction`](fedimint_core::transaction::Transaction) before it was finalized 534 pub DynOutputOutcome(Box<IOutputOutcome>) 535 } 536 module_plugin_static_trait_define! { 537 DynOutputOutcome, OutputOutcome, IOutputOutcome, 538 { }, 539 { 540 erased_eq_no_instance_id!(DynOutputOutcome); 541 } 542 } 543 module_plugin_dyn_newtype_encode_decode!(DynOutputOutcome); 544 module_plugin_dyn_newtype_clone_passthrough!(DynOutputOutcome); 545 module_plugin_dyn_newtype_eq_passthrough!(DynOutputOutcome); 546 module_plugin_dyn_newtype_display_passthrough!(DynOutputOutcome); 547 548 pub trait IModuleConsensusItem: Debug + Display + DynEncodable { 549 fn as_any(&self) -> &(dyn Any + Send + Sync); 550 fn clone(&self, module_instance_id: ModuleInstanceId) -> DynModuleConsensusItem; 551 fn dyn_hash(&self) -> u64; 552 553 fn erased_eq_no_instance_id(&self, other: &DynModuleConsensusItem) -> bool; 554 } 555 556 module_plugin_dyn_newtype_define! { 557 /// An owned, immutable output of a [`Transaction`](fedimint_core::transaction::Transaction) before it was finalized 558 pub DynModuleConsensusItem(Box<IModuleConsensusItem>) 559 } 560 module_plugin_static_trait_define! { 561 DynModuleConsensusItem, ModuleConsensusItem, IModuleConsensusItem, 562 { }, 563 { 564 erased_eq_no_instance_id!(DynModuleConsensusItem); 565 } 566 } 567 module_plugin_dyn_newtype_encode_decode!(DynModuleConsensusItem); 568 569 module_plugin_dyn_newtype_clone_passthrough!(DynModuleConsensusItem); 570 571 module_plugin_dyn_newtype_eq_passthrough!(DynModuleConsensusItem); 572 573 module_plugin_dyn_newtype_display_passthrough!(DynModuleConsensusItem); 574 575 pub trait IOutputError: Debug + Display + DynEncodable { 576 fn as_any(&self) -> &(dyn Any + Send + Sync); 577 fn clone(&self, module_instance_id: ModuleInstanceId) -> DynOutputError; 578 fn dyn_hash(&self) -> u64; 579 580 fn erased_eq_no_instance_id(&self, other: &DynOutputError) -> bool; 581 } 582 583 module_plugin_dyn_newtype_define! { 584 pub DynOutputError(Box<IOutputError>) 585 } 586 module_plugin_static_trait_define! { 587 DynOutputError, OutputError, IOutputError, 588 { }, 589 { 590 erased_eq_no_instance_id!(DynOutputError); 591 } 592 } 593 module_plugin_dyn_newtype_encode_decode!(DynOutputError); 594 595 module_plugin_dyn_newtype_clone_passthrough!(DynOutputError); 596 597 module_plugin_dyn_newtype_eq_passthrough!(DynOutputError); 598 599 module_plugin_dyn_newtype_display_passthrough!(DynOutputError); 600 601 pub trait IInputError: Debug + Display + DynEncodable { 602 fn as_any(&self) -> &(dyn Any + Send + Sync); 603 fn clone(&self, module_instance_id: ModuleInstanceId) -> DynInputError; 604 fn dyn_hash(&self) -> u64; 605 606 fn erased_eq_no_instance_id(&self, other: &DynInputError) -> bool; 607 } 608 609 module_plugin_dyn_newtype_define! { 610 pub DynInputError(Box<IInputError>) 611 } 612 module_plugin_static_trait_define! { 613 DynInputError, InputError, IInputError, 614 { }, 615 { 616 erased_eq_no_instance_id!(DynInputError); 617 } 618 } 619 module_plugin_dyn_newtype_encode_decode!(DynInputError); 620 621 module_plugin_dyn_newtype_clone_passthrough!(DynInputError); 622 623 module_plugin_dyn_newtype_eq_passthrough!(DynInputError); 624 625 module_plugin_dyn_newtype_display_passthrough!(DynInputError);