fedimint_core/encoding/
mod.rs

1//! Binary encoding interface suitable for
2//! consensus critical encoding.
3//!
4//! Over time all structs that ! need to be encoded to binary will be migrated
5//! to this interface.
6//!
7//! This code is based on corresponding `rust-bitcoin` types.
8//!
9//! See [`Encodable`] and [`Decodable`] for two main traits.
10
11pub 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::fmt::{Debug, Formatter};
22use std::io::{self, Error, Read, Write};
23use std::time::{Duration, SystemTime, UNIX_EPOCH};
24
25use anyhow::Context;
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
37/// A writer counting number of bytes written to it
38///
39/// Copy&pasted from <https://github.com/SOF3/count-write> which
40/// uses Apache license (and it's a trivial amount of code, repeating
41/// on stack overflow).
42pub struct CountWrite<W> {
43    inner: W,
44    count: u64,
45}
46
47impl<W> CountWrite<W> {
48    /// Returns the number of bytes successfully written so far
49    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
72/// Object-safe trait for things that can encode themselves
73///
74/// Like `rust-bitcoin`'s `consensus_encode`, but without generics,
75/// so can be used in `dyn` objects.
76pub 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
113/// Data which can be encoded in a consensus-consistent way
114pub trait Encodable {
115    /// Encode an object with a well-defined format.
116    /// Returns the number of bytes written on success.
117    ///
118    /// The only errors returned are errors propagated from the writer.
119    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error>;
120
121    /// [`Self::consensus_encode`] to newly allocated `Vec<u8>`
122    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    /// Encode and convert to hex string representation
130    fn consensus_encode_to_hex(&self) -> String {
131        // TODO: This double allocation offends real Rustaceans. We should
132        // be able to go straight to String, but this use case seems under-served
133        // by hex encoding crates.
134        self.consensus_encode_to_vec().encode_hex()
135    }
136
137    /// Encode without storing the encoding, return the size
138    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    /// Generate a SHA256 hash of the consensus encoding using the default hash
147    /// engine for `H`.
148    ///
149    /// Can be used to validate all federation members agree on state without
150    /// revealing the object
151    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    /// [`Self::consensus_hash`] for [`bitcoin::hashes::sha256::Hash`]
163    fn consensus_hash_sha256(&self) -> sha256::Hash {
164        self.consensus_hash()
165    }
166}
167
168/// Maximum size, in bytes, of data we are allowed to ever decode
169/// for a single value.
170pub const MAX_DECODE_SIZE: usize = 16_000_000;
171
172/// Data which can be encoded in a consensus-consistent way
173pub trait Decodable: Sized {
174    /// Decode `Self` from a size-limited reader.
175    ///
176    /// Like `consensus_decode_partial` but relies on the reader being limited
177    /// in the amount of data it returns, e.g. by being wrapped in
178    /// [`std::io::Take`].
179    ///
180    /// Failing to abide to this requirement might lead to memory exhaustion
181    /// caused by malicious inputs.
182    ///
183    /// Users should default to `consensus_decode_partial`, but when data to be
184    /// decoded is already in a byte vector of a limited size, calling this
185    /// function directly might be marginally faster (due to avoiding extra
186    /// checks).
187    ///
188    /// ### Rules for trait implementations
189    ///
190    /// * Simple types that that have a fixed size (own and member fields),
191    ///   don't have to overwrite this method, or be concern with it, should
192    ///   only impl `consensus_decode_partial`.
193    /// * Types that deserialize based on decoded untrusted length should
194    ///   implement `consensus_decode_partial_from_finite_reader` only:
195    ///   * Default implementation of `consensus_decode_partial` will forward to
196    ///     `consensus_decode_partial_from_finite_reader` with the reader
197    ///     wrapped by `Take`, protecting from readers that keep returning data.
198    ///   * Implementation must make sure to put a cap on things like
199    ///     `Vec::with_capacity` and other allocations to avoid oversized
200    ///     allocations, and rely on the reader being finite and running out of
201    ///     data, and collections reallocating on a legitimately oversized input
202    ///     data, instead of trying to enforce arbitrary length limits.
203    /// * Types that contain other types that might be require limited reader
204    ///   (thus implementing `consensus_decode_partial_from_finite_reader`),
205    ///   should also implement it applying same rules, and in addition make
206    ///   sure to call `consensus_decode_partial_from_finite_reader` on all
207    ///   members, to avoid creating redundant `Take` wrappers
208    ///   (`Take<Take<...>>`). Failure to do so might result only in a tiny
209    ///   performance hit.
210    #[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        // This method is always strictly less general than, `consensus_decode_partial`,
216        // so it's safe and make sense to default to just calling it. This way
217        // most types, that don't care about protecting against resource
218        // exhaustion due to malicious input, can just ignore it.
219        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        // This method is always strictly less general than, `consensus_decode_partial`,
233        // so it's safe and make sense to default to just calling it. This way
234        // most types, that don't care about protecting against resource
235        // exhaustion due to malicious input, can just ignore it.
236        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::new_custom(
241                anyhow::anyhow!(
242                    "Type did not consume all bytes during decoding; expected={}; left={}; type={}",
243                    total_len,
244                    left,
245                    std::any::type_name::<Self>(),
246                ),
247            ));
248        }
249        Ok(res)
250    }
251    /// Decode an object with a well-defined format.
252    ///
253    /// This is the method that should be implemented for a typical, fixed sized
254    /// type implementing this trait. Default implementation is wrapping the
255    /// reader in [`std::io::Take`] to limit the input size to
256    /// [`MAX_DECODE_SIZE`], and forwards the call to
257    /// [`Self::consensus_decode_partial_from_finite_reader`], which is
258    /// convenient for types that override
259    /// [`Self::consensus_decode_partial_from_finite_reader`] instead.
260    #[inline]
261    fn consensus_decode_partial<R: std::io::Read>(
262        r: &mut R,
263        modules: &ModuleDecoderRegistry,
264    ) -> Result<Self, DecodeError> {
265        Self::consensus_decode_partial_from_finite_reader(
266            &mut r.take(MAX_DECODE_SIZE as u64),
267            modules,
268        )
269    }
270
271    /// Decode an object from hex
272    fn consensus_decode_hex(
273        hex: &str,
274        modules: &ModuleDecoderRegistry,
275    ) -> Result<Self, DecodeError> {
276        let bytes = Vec::<u8>::from_hex(hex)
277            .map_err(anyhow::Error::from)
278            .map_err(DecodeError::new_custom)?;
279        Decodable::consensus_decode_whole(&bytes, modules)
280    }
281}
282
283impl Encodable for SafeUrl {
284    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
285        self.to_string().consensus_encode(writer)
286    }
287}
288
289impl Decodable for SafeUrl {
290    fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
291        d: &mut D,
292        modules: &ModuleDecoderRegistry,
293    ) -> Result<Self, DecodeError> {
294        String::consensus_decode_partial_from_finite_reader(d, modules)?
295            .parse::<Self>()
296            .map_err(DecodeError::from_err)
297    }
298}
299
300#[derive(Debug, Error)]
301pub struct DecodeError(pub(crate) anyhow::Error);
302
303impl DecodeError {
304    pub fn new_custom(e: anyhow::Error) -> Self {
305        Self(e)
306    }
307}
308
309impl From<anyhow::Error> for DecodeError {
310    fn from(e: anyhow::Error) -> Self {
311        Self(e)
312    }
313}
314
315macro_rules! impl_encode_decode_num_as_plain {
316    ($num_type:ty) => {
317        impl Encodable for $num_type {
318            fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
319                let bytes = self.to_be_bytes();
320                writer.write_all(&bytes[..])?;
321                Ok(())
322            }
323        }
324
325        impl Decodable for $num_type {
326            fn consensus_decode_partial<D: std::io::Read>(
327                d: &mut D,
328                _modules: &ModuleDecoderRegistry,
329            ) -> Result<Self, crate::encoding::DecodeError> {
330                let mut bytes = [0u8; (<$num_type>::BITS / 8) as usize];
331                d.read_exact(&mut bytes).map_err(DecodeError::from_err)?;
332                Ok(<$num_type>::from_be_bytes(bytes))
333            }
334        }
335    };
336}
337
338macro_rules! impl_encode_decode_num_as_bigsize {
339    ($num_type:ty) => {
340        impl Encodable for $num_type {
341            fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
342                BigSize(u64::from(*self)).consensus_encode(writer)
343            }
344        }
345
346        impl Decodable for $num_type {
347            fn consensus_decode_partial<D: std::io::Read>(
348                d: &mut D,
349                _modules: &ModuleDecoderRegistry,
350            ) -> Result<Self, crate::encoding::DecodeError> {
351                let varint = BigSize::consensus_decode_partial(d, &Default::default())
352                    .context(concat!("VarInt inside ", stringify!($num_type)))?;
353                <$num_type>::try_from(varint.0).map_err(crate::encoding::DecodeError::from_err)
354            }
355        }
356    };
357}
358
359impl_encode_decode_num_as_bigsize!(u64);
360impl_encode_decode_num_as_bigsize!(u32);
361impl_encode_decode_num_as_bigsize!(u16);
362impl_encode_decode_num_as_plain!(u8);
363
364macro_rules! impl_encode_decode_tuple {
365    ($($x:ident),*) => (
366        #[allow(non_snake_case)]
367        impl <$($x: Encodable),*> Encodable for ($($x),*) {
368            fn consensus_encode<W: std::io::Write>(&self, s: &mut W) -> Result<(), std::io::Error> {
369                let &($(ref $x),*) = self;
370                $($x.consensus_encode(s)?;)*
371                Ok(())
372            }
373        }
374
375        #[allow(non_snake_case)]
376        impl<$($x: Decodable),*> Decodable for ($($x),*) {
377            fn consensus_decode_partial<D: std::io::Read>(d: &mut D, modules: &ModuleDecoderRegistry) -> Result<Self, DecodeError> {
378                Ok(($({let $x = Decodable::consensus_decode_partial(d, modules)?; $x }),*))
379            }
380        }
381    );
382}
383
384impl_encode_decode_tuple!(T1, T2);
385impl_encode_decode_tuple!(T1, T2, T3);
386impl_encode_decode_tuple!(T1, T2, T3, T4);
387
388impl<T> Encodable for Option<T>
389where
390    T: Encodable,
391{
392    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
393        if let Some(inner) = self {
394            1u8.consensus_encode(writer)?;
395            inner.consensus_encode(writer)?;
396        } else {
397            0u8.consensus_encode(writer)?;
398        }
399        Ok(())
400    }
401}
402
403impl<T> Decodable for Option<T>
404where
405    T: Decodable,
406{
407    fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
408        d: &mut D,
409        modules: &ModuleDecoderRegistry,
410    ) -> Result<Self, DecodeError> {
411        let flag = u8::consensus_decode_partial_from_finite_reader(d, modules)?;
412        match flag {
413            0 => Ok(None),
414            1 => Ok(Some(T::consensus_decode_partial_from_finite_reader(
415                d, modules,
416            )?)),
417            _ => Err(DecodeError::from_str(
418                "Invalid flag for option enum, expected 0 or 1",
419            )),
420        }
421    }
422}
423
424impl<T, E> Encodable for Result<T, E>
425where
426    T: Encodable,
427    E: Encodable,
428{
429    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
430        match self {
431            Ok(value) => {
432                1u8.consensus_encode(writer)?;
433                value.consensus_encode(writer)?;
434            }
435            Err(error) => {
436                0u8.consensus_encode(writer)?;
437                error.consensus_encode(writer)?;
438            }
439        }
440
441        Ok(())
442    }
443}
444
445impl<T, E> Decodable for Result<T, E>
446where
447    T: Decodable,
448    E: Decodable,
449{
450    fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
451        d: &mut D,
452        modules: &ModuleDecoderRegistry,
453    ) -> Result<Self, DecodeError> {
454        let flag = u8::consensus_decode_partial_from_finite_reader(d, modules)?;
455        match flag {
456            0 => Ok(Err(E::consensus_decode_partial_from_finite_reader(
457                d, modules,
458            )?)),
459            1 => Ok(Ok(T::consensus_decode_partial_from_finite_reader(
460                d, modules,
461            )?)),
462            _ => Err(DecodeError::from_str(
463                "Invalid flag for option enum, expected 0 or 1",
464            )),
465        }
466    }
467}
468
469impl<T> Encodable for Box<T>
470where
471    T: Encodable,
472{
473    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
474        self.as_ref().consensus_encode(writer)
475    }
476}
477
478impl<T> Decodable for Box<T>
479where
480    T: Decodable,
481{
482    fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
483        d: &mut D,
484        modules: &ModuleDecoderRegistry,
485    ) -> Result<Self, DecodeError> {
486        Ok(Self::new(T::consensus_decode_partial_from_finite_reader(
487            d, modules,
488        )?))
489    }
490}
491
492impl Encodable for () {
493    fn consensus_encode<W: std::io::Write>(&self, _writer: &mut W) -> Result<(), std::io::Error> {
494        Ok(())
495    }
496}
497
498impl Decodable for () {
499    fn consensus_decode_partial<D: std::io::Read>(
500        _d: &mut D,
501        _modules: &ModuleDecoderRegistry,
502    ) -> Result<Self, DecodeError> {
503        Ok(())
504    }
505}
506
507impl Encodable for &str {
508    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
509        self.as_bytes().consensus_encode(writer)
510    }
511}
512
513impl Encodable for String {
514    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
515        self.as_bytes().consensus_encode(writer)
516    }
517}
518
519impl Decodable for String {
520    fn consensus_decode_partial_from_finite_reader<D: std::io::Read>(
521        d: &mut D,
522        modules: &ModuleDecoderRegistry,
523    ) -> Result<Self, DecodeError> {
524        Self::from_utf8(Decodable::consensus_decode_partial_from_finite_reader(
525            d, modules,
526        )?)
527        .map_err(DecodeError::from_err)
528    }
529}
530
531impl Encodable for SystemTime {
532    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
533        let duration = self.duration_since(UNIX_EPOCH).expect("valid duration");
534        duration.consensus_encode_dyn(writer)
535    }
536}
537
538impl Decodable for SystemTime {
539    fn consensus_decode_partial<D: std::io::Read>(
540        d: &mut D,
541        modules: &ModuleDecoderRegistry,
542    ) -> Result<Self, DecodeError> {
543        let duration = Duration::consensus_decode_partial(d, modules)?;
544        Ok(UNIX_EPOCH + duration)
545    }
546}
547
548impl Encodable for Duration {
549    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
550        self.as_secs().consensus_encode(writer)?;
551        self.subsec_nanos().consensus_encode(writer)?;
552
553        Ok(())
554    }
555}
556
557impl Decodable for Duration {
558    fn consensus_decode_partial<D: std::io::Read>(
559        d: &mut D,
560        modules: &ModuleDecoderRegistry,
561    ) -> Result<Self, DecodeError> {
562        let secs = Decodable::consensus_decode_partial(d, modules)?;
563        let nsecs = Decodable::consensus_decode_partial(d, modules)?;
564        Ok(Self::new(secs, nsecs))
565    }
566}
567
568impl Encodable for bool {
569    fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
570        let bool_as_u8 = u8::from(*self);
571        writer.write_all(&[bool_as_u8])?;
572        Ok(())
573    }
574}
575
576impl Decodable for bool {
577    fn consensus_decode_partial<D: Read>(
578        d: &mut D,
579        _modules: &ModuleDecoderRegistry,
580    ) -> Result<Self, DecodeError> {
581        let mut bool_as_u8 = [0u8];
582        d.read_exact(&mut bool_as_u8)
583            .map_err(DecodeError::from_err)?;
584        match bool_as_u8[0] {
585            0 => Ok(false),
586            1 => Ok(true),
587            _ => Err(DecodeError::from_str("Out of range, expected 0 or 1")),
588        }
589    }
590}
591
592impl DecodeError {
593    // TODO: think about better name
594    #[allow(clippy::should_implement_trait)]
595    pub fn from_str(s: &'static str) -> Self {
596        #[derive(Debug)]
597        struct StrError(&'static str);
598
599        impl std::fmt::Display for StrError {
600            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
601                std::fmt::Display::fmt(&self.0, f)
602            }
603        }
604
605        impl std::error::Error for StrError {}
606
607        Self(anyhow::Error::from(StrError(s)))
608    }
609
610    pub fn from_err<E: std::error::Error + Send + Sync + 'static>(e: E) -> Self {
611        Self(anyhow::Error::from(e))
612    }
613}
614
615impl std::fmt::Display for DecodeError {
616    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
617        f.write_fmt(format_args!("{:#}", self.0))
618    }
619}
620
621impl Encodable for Cow<'static, str> {
622    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
623        self.as_ref().consensus_encode(writer)
624    }
625}
626
627impl Decodable for Cow<'static, str> {
628    fn consensus_decode_partial<D: std::io::Read>(
629        d: &mut D,
630        modules: &ModuleDecoderRegistry,
631    ) -> Result<Self, DecodeError> {
632        Ok(Cow::Owned(String::consensus_decode_partial(d, modules)?))
633    }
634}
635
636/// A type that decodes `module_instance_id`-prefixed `T`s even
637/// when corresponding `Decoder` is not available.
638///
639/// All dyn-module types are encoded as:
640///
641/// ```norust
642/// module_instance_id | len_u64 | data
643/// ```
644///
645/// So clients that don't have a corresponding module, can read
646/// the `len_u64` and skip the amount of data specified in it.
647///
648/// This type makes it more convenient. It's possible to attempt
649/// to retry decoding after more modules become available by using
650/// [`DynRawFallback::redecode_raw`].
651///
652/// Notably this struct does not ignore any errors. It only skips
653/// decoding when the module decoder is not available.
654#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
655pub enum DynRawFallback<T> {
656    Raw {
657        module_instance_id: ModuleInstanceId,
658        #[serde(with = "::fedimint_core::encoding::as_hex")]
659        raw: Vec<u8>,
660    },
661    Decoded(T),
662}
663
664impl<T> DynRawFallback<T>
665where
666    T: Decodable + 'static,
667{
668    /// Get the decoded `T` or `None` if not decoded yet
669    pub fn decoded(self) -> Option<T> {
670        match self {
671            Self::Raw { .. } => None,
672            Self::Decoded(v) => Some(v),
673        }
674    }
675
676    /// Convert into the decoded `T` and panic if not decoded yet
677    pub fn expect_decoded(self) -> T {
678        match self {
679            Self::Raw { .. } => {
680                panic!("Expected decoded value. Possibly `redecode_raw` call is missing.")
681            }
682            Self::Decoded(v) => v,
683        }
684    }
685
686    /// Get the decoded `T` and panic if not decoded yet
687    pub fn expect_decoded_ref(&self) -> &T {
688        match self {
689            Self::Raw { .. } => {
690                panic!("Expected decoded value. Possibly `redecode_raw` call is missing.")
691            }
692            Self::Decoded(v) => v,
693        }
694    }
695
696    /// Attempt to re-decode raw values with new set of of `modules`
697    ///
698    /// In certain contexts it might be necessary to try again with
699    /// a new set of modules.
700    pub fn redecode_raw(
701        self,
702        decoders: &ModuleDecoderRegistry,
703    ) -> Result<Self, crate::encoding::DecodeError> {
704        Ok(match self {
705            Self::Raw {
706                module_instance_id,
707                raw,
708            } => match decoders.get(module_instance_id) {
709                Some(decoder) => Self::Decoded(decoder.decode_complete(
710                    &mut &raw[..],
711                    raw.len() as u64,
712                    module_instance_id,
713                    decoders,
714                )?),
715                None => Self::Raw {
716                    module_instance_id,
717                    raw,
718                },
719            },
720            Self::Decoded(v) => Self::Decoded(v),
721        })
722    }
723}
724
725impl<T> From<T> for DynRawFallback<T> {
726    fn from(value: T) -> Self {
727        Self::Decoded(value)
728    }
729}
730
731impl<T> Decodable for DynRawFallback<T>
732where
733    T: Decodable + 'static,
734{
735    fn consensus_decode_partial_from_finite_reader<R: std::io::Read>(
736        reader: &mut R,
737        decoders: &ModuleDecoderRegistry,
738    ) -> Result<Self, crate::encoding::DecodeError> {
739        let module_instance_id =
740            fedimint_core::core::ModuleInstanceId::consensus_decode_partial_from_finite_reader(
741                reader, decoders,
742            )?;
743        Ok(match decoders.get(module_instance_id) {
744            Some(decoder) => {
745                let total_len_u64 =
746                    u64::consensus_decode_partial_from_finite_reader(reader, decoders)?;
747                Self::Decoded(decoder.decode_complete(
748                    reader,
749                    total_len_u64,
750                    module_instance_id,
751                    decoders,
752                )?)
753            }
754            None => {
755                // since the decoder is not available, just read the raw data
756                Self::Raw {
757                    module_instance_id,
758                    raw: Vec::consensus_decode_partial_from_finite_reader(reader, decoders)?,
759                }
760            }
761        })
762    }
763}
764
765impl<T> Encodable for DynRawFallback<T>
766where
767    T: Encodable,
768{
769    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
770        match self {
771            Self::Raw {
772                module_instance_id,
773                raw,
774            } => {
775                module_instance_id.consensus_encode(writer)?;
776                raw.consensus_encode(writer)?;
777                Ok(())
778            }
779            Self::Decoded(v) => v.consensus_encode(writer),
780        }
781    }
782}
783
784#[cfg(test)]
785mod tests {
786    use std::fmt::Debug;
787    use std::io::Cursor;
788
789    use super::*;
790    use crate::encoding::{Decodable, Encodable};
791    use crate::module::registry::ModuleRegistry;
792
793    pub(crate) fn test_roundtrip<T>(value: &T)
794    where
795        T: Encodable + Decodable + Eq + Debug,
796    {
797        let mut bytes = Vec::new();
798        value.consensus_encode(&mut bytes).unwrap();
799
800        let mut cursor = Cursor::new(bytes);
801        let decoded =
802            T::consensus_decode_partial(&mut cursor, &ModuleDecoderRegistry::default()).unwrap();
803        assert_eq!(value, &decoded);
804    }
805
806    pub(crate) fn test_roundtrip_expected<T>(value: &T, expected: &[u8])
807    where
808        T: Encodable + Decodable + Eq + Debug,
809    {
810        let mut bytes = Vec::new();
811        value.consensus_encode(&mut bytes).unwrap();
812        assert_eq!(&expected, &bytes);
813
814        let mut cursor = Cursor::new(bytes);
815        let decoded =
816            T::consensus_decode_partial(&mut cursor, &ModuleDecoderRegistry::default()).unwrap();
817        assert_eq!(value, &decoded);
818    }
819
820    #[derive(Debug, Eq, PartialEq, Encodable, Decodable)]
821    enum NoDefaultEnum {
822        Foo,
823        Bar(u32, String),
824        Baz { baz: u8 },
825    }
826
827    #[derive(Debug, Eq, PartialEq, Encodable, Decodable)]
828    enum DefaultEnum {
829        Foo,
830        Bar(u32, String),
831        #[encodable_default]
832        Default {
833            variant: u64,
834            bytes: Vec<u8>,
835        },
836    }
837
838    #[test_log::test]
839    fn test_derive_enum_no_default_roundtrip_success() {
840        let enums = [
841            NoDefaultEnum::Foo,
842            NoDefaultEnum::Bar(
843                42,
844                "The answer to life, the universe, and everything".to_string(),
845            ),
846            NoDefaultEnum::Baz { baz: 0 },
847        ];
848
849        for e in enums {
850            test_roundtrip(&e);
851        }
852    }
853
854    #[test_log::test]
855    fn test_derive_enum_no_default_decode_fail() {
856        let unknown_variant = DefaultEnum::Default {
857            variant: 42,
858            bytes: vec![0, 1, 2, 3],
859        };
860        let mut unknown_variant_encoding = vec![];
861        unknown_variant
862            .consensus_encode(&mut unknown_variant_encoding)
863            .unwrap();
864
865        let mut cursor = Cursor::new(&unknown_variant_encoding);
866        let decode_res =
867            NoDefaultEnum::consensus_decode_partial(&mut cursor, &ModuleRegistry::default());
868
869        match decode_res {
870            Ok(_) => panic!("Should return error"),
871            Err(e) => assert!(e.to_string().contains("Invalid enum variant")),
872        }
873    }
874
875    #[test_log::test]
876    fn test_derive_enum_default_decode_success() {
877        let unknown_variant = NoDefaultEnum::Baz { baz: 123 };
878        let mut unknown_variant_encoding = vec![];
879        unknown_variant
880            .consensus_encode(&mut unknown_variant_encoding)
881            .unwrap();
882
883        let mut cursor = Cursor::new(&unknown_variant_encoding);
884        let decode_res =
885            DefaultEnum::consensus_decode_partial(&mut cursor, &ModuleRegistry::default());
886
887        assert_eq!(
888            decode_res.unwrap(),
889            DefaultEnum::Default {
890                variant: 2,
891                bytes: vec![123],
892            }
893        );
894    }
895
896    #[test_log::test]
897    fn test_derive_struct() {
898        #[derive(Debug, Encodable, Decodable, Eq, PartialEq)]
899        struct TestStruct {
900            vec: Vec<u8>,
901            num: u32,
902        }
903
904        let reference = TestStruct {
905            vec: vec![1, 2, 3],
906            num: 42,
907        };
908        let bytes = [3, 1, 2, 3, 42];
909
910        test_roundtrip_expected(&reference, &bytes);
911    }
912
913    #[test_log::test]
914    fn test_derive_tuple_struct() {
915        #[derive(Debug, Encodable, Decodable, Eq, PartialEq)]
916        struct TestStruct(Vec<u8>, u32);
917
918        let reference = TestStruct(vec![1, 2, 3], 42);
919        let bytes = [3, 1, 2, 3, 42];
920
921        test_roundtrip_expected(&reference, &bytes);
922    }
923
924    #[test_log::test]
925    fn test_derive_enum() {
926        #[derive(Debug, Encodable, Decodable, Eq, PartialEq)]
927        enum TestEnum {
928            Foo(Option<u64>),
929            Bar { bazz: Vec<u8> },
930        }
931
932        let test_cases = [
933            (TestEnum::Foo(Some(42)), vec![0, 2, 1, 42]),
934            (TestEnum::Foo(None), vec![0, 1, 0]),
935            (
936                TestEnum::Bar {
937                    bazz: vec![1, 2, 3],
938                },
939                vec![1, 4, 3, 1, 2, 3],
940            ),
941        ];
942
943        for (reference, bytes) in test_cases {
944            test_roundtrip_expected(&reference, &bytes);
945        }
946    }
947
948    #[test_log::test]
949    fn test_systemtime() {
950        test_roundtrip(&fedimint_core::time::now());
951    }
952
953    #[test]
954    fn test_derive_empty_enum_decode() {
955        #[derive(Debug, Encodable, Decodable)]
956        enum NotConstructable {}
957
958        let vec = vec![42u8];
959        let mut cursor = Cursor::new(vec);
960
961        assert!(
962            NotConstructable::consensus_decode_partial(
963                &mut cursor,
964                &ModuleDecoderRegistry::default()
965            )
966            .is_err()
967        );
968    }
969
970    #[test]
971    fn test_custom_index_enum() {
972        #[derive(Debug, PartialEq, Eq, Encodable, Decodable)]
973        enum Old {
974            Foo,
975            Bar,
976            Baz,
977        }
978
979        #[derive(Debug, PartialEq, Eq, Encodable, Decodable)]
980        enum New {
981            #[encodable(index = 0)]
982            Foo,
983            #[encodable(index = 2)]
984            Baz,
985            #[encodable_default]
986            Default { variant: u64, bytes: Vec<u8> },
987        }
988
989        let test_vector = vec![
990            (Old::Foo, New::Foo),
991            (
992                Old::Bar,
993                New::Default {
994                    variant: 1,
995                    bytes: vec![],
996                },
997            ),
998            (Old::Baz, New::Baz),
999        ];
1000
1001        for (old, new) in test_vector {
1002            let old_bytes = old.consensus_encode_to_vec();
1003            let decoded_new = New::consensus_decode_whole(&old_bytes, &ModuleRegistry::default())
1004                .expect("Decoding failed");
1005            assert_eq!(decoded_new, new);
1006        }
1007    }
1008
1009    fn encode_value<T: Encodable>(value: &T) -> Vec<u8> {
1010        let mut writer = Vec::new();
1011        value.consensus_encode(&mut writer).unwrap();
1012        writer
1013    }
1014
1015    fn decode_value<T: Decodable>(bytes: &[u8]) -> T {
1016        T::consensus_decode_whole(bytes, &ModuleDecoderRegistry::default()).unwrap()
1017    }
1018
1019    fn keeps_ordering_after_serialization<T: Ord + Encodable + Decodable + Debug>(mut vec: Vec<T>) {
1020        vec.sort();
1021        let mut encoded = vec.iter().map(encode_value).collect::<Vec<_>>();
1022        encoded.sort();
1023        let decoded = encoded.iter().map(|v| decode_value(v)).collect::<Vec<_>>();
1024        for (i, (a, b)) in vec.iter().zip(decoded.iter()).enumerate() {
1025            assert_eq!(a, b, "difference at index {i}");
1026        }
1027    }
1028
1029    #[test]
1030    fn test_lexicographical_sorting() {
1031        #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)]
1032        struct TestAmount(u64);
1033
1034        #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)]
1035        struct TestComplexAmount(u16, u32, u64);
1036
1037        #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Encodable, Decodable)]
1038        struct Text(String);
1039
1040        let amounts = (0..20000).map(TestAmount).collect::<Vec<_>>();
1041        keeps_ordering_after_serialization(amounts);
1042
1043        let complex_amounts = (10..20000)
1044            .flat_map(|i| {
1045                (i - 1..=i + 1).flat_map(move |j| {
1046                    (i - 1..=i + 1).map(move |k| TestComplexAmount(i as u16, j as u32, k as u64))
1047                })
1048            })
1049            .collect::<Vec<_>>();
1050        keeps_ordering_after_serialization(complex_amounts);
1051
1052        let texts = (' '..'~')
1053            .flat_map(|i| {
1054                (' '..'~')
1055                    .map(|j| Text(format!("{i}{j}")))
1056                    .collect::<Vec<_>>()
1057            })
1058            .collect::<Vec<_>>();
1059        keeps_ordering_after_serialization(texts);
1060
1061        // bitcoin structures are not lexicographically sortable so we cannot
1062        // test them here. in future we may crate a wrapper type that is
1063        // lexicographically sortable to use when needed
1064    }
1065}