mod.rs
1 //! This module defines a binary encoding interface which is more suitable for 2 //! consensus critical encoding than e.g. `bincode`. Over time all structs that 3 //! need to be encoded to binary will be migrated to this interface. 4 //! 5 //! This code is based on corresponding `rust-bitcoin` types. 6 //! 7 //! See [`Encodable`] and [`Decodable`] for two main traits. 8 9 pub mod as_hex; 10 mod bls12_381; 11 mod btc; 12 mod secp256k1; 13 mod threshold_crypto; 14 15 #[cfg(not(target_family = "wasm"))] 16 mod tls; 17 18 use std::any::TypeId; 19 use std::borrow::Cow; 20 use std::collections::{BTreeMap, BTreeSet}; 21 use std::fmt::{Debug, Formatter}; 22 use std::io::{self, Error, Read, Write}; 23 use std::time::{Duration, SystemTime, UNIX_EPOCH}; 24 use std::{cmp, mem}; 25 26 use anyhow::{format_err, Context}; 27 pub use fedimint_derive::{Decodable, Encodable}; 28 use hex::{FromHex, ToHex}; 29 use lightning::util::ser::{Readable, Writeable}; 30 use serde::{Deserialize, Serialize}; 31 use thiserror::Error; 32 33 use crate::core::ModuleInstanceId; 34 use crate::module::registry::ModuleDecoderRegistry; 35 use crate::util::SafeUrl; 36 37 /// Object-safe trait for things that can encode themselves 38 /// 39 /// Like `rust-bitcoin`'s `consensus_encode`, but without generics, 40 /// so can be used in `dyn` objects. 41 pub trait DynEncodable { 42 fn consensus_encode_dyn( 43 &self, 44 writer: &mut dyn std::io::Write, 45 ) -> Result<usize, std::io::Error>; 46 } 47 48 impl Encodable for dyn DynEncodable { 49 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 50 self.consensus_encode_dyn(writer) 51 } 52 } 53 54 impl<T> DynEncodable for T 55 where 56 T: Encodable, 57 { 58 fn consensus_encode_dyn( 59 &self, 60 mut writer: &mut dyn std::io::Write, 61 ) -> Result<usize, std::io::Error> { 62 <Self as Encodable>::consensus_encode(self, &mut writer) 63 } 64 } 65 66 impl Encodable for Box<dyn DynEncodable> { 67 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 68 (**self).consensus_encode_dyn(writer) 69 } 70 } 71 72 /// Data which can be encoded in a consensus-consistent way 73 pub trait Encodable { 74 /// Encode an object with a well-defined format. 75 /// Returns the number of bytes written on success. 76 /// 77 /// The only errors returned are errors propagated from the writer. 78 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error>; 79 80 /// [`Self::consensus_encode`] to newly allocated `Vec<u8>` 81 fn consensus_encode_to_vec(&self) -> Vec<u8> { 82 let mut bytes = vec![]; 83 self.consensus_encode(&mut bytes) 84 .expect("encoding to bytes can't fail for io reasons"); 85 bytes 86 } 87 88 /// Encode and convert to hex string representation 89 fn consensus_encode_to_hex(&self) -> String { 90 let mut bytes = vec![]; 91 self.consensus_encode(&mut bytes) 92 .expect("encoding to bytes can't fail for io reasons"); 93 // TODO: This double allocation offends real Rustaceans. We should 94 // be able to go straight to String, but this use case seems under-served 95 // by hex encoding crates. 96 bytes.encode_hex() 97 } 98 99 /// Encode without storing the encoding, return the size 100 fn consensus_encode_to_len(&self) -> usize { 101 self.consensus_encode(&mut io::sink()) 102 .expect("encoding to bytes can't fail for io reasons") 103 } 104 /// Generate a SHA256 hash of the consensus encoding using the default hash 105 /// engine for `H`. 106 /// 107 /// Can be used to validate all federation members agree on state without 108 /// revealing the object 109 fn consensus_hash<H>(&self) -> H 110 where 111 H: bitcoin_hashes::Hash, 112 H::Engine: std::io::Write, 113 { 114 let mut engine = H::engine(); 115 self.consensus_encode(&mut engine) 116 .expect("writing to HashEngine cannot fail"); 117 H::from_engine(engine) 118 } 119 } 120 121 /// Maximum size, in bytes, of data we are allowed to ever decode 122 /// for a single value. 123 pub const MAX_DECODE_SIZE: usize = 16_000_000; 124 125 /// Data which can be encoded in a consensus-consistent way 126 pub trait Decodable: Sized { 127 /// Decode `Self` from a size-limited reader. 128 /// 129 /// Like `consensus_decode` but relies on the reader being limited in the 130 /// amount of data it returns, e.g. by being wrapped in 131 /// [`std::io::Take`]. 132 /// 133 /// Failing to abide to this requirement might lead to memory exhaustion 134 /// caused by malicious inputs. 135 /// 136 /// Users should default to `consensus_decode`, but when data to be decoded 137 /// is already in a byte vector of a limited size, calling this function 138 /// directly might be marginally faster (due to avoiding extra checks). 139 /// 140 /// ### Rules for trait implementations 141 /// 142 /// * Simple types that that have a fixed size (own and member fields), 143 /// don't have to overwrite this method, or be concern with it, should 144 /// only impl `consensus_decode`. 145 /// * Types that deserialize based on decoded untrusted length should 146 /// implement `consensus_decode_from_finite_reader` only: 147 /// * Default implementation of `consensus_decode` will forward to 148 /// `consensus_decode_bytes_from_finite_reader` with the reader wrapped 149 /// by `Take`, protecting from readers that keep returning data. 150 /// * Implementation must make sure to put a cap on things like 151 /// `Vec::with_capacity` and other allocations to avoid oversized 152 /// allocations, and rely on the reader being finite and running out of 153 /// data, and collections reallocating on a legitimately oversized input 154 /// data, instead of trying to enforce arbitrary length limits. 155 /// * Types that contain other types that might be require limited reader 156 /// (thus implementing `consensus_decode_from_finite_reader`), should also 157 /// implement it applying same rules, and in addition make sure to call 158 /// `consensus_decode_from_finite_reader` on all members, to avoid 159 /// creating redundant `Take` wrappers (`Take<Take<...>>`). Failure to do 160 /// so might result only in a tiny performance hit. 161 #[inline] 162 fn consensus_decode_from_finite_reader<R: std::io::Read>( 163 r: &mut R, 164 modules: &ModuleDecoderRegistry, 165 ) -> Result<Self, DecodeError> { 166 // This method is always strictly less general than, `consensus_decode`, so it's 167 // safe and make sense to default to just calling it. This way most 168 // types, that don't care about protecting against resource exhaustion 169 // due to malicious input, can just ignore it. 170 Self::consensus_decode(r, modules) 171 } 172 173 /// Decode an object with a well-defined format. 174 /// 175 /// This is the method that should be implemented for a typical, fixed sized 176 /// type implementing this trait. Default implementation is wrapping the 177 /// reader in [`std::io::Take`] to limit the input size to 178 /// [`MAX_DECODE_SIZE`], and forwards the call to 179 /// [`Self::consensus_decode_from_finite_reader`], which is convenient 180 /// for types that override [`Self::consensus_decode_from_finite_reader`] 181 /// instead. 182 #[inline] 183 fn consensus_decode<R: std::io::Read>( 184 r: &mut R, 185 modules: &ModuleDecoderRegistry, 186 ) -> Result<Self, DecodeError> { 187 Self::consensus_decode_from_finite_reader(&mut r.take(MAX_DECODE_SIZE as u64), modules) 188 } 189 190 /// Decode an object from hex 191 fn consensus_decode_hex( 192 hex: &str, 193 modules: &ModuleDecoderRegistry, 194 ) -> Result<Self, DecodeError> { 195 let bytes = Vec::<u8>::from_hex(hex) 196 .map_err(anyhow::Error::from) 197 .map_err(DecodeError::new_custom)?; 198 let mut reader = std::io::Cursor::new(bytes); 199 Decodable::consensus_decode(&mut reader, modules) 200 } 201 202 fn consensus_decode_vec( 203 bytes: Vec<u8>, 204 modules: &ModuleDecoderRegistry, 205 ) -> Result<Self, DecodeError> { 206 let mut reader = std::io::Cursor::new(bytes); 207 Decodable::consensus_decode(&mut reader, modules) 208 } 209 } 210 211 impl Encodable for SafeUrl { 212 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> { 213 self.to_string().consensus_encode(writer) 214 } 215 } 216 217 impl Decodable for SafeUrl { 218 fn consensus_decode_from_finite_reader<D: std::io::Read>( 219 d: &mut D, 220 modules: &ModuleDecoderRegistry, 221 ) -> Result<Self, DecodeError> { 222 String::consensus_decode_from_finite_reader(d, modules)? 223 .parse::<SafeUrl>() 224 .map_err(DecodeError::from_err) 225 } 226 } 227 228 #[derive(Debug, Error)] 229 pub struct DecodeError(pub(crate) anyhow::Error); 230 231 impl DecodeError { 232 pub fn new_custom(e: anyhow::Error) -> Self { 233 Self(e) 234 } 235 } 236 237 impl From<anyhow::Error> for DecodeError { 238 fn from(e: anyhow::Error) -> Self { 239 DecodeError(e) 240 } 241 } 242 243 pub use lightning::util::ser::BigSize; 244 245 impl Encodable for BigSize { 246 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 247 let mut writer = CountWrite::from(writer); 248 self.write(&mut writer)?; 249 Ok(usize::try_from(writer.count()).expect("can't overflow")) 250 } 251 } 252 253 impl Decodable for BigSize { 254 fn consensus_decode<R: std::io::Read>( 255 r: &mut R, 256 _modules: &ModuleDecoderRegistry, 257 ) -> Result<Self, DecodeError> { 258 BigSize::read(r) 259 .map_err(|e| DecodeError::new_custom(anyhow::anyhow!("BigSize decoding error: {e:?}"))) 260 } 261 } 262 263 macro_rules! impl_encode_decode_num_as_plain { 264 ($num_type:ty) => { 265 impl Encodable for $num_type { 266 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> { 267 let bytes = self.to_be_bytes(); 268 writer.write_all(&bytes[..])?; 269 Ok(bytes.len()) 270 } 271 } 272 273 impl Decodable for $num_type { 274 fn consensus_decode<D: std::io::Read>( 275 d: &mut D, 276 _modules: &ModuleDecoderRegistry, 277 ) -> Result<Self, crate::encoding::DecodeError> { 278 let mut bytes = [0u8; (<$num_type>::BITS / 8) as usize]; 279 d.read_exact(&mut bytes).map_err(DecodeError::from_err)?; 280 Ok(<$num_type>::from_be_bytes(bytes)) 281 } 282 } 283 }; 284 } 285 286 macro_rules! impl_encode_decode_num_as_bigsize { 287 ($num_type:ty) => { 288 impl Encodable for $num_type { 289 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> { 290 BigSize(*self as u64).consensus_encode(writer) 291 } 292 } 293 294 impl Decodable for $num_type { 295 fn consensus_decode<D: std::io::Read>( 296 d: &mut D, 297 _modules: &ModuleDecoderRegistry, 298 ) -> Result<Self, crate::encoding::DecodeError> { 299 let varint = BigSize::consensus_decode(d, &Default::default()) 300 .context(concat!("VarInt inside ", stringify!($num_type)))?; 301 <$num_type>::try_from(varint.0).map_err(crate::encoding::DecodeError::from_err) 302 } 303 } 304 }; 305 } 306 307 impl_encode_decode_num_as_bigsize!(u64); 308 impl_encode_decode_num_as_bigsize!(u32); 309 impl_encode_decode_num_as_bigsize!(u16); 310 impl_encode_decode_num_as_plain!(u8); 311 312 macro_rules! impl_encode_decode_tuple { 313 ($($x:ident),*) => ( 314 #[allow(non_snake_case)] 315 impl <$($x: Encodable),*> Encodable for ($($x),*) { 316 fn consensus_encode<W: std::io::Write>(&self, s: &mut W) -> Result<usize, std::io::Error> { 317 let &($(ref $x),*) = self; 318 let mut len = 0; 319 $(len += $x.consensus_encode(s)?;)* 320 Ok(len) 321 } 322 } 323 324 #[allow(non_snake_case)] 325 impl<$($x: Decodable),*> Decodable for ($($x),*) { 326 fn consensus_decode<D: std::io::Read>(d: &mut D, modules: &ModuleDecoderRegistry) -> Result<Self, DecodeError> { 327 Ok(($({let $x = Decodable::consensus_decode(d, modules)?; $x }),*)) 328 } 329 } 330 ); 331 } 332 333 /// Specialized version of Encodable for bytes 334 pub fn consensus_encode_bytes<W: std::io::Write>( 335 bytes: &[u8], 336 writer: &mut W, 337 ) -> Result<usize, Error> { 338 let mut len = 0; 339 len += (bytes.len() as u64).consensus_encode(writer)?; 340 writer.write_all(bytes)?; 341 len += bytes.len(); 342 Ok(len) 343 } 344 345 /// Specialized version of Encodable for static byte arrays 346 pub fn consensus_encode_bytes_static<const N: usize, W: std::io::Write>( 347 bytes: &[u8; N], 348 writer: &mut W, 349 ) -> Result<usize, Error> { 350 writer.write_all(bytes)?; 351 Ok(bytes.len()) 352 } 353 354 struct ReadBytesFromFiniteReaderOpts { 355 len: usize, 356 chunk_size: usize, 357 } 358 359 /// Read `opts.len` bytes from reader, where `opts.len` could potentially be 360 /// malicious. 361 /// 362 /// Adapted from <https://github.com/rust-bitcoin/rust-bitcoin/blob/e2b9555070d9357fb552e56085fb6fb3f0274560/bitcoin/src/consensus/encode.rs#L659> 363 #[inline] 364 fn read_bytes_from_finite_reader<D: Read + ?Sized>( 365 d: &mut D, 366 mut opts: ReadBytesFromFiniteReaderOpts, 367 ) -> Result<Vec<u8>, io::Error> { 368 let mut ret = vec![]; 369 370 assert_ne!(opts.chunk_size, 0); 371 372 while opts.len > 0 { 373 let chunk_start = ret.len(); 374 let chunk_size = core::cmp::min(opts.len, opts.chunk_size); 375 let chunk_end = chunk_start + chunk_size; 376 ret.resize(chunk_end, 0u8); 377 d.read_exact(&mut ret[chunk_start..chunk_end])?; 378 opts.len -= chunk_size; 379 } 380 381 Ok(ret) 382 } 383 384 /// Specialized version of Decodable for bytes 385 pub fn consensus_decode_bytes<D: std::io::Read>(r: &mut D) -> Result<Vec<u8>, DecodeError> { 386 consensus_decode_bytes_from_finite_reader(&mut r.take(MAX_DECODE_SIZE as u64)) 387 } 388 389 /// Specialized version of Decodable for bytes 390 pub fn consensus_decode_bytes_from_finite_reader<D: std::io::Read>( 391 r: &mut D, 392 ) -> Result<Vec<u8>, DecodeError> { 393 let len = u64::consensus_decode_from_finite_reader(r, &Default::default())?; 394 395 let len: usize = 396 usize::try_from(len).map_err(|_| DecodeError::from_str("size exceeds memory"))?; 397 398 let opts = ReadBytesFromFiniteReaderOpts { 399 len, 400 chunk_size: 64 * 1024, 401 }; 402 403 read_bytes_from_finite_reader(r, opts).map_err(DecodeError::from_err) 404 } 405 406 /// Specialized version of Decodable for fixed-size byte arrays 407 pub fn consensus_decode_bytes_static<const N: usize, D: std::io::Read>( 408 r: &mut D, 409 ) -> Result<[u8; N], DecodeError> { 410 consensus_decode_bytes_static_from_finite_reader(&mut r.take(MAX_DECODE_SIZE as u64)) 411 } 412 /// Specialized version of Decodable for fixed-size byte arrays 413 pub fn consensus_decode_bytes_static_from_finite_reader<const N: usize, D: std::io::Read>( 414 r: &mut D, 415 ) -> Result<[u8; N], DecodeError> { 416 let mut bytes = [0u8; N]; 417 r.read_exact(bytes.as_mut_slice()) 418 .map_err(DecodeError::from_err)?; 419 Ok(bytes) 420 } 421 422 impl_encode_decode_tuple!(T1, T2); 423 impl_encode_decode_tuple!(T1, T2, T3); 424 impl_encode_decode_tuple!(T1, T2, T3, T4); 425 426 impl<T> Encodable for &[T] 427 where 428 T: Encodable + 'static, 429 { 430 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> { 431 if TypeId::of::<T>() == TypeId::of::<u8>() { 432 // unsafe: we've just checked that T is `u8` so the transmute here is a no-op 433 return consensus_encode_bytes(unsafe { mem::transmute::<&[T], &[u8]>(self) }, writer); 434 } 435 436 let mut len = 0; 437 len += (self.len() as u64).consensus_encode(writer)?; 438 439 for item in self.iter() { 440 len += item.consensus_encode(writer)?; 441 } 442 Ok(len) 443 } 444 } 445 446 impl<T> Encodable for Vec<T> 447 where 448 T: Encodable + 'static, 449 { 450 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> { 451 (self as &[T]).consensus_encode(writer) 452 } 453 } 454 455 impl<T> Decodable for Vec<T> 456 where 457 T: Decodable + 'static, 458 { 459 fn consensus_decode_from_finite_reader<D: std::io::Read>( 460 d: &mut D, 461 modules: &ModuleDecoderRegistry, 462 ) -> Result<Self, DecodeError> { 463 if TypeId::of::<T>() == TypeId::of::<u8>() { 464 // unsafe: we've just checked that T is `u8` so the transmute here is a no-op 465 return Ok(unsafe { 466 mem::transmute::<Vec<u8>, Vec<T>>(consensus_decode_bytes_from_finite_reader(d)?) 467 }); 468 } 469 let len = u64::consensus_decode_from_finite_reader(d, modules)?; 470 471 // `collect` under the hood uses `FromIter::from_iter`, which can potentially be 472 // backed by code like: 473 // <https://github.com/rust-lang/rust/blob/fe03b46ee4688a99d7155b4f9dcd875b6903952d/library/alloc/src/vec/spec_from_iter_nested.rs#L31> 474 // This can take `size_hint` from input iterator and pre-allocate memory 475 // upfront with `Vec::with_capacity`. Because of that untrusted `len` 476 // should not be used directly. 477 let cap_len = cmp::min(8_000 / mem::size_of::<T>() as u64, len); 478 479 // Up to a cap, use the (potentially specialized for better perf in stdlib) 480 // `from_iter`. 481 let mut v: Vec<_> = (0..cap_len) 482 .map(|_| T::consensus_decode_from_finite_reader(d, modules)) 483 .collect::<Result<Vec<_>, DecodeError>>()?; 484 485 // Add any excess manually avoiding any surprises. 486 while (v.len() as u64) < len { 487 v.push(T::consensus_decode_from_finite_reader(d, modules)?); 488 } 489 490 assert_eq!(v.len() as u64, len); 491 492 Ok(v) 493 } 494 } 495 496 #[test] 497 fn vec_decode_sanity() { 498 let buf = [ 499 0xffu8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 500 ]; 501 502 // On malicious large len, return an error instead of panicking. 503 // Note: This was supposed to expose the panic, but I was not able to trigger it 504 // for some reason. 505 assert!(Vec::<u8>::consensus_decode(&mut buf.as_slice(), &Default::default()).is_err()); 506 assert!(Vec::<u16>::consensus_decode(&mut buf.as_slice(), &Default::default()).is_err()); 507 } 508 509 impl<T, const SIZE: usize> Encodable for [T; SIZE] 510 where 511 T: Encodable + 'static, 512 { 513 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 514 if TypeId::of::<T>() == TypeId::of::<u8>() { 515 // unsafe: we've just checked that T is `u8` so the transmute here is a no-op 516 return consensus_encode_bytes_static( 517 unsafe { mem::transmute::<&[T; SIZE], &[u8; SIZE]>(self) }, 518 writer, 519 ); 520 } 521 522 let mut len = 0; 523 for item in self.iter() { 524 len += item.consensus_encode(writer)?; 525 } 526 Ok(len) 527 } 528 } 529 530 // From <https://github.com/rust-lang/rust/issues/61956> 531 unsafe fn horribe_array_transmute_workaround<const N: usize, A, B>(mut arr: [A; N]) -> [B; N] { 532 let ptr = &mut arr as *mut _ as *mut [B; N]; 533 let res = unsafe { ptr.read() }; 534 core::mem::forget(arr); 535 res 536 } 537 538 impl<T, const SIZE: usize> Decodable for [T; SIZE] 539 where 540 T: Decodable + Debug + Default + Copy + 'static, 541 { 542 fn consensus_decode_from_finite_reader<D: std::io::Read>( 543 d: &mut D, 544 modules: &ModuleDecoderRegistry, 545 ) -> Result<Self, DecodeError> { 546 if TypeId::of::<T>() == TypeId::of::<u8>() { 547 // unsafe: we've just checked that T is `u8` so the transmute here is a no-op 548 return Ok(unsafe { 549 let arr = consensus_decode_bytes_static_from_finite_reader(d)?; 550 horribe_array_transmute_workaround::<SIZE, u8, T>(arr) 551 }); 552 } 553 // todo: impl without copy 554 let mut data = [T::default(); SIZE]; 555 for item in data.iter_mut() { 556 *item = T::consensus_decode_from_finite_reader(d, modules)?; 557 } 558 Ok(data) 559 } 560 } 561 562 impl<T> Encodable for Option<T> 563 where 564 T: Encodable, 565 { 566 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 567 let mut len = 0; 568 if let Some(inner) = self { 569 len += 1u8.consensus_encode(writer)?; 570 len += inner.consensus_encode(writer)?; 571 } else { 572 len += 0u8.consensus_encode(writer)?; 573 } 574 Ok(len) 575 } 576 } 577 578 impl<T> Decodable for Option<T> 579 where 580 T: Decodable, 581 { 582 fn consensus_decode_from_finite_reader<D: std::io::Read>( 583 d: &mut D, 584 modules: &ModuleDecoderRegistry, 585 ) -> Result<Self, DecodeError> { 586 let flag = u8::consensus_decode_from_finite_reader(d, modules)?; 587 match flag { 588 0 => Ok(None), 589 1 => Ok(Some(T::consensus_decode_from_finite_reader(d, modules)?)), 590 _ => Err(DecodeError::from_str( 591 "Invalid flag for option enum, expected 0 or 1", 592 )), 593 } 594 } 595 } 596 597 impl<T, E> Encodable for Result<T, E> 598 where 599 T: Encodable, 600 E: Encodable, 601 { 602 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 603 let mut len = 0; 604 605 match self { 606 Ok(value) => { 607 len += 1u8.consensus_encode(writer)?; 608 len += value.consensus_encode(writer)?; 609 } 610 Err(error) => { 611 len += 0u8.consensus_encode(writer)?; 612 len += error.consensus_encode(writer)?; 613 } 614 } 615 616 Ok(len) 617 } 618 } 619 620 impl<T, E> Decodable for Result<T, E> 621 where 622 T: Decodable, 623 E: Decodable, 624 { 625 fn consensus_decode_from_finite_reader<D: std::io::Read>( 626 d: &mut D, 627 modules: &ModuleDecoderRegistry, 628 ) -> Result<Self, DecodeError> { 629 let flag = u8::consensus_decode_from_finite_reader(d, modules)?; 630 match flag { 631 0 => Ok(Err(E::consensus_decode_from_finite_reader(d, modules)?)), 632 1 => Ok(Ok(T::consensus_decode_from_finite_reader(d, modules)?)), 633 _ => Err(DecodeError::from_str( 634 "Invalid flag for option enum, expected 0 or 1", 635 )), 636 } 637 } 638 } 639 640 impl<T> Encodable for Box<T> 641 where 642 T: Encodable, 643 { 644 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> { 645 self.as_ref().consensus_encode(writer) 646 } 647 } 648 649 impl<T> Decodable for Box<T> 650 where 651 T: Decodable, 652 { 653 fn consensus_decode_from_finite_reader<D: std::io::Read>( 654 d: &mut D, 655 modules: &ModuleDecoderRegistry, 656 ) -> Result<Self, DecodeError> { 657 Ok(Box::new(T::consensus_decode_from_finite_reader( 658 d, modules, 659 )?)) 660 } 661 } 662 663 impl Encodable for () { 664 fn consensus_encode<W: std::io::Write>( 665 &self, 666 _writer: &mut W, 667 ) -> Result<usize, std::io::Error> { 668 Ok(0) 669 } 670 } 671 672 impl Decodable for () { 673 fn consensus_decode<D: std::io::Read>( 674 _d: &mut D, 675 _modules: &ModuleDecoderRegistry, 676 ) -> Result<Self, DecodeError> { 677 Ok(()) 678 } 679 } 680 681 impl Encodable for &str { 682 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> { 683 self.as_bytes().consensus_encode(writer) 684 } 685 } 686 687 impl Encodable for String { 688 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> { 689 self.as_bytes().consensus_encode(writer) 690 } 691 } 692 693 impl Decodable for String { 694 fn consensus_decode_from_finite_reader<D: std::io::Read>( 695 d: &mut D, 696 modules: &ModuleDecoderRegistry, 697 ) -> Result<Self, DecodeError> { 698 String::from_utf8(Decodable::consensus_decode_from_finite_reader(d, modules)?) 699 .map_err(DecodeError::from_err) 700 } 701 } 702 703 impl Encodable for SystemTime { 704 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 705 let duration = self.duration_since(UNIX_EPOCH).expect("valid duration"); 706 duration.consensus_encode_dyn(writer) 707 } 708 } 709 710 impl Decodable for SystemTime { 711 fn consensus_decode<D: std::io::Read>( 712 d: &mut D, 713 modules: &ModuleDecoderRegistry, 714 ) -> Result<Self, DecodeError> { 715 let duration = Duration::consensus_decode(d, modules)?; 716 Ok(UNIX_EPOCH + duration) 717 } 718 } 719 720 impl Encodable for Duration { 721 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 722 let mut count = 0; 723 count += self.as_secs().consensus_encode(writer)?; 724 count += self.subsec_nanos().consensus_encode(writer)?; 725 726 Ok(count) 727 } 728 } 729 730 impl Decodable for Duration { 731 fn consensus_decode<D: std::io::Read>( 732 d: &mut D, 733 modules: &ModuleDecoderRegistry, 734 ) -> Result<Self, DecodeError> { 735 let secs = Decodable::consensus_decode(d, modules)?; 736 let nsecs = Decodable::consensus_decode(d, modules)?; 737 Ok(Duration::new(secs, nsecs)) 738 } 739 } 740 741 impl Encodable for lightning_invoice::Bolt11Invoice { 742 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> { 743 self.to_string().consensus_encode(writer) 744 } 745 } 746 747 impl Encodable for lightning_invoice::RoutingFees { 748 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> { 749 let mut len = 0; 750 len += self.base_msat.consensus_encode(writer)?; 751 len += self.proportional_millionths.consensus_encode(writer)?; 752 Ok(len) 753 } 754 } 755 756 impl Decodable for lightning_invoice::RoutingFees { 757 fn consensus_decode<D: std::io::Read>( 758 d: &mut D, 759 modules: &ModuleDecoderRegistry, 760 ) -> Result<Self, DecodeError> { 761 let base_msat = Decodable::consensus_decode(d, modules)?; 762 let proportional_millionths = Decodable::consensus_decode(d, modules)?; 763 Ok(lightning_invoice::RoutingFees { 764 base_msat, 765 proportional_millionths, 766 }) 767 } 768 } 769 770 impl Decodable for lightning_invoice::Bolt11Invoice { 771 fn consensus_decode<D: std::io::Read>( 772 d: &mut D, 773 modules: &ModuleDecoderRegistry, 774 ) -> Result<Self, DecodeError> { 775 String::consensus_decode(d, modules)? 776 .parse::<lightning_invoice::Bolt11Invoice>() 777 .map_err(DecodeError::from_err) 778 } 779 } 780 781 impl Encodable for bool { 782 fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<usize, Error> { 783 let bool_as_u8 = u8::from(*self); 784 writer.write_all(&[bool_as_u8])?; 785 Ok(1) 786 } 787 } 788 789 impl Decodable for bool { 790 fn consensus_decode<D: Read>( 791 d: &mut D, 792 _modules: &ModuleDecoderRegistry, 793 ) -> Result<Self, DecodeError> { 794 let mut bool_as_u8 = [0u8]; 795 d.read_exact(&mut bool_as_u8) 796 .map_err(DecodeError::from_err)?; 797 match bool_as_u8[0] { 798 0 => Ok(false), 799 1 => Ok(true), 800 _ => Err(DecodeError::from_str("Out of range, expected 0 or 1")), 801 } 802 } 803 } 804 805 impl DecodeError { 806 // TODO: think about better name 807 #[allow(clippy::should_implement_trait)] 808 pub fn from_str(s: &'static str) -> Self { 809 #[derive(Debug)] 810 struct StrError(&'static str); 811 812 impl std::fmt::Display for StrError { 813 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 814 std::fmt::Display::fmt(&self.0, f) 815 } 816 } 817 818 impl std::error::Error for StrError {} 819 820 DecodeError(anyhow::Error::from(StrError(s))) 821 } 822 823 pub fn from_err<E: std::error::Error + Send + Sync + 'static>(e: E) -> Self { 824 DecodeError(anyhow::Error::from(e)) 825 } 826 } 827 828 impl std::fmt::Display for DecodeError { 829 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 830 std::fmt::Display::fmt(&self.0, f) 831 } 832 } 833 834 impl<K, V> Encodable for BTreeMap<K, V> 835 where 836 K: Encodable, 837 V: Encodable, 838 { 839 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 840 let mut len = 0; 841 len += (self.len() as u64).consensus_encode(writer)?; 842 for (k, v) in self.iter() { 843 len += k.consensus_encode(writer)?; 844 len += v.consensus_encode(writer)?; 845 } 846 Ok(len) 847 } 848 } 849 850 impl<K, V> Decodable for BTreeMap<K, V> 851 where 852 K: Decodable + Ord, 853 V: Decodable, 854 { 855 fn consensus_decode_from_finite_reader<D: std::io::Read>( 856 d: &mut D, 857 modules: &ModuleDecoderRegistry, 858 ) -> Result<Self, DecodeError> { 859 let mut res = BTreeMap::new(); 860 let len = u64::consensus_decode_from_finite_reader(d, modules)?; 861 for _ in 0..len { 862 let k = K::consensus_decode_from_finite_reader(d, modules)?; 863 if res 864 .last_key_value() 865 .map(|(prev_key, _v)| k <= *prev_key) 866 .unwrap_or_default() 867 { 868 return Err(DecodeError::from_str("Non-canonical encoding")); 869 } 870 let v = V::consensus_decode_from_finite_reader(d, modules)?; 871 if res.insert(k, v).is_some() { 872 return Err(DecodeError(format_err!("Duplicate key"))); 873 } 874 } 875 Ok(res) 876 } 877 } 878 879 impl<K> Encodable for BTreeSet<K> 880 where 881 K: Encodable, 882 { 883 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 884 let mut len = 0; 885 len += (self.len() as u64).consensus_encode(writer)?; 886 for k in self.iter() { 887 len += k.consensus_encode(writer)?; 888 } 889 Ok(len) 890 } 891 } 892 893 impl<K> Decodable for BTreeSet<K> 894 where 895 K: Decodable + Ord, 896 { 897 fn consensus_decode_from_finite_reader<D: std::io::Read>( 898 d: &mut D, 899 modules: &ModuleDecoderRegistry, 900 ) -> Result<Self, DecodeError> { 901 let mut res = BTreeSet::new(); 902 let len = u64::consensus_decode_from_finite_reader(d, modules)?; 903 for _ in 0..len { 904 let k = K::consensus_decode_from_finite_reader(d, modules)?; 905 if res 906 .last() 907 .map(|prev_key| k <= *prev_key) 908 .unwrap_or_default() 909 { 910 return Err(DecodeError::from_str("Non-canonical encoding")); 911 } 912 if !res.insert(k) { 913 return Err(DecodeError(format_err!("Duplicate key"))); 914 } 915 } 916 Ok(res) 917 } 918 } 919 920 impl Encodable for Cow<'static, str> { 921 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 922 self.as_ref().consensus_encode(writer) 923 } 924 } 925 926 impl Decodable for Cow<'static, str> { 927 fn consensus_decode<D: std::io::Read>( 928 d: &mut D, 929 modules: &ModuleDecoderRegistry, 930 ) -> Result<Self, DecodeError> { 931 Ok(Cow::Owned(String::consensus_decode(d, modules)?)) 932 } 933 } 934 935 /// A writer counting number of writes written to it 936 /// 937 /// Copy&pasted from <https://github.com/SOF3/count-write> which 938 /// uses Apache license (and it's a trivial amount of code, repeating 939 /// on stack overflow). 940 pub struct CountWrite<W> { 941 inner: W, 942 count: u64, 943 } 944 945 impl<W> CountWrite<W> { 946 /// Returns the number of bytes successfully written so far 947 pub fn count(&self) -> u64 { 948 self.count 949 } 950 951 /// Extracts the inner writer, discarding this wrapper 952 pub fn into_inner(self) -> W { 953 self.inner 954 } 955 } 956 957 impl<W> From<W> for CountWrite<W> { 958 fn from(inner: W) -> Self { 959 Self { inner, count: 0 } 960 } 961 } 962 963 impl<W: Write> Write for CountWrite<W> { 964 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 965 let written = self.inner.write(buf)?; 966 self.count += written as u64; 967 Ok(written) 968 } 969 970 fn flush(&mut self) -> io::Result<()> { 971 self.inner.flush() 972 } 973 } 974 975 /// A type that decodes `module_instance_id`-prefixed `T`s even 976 /// when corresponding `Decoder` is not available. 977 /// 978 /// All dyn-module types are encoded as: 979 /// 980 /// ```norust 981 /// module_instance_id | len_u64 | data 982 /// ``` 983 /// 984 /// So clients that don't have a corresponding module, can read 985 /// the `len_u64` and skip the amount of data specified in it. 986 /// 987 /// This type makes it more convenient. It's possible to attempt 988 /// to retry decoding after more modules become available by using 989 /// [`DynRawFallback::redecode_raw`]. 990 /// 991 /// Notably this struct does not ignore any errors. It only skips 992 /// decoding when the module decoder is not available. 993 #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] 994 pub enum DynRawFallback<T> { 995 Raw { 996 module_instance_id: ModuleInstanceId, 997 #[serde(with = "::fedimint_core::encoding::as_hex")] 998 raw: Vec<u8>, 999 }, 1000 Decoded(T), 1001 } 1002 1003 impl<T> DynRawFallback<T> 1004 where 1005 T: Decodable + 'static, 1006 { 1007 /// Get the decoded `T` or `None` if not decoded yet 1008 pub fn decoded(self) -> Option<T> { 1009 match self { 1010 DynRawFallback::Raw { .. } => None, 1011 DynRawFallback::Decoded(v) => Some(v), 1012 } 1013 } 1014 1015 /// Convert into the decoded `T` and panic if not decoded yet 1016 pub fn expect_decoded(self) -> T { 1017 match self { 1018 DynRawFallback::Raw { .. } => { 1019 panic!("Expected decoded value. Possibly `redecode_raw` call is missing.") 1020 } 1021 DynRawFallback::Decoded(v) => v, 1022 } 1023 } 1024 1025 /// Get the decoded `T` and panic if not decoded yet 1026 pub fn expect_decoded_ref(&self) -> &T { 1027 match self { 1028 DynRawFallback::Raw { .. } => { 1029 panic!("Expected decoded value. Possibly `redecode_raw` call is missing.") 1030 } 1031 DynRawFallback::Decoded(v) => v, 1032 } 1033 } 1034 1035 /// Attempt to re-decode raw values with new set of of `modules` 1036 /// 1037 /// In certain contexts it might be necessary to try again with 1038 /// a new set of modules. 1039 pub fn redecode_raw( 1040 self, 1041 decoders: &ModuleDecoderRegistry, 1042 ) -> Result<Self, crate::encoding::DecodeError> { 1043 Ok(match self { 1044 DynRawFallback::Raw { 1045 module_instance_id, 1046 raw, 1047 } => match decoders.get(module_instance_id) { 1048 Some(decoder) => DynRawFallback::Decoded(decoder.decode_complete( 1049 &mut &raw[..], 1050 raw.len() as u64, 1051 module_instance_id, 1052 decoders, 1053 )?), 1054 None => DynRawFallback::Raw { 1055 module_instance_id, 1056 raw, 1057 }, 1058 }, 1059 DynRawFallback::Decoded(v) => DynRawFallback::Decoded(v), 1060 }) 1061 } 1062 } 1063 1064 impl<T> From<T> for DynRawFallback<T> { 1065 fn from(value: T) -> Self { 1066 Self::Decoded(value) 1067 } 1068 } 1069 1070 impl<T> Decodable for DynRawFallback<T> 1071 where 1072 T: Decodable + 'static, 1073 { 1074 fn consensus_decode_from_finite_reader<R: std::io::Read>( 1075 reader: &mut R, 1076 decoders: &ModuleDecoderRegistry, 1077 ) -> Result<Self, crate::encoding::DecodeError> { 1078 let module_instance_id = 1079 fedimint_core::core::ModuleInstanceId::consensus_decode_from_finite_reader( 1080 reader, decoders, 1081 )?; 1082 Ok(match decoders.get(module_instance_id) { 1083 Some(decoder) => { 1084 let total_len_u64 = u64::consensus_decode_from_finite_reader(reader, decoders)?; 1085 DynRawFallback::Decoded(decoder.decode_complete( 1086 reader, 1087 total_len_u64, 1088 module_instance_id, 1089 decoders, 1090 )?) 1091 } 1092 None => { 1093 // since the decoder is not available, just read the raw data 1094 Self::Raw { 1095 module_instance_id, 1096 raw: Vec::consensus_decode_from_finite_reader(reader, decoders)?, 1097 } 1098 } 1099 }) 1100 } 1101 } 1102 1103 impl<T> Encodable for DynRawFallback<T> 1104 where 1105 T: Encodable, 1106 { 1107 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 1108 match self { 1109 DynRawFallback::Raw { 1110 module_instance_id, 1111 raw, 1112 } => { 1113 let mut written = module_instance_id.consensus_encode(writer)?; 1114 written += raw.consensus_encode(writer)?; 1115 Ok(written) 1116 } 1117 DynRawFallback::Decoded(v) => v.consensus_encode(writer), 1118 } 1119 } 1120 } 1121 1122 #[cfg(test)] 1123 mod tests { 1124 use std::fmt::Debug; 1125 use std::io::Cursor; 1126 use std::str::FromStr; 1127 1128 use super::*; 1129 use crate::db::DatabaseValue; 1130 use crate::encoding::{Decodable, Encodable}; 1131 1132 pub(crate) fn test_roundtrip<T>(value: T) 1133 where 1134 T: Encodable + Decodable + Eq + Debug, 1135 { 1136 let mut bytes = Vec::new(); 1137 let len = value.consensus_encode(&mut bytes).unwrap(); 1138 assert_eq!(len, bytes.len()); 1139 1140 let mut cursor = Cursor::new(bytes); 1141 let decoded = T::consensus_decode(&mut cursor, &ModuleDecoderRegistry::default()).unwrap(); 1142 assert_eq!(value, decoded); 1143 assert_eq!(cursor.position(), len as u64); 1144 } 1145 1146 pub(crate) fn test_roundtrip_expected<T>(value: T, expected: &[u8]) 1147 where 1148 T: Encodable + Decodable + Eq + Debug, 1149 { 1150 let mut bytes = Vec::new(); 1151 let len = value.consensus_encode(&mut bytes).unwrap(); 1152 assert_eq!(len, bytes.len()); 1153 assert_eq!(&expected, &bytes); 1154 1155 let mut cursor = Cursor::new(bytes); 1156 let decoded = T::consensus_decode(&mut cursor, &ModuleDecoderRegistry::default()).unwrap(); 1157 assert_eq!(value, decoded); 1158 assert_eq!(cursor.position(), len as u64); 1159 } 1160 1161 #[derive(Debug, Eq, PartialEq, Encodable, Decodable)] 1162 enum NoDefaultEnum { 1163 Foo, 1164 Bar(u32, String), 1165 Baz { baz: u8 }, 1166 } 1167 1168 #[derive(Debug, Eq, PartialEq, Encodable, Decodable)] 1169 enum DefaultEnum { 1170 Foo, 1171 Bar(u32, String), 1172 #[encodable_default] 1173 Default { 1174 variant: u64, 1175 bytes: Vec<u8>, 1176 }, 1177 } 1178 1179 #[test_log::test] 1180 fn test_derive_enum_no_default_roundtrip_success() { 1181 let enums = [ 1182 NoDefaultEnum::Foo, 1183 NoDefaultEnum::Bar( 1184 42, 1185 "The answer to life, the universe, and everything".to_string(), 1186 ), 1187 NoDefaultEnum::Baz { baz: 0 }, 1188 ]; 1189 1190 for e in enums { 1191 test_roundtrip(e); 1192 } 1193 } 1194 1195 #[test_log::test] 1196 fn test_derive_enum_no_default_decode_fail() { 1197 let unknown_variant = DefaultEnum::Default { 1198 variant: 42, 1199 bytes: vec![0, 1, 2, 3], 1200 }; 1201 let mut unknown_variant_encoding = vec![]; 1202 unknown_variant 1203 .consensus_encode(&mut unknown_variant_encoding) 1204 .unwrap(); 1205 1206 let mut cursor = Cursor::new(&unknown_variant_encoding); 1207 let decode_res = NoDefaultEnum::consensus_decode(&mut cursor, &Default::default()); 1208 1209 match decode_res { 1210 Ok(_) => panic!("Should return error"), 1211 Err(e) => assert!(e.to_string().contains("Invalid enum variant")), 1212 } 1213 } 1214 1215 #[test_log::test] 1216 fn test_derive_enum_default_decode_success() { 1217 let unknown_variant = NoDefaultEnum::Baz { baz: 123 }; 1218 let mut unknown_variant_encoding = vec![]; 1219 unknown_variant 1220 .consensus_encode(&mut unknown_variant_encoding) 1221 .unwrap(); 1222 1223 let mut cursor = Cursor::new(&unknown_variant_encoding); 1224 let decode_res = DefaultEnum::consensus_decode(&mut cursor, &Default::default()); 1225 1226 assert_eq!( 1227 decode_res.unwrap(), 1228 DefaultEnum::Default { 1229 variant: 2, 1230 bytes: vec![123], 1231 } 1232 ); 1233 } 1234 1235 #[test_log::test] 1236 fn test_derive_struct() { 1237 #[derive(Debug, Encodable, Decodable, Eq, PartialEq)] 1238 struct TestStruct { 1239 vec: Vec<u8>, 1240 num: u32, 1241 } 1242 1243 let reference = TestStruct { 1244 vec: vec![1, 2, 3], 1245 num: 42, 1246 }; 1247 let bytes = [3, 1, 2, 3, 42]; 1248 1249 test_roundtrip_expected(reference, &bytes); 1250 } 1251 1252 #[test_log::test] 1253 fn test_derive_tuple_struct() { 1254 #[derive(Debug, Encodable, Decodable, Eq, PartialEq)] 1255 struct TestStruct(Vec<u8>, u32); 1256 1257 let reference = TestStruct(vec![1, 2, 3], 42); 1258 let bytes = [3, 1, 2, 3, 42]; 1259 1260 test_roundtrip_expected(reference, &bytes); 1261 } 1262 1263 #[test_log::test] 1264 fn test_derive_enum() { 1265 #[derive(Debug, Encodable, Decodable, Eq, PartialEq)] 1266 enum TestEnum { 1267 Foo(Option<u64>), 1268 Bar { bazz: Vec<u8> }, 1269 } 1270 1271 let test_cases = [ 1272 (TestEnum::Foo(Some(42)), vec![0, 2, 1, 42]), 1273 (TestEnum::Foo(None), vec![0, 1, 0]), 1274 ( 1275 TestEnum::Bar { 1276 bazz: vec![1, 2, 3], 1277 }, 1278 vec![1, 4, 3, 1, 2, 3], 1279 ), 1280 ]; 1281 1282 for (reference, bytes) in test_cases { 1283 test_roundtrip_expected(reference, &bytes); 1284 } 1285 } 1286 1287 #[test_log::test] 1288 fn test_invoice() { 1289 let invoice_str = "lnbc100p1psj9jhxdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4q0d3p2sfluzdx45tqcs\ 1290 h2pu5qc7lgq0xs578ngs6s0s68ua4h7cvspp5q6rmq35js88zp5dvwrv9m459tnk2zunwj5jalqtyxqulh0l\ 1291 5gflssp5nf55ny5gcrfl30xuhzj3nphgj27rstekmr9fw3ny5989s300gyus9qyysgqcqpcrzjqw2sxwe993\ 1292 h5pcm4dxzpvttgza8zhkqxpgffcrf5v25nwpr3cmfg7z54kuqq8rgqqqqqqqq2qqqqq9qq9qrzjqd0ylaqcl\ 1293 j9424x9m8h2vcukcgnm6s56xfgu3j78zyqzhgs4hlpzvznlugqq9vsqqqqqqqlgqqqqqeqq9qrzjqwldmj9d\ 1294 ha74df76zhx6l9we0vjdquygcdt3kssupehe64g6yyp5yz5rhuqqwccqqyqqqqlgqqqqjcqq9qrzjqf9e58a\ 1295 guqr0rcun0ajlvmzq3ek63cw2w282gv3z5uupmuwvgjtq2z55qsqqg6qqqyqqqrtnqqqzq3cqygrzjqvphms\ 1296 ywntrrhqjcraumvc4y6r8v4z5v593trte429v4hredj7ms5z52usqq9ngqqqqqqqlgqqqqqqgq9qrzjq2v0v\ 1297 p62g49p7569ev48cmulecsxe59lvaw3wlxm7r982zxa9zzj7z5l0cqqxusqqyqqqqlgqqqqqzsqygarl9fh3\ 1298 8s0gyuxjjgux34w75dnc6xp2l35j7es3jd4ugt3lu0xzre26yg5m7ke54n2d5sym4xcmxtl8238xxvw5h5h5\ 1299 j5r6drg6k6zcqj0fcwg"; 1300 let invoice = invoice_str 1301 .parse::<lightning_invoice::Bolt11Invoice>() 1302 .unwrap(); 1303 test_roundtrip(invoice); 1304 } 1305 1306 #[test_log::test] 1307 fn test_btreemap() { 1308 test_roundtrip(BTreeMap::from([ 1309 ("a".to_string(), 1u32), 1310 ("b".to_string(), 2), 1311 ])); 1312 } 1313 1314 #[test_log::test] 1315 fn test_btreeset() { 1316 test_roundtrip(BTreeSet::from(["a".to_string(), "b".to_string()])); 1317 } 1318 1319 #[test_log::test] 1320 fn test_systemtime() { 1321 test_roundtrip(fedimint_core::time::now()); 1322 } 1323 1324 #[test] 1325 fn test_derive_empty_enum_decode() { 1326 #[derive(Debug, Encodable, Decodable)] 1327 enum NotConstructable {} 1328 1329 let vec = vec![42u8]; 1330 let mut cursor = Cursor::new(vec); 1331 1332 assert!( 1333 NotConstructable::consensus_decode(&mut cursor, &ModuleDecoderRegistry::default()) 1334 .is_err() 1335 ); 1336 } 1337 1338 #[test] 1339 fn test_custom_index_enum() { 1340 #[derive(Debug, PartialEq, Eq, Encodable, Decodable)] 1341 enum Old { 1342 Foo, 1343 Bar, 1344 Baz, 1345 } 1346 1347 #[derive(Debug, PartialEq, Eq, Encodable, Decodable)] 1348 enum New { 1349 #[encodable(index = 0)] 1350 Foo, 1351 #[encodable(index = 2)] 1352 Baz, 1353 #[encodable_default] 1354 Default { variant: u64, bytes: Vec<u8> }, 1355 } 1356 1357 let test_vector = vec![ 1358 (Old::Foo, New::Foo), 1359 ( 1360 Old::Bar, 1361 New::Default { 1362 variant: 1, 1363 bytes: vec![], 1364 }, 1365 ), 1366 (Old::Baz, New::Baz), 1367 ]; 1368 1369 for (old, new) in test_vector { 1370 let old_bytes = old.consensus_encode_to_vec(); 1371 let decoded_new = 1372 New::consensus_decode_vec(old_bytes, &Default::default()).expect("Decoding failed"); 1373 assert_eq!(decoded_new, new); 1374 } 1375 } 1376 1377 fn encode_value<T: Encodable>(value: &T) -> Vec<u8> { 1378 let mut writer = Vec::new(); 1379 value.consensus_encode(&mut writer).unwrap(); 1380 writer 1381 } 1382 1383 fn decode_value<T: Decodable>(bytes: &Vec<u8>) -> T { 1384 T::consensus_decode(&mut Cursor::new(bytes), &ModuleDecoderRegistry::default()).unwrap() 1385 } 1386 1387 fn keeps_ordering_after_serialization<T: Ord + Encodable + Decodable + Debug>(mut vec: Vec<T>) { 1388 vec.sort(); 1389 let mut encoded = vec.iter().map(encode_value).collect::<Vec<_>>(); 1390 encoded.sort(); 1391 let decoded = encoded.iter().map(decode_value).collect::<Vec<_>>(); 1392 for (i, (a, b)) in vec.iter().zip(decoded.iter()).enumerate() { 1393 assert_eq!(a, b, "difference at index {i}"); 1394 } 1395 } 1396 1397 #[test] 1398 fn test_lexicographical_sorting() { 1399 #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)] 1400 struct TestAmount(u64); 1401 let amounts = (0..20000).map(TestAmount).collect::<Vec<_>>(); 1402 keeps_ordering_after_serialization(amounts); 1403 1404 #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)] 1405 struct TestComplexAmount(u16, u32, u64); 1406 let complex_amounts = (10..20000) 1407 .flat_map(|i| { 1408 (i - 1..=i + 1).flat_map(move |j| { 1409 (i - 1..=i + 1).map(move |k| TestComplexAmount(i as u16, j as u32, k as u64)) 1410 }) 1411 }) 1412 .collect::<Vec<_>>(); 1413 keeps_ordering_after_serialization(complex_amounts); 1414 1415 #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)] 1416 struct Text(String); 1417 let texts = (' '..'~') 1418 .flat_map(|i| { 1419 (' '..'~') 1420 .map(|j| Text(format!("{i}{j}"))) 1421 .collect::<Vec<_>>() 1422 }) 1423 .collect::<Vec<_>>(); 1424 keeps_ordering_after_serialization(texts); 1425 1426 // bitcoin structures are not lexicographically sortable so we cannot 1427 // test them here. in future we may crate a wrapper type that is 1428 // lexicographically sortable to use when needed 1429 } 1430 1431 #[test] 1432 fn test_bitcoin_consensus_encoding() { 1433 // encodings should follow the bitcoin consensus encoding 1434 let txid = bitcoin::Txid::from_str( 1435 "51f7ed2f23e58cc6e139e715e9ce304a1e858416edc9079dd7b74fa8d2efc09a", 1436 ) 1437 .unwrap(); 1438 test_roundtrip_expected( 1439 txid, 1440 &[ 1441 154, 192, 239, 210, 168, 79, 183, 215, 157, 7, 201, 237, 22, 132, 133, 30, 74, 48, 1442 206, 233, 21, 231, 57, 225, 198, 140, 229, 35, 47, 237, 247, 81, 1443 ], 1444 ); 1445 let transaction: Vec<u8> = FromHex::from_hex( 1446 "02000000000101d35b66c54cf6c09b81a8d94cd5d179719cd7595c258449452a9305ab9b12df250200000000fdffffff020cd50a0000000000160014ae5d450b71c04218e6e81c86fcc225882d7b7caae695b22100000000160014f60834ef165253c571b11ce9fa74e46692fc5ec10248304502210092062c609f4c8dc74cd7d4596ecedc1093140d90b3fd94b4bdd9ad3e102ce3bc02206bb5a6afc68d583d77d5d9bcfb6252a364d11a307f3418be1af9f47f7b1b3d780121026e5628506ecd33242e5ceb5fdafe4d3066b5c0f159b3c05a621ef65f177ea28600000000" 1447 ).unwrap(); 1448 let transaction = 1449 bitcoin::Transaction::from_bytes(&transaction, &ModuleDecoderRegistry::default()) 1450 .unwrap(); 1451 test_roundtrip_expected( 1452 transaction, 1453 &[ 1454 2, 0, 0, 0, 0, 1, 1, 211, 91, 102, 197, 76, 246, 192, 155, 129, 168, 217, 76, 213, 1455 209, 121, 113, 156, 215, 89, 92, 37, 132, 73, 69, 42, 147, 5, 171, 155, 18, 223, 1456 37, 2, 0, 0, 0, 0, 253, 255, 255, 255, 2, 12, 213, 10, 0, 0, 0, 0, 0, 22, 0, 20, 1457 174, 93, 69, 11, 113, 192, 66, 24, 230, 232, 28, 134, 252, 194, 37, 136, 45, 123, 1458 124, 170, 230, 149, 178, 33, 0, 0, 0, 0, 22, 0, 20, 246, 8, 52, 239, 22, 82, 83, 1459 197, 113, 177, 28, 233, 250, 116, 228, 102, 146, 252, 94, 193, 2, 72, 48, 69, 2, 1460 33, 0, 146, 6, 44, 96, 159, 76, 141, 199, 76, 215, 212, 89, 110, 206, 220, 16, 147, 1461 20, 13, 144, 179, 253, 148, 180, 189, 217, 173, 62, 16, 44, 227, 188, 2, 32, 107, 1462 181, 166, 175, 198, 141, 88, 61, 119, 213, 217, 188, 251, 98, 82, 163, 100, 209, 1463 26, 48, 127, 52, 24, 190, 26, 249, 244, 127, 123, 27, 61, 120, 1, 33, 2, 110, 86, 1464 40, 80, 110, 205, 51, 36, 46, 92, 235, 95, 218, 254, 77, 48, 102, 181, 192, 241, 1465 89, 179, 192, 90, 98, 30, 246, 95, 23, 126, 162, 134, 0, 0, 0, 0, 1466 ], 1467 ); 1468 let blockhash = bitcoin::BlockHash::from_str( 1469 "0000000000000000000065bda8f8a88f2e1e00d9a6887a43d640e52a4c7660f2", 1470 ) 1471 .unwrap(); 1472 test_roundtrip_expected( 1473 blockhash, 1474 &[ 1475 242, 96, 118, 76, 42, 229, 64, 214, 67, 122, 136, 166, 217, 0, 30, 46, 143, 168, 1476 248, 168, 189, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1477 ], 1478 ); 1479 } 1480 }