1pub mod as_base64;
12pub mod as_hex;
13mod bls12_381;
14pub mod btc;
15mod collections;
16mod iroh;
17mod secp256k1;
18mod threshold_crypto;
19
20use std::borrow::Cow;
21use std::cmp;
22use std::fmt::{Debug, Formatter};
23use std::io::{self, Error, Read, Write};
24use std::time::{Duration, SystemTime, UNIX_EPOCH};
25
26use anyhow::Context;
27use bitcoin::hashes::sha256;
28pub use fedimint_derive::{Decodable, Encodable};
29use hex::{FromHex, ToHex};
30use lightning::util::ser::BigSize;
31use serde::{Deserialize, Serialize};
32use thiserror::Error;
33
34use crate::core::ModuleInstanceId;
35use crate::module::registry::ModuleDecoderRegistry;
36use crate::util::SafeUrl;
37
38pub struct CountWrite<W> {
44 inner: W,
45 count: u64,
46}
47
48impl<W> CountWrite<W> {
49 pub fn count(&self) -> u64 {
51 self.count
52 }
53}
54
55impl<W> From<W> for CountWrite<W> {
56 fn from(inner: W) -> Self {
57 Self { inner, count: 0 }
58 }
59}
60
61impl<W: Write> io::Write for CountWrite<W> {
62 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
63 let written = self.inner.write(buf)?;
64 self.count += written as u64;
65 Ok(written)
66 }
67
68 fn flush(&mut self) -> io::Result<()> {
69 self.inner.flush()
70 }
71}
72
73pub trait DynEncodable {
78 fn consensus_encode_dyn(&self, writer: &mut dyn std::io::Write) -> Result<(), std::io::Error>;
79}
80
81impl Encodable for dyn DynEncodable {
82 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
83 self.consensus_encode_dyn(writer)
84 }
85}
86
87impl<T> DynEncodable for T
88where
89 T: Encodable,
90{
91 fn consensus_encode_dyn(
92 &self,
93 mut writer: &mut dyn std::io::Write,
94 ) -> Result<(), std::io::Error> {
95 <Self as Encodable>::consensus_encode(self, &mut writer)
96 }
97}
98
99impl Encodable for Box<dyn DynEncodable> {
100 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
101 (**self).consensus_encode_dyn(writer)
102 }
103}
104
105impl<T> Encodable for &T
106where
107 T: Encodable,
108{
109 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
110 (**self).consensus_encode(writer)
111 }
112}
113
114pub trait Encodable {
116 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error>;
121
122 fn consensus_encode_to_vec(&self) -> Vec<u8> {
124 let mut bytes = vec![];
125 self.consensus_encode(&mut bytes)
126 .expect("encoding to bytes can't fail for io reasons");
127 bytes
128 }
129
130 fn consensus_encode_to_hex(&self) -> String {
132 self.consensus_encode_to_vec().encode_hex()
136 }
137
138 fn consensus_encode_to_len(&self) -> u64 {
140 let mut writer = CountWrite::from(io::sink());
141 self.consensus_encode(&mut writer)
142 .expect("encoding to bytes can't fail for io reasons");
143
144 writer.count()
145 }
146
147 fn consensus_hash<H>(&self) -> H
153 where
154 H: bitcoin::hashes::Hash,
155 H::Engine: std::io::Write,
156 {
157 let mut engine = H::engine();
158 self.consensus_encode(&mut engine)
159 .expect("writing to HashEngine cannot fail");
160 H::from_engine(engine)
161 }
162
163 fn consensus_hash_sha256(&self) -> sha256::Hash {
165 self.consensus_hash()
166 }
167}
168
169pub const MAX_DECODE_SIZE: usize = 16_000_000;
172
173pub trait Decodable: Sized {
175 #[inline]
212 fn consensus_decode_partial_from_finite_reader<R: std::io::Read>(
213 r: &mut R,
214 modules: &ModuleDecoderRegistry,
215 ) -> Result<Self, DecodeError> {
216 Self::consensus_decode_partial(r, modules)
221 }
222
223 #[inline]
224 fn consensus_decode_whole(
225 slice: &[u8],
226 modules: &ModuleDecoderRegistry,
227 ) -> Result<Self, DecodeError> {
228 let total_len = slice.len() as u64;
229
230 let r = &mut &slice[..];
231 let mut r = Read::take(r, total_len);
232
233 let res = Self::consensus_decode_partial_from_finite_reader(&mut r, modules)?;
238 let left = r.limit();
239
240 if left != 0 {
241 return Err(fedimint_core::encoding::DecodeError::new_custom(
242 anyhow::anyhow!(
243 "Type did not consume all bytes during decoding; expected={}; left={}; type={}",
244 total_len,
245 left,
246 std::any::type_name::<Self>(),
247 ),
248 ));
249 }
250 Ok(res)
251 }
252 #[inline]
262 fn consensus_decode_partial<R: std::io::Read>(
263 r: &mut R,
264 modules: &ModuleDecoderRegistry,
265 ) -> Result<Self, DecodeError> {
266 Self::consensus_decode_partial_from_finite_reader(
267 &mut r.take(MAX_DECODE_SIZE as u64),
268 modules,
269 )
270 }
271
272 fn consensus_decode_hex(
274 hex: &str,
275 modules: &ModuleDecoderRegistry,
276 ) -> Result<Self, DecodeError> {
277 let bytes = Vec::<u8>::from_hex(hex)
278 .map_err(anyhow::Error::from)
279 .map_err(DecodeError::new_custom)?;
280 Decodable::consensus_decode_whole(&bytes, modules)
281 }
282}
283
284pub fn encode_legacy_system_time<W: std::io::Write>(
290 time: &SystemTime,
291 writer: &mut W,
292) -> Result<(), std::io::Error> {
293 let duration = time
294 .duration_since(UNIX_EPOCH)
295 .expect("timestamps before the Unix epoch are unsupported");
296 duration.consensus_encode_dyn(writer)
297}
298
299pub fn decode_legacy_system_time_from_finite_reader<D: std::io::Read>(
304 decoder: &mut D,
305 modules: &ModuleDecoderRegistry,
306) -> Result<SystemTime, DecodeError> {
307 let duration = Duration::consensus_decode_partial_from_finite_reader(decoder, modules)?;
308 Ok(UNIX_EPOCH + duration)
309}
310
311pub fn encode_legacy_option_system_time<W: std::io::Write>(
316 time: &Option<SystemTime>,
317 writer: &mut W,
318) -> Result<(), std::io::Error> {
319 match time {
320 Some(time) => {
321 1u8.consensus_encode(writer)?;
322 encode_legacy_system_time(time, writer)
323 }
324 None => 0u8.consensus_encode(writer),
325 }
326}
327
328pub fn decode_legacy_option_system_time_from_finite_reader<D: std::io::Read>(
333 decoder: &mut D,
334 modules: &ModuleDecoderRegistry,
335) -> Result<Option<SystemTime>, DecodeError> {
336 match u8::consensus_decode_partial_from_finite_reader(decoder, modules)? {
337 0 => Ok(None),
338 1 => Ok(Some(decode_legacy_system_time_from_finite_reader(
339 decoder, modules,
340 )?)),
341 _ => Err(DecodeError::from_str(
342 "Invalid flag for option enum, expected 0 or 1",
343 )),
344 }
345}
346
347pub fn decode_field_from_finite_reader<T: Decodable, D: std::io::Read>(
350 decoder: &mut D,
351 modules: &ModuleDecoderRegistry,
352 context: &'static str,
353) -> Result<T, DecodeError> {
354 with_decoding_context(
355 T::consensus_decode_partial_from_finite_reader(decoder, modules),
356 context,
357 )
358}
359
360pub fn with_decoding_context<T>(
362 result: Result<T, DecodeError>,
363 context: &'static str,
364) -> Result<T, DecodeError> {
365 result.map_err(|error| DecodeError::new_custom(anyhow::Error::new(error).context(context)))
366}
367
368impl Encodable for SafeUrl {
369 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
370 self.to_string().consensus_encode(writer)
371 }
372}
373
374impl Decodable for SafeUrl {
375 fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
376 d: &mut D,
377 modules: &ModuleDecoderRegistry,
378 ) -> Result<Self, DecodeError> {
379 String::consensus_decode_partial_from_finite_reader(d, modules)?
380 .parse::<Self>()
381 .map_err(DecodeError::from_err)
382 }
383}
384
385#[derive(Debug, Error)]
386pub struct DecodeError(pub(crate) anyhow::Error);
387
388impl DecodeError {
389 pub fn new_custom(e: anyhow::Error) -> Self {
390 Self(e)
391 }
392}
393
394impl From<anyhow::Error> for DecodeError {
395 fn from(e: anyhow::Error) -> Self {
396 Self(e)
397 }
398}
399
400macro_rules! impl_encode_decode_num_as_plain {
401 ($num_type:ty) => {
402 impl Encodable for $num_type {
403 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
404 let bytes = self.to_be_bytes();
405 writer.write_all(&bytes[..])?;
406 Ok(())
407 }
408 }
409
410 impl Decodable for $num_type {
411 fn consensus_decode_partial<D: std::io::Read>(
412 d: &mut D,
413 _modules: &ModuleDecoderRegistry,
414 ) -> Result<Self, crate::encoding::DecodeError> {
415 let mut bytes = [0u8; (<$num_type>::BITS / 8) as usize];
416 d.read_exact(&mut bytes).map_err(DecodeError::from_err)?;
417 Ok(<$num_type>::from_be_bytes(bytes))
418 }
419 }
420 };
421}
422
423macro_rules! impl_encode_decode_num_as_bigsize {
424 ($num_type:ty) => {
425 impl Encodable for $num_type {
426 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
427 BigSize(u64::from(*self)).consensus_encode(writer)
428 }
429 }
430
431 impl Decodable for $num_type {
432 fn consensus_decode_partial<D: std::io::Read>(
433 d: &mut D,
434 _modules: &ModuleDecoderRegistry,
435 ) -> Result<Self, crate::encoding::DecodeError> {
436 let varint = BigSize::consensus_decode_partial(d, &Default::default())
437 .context(concat!("VarInt inside ", stringify!($num_type)))?;
438 <$num_type>::try_from(varint.0).map_err(crate::encoding::DecodeError::from_err)
439 }
440 }
441 };
442}
443
444impl_encode_decode_num_as_bigsize!(u64);
445impl_encode_decode_num_as_bigsize!(u32);
446impl_encode_decode_num_as_bigsize!(u16);
447impl_encode_decode_num_as_plain!(u8);
448
449macro_rules! impl_encode_decode_tuple {
450 ($($x:ident),*) => (
451 #[allow(non_snake_case)]
452 impl <$($x: Encodable),*> Encodable for ($($x),*) {
453 fn consensus_encode<W: std::io::Write>(&self, s: &mut W) -> Result<(), std::io::Error> {
454 let &($(ref $x),*) = self;
455 $($x.consensus_encode(s)?;)*
456 Ok(())
457 }
458 }
459
460 #[allow(non_snake_case)]
461 impl<$($x: Decodable),*> Decodable for ($($x),*) {
462 fn consensus_decode_partial<D: std::io::Read>(d: &mut D, modules: &ModuleDecoderRegistry) -> Result<Self, DecodeError> {
463 Ok(($({let $x = Decodable::consensus_decode_partial(d, modules)?; $x }),*))
464 }
465 }
466 );
467}
468
469impl_encode_decode_tuple!(T1, T2);
470impl_encode_decode_tuple!(T1, T2, T3);
471impl_encode_decode_tuple!(T1, T2, T3, T4);
472impl_encode_decode_tuple!(T1, T2, T3, T4, T5);
473impl_encode_decode_tuple!(T1, T2, T3, T4, T5, T6);
474
475impl<T> Encodable for Option<T>
476where
477 T: Encodable,
478{
479 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
480 if let Some(inner) = self {
481 1u8.consensus_encode(writer)?;
482 inner.consensus_encode(writer)?;
483 } else {
484 0u8.consensus_encode(writer)?;
485 }
486 Ok(())
487 }
488}
489
490impl<T> Decodable for Option<T>
491where
492 T: Decodable,
493{
494 fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
495 d: &mut D,
496 modules: &ModuleDecoderRegistry,
497 ) -> Result<Self, DecodeError> {
498 let flag = u8::consensus_decode_partial_from_finite_reader(d, modules)?;
499 match flag {
500 0 => Ok(None),
501 1 => Ok(Some(T::consensus_decode_partial_from_finite_reader(
502 d, modules,
503 )?)),
504 _ => Err(DecodeError::from_str(
505 "Invalid flag for option enum, expected 0 or 1",
506 )),
507 }
508 }
509}
510
511impl<T, E> Encodable for Result<T, E>
512where
513 T: Encodable,
514 E: Encodable,
515{
516 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
517 match self {
518 Ok(value) => {
519 1u8.consensus_encode(writer)?;
520 value.consensus_encode(writer)?;
521 }
522 Err(error) => {
523 0u8.consensus_encode(writer)?;
524 error.consensus_encode(writer)?;
525 }
526 }
527
528 Ok(())
529 }
530}
531
532impl<T, E> Decodable for Result<T, E>
533where
534 T: Decodable,
535 E: Decodable,
536{
537 fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
538 d: &mut D,
539 modules: &ModuleDecoderRegistry,
540 ) -> Result<Self, DecodeError> {
541 let flag = u8::consensus_decode_partial_from_finite_reader(d, modules)?;
542 match flag {
543 0 => Ok(Err(E::consensus_decode_partial_from_finite_reader(
544 d, modules,
545 )?)),
546 1 => Ok(Ok(T::consensus_decode_partial_from_finite_reader(
547 d, modules,
548 )?)),
549 _ => Err(DecodeError::from_str(
550 "Invalid flag for option enum, expected 0 or 1",
551 )),
552 }
553 }
554}
555
556impl<T> Encodable for Box<T>
557where
558 T: Encodable,
559{
560 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
561 self.as_ref().consensus_encode(writer)
562 }
563}
564
565impl<T> Decodable for Box<T>
566where
567 T: Decodable,
568{
569 fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
570 d: &mut D,
571 modules: &ModuleDecoderRegistry,
572 ) -> Result<Self, DecodeError> {
573 Ok(Self::new(T::consensus_decode_partial_from_finite_reader(
574 d, modules,
575 )?))
576 }
577}
578
579impl Encodable for () {
580 fn consensus_encode<W: std::io::Write>(&self, _writer: &mut W) -> Result<(), std::io::Error> {
581 Ok(())
582 }
583}
584
585impl Decodable for () {
586 fn consensus_decode_partial<D: std::io::Read>(
587 _d: &mut D,
588 _modules: &ModuleDecoderRegistry,
589 ) -> Result<Self, DecodeError> {
590 Ok(())
591 }
592}
593
594impl Encodable for &str {
595 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
596 self.as_bytes().consensus_encode(writer)
597 }
598}
599
600impl Encodable for String {
601 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
602 self.as_bytes().consensus_encode(writer)
603 }
604}
605
606impl Decodable for String {
607 fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
608 d: &mut D,
609 modules: &ModuleDecoderRegistry,
610 ) -> Result<Self, DecodeError> {
611 Self::from_utf8(Decodable::consensus_decode_partial_from_finite_reader(
612 d, modules,
613 )?)
614 .map_err(DecodeError::from_err)
615 }
616}
617
618impl Encodable for Duration {
619 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
620 self.as_secs().consensus_encode(writer)?;
621 self.subsec_nanos().consensus_encode(writer)?;
622
623 Ok(())
624 }
625}
626
627impl Decodable for Duration {
628 fn consensus_decode_partial<D: std::io::Read>(
629 d: &mut D,
630 modules: &ModuleDecoderRegistry,
631 ) -> Result<Self, DecodeError> {
632 let secs = Decodable::consensus_decode_partial(d, modules)?;
633 let nsecs = Decodable::consensus_decode_partial(d, modules)?;
634 Ok(Self::new(secs, nsecs))
635 }
636}
637
638impl Encodable for bool {
639 fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
640 let bool_as_u8 = u8::from(*self);
641 writer.write_all(&[bool_as_u8])?;
642 Ok(())
643 }
644}
645
646impl Decodable for bool {
647 fn consensus_decode_partial<D: Read>(
648 d: &mut D,
649 _modules: &ModuleDecoderRegistry,
650 ) -> Result<Self, DecodeError> {
651 let mut bool_as_u8 = [0u8];
652 d.read_exact(&mut bool_as_u8)
653 .map_err(DecodeError::from_err)?;
654 match bool_as_u8[0] {
655 0 => Ok(false),
656 1 => Ok(true),
657 _ => Err(DecodeError::from_str("Out of range, expected 0 or 1")),
658 }
659 }
660}
661
662impl DecodeError {
663 #[allow(clippy::should_implement_trait)]
665 pub fn from_str(s: &'static str) -> Self {
666 #[derive(Debug)]
667 struct StrError(&'static str);
668
669 impl std::fmt::Display for StrError {
670 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
671 std::fmt::Display::fmt(&self.0, f)
672 }
673 }
674
675 impl std::error::Error for StrError {}
676
677 Self(anyhow::Error::from(StrError(s)))
678 }
679
680 pub fn from_err<E: std::error::Error + Send + Sync + 'static>(e: E) -> Self {
681 Self(anyhow::Error::from(e))
682 }
683}
684
685impl std::fmt::Display for DecodeError {
686 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
687 f.write_fmt(format_args!("{:#}", self.0))
688 }
689}
690
691impl Encodable for Cow<'static, str> {
692 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
693 self.as_ref().consensus_encode(writer)
694 }
695}
696
697impl Decodable for Cow<'static, str> {
698 fn consensus_decode_partial<D: std::io::Read>(
699 d: &mut D,
700 modules: &ModuleDecoderRegistry,
701 ) -> Result<Self, DecodeError> {
702 Ok(Cow::Owned(String::consensus_decode_partial(d, modules)?))
703 }
704}
705
706#[derive(Debug, Clone, Serialize, Deserialize)]
725pub enum DynRawFallback<T> {
726 Raw {
727 module_instance_id: ModuleInstanceId,
728 #[serde(with = "::fedimint_core::encoding::as_hex")]
729 raw: Vec<u8>,
730 },
731 Decoded(T),
732}
733
734impl<T> cmp::PartialEq for DynRawFallback<T>
735where
736 T: cmp::PartialEq + Encodable,
737{
738 fn eq(&self, other: &Self) -> bool {
739 match (self, other) {
740 (
741 Self::Raw {
742 module_instance_id: mid_self,
743 raw: raw_self,
744 },
745 Self::Raw {
746 module_instance_id: mid_other,
747 raw: raw_other,
748 },
749 ) => mid_self.eq(mid_other) && raw_self.eq(raw_other),
750 (r @ Self::Raw { .. }, d @ Self::Decoded(_))
751 | (d @ Self::Decoded(_), r @ Self::Raw { .. }) => {
752 r.consensus_encode_to_vec() == d.consensus_encode_to_vec()
753 }
754 (Self::Decoded(s), Self::Decoded(o)) => s == o,
755 }
756 }
757}
758
759impl<T> cmp::Eq for DynRawFallback<T> where T: cmp::Eq + Encodable {}
760
761impl<T> DynRawFallback<T>
762where
763 T: Decodable + 'static,
764{
765 pub fn decoded(self) -> Option<T> {
767 match self {
768 Self::Raw { .. } => None,
769 Self::Decoded(v) => Some(v),
770 }
771 }
772
773 pub fn expect_decoded(self) -> T {
775 match self {
776 Self::Raw { .. } => {
777 panic!("Expected decoded value. Possibly `redecode_raw` call is missing.")
778 }
779 Self::Decoded(v) => v,
780 }
781 }
782
783 pub fn expect_decoded_ref(&self) -> &T {
785 match self {
786 Self::Raw { .. } => {
787 panic!("Expected decoded value. Possibly `redecode_raw` call is missing.")
788 }
789 Self::Decoded(v) => v,
790 }
791 }
792
793 pub fn redecode_raw(
798 self,
799 decoders: &ModuleDecoderRegistry,
800 ) -> Result<Self, crate::encoding::DecodeError> {
801 Ok(match self {
802 Self::Raw {
803 module_instance_id,
804 raw,
805 } => match decoders.get(module_instance_id) {
806 Some(decoder) => Self::Decoded(decoder.decode_complete(
807 &mut &raw[..],
808 raw.len() as u64,
809 module_instance_id,
810 decoders,
811 )?),
812 None => Self::Raw {
813 module_instance_id,
814 raw,
815 },
816 },
817 Self::Decoded(v) => Self::Decoded(v),
818 })
819 }
820}
821
822impl<T> From<T> for DynRawFallback<T> {
823 fn from(value: T) -> Self {
824 Self::Decoded(value)
825 }
826}
827
828impl<T> Decodable for DynRawFallback<T>
829where
830 T: Decodable + 'static,
831{
832 fn consensus_decode_partial_from_finite_reader<R: std::io::Read>(
833 reader: &mut R,
834 decoders: &ModuleDecoderRegistry,
835 ) -> Result<Self, crate::encoding::DecodeError> {
836 let module_instance_id =
837 fedimint_core::core::ModuleInstanceId::consensus_decode_partial_from_finite_reader(
838 reader, decoders,
839 )?;
840 Ok(match decoders.get(module_instance_id) {
841 Some(decoder) => {
842 let total_len_u64 =
843 u64::consensus_decode_partial_from_finite_reader(reader, decoders)?;
844 Self::Decoded(decoder.decode_complete(
845 reader,
846 total_len_u64,
847 module_instance_id,
848 decoders,
849 )?)
850 }
851 None => {
852 Self::Raw {
854 module_instance_id,
855 raw: Vec::consensus_decode_partial_from_finite_reader(reader, decoders)?,
856 }
857 }
858 })
859 }
860}
861
862impl<T> Encodable for DynRawFallback<T>
863where
864 T: Encodable,
865{
866 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
867 match self {
868 Self::Raw {
869 module_instance_id,
870 raw,
871 } => {
872 module_instance_id.consensus_encode(writer)?;
873 raw.consensus_encode(writer)?;
874 Ok(())
875 }
876 Self::Decoded(v) => v.consensus_encode(writer),
877 }
878 }
879}
880
881#[cfg(test)]
882mod tests {
883 use std::fmt::Debug;
884 use std::io::Cursor;
885
886 use super::*;
887 use crate::encoding::{Decodable, Encodable};
888 use crate::module::registry::ModuleRegistry;
889
890 pub(crate) fn test_roundtrip<T>(value: &T)
891 where
892 T: Encodable + Decodable + Eq + Debug,
893 {
894 let mut bytes = Vec::new();
895 value.consensus_encode(&mut bytes).unwrap();
896
897 let mut cursor = Cursor::new(bytes);
898 let decoded =
899 T::consensus_decode_partial(&mut cursor, &ModuleDecoderRegistry::default()).unwrap();
900 assert_eq!(value, &decoded);
901 }
902
903 pub(crate) fn test_roundtrip_expected<T>(value: &T, expected: &[u8])
904 where
905 T: Encodable + Decodable + Eq + Debug,
906 {
907 let mut bytes = Vec::new();
908 value.consensus_encode(&mut bytes).unwrap();
909 assert_eq!(&expected, &bytes);
910
911 let mut cursor = Cursor::new(bytes);
912 let decoded =
913 T::consensus_decode_partial(&mut cursor, &ModuleDecoderRegistry::default()).unwrap();
914 assert_eq!(value, &decoded);
915 }
916
917 #[derive(Debug, Eq, PartialEq, Encodable, Decodable)]
918 enum NoDefaultEnum {
919 Foo,
920 Bar(u32, String),
921 Baz { baz: u8 },
922 }
923
924 #[derive(Debug, Eq, PartialEq, Encodable, Decodable)]
925 enum DefaultEnum {
926 Foo,
927 Bar(u32, String),
928 #[encodable_default]
929 Default {
930 variant: u64,
931 bytes: Vec<u8>,
932 },
933 }
934
935 #[test_log::test]
936 fn test_derive_enum_no_default_roundtrip_success() {
937 let enums = [
938 NoDefaultEnum::Foo,
939 NoDefaultEnum::Bar(
940 42,
941 "The answer to life, the universe, and everything".to_string(),
942 ),
943 NoDefaultEnum::Baz { baz: 0 },
944 ];
945
946 for e in enums {
947 test_roundtrip(&e);
948 }
949 }
950
951 #[test_log::test]
952 fn test_derive_enum_no_default_decode_fail() {
953 let unknown_variant = DefaultEnum::Default {
954 variant: 42,
955 bytes: vec![0, 1, 2, 3],
956 };
957 let mut unknown_variant_encoding = vec![];
958 unknown_variant
959 .consensus_encode(&mut unknown_variant_encoding)
960 .unwrap();
961
962 let mut cursor = Cursor::new(&unknown_variant_encoding);
963 let decode_res =
964 NoDefaultEnum::consensus_decode_partial(&mut cursor, &ModuleRegistry::default());
965
966 match decode_res {
967 Ok(_) => panic!("Should return error"),
968 Err(e) => assert!(e.to_string().contains("Invalid enum variant")),
969 }
970 }
971
972 #[test_log::test]
973 fn test_derive_enum_default_decode_success() {
974 let unknown_variant = NoDefaultEnum::Baz { baz: 123 };
975 let mut unknown_variant_encoding = vec![];
976 unknown_variant
977 .consensus_encode(&mut unknown_variant_encoding)
978 .unwrap();
979
980 let mut cursor = Cursor::new(&unknown_variant_encoding);
981 let decode_res =
982 DefaultEnum::consensus_decode_partial(&mut cursor, &ModuleRegistry::default());
983
984 assert_eq!(
985 decode_res.unwrap(),
986 DefaultEnum::Default {
987 variant: 2,
988 bytes: vec![123],
989 }
990 );
991 }
992
993 #[derive(Debug, Encodable, Decodable, Eq, PartialEq)]
994 struct TestStruct {
995 vec: Vec<u8>,
996 num: u32,
997 }
998
999 #[test_log::test]
1000 fn test_derive_struct() {
1001 let reference = TestStruct {
1002 vec: vec![1, 2, 3],
1003 num: 42,
1004 };
1005 let bytes = [3, 1, 2, 3, 42];
1006
1007 test_roundtrip_expected(&reference, &bytes);
1008 }
1009
1010 #[derive(Debug, Encodable, Decodable, Eq, PartialEq)]
1011 struct TestTupleStruct(Vec<u8>, u32);
1012
1013 #[derive(Debug)]
1014 struct TestFiniteReader;
1015
1016 impl Decodable for TestFiniteReader {
1017 fn consensus_decode_partial_from_finite_reader<R: std::io::Read>(
1018 reader: &mut R,
1019 modules: &ModuleDecoderRegistry,
1020 ) -> Result<Self, DecodeError> {
1021 let _: Vec<u8> = decode_field_from_finite_reader(
1022 reader,
1023 modules,
1024 "Decoding tuple block TestFiniteReader field field_0",
1025 )?;
1026 let _: Vec<u8> = decode_field_from_finite_reader(
1027 reader,
1028 modules,
1029 "Decoding tuple block TestFiniteReader field field_1",
1030 )?;
1031 Ok(Self)
1032 }
1033 }
1034
1035 #[test_log::test]
1036 fn test_derive_tuple_struct() {
1037 let reference = TestTupleStruct(vec![1, 2, 3], 42);
1038 let bytes = [3, 1, 2, 3, 42];
1039
1040 test_roundtrip_expected(&reference, &bytes);
1041 }
1042
1043 #[test_log::test]
1044 fn test_legacy_system_time_encoding() {
1045 let time = UNIX_EPOCH + Duration::new(42, 100);
1046 let expected = [42, 100];
1047 let mut bytes = vec![];
1048 encode_legacy_system_time(&time, &mut bytes).expect("encoding to a vector cannot fail");
1049 assert_eq!(bytes, expected);
1050
1051 let mut cursor = Cursor::new(expected);
1052 let decoded = decode_legacy_system_time_from_finite_reader(
1053 &mut cursor,
1054 &ModuleDecoderRegistry::default(),
1055 )
1056 .expect("valid encoding");
1057 assert_eq!(decoded, time);
1058 }
1059
1060 #[test_log::test]
1061 fn test_client_backup_snapshot_uses_legacy_system_time_encoding() {
1062 let reference = crate::backup::ClientBackupSnapshot {
1063 timestamp: UNIX_EPOCH + Duration::new(42, 100),
1064 data: vec![1, 2, 3],
1065 };
1066 let expected = [42, 100, 3, 1, 2, 3];
1067
1068 test_roundtrip_expected(&reference, &expected);
1069 }
1070
1071 #[test_log::test]
1072 fn test_legacy_optional_system_time_encoding() {
1073 let time = Some(UNIX_EPOCH + Duration::new(42, 100));
1074 let expected = [1, 42, 100];
1075 let mut bytes = vec![];
1076 encode_legacy_option_system_time(&time, &mut bytes)
1077 .expect("encoding to a vector cannot fail");
1078 assert_eq!(bytes, expected);
1079
1080 let mut cursor = Cursor::new(expected);
1081 let decoded = decode_legacy_option_system_time_from_finite_reader(
1082 &mut cursor,
1083 &ModuleDecoderRegistry::default(),
1084 )
1085 .expect("valid encoding");
1086 assert_eq!(decoded, time);
1087 }
1088
1089 #[test_log::test]
1090 fn test_legacy_optional_system_time_encoding_none() {
1091 let mut bytes = vec![];
1092 encode_legacy_option_system_time(&None, &mut bytes)
1093 .expect("encoding to a vector cannot fail");
1094 assert_eq!(bytes, [0]);
1095
1096 let mut cursor = Cursor::new(bytes);
1097 let decoded = decode_legacy_option_system_time_from_finite_reader(
1098 &mut cursor,
1099 &ModuleDecoderRegistry::default(),
1100 )
1101 .expect("valid encoding");
1102 assert_eq!(decoded, None);
1103 }
1104
1105 #[test_log::test]
1106 fn test_legacy_optional_system_time_encoding_rejects_invalid_flag() {
1107 let error = decode_legacy_option_system_time_from_finite_reader(
1108 &mut Cursor::new([2]),
1109 &ModuleDecoderRegistry::default(),
1110 )
1111 .expect_err("invalid option flag must fail");
1112 assert_eq!(
1113 error.to_string(),
1114 "Invalid flag for option enum, expected 0 or 1"
1115 );
1116 }
1117
1118 #[test_log::test]
1119 fn test_legacy_system_time_field_decode_adds_context() {
1120 let error = with_decoding_context(
1121 decode_legacy_system_time_from_finite_reader(
1122 &mut Cursor::new([42]),
1123 &ModuleDecoderRegistry::default(),
1124 ),
1125 "Decoding named block field: Test{ ... timestamp ... }",
1126 )
1127 .expect_err("truncated timestamp must fail");
1128 assert!(
1129 error
1130 .to_string()
1131 .contains("Decoding named block field: Test{ ... timestamp ... }")
1132 );
1133 }
1134
1135 #[test_log::test]
1136 fn test_finite_reader_shares_decode_limit_between_fields() {
1137 let field = vec![0u8; MAX_DECODE_SIZE / 2];
1138 let mut bytes = vec![];
1139 field
1140 .consensus_encode(&mut bytes)
1141 .expect("encoding to a vector cannot fail");
1142 field
1143 .consensus_encode(&mut bytes)
1144 .expect("encoding to a vector cannot fail");
1145
1146 let error = TestFiniteReader::consensus_decode_partial(
1147 &mut Cursor::new(bytes),
1148 &ModuleDecoderRegistry::default(),
1149 )
1150 .expect_err("both fields cannot exceed one decode limit");
1151 assert!(
1152 error
1153 .to_string()
1154 .contains("Decoding tuple block TestFiniteReader field field_1")
1155 );
1156 }
1157
1158 #[derive(Debug, Encodable, Decodable, Eq, PartialEq)]
1159 enum TestEnum {
1160 Foo(Option<u64>),
1161 Bar { bazz: Vec<u8> },
1162 }
1163
1164 #[test_log::test]
1165 fn test_derive_enum() {
1166 let test_cases = [
1167 (TestEnum::Foo(Some(42)), vec![0, 2, 1, 42]),
1168 (TestEnum::Foo(None), vec![0, 1, 0]),
1169 (
1170 TestEnum::Bar {
1171 bazz: vec![1, 2, 3],
1172 },
1173 vec![1, 4, 3, 1, 2, 3],
1174 ),
1175 ];
1176
1177 for (reference, bytes) in test_cases {
1178 test_roundtrip_expected(&reference, &bytes);
1179 }
1180 }
1181
1182 #[test]
1183 fn test_derive_empty_enum_decode() {
1184 #[derive(Debug, Encodable, Decodable)]
1185 enum NotConstructable {}
1186
1187 let vec = vec![42u8];
1188 let mut cursor = Cursor::new(vec);
1189
1190 assert!(
1191 NotConstructable::consensus_decode_partial(
1192 &mut cursor,
1193 &ModuleDecoderRegistry::default()
1194 )
1195 .is_err()
1196 );
1197 }
1198
1199 #[test]
1200 fn test_custom_index_enum() {
1201 #[derive(Debug, PartialEq, Eq, Encodable, Decodable)]
1202 enum Old {
1203 Foo,
1204 Bar,
1205 Baz,
1206 }
1207
1208 #[derive(Debug, PartialEq, Eq, Encodable, Decodable)]
1209 enum New {
1210 #[encodable(index = 0)]
1211 Foo,
1212 #[encodable(index = 2)]
1213 Baz,
1214 #[encodable_default]
1215 Default { variant: u64, bytes: Vec<u8> },
1216 }
1217
1218 let test_vector = vec![
1219 (Old::Foo, New::Foo),
1220 (
1221 Old::Bar,
1222 New::Default {
1223 variant: 1,
1224 bytes: vec![],
1225 },
1226 ),
1227 (Old::Baz, New::Baz),
1228 ];
1229
1230 for (old, new) in test_vector {
1231 let old_bytes = old.consensus_encode_to_vec();
1232 let decoded_new = New::consensus_decode_whole(&old_bytes, &ModuleRegistry::default())
1233 .expect("Decoding failed");
1234 assert_eq!(decoded_new, new);
1235 }
1236 }
1237
1238 fn encode_value<T: Encodable>(value: &T) -> Vec<u8> {
1239 let mut writer = Vec::new();
1240 value.consensus_encode(&mut writer).unwrap();
1241 writer
1242 }
1243
1244 fn decode_value<T: Decodable>(bytes: &[u8]) -> T {
1245 T::consensus_decode_whole(bytes, &ModuleDecoderRegistry::default()).unwrap()
1246 }
1247
1248 fn keeps_ordering_after_serialization<T: Ord + Encodable + Decodable + Debug>(mut vec: Vec<T>) {
1249 vec.sort();
1250 let mut encoded = vec.iter().map(encode_value).collect::<Vec<_>>();
1251 encoded.sort();
1252 let decoded = encoded.iter().map(|v| decode_value(v)).collect::<Vec<_>>();
1253 for (i, (a, b)) in vec.iter().zip(decoded.iter()).enumerate() {
1254 assert_eq!(a, b, "difference at index {i}");
1255 }
1256 }
1257
1258 #[test]
1259 fn test_lexicographical_sorting() {
1260 #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)]
1261 struct TestAmount(u64);
1262
1263 #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)]
1264 struct TestComplexAmount(u16, u32, u64);
1265
1266 #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)]
1267 struct Text(String);
1268
1269 let amounts = (0..20000).map(TestAmount).collect::<Vec<_>>();
1270 keeps_ordering_after_serialization(amounts);
1271
1272 let complex_amounts = (10..20000)
1273 .flat_map(|i| {
1274 (i - 1..=i + 1).flat_map(move |j| {
1275 (i - 1..=i + 1).map(move |k| TestComplexAmount(i as u16, j as u32, k as u64))
1276 })
1277 })
1278 .collect::<Vec<_>>();
1279 keeps_ordering_after_serialization(complex_amounts);
1280
1281 let texts = (' '..'~')
1282 .flat_map(|i| {
1283 (' '..'~')
1284 .map(|j| Text(format!("{i}{j}")))
1285 .collect::<Vec<_>>()
1286 })
1287 .collect::<Vec<_>>();
1288 keeps_ordering_after_serialization(texts);
1289
1290 }
1294}