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, Display};
23use std::io::{self, Error, Read, Write};
24use std::time::{Duration, SystemTime, UNIX_EPOCH};
25
26use bitcoin::hashes::sha256;
27pub use fedimint_derive::{Decodable, Encodable};
28use hex::{FromHex, ToHex};
29use lightning::util::ser::BigSize;
30use serde::{Deserialize, Serialize};
31use thiserror::Error;
32
33use crate::core::ModuleInstanceId;
34use crate::module::registry::ModuleDecoderRegistry;
35use crate::util::SafeUrl;
36
37pub struct CountWrite<W> {
43 inner: W,
44 count: u64,
45}
46
47impl<W> CountWrite<W> {
48 pub fn count(&self) -> u64 {
50 self.count
51 }
52}
53
54impl<W> From<W> for CountWrite<W> {
55 fn from(inner: W) -> Self {
56 Self { inner, count: 0 }
57 }
58}
59
60impl<W: Write> io::Write for CountWrite<W> {
61 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
62 let written = self.inner.write(buf)?;
63 self.count += written as u64;
64 Ok(written)
65 }
66
67 fn flush(&mut self) -> io::Result<()> {
68 self.inner.flush()
69 }
70}
71
72pub trait DynEncodable {
77 fn consensus_encode_dyn(&self, writer: &mut dyn std::io::Write) -> Result<(), std::io::Error>;
78}
79
80impl Encodable for dyn DynEncodable {
81 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
82 self.consensus_encode_dyn(writer)
83 }
84}
85
86impl<T> DynEncodable for T
87where
88 T: Encodable,
89{
90 fn consensus_encode_dyn(
91 &self,
92 mut writer: &mut dyn std::io::Write,
93 ) -> Result<(), std::io::Error> {
94 <Self as Encodable>::consensus_encode(self, &mut writer)
95 }
96}
97
98impl Encodable for Box<dyn DynEncodable> {
99 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
100 (**self).consensus_encode_dyn(writer)
101 }
102}
103
104impl<T> Encodable for &T
105where
106 T: Encodable,
107{
108 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
109 (**self).consensus_encode(writer)
110 }
111}
112
113pub trait Encodable {
115 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error>;
120
121 fn consensus_encode_to_vec(&self) -> Vec<u8> {
123 let mut bytes = vec![];
124 self.consensus_encode(&mut bytes)
125 .expect("encoding to bytes can't fail for io reasons");
126 bytes
127 }
128
129 fn consensus_encode_to_hex(&self) -> String {
131 self.consensus_encode_to_vec().encode_hex()
135 }
136
137 fn consensus_encode_to_len(&self) -> u64 {
139 let mut writer = CountWrite::from(io::sink());
140 self.consensus_encode(&mut writer)
141 .expect("encoding to bytes can't fail for io reasons");
142
143 writer.count()
144 }
145
146 fn consensus_hash<H>(&self) -> H
152 where
153 H: bitcoin::hashes::Hash,
154 H::Engine: std::io::Write,
155 {
156 let mut engine = H::engine();
157 self.consensus_encode(&mut engine)
158 .expect("writing to HashEngine cannot fail");
159 H::from_engine(engine)
160 }
161
162 fn consensus_hash_sha256(&self) -> sha256::Hash {
164 self.consensus_hash()
165 }
166}
167
168pub const MAX_DECODE_SIZE: usize = 16_000_000;
171
172pub trait Decodable: Sized {
174 #[inline]
211 fn consensus_decode_partial_from_finite_reader<R: std::io::Read>(
212 r: &mut R,
213 modules: &ModuleDecoderRegistry,
214 ) -> Result<Self, DecodeError> {
215 Self::consensus_decode_partial(r, modules)
220 }
221
222 #[inline]
223 fn consensus_decode_whole(
224 slice: &[u8],
225 modules: &ModuleDecoderRegistry,
226 ) -> Result<Self, DecodeError> {
227 let total_len = slice.len() as u64;
228
229 let r = &mut &slice[..];
230 let mut r = Read::take(r, total_len);
231
232 let res = Self::consensus_decode_partial_from_finite_reader(&mut r, modules)?;
237 let left = r.limit();
238
239 if left != 0 {
240 return Err(fedimint_core::encoding::DecodeError::custom(format!(
241 "Type did not consume all bytes during decoding; expected={total_len}; \
242 left={left}; type={}",
243 std::any::type_name::<Self>(),
244 )));
245 }
246 Ok(res)
247 }
248 #[inline]
258 fn consensus_decode_partial<R: std::io::Read>(
259 r: &mut R,
260 modules: &ModuleDecoderRegistry,
261 ) -> Result<Self, DecodeError> {
262 Self::consensus_decode_partial_from_finite_reader(
263 &mut r.take(MAX_DECODE_SIZE as u64),
264 modules,
265 )
266 }
267
268 fn consensus_decode_hex(
270 hex: &str,
271 modules: &ModuleDecoderRegistry,
272 ) -> Result<Self, DecodeError> {
273 let bytes = Vec::<u8>::from_hex(hex).map_err(DecodeError::from_err)?;
274 Decodable::consensus_decode_whole(&bytes, modules)
275 }
276}
277
278pub fn encode_legacy_system_time<W: std::io::Write>(
284 time: &SystemTime,
285 writer: &mut W,
286) -> Result<(), std::io::Error> {
287 let duration = time
288 .duration_since(UNIX_EPOCH)
289 .expect("timestamps before the Unix epoch are unsupported");
290 duration.consensus_encode_dyn(writer)
291}
292
293pub fn decode_legacy_system_time_from_finite_reader<D: std::io::Read>(
298 decoder: &mut D,
299 modules: &ModuleDecoderRegistry,
300) -> Result<SystemTime, DecodeError> {
301 let duration = Duration::consensus_decode_partial_from_finite_reader(decoder, modules)?;
302 UNIX_EPOCH
307 .checked_add(duration)
308 .ok_or_else(|| DecodeError::from_str("SystemTime overflow: duration too large"))
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.context(context)
366}
367
368#[derive(Debug, Error)]
375#[non_exhaustive]
376pub enum DecodeError {
377 #[error(transparent)]
379 Io(#[from] std::io::Error),
380 #[error("Invalid enum variant {variant} while decoding {type_name}")]
382 InvalidVariant {
383 variant: u64,
385 type_name: &'static str,
387 },
388 #[error("{context}")]
390 Context {
391 context: String,
393 #[source]
395 source: Box<Self>,
396 },
397 #[error(transparent)]
400 Invalid(Box<dyn std::error::Error + Send + Sync>),
401 #[error("{message}")]
403 Custom {
404 message: String,
406 },
407}
408
409impl DecodeError {
410 pub fn custom(message: impl Into<String>) -> Self {
412 Self::Custom {
413 message: message.into(),
414 }
415 }
416
417 #[allow(clippy::should_implement_trait)]
420 pub fn from_str(s: &'static str) -> Self {
421 Self::custom(s)
422 }
423
424 pub fn from_err<E>(e: E) -> Self
426 where
427 E: std::error::Error + Send + Sync + 'static,
428 {
429 Self::Invalid(Box::new(e))
430 }
431
432 pub fn context(self, context: impl Display) -> Self {
434 Self::Context {
435 context: context.to_string(),
436 source: Box::new(self),
437 }
438 }
439}
440
441pub trait DecodeContext<T> {
448 fn context<C>(self, context: C) -> Result<T, DecodeError>
450 where
451 C: Display;
452
453 fn with_context<C, F>(self, context: F) -> Result<T, DecodeError>
456 where
457 C: Display,
458 F: FnOnce() -> C;
459}
460
461impl<T, E> DecodeContext<T> for Result<T, E>
462where
463 E: Into<DecodeError>,
464{
465 fn context<C>(self, context: C) -> Result<T, DecodeError>
466 where
467 C: Display,
468 {
469 self.map_err(|error| error.into().context(context))
470 }
471
472 fn with_context<C, F>(self, context: F) -> Result<T, DecodeError>
473 where
474 C: Display,
475 F: FnOnce() -> C,
476 {
477 self.map_err(|error| error.into().context(context()))
478 }
479}
480
481impl Encodable for SafeUrl {
482 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
483 self.to_string().consensus_encode(writer)
484 }
485}
486
487impl Decodable for SafeUrl {
488 fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
489 d: &mut D,
490 modules: &ModuleDecoderRegistry,
491 ) -> Result<Self, DecodeError> {
492 String::consensus_decode_partial_from_finite_reader(d, modules)?
493 .parse::<Self>()
494 .map_err(DecodeError::from_err)
495 }
496}
497
498macro_rules! impl_encode_decode_num_as_plain {
499 ($num_type:ty) => {
500 impl Encodable for $num_type {
501 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
502 let bytes = self.to_be_bytes();
503 writer.write_all(&bytes[..])?;
504 Ok(())
505 }
506 }
507
508 impl Decodable for $num_type {
509 fn consensus_decode_partial<D: std::io::Read>(
510 d: &mut D,
511 _modules: &ModuleDecoderRegistry,
512 ) -> Result<Self, crate::encoding::DecodeError> {
513 let mut bytes = [0u8; (<$num_type>::BITS / 8) as usize];
514 d.read_exact(&mut bytes)?;
515 Ok(<$num_type>::from_be_bytes(bytes))
516 }
517 }
518 };
519}
520
521macro_rules! impl_encode_decode_num_as_bigsize {
522 ($num_type:ty) => {
523 impl Encodable for $num_type {
524 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
525 BigSize(u64::from(*self)).consensus_encode(writer)
526 }
527 }
528
529 impl Decodable for $num_type {
530 fn consensus_decode_partial<D: std::io::Read>(
531 d: &mut D,
532 _modules: &ModuleDecoderRegistry,
533 ) -> Result<Self, crate::encoding::DecodeError> {
534 let varint = BigSize::consensus_decode_partial(d, &Default::default())?;
535 <$num_type>::try_from(varint.0).map_err(crate::encoding::DecodeError::from_err)
536 }
537 }
538 };
539}
540
541impl_encode_decode_num_as_bigsize!(u64);
542impl_encode_decode_num_as_bigsize!(u32);
543impl_encode_decode_num_as_bigsize!(u16);
544impl_encode_decode_num_as_plain!(u8);
545
546macro_rules! impl_encode_decode_tuple {
547 ($($x:ident),*) => (
548 #[allow(non_snake_case)]
549 impl <$($x: Encodable),*> Encodable for ($($x),*) {
550 fn consensus_encode<W: std::io::Write>(&self, s: &mut W) -> Result<(), std::io::Error> {
551 let &($(ref $x),*) = self;
552 $($x.consensus_encode(s)?;)*
553 Ok(())
554 }
555 }
556
557 #[allow(non_snake_case)]
558 impl<$($x: Decodable),*> Decodable for ($($x),*) {
559 fn consensus_decode_partial<D: std::io::Read>(d: &mut D, modules: &ModuleDecoderRegistry) -> Result<Self, DecodeError> {
560 Ok(($({let $x = Decodable::consensus_decode_partial(d, modules)?; $x }),*))
561 }
562 }
563 );
564}
565
566impl_encode_decode_tuple!(T1, T2);
567impl_encode_decode_tuple!(T1, T2, T3);
568impl_encode_decode_tuple!(T1, T2, T3, T4);
569impl_encode_decode_tuple!(T1, T2, T3, T4, T5);
570impl_encode_decode_tuple!(T1, T2, T3, T4, T5, T6);
571
572impl<T> Encodable for Option<T>
573where
574 T: Encodable,
575{
576 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
577 if let Some(inner) = self {
578 1u8.consensus_encode(writer)?;
579 inner.consensus_encode(writer)?;
580 } else {
581 0u8.consensus_encode(writer)?;
582 }
583 Ok(())
584 }
585}
586
587impl<T> Decodable for Option<T>
588where
589 T: Decodable,
590{
591 fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
592 d: &mut D,
593 modules: &ModuleDecoderRegistry,
594 ) -> Result<Self, DecodeError> {
595 let flag = u8::consensus_decode_partial_from_finite_reader(d, modules)?;
596 match flag {
597 0 => Ok(None),
598 1 => Ok(Some(T::consensus_decode_partial_from_finite_reader(
599 d, modules,
600 )?)),
601 _ => Err(DecodeError::from_str(
602 "Invalid flag for option enum, expected 0 or 1",
603 )),
604 }
605 }
606}
607
608impl<T, E> Encodable for Result<T, E>
609where
610 T: Encodable,
611 E: Encodable,
612{
613 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
614 match self {
615 Ok(value) => {
616 1u8.consensus_encode(writer)?;
617 value.consensus_encode(writer)?;
618 }
619 Err(error) => {
620 0u8.consensus_encode(writer)?;
621 error.consensus_encode(writer)?;
622 }
623 }
624
625 Ok(())
626 }
627}
628
629impl<T, E> Decodable for Result<T, E>
630where
631 T: Decodable,
632 E: Decodable,
633{
634 fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
635 d: &mut D,
636 modules: &ModuleDecoderRegistry,
637 ) -> Result<Self, DecodeError> {
638 let flag = u8::consensus_decode_partial_from_finite_reader(d, modules)?;
639 match flag {
640 0 => Ok(Err(E::consensus_decode_partial_from_finite_reader(
641 d, modules,
642 )?)),
643 1 => Ok(Ok(T::consensus_decode_partial_from_finite_reader(
644 d, modules,
645 )?)),
646 _ => Err(DecodeError::from_str(
647 "Invalid flag for option enum, expected 0 or 1",
648 )),
649 }
650 }
651}
652
653impl<T> Encodable for Box<T>
654where
655 T: Encodable,
656{
657 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
658 self.as_ref().consensus_encode(writer)
659 }
660}
661
662impl<T> Decodable for Box<T>
663where
664 T: Decodable,
665{
666 fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
667 d: &mut D,
668 modules: &ModuleDecoderRegistry,
669 ) -> Result<Self, DecodeError> {
670 Ok(Self::new(T::consensus_decode_partial_from_finite_reader(
671 d, modules,
672 )?))
673 }
674}
675
676impl Encodable for () {
677 fn consensus_encode<W: std::io::Write>(&self, _writer: &mut W) -> Result<(), std::io::Error> {
678 Ok(())
679 }
680}
681
682impl Decodable for () {
683 fn consensus_decode_partial<D: std::io::Read>(
684 _d: &mut D,
685 _modules: &ModuleDecoderRegistry,
686 ) -> Result<Self, DecodeError> {
687 Ok(())
688 }
689}
690
691impl Encodable for &str {
692 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
693 self.as_bytes().consensus_encode(writer)
694 }
695}
696
697impl Encodable for String {
698 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
699 self.as_bytes().consensus_encode(writer)
700 }
701}
702
703impl Decodable for String {
704 fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
705 d: &mut D,
706 modules: &ModuleDecoderRegistry,
707 ) -> Result<Self, DecodeError> {
708 Self::from_utf8(Decodable::consensus_decode_partial_from_finite_reader(
709 d, modules,
710 )?)
711 .map_err(DecodeError::from_err)
712 }
713}
714
715impl Encodable for Duration {
716 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
717 self.as_secs().consensus_encode(writer)?;
718 self.subsec_nanos().consensus_encode(writer)?;
719
720 Ok(())
721 }
722}
723
724impl Decodable for Duration {
725 fn consensus_decode_partial<D: std::io::Read>(
726 d: &mut D,
727 modules: &ModuleDecoderRegistry,
728 ) -> Result<Self, DecodeError> {
729 let secs = Decodable::consensus_decode_partial(d, modules)?;
730 let nsecs = Decodable::consensus_decode_partial(d, modules)?;
731 if 1_000_000_000 <= nsecs {
736 return Err(DecodeError::from_str("Duration nanoseconds out of range"));
737 }
738 Ok(Self::new(secs, nsecs))
739 }
740}
741
742impl Encodable for bool {
743 fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
744 let bool_as_u8 = u8::from(*self);
745 writer.write_all(&[bool_as_u8])?;
746 Ok(())
747 }
748}
749
750impl Decodable for bool {
751 fn consensus_decode_partial<D: Read>(
752 d: &mut D,
753 _modules: &ModuleDecoderRegistry,
754 ) -> Result<Self, DecodeError> {
755 let mut bool_as_u8 = [0u8];
756 d.read_exact(&mut bool_as_u8)?;
757 match bool_as_u8[0] {
758 0 => Ok(false),
759 1 => Ok(true),
760 _ => Err(DecodeError::from_str("Out of range, expected 0 or 1")),
761 }
762 }
763}
764
765impl Encodable for Cow<'static, str> {
766 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
767 self.as_ref().consensus_encode(writer)
768 }
769}
770
771impl Decodable for Cow<'static, str> {
772 fn consensus_decode_partial<D: std::io::Read>(
773 d: &mut D,
774 modules: &ModuleDecoderRegistry,
775 ) -> Result<Self, DecodeError> {
776 Ok(Cow::Owned(String::consensus_decode_partial(d, modules)?))
777 }
778}
779
780#[derive(Debug, Clone, Serialize, Deserialize)]
799pub enum DynRawFallback<T> {
800 Raw {
801 module_instance_id: ModuleInstanceId,
802 #[serde(with = "::fedimint_core::encoding::as_hex")]
803 raw: Vec<u8>,
804 },
805 Decoded(T),
806}
807
808impl<T> cmp::PartialEq for DynRawFallback<T>
809where
810 T: cmp::PartialEq + Encodable,
811{
812 fn eq(&self, other: &Self) -> bool {
813 match (self, other) {
814 (
815 Self::Raw {
816 module_instance_id: mid_self,
817 raw: raw_self,
818 },
819 Self::Raw {
820 module_instance_id: mid_other,
821 raw: raw_other,
822 },
823 ) => mid_self.eq(mid_other) && raw_self.eq(raw_other),
824 (r @ Self::Raw { .. }, d @ Self::Decoded(_))
825 | (d @ Self::Decoded(_), r @ Self::Raw { .. }) => {
826 r.consensus_encode_to_vec() == d.consensus_encode_to_vec()
827 }
828 (Self::Decoded(s), Self::Decoded(o)) => s == o,
829 }
830 }
831}
832
833impl<T> cmp::Eq for DynRawFallback<T> where T: cmp::Eq + Encodable {}
834
835impl<T> DynRawFallback<T>
836where
837 T: Decodable + 'static,
838{
839 pub fn decoded(self) -> Option<T> {
841 match self {
842 Self::Raw { .. } => None,
843 Self::Decoded(v) => Some(v),
844 }
845 }
846
847 pub fn expect_decoded(self) -> T {
849 match self {
850 Self::Raw { .. } => {
851 panic!("Expected decoded value. Possibly `redecode_raw` call is missing.")
852 }
853 Self::Decoded(v) => v,
854 }
855 }
856
857 pub fn expect_decoded_ref(&self) -> &T {
859 match self {
860 Self::Raw { .. } => {
861 panic!("Expected decoded value. Possibly `redecode_raw` call is missing.")
862 }
863 Self::Decoded(v) => v,
864 }
865 }
866
867 pub fn redecode_raw(
872 self,
873 decoders: &ModuleDecoderRegistry,
874 ) -> Result<Self, crate::encoding::DecodeError> {
875 Ok(match self {
876 Self::Raw {
877 module_instance_id,
878 raw,
879 } => match decoders.get(module_instance_id) {
880 Some(decoder) => Self::Decoded(decoder.decode_complete(
881 &mut &raw[..],
882 raw.len() as u64,
883 module_instance_id,
884 decoders,
885 )?),
886 None => Self::Raw {
887 module_instance_id,
888 raw,
889 },
890 },
891 Self::Decoded(v) => Self::Decoded(v),
892 })
893 }
894}
895
896impl<T> From<T> for DynRawFallback<T> {
897 fn from(value: T) -> Self {
898 Self::Decoded(value)
899 }
900}
901
902impl<T> Decodable for DynRawFallback<T>
903where
904 T: Decodable + 'static,
905{
906 fn consensus_decode_partial_from_finite_reader<R: std::io::Read>(
907 reader: &mut R,
908 decoders: &ModuleDecoderRegistry,
909 ) -> Result<Self, crate::encoding::DecodeError> {
910 let module_instance_id =
911 fedimint_core::core::ModuleInstanceId::consensus_decode_partial_from_finite_reader(
912 reader, decoders,
913 )?;
914 Ok(match decoders.get(module_instance_id) {
915 Some(decoder) => {
916 let total_len_u64 =
917 u64::consensus_decode_partial_from_finite_reader(reader, decoders)?;
918 Self::Decoded(decoder.decode_complete(
919 reader,
920 total_len_u64,
921 module_instance_id,
922 decoders,
923 )?)
924 }
925 None => {
926 Self::Raw {
928 module_instance_id,
929 raw: Vec::consensus_decode_partial_from_finite_reader(reader, decoders)?,
930 }
931 }
932 })
933 }
934}
935
936impl<T> Encodable for DynRawFallback<T>
937where
938 T: Encodable,
939{
940 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
941 match self {
942 Self::Raw {
943 module_instance_id,
944 raw,
945 } => {
946 module_instance_id.consensus_encode(writer)?;
947 raw.consensus_encode(writer)?;
948 Ok(())
949 }
950 Self::Decoded(v) => v.consensus_encode(writer),
951 }
952 }
953}
954
955#[cfg(test)]
956mod tests {
957 use std::fmt::Debug;
958 use std::io::Cursor;
959
960 use super::*;
961 use crate::encoding::{Decodable, Encodable};
962 use crate::module::registry::ModuleRegistry;
963 use crate::util::FmtCompact as _;
964
965 pub(crate) fn test_roundtrip<T>(value: &T)
966 where
967 T: Encodable + Decodable + Eq + Debug,
968 {
969 let mut bytes = Vec::new();
970 value.consensus_encode(&mut bytes).unwrap();
971
972 let mut cursor = Cursor::new(bytes);
973 let decoded =
974 T::consensus_decode_partial(&mut cursor, &ModuleDecoderRegistry::default()).unwrap();
975 assert_eq!(value, &decoded);
976 }
977
978 pub(crate) fn test_roundtrip_expected<T>(value: &T, expected: &[u8])
979 where
980 T: Encodable + Decodable + Eq + Debug,
981 {
982 let mut bytes = Vec::new();
983 value.consensus_encode(&mut bytes).unwrap();
984 assert_eq!(&expected, &bytes);
985
986 let mut cursor = Cursor::new(bytes);
987 let decoded =
988 T::consensus_decode_partial(&mut cursor, &ModuleDecoderRegistry::default()).unwrap();
989 assert_eq!(value, &decoded);
990 }
991
992 #[derive(Debug, Eq, PartialEq, Encodable, Decodable)]
993 enum NoDefaultEnum {
994 Foo,
995 Bar(u32, String),
996 Baz { baz: u8 },
997 }
998
999 #[derive(Debug, Eq, PartialEq, Encodable, Decodable)]
1000 enum DefaultEnum {
1001 Foo,
1002 Bar(u32, String),
1003 #[encodable_default]
1004 Default {
1005 variant: u64,
1006 bytes: Vec<u8>,
1007 },
1008 }
1009
1010 #[test_log::test]
1011 fn test_derive_enum_no_default_roundtrip_success() {
1012 let enums = [
1013 NoDefaultEnum::Foo,
1014 NoDefaultEnum::Bar(
1015 42,
1016 "The answer to life, the universe, and everything".to_string(),
1017 ),
1018 NoDefaultEnum::Baz { baz: 0 },
1019 ];
1020
1021 for e in enums {
1022 test_roundtrip(&e);
1023 }
1024 }
1025
1026 #[test_log::test]
1027 fn test_derive_enum_no_default_decode_fail() {
1028 let unknown_variant = DefaultEnum::Default {
1029 variant: 42,
1030 bytes: vec![0, 1, 2, 3],
1031 };
1032 let mut unknown_variant_encoding = vec![];
1033 unknown_variant
1034 .consensus_encode(&mut unknown_variant_encoding)
1035 .unwrap();
1036
1037 let mut cursor = Cursor::new(&unknown_variant_encoding);
1038 let decode_res =
1039 NoDefaultEnum::consensus_decode_partial(&mut cursor, &ModuleRegistry::default());
1040
1041 match decode_res {
1042 Ok(_) => panic!("Should return error"),
1043 Err(e) => assert!(e.to_string().contains("Invalid enum variant")),
1044 }
1045 }
1046
1047 #[test_log::test]
1048 fn test_derive_enum_default_decode_success() {
1049 let unknown_variant = NoDefaultEnum::Baz { baz: 123 };
1050 let mut unknown_variant_encoding = vec![];
1051 unknown_variant
1052 .consensus_encode(&mut unknown_variant_encoding)
1053 .unwrap();
1054
1055 let mut cursor = Cursor::new(&unknown_variant_encoding);
1056 let decode_res =
1057 DefaultEnum::consensus_decode_partial(&mut cursor, &ModuleRegistry::default());
1058
1059 assert_eq!(
1060 decode_res.unwrap(),
1061 DefaultEnum::Default {
1062 variant: 2,
1063 bytes: vec![123],
1064 }
1065 );
1066 }
1067
1068 #[derive(Debug, Encodable, Decodable, Eq, PartialEq)]
1069 struct TestStruct {
1070 vec: Vec<u8>,
1071 num: u32,
1072 }
1073
1074 #[test_log::test]
1075 fn test_derive_struct() {
1076 let reference = TestStruct {
1077 vec: vec![1, 2, 3],
1078 num: 42,
1079 };
1080 let bytes = [3, 1, 2, 3, 42];
1081
1082 test_roundtrip_expected(&reference, &bytes);
1083 }
1084
1085 #[derive(Debug, Encodable, Decodable, Eq, PartialEq)]
1086 struct TestTupleStruct(Vec<u8>, u32);
1087
1088 #[derive(Debug)]
1089 struct TestFiniteReader;
1090
1091 impl Decodable for TestFiniteReader {
1092 fn consensus_decode_partial_from_finite_reader<R: std::io::Read>(
1093 reader: &mut R,
1094 modules: &ModuleDecoderRegistry,
1095 ) -> Result<Self, DecodeError> {
1096 let _: Vec<u8> = decode_field_from_finite_reader(
1097 reader,
1098 modules,
1099 "Decoding tuple block TestFiniteReader field field_0",
1100 )?;
1101 let _: Vec<u8> = decode_field_from_finite_reader(
1102 reader,
1103 modules,
1104 "Decoding tuple block TestFiniteReader field field_1",
1105 )?;
1106 Ok(Self)
1107 }
1108 }
1109
1110 #[test_log::test]
1111 fn test_derive_tuple_struct() {
1112 let reference = TestTupleStruct(vec![1, 2, 3], 42);
1113 let bytes = [3, 1, 2, 3, 42];
1114
1115 test_roundtrip_expected(&reference, &bytes);
1116 }
1117
1118 #[test_log::test]
1119 fn test_legacy_system_time_encoding() {
1120 let time = UNIX_EPOCH + Duration::new(42, 100);
1121 let expected = [42, 100];
1122 let mut bytes = vec![];
1123 encode_legacy_system_time(&time, &mut bytes).expect("encoding to a vector cannot fail");
1124 assert_eq!(bytes, expected);
1125
1126 let mut cursor = Cursor::new(expected);
1127 let decoded = decode_legacy_system_time_from_finite_reader(
1128 &mut cursor,
1129 &ModuleDecoderRegistry::default(),
1130 )
1131 .expect("valid encoding");
1132 assert_eq!(decoded, time);
1133 }
1134
1135 #[test_log::test]
1136 fn test_client_backup_snapshot_uses_legacy_system_time_encoding() {
1137 let reference = crate::backup::ClientBackupSnapshot {
1138 timestamp: UNIX_EPOCH + Duration::new(42, 100),
1139 data: vec![1, 2, 3],
1140 };
1141 let expected = [42, 100, 3, 1, 2, 3];
1142
1143 test_roundtrip_expected(&reference, &expected);
1144 }
1145
1146 #[test_log::test]
1147 fn test_legacy_optional_system_time_encoding() {
1148 let time = Some(UNIX_EPOCH + Duration::new(42, 100));
1149 let expected = [1, 42, 100];
1150 let mut bytes = vec![];
1151 encode_legacy_option_system_time(&time, &mut bytes)
1152 .expect("encoding to a vector cannot fail");
1153 assert_eq!(bytes, expected);
1154
1155 let mut cursor = Cursor::new(expected);
1156 let decoded = decode_legacy_option_system_time_from_finite_reader(
1157 &mut cursor,
1158 &ModuleDecoderRegistry::default(),
1159 )
1160 .expect("valid encoding");
1161 assert_eq!(decoded, time);
1162 }
1163
1164 #[test_log::test]
1165 fn test_legacy_optional_system_time_encoding_none() {
1166 let mut bytes = vec![];
1167 encode_legacy_option_system_time(&None, &mut bytes)
1168 .expect("encoding to a vector cannot fail");
1169 assert_eq!(bytes, [0]);
1170
1171 let mut cursor = Cursor::new(bytes);
1172 let decoded = decode_legacy_option_system_time_from_finite_reader(
1173 &mut cursor,
1174 &ModuleDecoderRegistry::default(),
1175 )
1176 .expect("valid encoding");
1177 assert_eq!(decoded, None);
1178 }
1179
1180 #[test_log::test]
1181 fn test_legacy_optional_system_time_encoding_rejects_invalid_flag() {
1182 let error = decode_legacy_option_system_time_from_finite_reader(
1183 &mut Cursor::new([2]),
1184 &ModuleDecoderRegistry::default(),
1185 )
1186 .expect_err("invalid option flag must fail");
1187 assert_eq!(
1188 error.to_string(),
1189 "Invalid flag for option enum, expected 0 or 1"
1190 );
1191 }
1192
1193 #[test_log::test]
1194 fn test_legacy_system_time_field_decode_adds_context() {
1195 let error = with_decoding_context(
1196 decode_legacy_system_time_from_finite_reader(
1197 &mut Cursor::new([42]),
1198 &ModuleDecoderRegistry::default(),
1199 ),
1200 "Decoding named block field: Test{ ... timestamp ... }",
1201 )
1202 .expect_err("truncated timestamp must fail");
1203 assert!(
1204 error
1205 .to_string()
1206 .contains("Decoding named block field: Test{ ... timestamp ... }")
1207 );
1208 }
1209
1210 #[test_log::test]
1211 fn test_legacy_system_time_decode_overflow_is_an_error() {
1212 let mut bytes = Vec::new();
1215 u64::MAX.consensus_encode(&mut bytes).unwrap();
1216 0u32.consensus_encode(&mut bytes).unwrap();
1217 decode_legacy_system_time_from_finite_reader(
1218 &mut Cursor::new(bytes),
1219 &ModuleDecoderRegistry::default(),
1220 )
1221 .expect_err("an unrepresentable timestamp must be a decode error, not a panic");
1222 }
1223
1224 #[test_log::test]
1225 fn test_duration_decode_rejects_out_of_range_nsecs() {
1226 let reg = ModuleDecoderRegistry::default();
1229 let mut bad = Vec::new();
1230 u64::MAX.consensus_encode(&mut bad).unwrap();
1231 1_000_000_000u32.consensus_encode(&mut bad).unwrap();
1232 Duration::consensus_decode_partial(&mut Cursor::new(bad), ®)
1233 .expect_err("nsecs of one billion must be rejected");
1234
1235 let mut ok = Vec::new();
1237 u64::MAX.consensus_encode(&mut ok).unwrap();
1238 999_999_999u32.consensus_encode(&mut ok).unwrap();
1239 Duration::consensus_decode_partial(&mut Cursor::new(ok), ®)
1240 .expect("the largest canonical nsecs must decode");
1241 }
1242
1243 #[test_log::test]
1244 fn test_finite_reader_shares_decode_limit_between_fields() {
1245 let field = vec![0u8; MAX_DECODE_SIZE / 2];
1246 let mut bytes = vec![];
1247 field
1248 .consensus_encode(&mut bytes)
1249 .expect("encoding to a vector cannot fail");
1250 field
1251 .consensus_encode(&mut bytes)
1252 .expect("encoding to a vector cannot fail");
1253
1254 let error = TestFiniteReader::consensus_decode_partial(
1255 &mut Cursor::new(bytes),
1256 &ModuleDecoderRegistry::default(),
1257 )
1258 .expect_err("both fields cannot exceed one decode limit");
1259 assert!(
1260 error
1261 .to_string()
1262 .contains("Decoding tuple block TestFiniteReader field field_1")
1263 );
1264 }
1265
1266 #[derive(Debug, Encodable, Decodable, Eq, PartialEq)]
1267 enum TestEnum {
1268 Foo(Option<u64>),
1269 Bar { bazz: Vec<u8> },
1270 }
1271
1272 #[test_log::test]
1273 fn test_derive_enum() {
1274 let test_cases = [
1275 (TestEnum::Foo(Some(42)), vec![0, 2, 1, 42]),
1276 (TestEnum::Foo(None), vec![0, 1, 0]),
1277 (
1278 TestEnum::Bar {
1279 bazz: vec![1, 2, 3],
1280 },
1281 vec![1, 4, 3, 1, 2, 3],
1282 ),
1283 ];
1284
1285 for (reference, bytes) in test_cases {
1286 test_roundtrip_expected(&reference, &bytes);
1287 }
1288 }
1289
1290 #[test]
1291 fn test_derive_empty_enum_decode() {
1292 #[derive(Debug, Encodable, Decodable)]
1293 enum NotConstructable {}
1294
1295 let vec = vec![42u8];
1296 let mut cursor = Cursor::new(vec);
1297
1298 assert!(
1299 NotConstructable::consensus_decode_partial(
1300 &mut cursor,
1301 &ModuleDecoderRegistry::default()
1302 )
1303 .is_err()
1304 );
1305 }
1306
1307 #[test]
1308 fn test_custom_index_enum() {
1309 #[derive(Debug, PartialEq, Eq, Encodable, Decodable)]
1310 enum Old {
1311 Foo,
1312 Bar,
1313 Baz,
1314 }
1315
1316 #[derive(Debug, PartialEq, Eq, Encodable, Decodable)]
1317 enum New {
1318 #[encodable(index = 0)]
1319 Foo,
1320 #[encodable(index = 2)]
1321 Baz,
1322 #[encodable_default]
1323 Default { variant: u64, bytes: Vec<u8> },
1324 }
1325
1326 let test_vector = vec![
1327 (Old::Foo, New::Foo),
1328 (
1329 Old::Bar,
1330 New::Default {
1331 variant: 1,
1332 bytes: vec![],
1333 },
1334 ),
1335 (Old::Baz, New::Baz),
1336 ];
1337
1338 for (old, new) in test_vector {
1339 let old_bytes = old.consensus_encode_to_vec();
1340 let decoded_new = New::consensus_decode_whole(&old_bytes, &ModuleRegistry::default())
1341 .expect("Decoding failed");
1342 assert_eq!(decoded_new, new);
1343 }
1344 }
1345
1346 fn encode_value<T: Encodable>(value: &T) -> Vec<u8> {
1347 let mut writer = Vec::new();
1348 value.consensus_encode(&mut writer).unwrap();
1349 writer
1350 }
1351
1352 fn decode_value<T: Decodable>(bytes: &[u8]) -> T {
1353 T::consensus_decode_whole(bytes, &ModuleDecoderRegistry::default()).unwrap()
1354 }
1355
1356 fn keeps_ordering_after_serialization<T: Ord + Encodable + Decodable + Debug>(mut vec: Vec<T>) {
1357 vec.sort();
1358 let mut encoded = vec.iter().map(encode_value).collect::<Vec<_>>();
1359 encoded.sort();
1360 let decoded = encoded.iter().map(|v| decode_value(v)).collect::<Vec<_>>();
1361 for (i, (a, b)) in vec.iter().zip(decoded.iter()).enumerate() {
1362 assert_eq!(a, b, "difference at index {i}");
1363 }
1364 }
1365
1366 #[test]
1367 fn test_lexicographical_sorting() {
1368 #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)]
1369 struct TestAmount(u64);
1370
1371 #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)]
1372 struct TestComplexAmount(u16, u32, u64);
1373
1374 #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)]
1375 struct Text(String);
1376
1377 let amounts = (0..20000).map(TestAmount).collect::<Vec<_>>();
1378 keeps_ordering_after_serialization(amounts);
1379
1380 let complex_amounts = (10..20000)
1381 .flat_map(|i| {
1382 (i - 1..=i + 1).flat_map(move |j| {
1383 (i - 1..=i + 1).map(move |k| TestComplexAmount(i as u16, j as u32, k as u64))
1384 })
1385 })
1386 .collect::<Vec<_>>();
1387 keeps_ordering_after_serialization(complex_amounts);
1388
1389 let texts = (' '..'~')
1390 .flat_map(|i| {
1391 (' '..'~')
1392 .map(|j| Text(format!("{i}{j}")))
1393 .collect::<Vec<_>>()
1394 })
1395 .collect::<Vec<_>>();
1396 keeps_ordering_after_serialization(texts);
1397
1398 }
1402
1403 #[test]
1404 fn whole_decode_rejects_trailing_bytes_with_a_message() {
1405 let err = u8::consensus_decode_whole(&[1, 2], &ModuleDecoderRegistry::default())
1406 .expect_err("one byte too many");
1407 assert!(matches!(err, DecodeError::Custom { .. }), "{err:?}");
1408 assert!(
1409 err.to_string()
1410 .starts_with("Type did not consume all bytes during decoding"),
1411 "{err}"
1412 );
1413 }
1414
1415 #[test]
1416 fn decode_error_display_is_the_outer_layer_and_the_chain_is_reachable() {
1417 let io = std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "short read");
1418 let err = Err::<(), _>(io)
1419 .context("Decoding field a")
1420 .context("Decoding Foo")
1421 .expect_err("built from an error");
1422
1423 assert_eq!(err.to_string(), "Decoding Foo");
1424 assert_eq!(
1425 err.fmt_compact().to_string(),
1426 "Decoding Foo: Decoding field a: short read"
1427 );
1428
1429 let DecodeError::Context { source: inner, .. } = &err else {
1430 panic!("outer layer is the last context added: {err:?}");
1431 };
1432 let DecodeError::Context { source: leaf, .. } = &**inner else {
1433 panic!("inner layer is the first context added: {inner:?}");
1434 };
1435 assert!(matches!(**leaf, DecodeError::Io(_)), "{leaf:?}");
1436 }
1437
1438 #[test]
1439 fn from_err_shows_the_typed_error_as_is() {
1440 let parse_error = "x".parse::<u8>().expect_err("not a number");
1441 let message = parse_error.to_string();
1442
1443 let err = DecodeError::from_err(parse_error);
1444
1445 assert!(matches!(err, DecodeError::Invalid(_)), "{err:?}");
1446 assert_eq!(err.to_string(), message);
1447 assert_eq!(err.fmt_compact().to_string(), message);
1448 }
1449
1450 #[test]
1451 fn custom_and_from_str_carry_only_a_message() {
1452 let err = DecodeError::custom(format!("Unknown network magic: {:x}", 0xd9b4_bef9_u32));
1453 assert!(matches!(err, DecodeError::Custom { .. }), "{err:?}");
1454 assert_eq!(err.to_string(), "Unknown network magic: d9b4bef9");
1455 assert!(std::error::Error::source(&err).is_none());
1456
1457 let err = DecodeError::from_str("Out of range, expected 0 or 1");
1458 assert_eq!(err.to_string(), "Out of range, expected 0 or 1");
1459 }
1460
1461 #[test]
1462 fn with_context_only_formats_on_error() {
1463 let ok: Result<u8, DecodeError> = Ok(1);
1464 let formatted = ok
1465 .with_context(|| panic!("must not be called on Ok"))
1466 .expect("still Ok");
1467 assert_eq!(formatted, 1);
1468
1469 let err = Err::<u8, _>(DecodeError::from_str("bad"))
1470 .with_context(|| format!("Decoding item {}", 3))
1471 .expect_err("still Err");
1472 assert_eq!(err.fmt_compact().to_string(), "Decoding item 3: bad");
1473 }
1474
1475 #[test]
1476 fn truncated_input_is_an_io_error() {
1477 let err = u8::consensus_decode_whole(&[], &ModuleDecoderRegistry::default())
1478 .expect_err("empty input is not a u8");
1479 assert!(matches!(err, DecodeError::Io(_)), "{err:?}");
1480 }
1481
1482 #[test]
1483 fn truncated_integer_is_an_io_error() {
1484 let err = u32::consensus_decode_whole(&[], &ModuleDecoderRegistry::default())
1485 .expect_err("zero bytes are not a u32");
1486 assert!(matches!(err, DecodeError::Io(_)), "{err:?}");
1487 }
1488
1489 #[test]
1490 fn truncated_transaction_id_is_an_io_error() {
1491 let err = crate::TransactionId::consensus_decode_whole(
1492 &[0u8; 31],
1493 &ModuleDecoderRegistry::default(),
1494 )
1495 .expect_err("31 bytes are not a transaction id");
1496 assert!(matches!(err, DecodeError::Io(_)), "{err:?}");
1497 }
1498
1499 #[test]
1500 fn derived_decode_names_the_failing_field_and_keeps_the_io_root() {
1501 let err = TestStruct::consensus_decode_whole(&[1, 7], &ModuleDecoderRegistry::default())
1503 .expect_err("payload is truncated");
1504
1505 let DecodeError::Context { context, source } = &err else {
1506 panic!("the failing field's context is the outer layer: {err:?}");
1507 };
1508 assert_eq!(
1509 context,
1510 "Decoding named block field: TestStruct{ ... num ... }"
1511 );
1512 assert!(matches!(**source, DecodeError::Io(_)), "{source:?}");
1513 }
1514
1515 #[test]
1516 fn derived_decode_reports_unknown_variants_structurally() {
1517 let unknown_variant = DefaultEnum::Default {
1518 variant: 42,
1519 bytes: vec![0, 1, 2, 3],
1520 };
1521 let mut encoding = vec![];
1522 unknown_variant
1523 .consensus_encode(&mut encoding)
1524 .expect("encodes");
1525
1526 let err = NoDefaultEnum::consensus_decode_whole(&encoding, &ModuleRegistry::default())
1527 .expect_err("variant 42 does not exist");
1528 assert!(
1529 matches!(
1530 err,
1531 DecodeError::InvalidVariant {
1532 variant: 42,
1533 type_name: "NoDefaultEnum"
1534 }
1535 ),
1536 "{err:?}"
1537 );
1538 }
1539}