Skip to main content

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::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
38/// A writer counting number of bytes written to it
39///
40/// Copy&pasted from <https://github.com/SOF3/count-write> which
41/// uses Apache license (and it's a trivial amount of code, repeating
42/// on stack overflow).
43pub struct CountWrite<W> {
44    inner: W,
45    count: u64,
46}
47
48impl<W> CountWrite<W> {
49    /// Returns the number of bytes successfully written so far
50    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
73/// Object-safe trait for things that can encode themselves
74///
75/// Like `rust-bitcoin`'s `consensus_encode`, but without generics,
76/// so can be used in `dyn` objects.
77pub 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
114/// Data which can be encoded in a consensus-consistent way
115pub trait Encodable {
116    /// Encode an object with a well-defined format.
117    /// Returns the number of bytes written on success.
118    ///
119    /// The only errors returned are errors propagated from the writer.
120    fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error>;
121
122    /// [`Self::consensus_encode`] to newly allocated `Vec<u8>`
123    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    /// Encode and convert to hex string representation
131    fn consensus_encode_to_hex(&self) -> String {
132        // TODO: This double allocation offends real Rustaceans. We should
133        // be able to go straight to String, but this use case seems under-served
134        // by hex encoding crates.
135        self.consensus_encode_to_vec().encode_hex()
136    }
137
138    /// Encode without storing the encoding, return the size
139    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    /// Generate a SHA256 hash of the consensus encoding using the default hash
148    /// engine for `H`.
149    ///
150    /// Can be used to validate all federation members agree on state without
151    /// revealing the object
152    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    /// [`Self::consensus_hash`] for [`bitcoin::hashes::sha256::Hash`]
164    fn consensus_hash_sha256(&self) -> sha256::Hash {
165        self.consensus_hash()
166    }
167}
168
169/// Maximum size, in bytes, of data we are allowed to ever decode
170/// for a single value.
171pub const MAX_DECODE_SIZE: usize = 16_000_000;
172
173/// Data which can be encoded in a consensus-consistent way
174pub trait Decodable: Sized {
175    /// Decode `Self` from a size-limited reader.
176    ///
177    /// Like `consensus_decode_partial` but relies on the reader being limited
178    /// in the amount of data it returns, e.g. by being wrapped in
179    /// [`std::io::Take`].
180    ///
181    /// Failing to abide to this requirement might lead to memory exhaustion
182    /// caused by malicious inputs.
183    ///
184    /// Users should default to `consensus_decode_partial`, but when data to be
185    /// decoded is already in a byte vector of a limited size, calling this
186    /// function directly might be marginally faster (due to avoiding extra
187    /// checks).
188    ///
189    /// ### Rules for trait implementations
190    ///
191    /// * Simple types that that have a fixed size (own and member fields),
192    ///   don't have to overwrite this method, or be concern with it, should
193    ///   only impl `consensus_decode_partial`.
194    /// * Types that deserialize based on decoded untrusted length should
195    ///   implement `consensus_decode_partial_from_finite_reader` only:
196    ///   * Default implementation of `consensus_decode_partial` will forward to
197    ///     `consensus_decode_partial_from_finite_reader` with the reader
198    ///     wrapped by `Take`, protecting from readers that keep returning data.
199    ///   * Implementation must make sure to put a cap on things like
200    ///     `Vec::with_capacity` and other allocations to avoid oversized
201    ///     allocations, and rely on the reader being finite and running out of
202    ///     data, and collections reallocating on a legitimately oversized input
203    ///     data, instead of trying to enforce arbitrary length limits.
204    /// * Types that contain other types that might be require limited reader
205    ///   (thus implementing `consensus_decode_partial_from_finite_reader`),
206    ///   should also implement it applying same rules, and in addition make
207    ///   sure to call `consensus_decode_partial_from_finite_reader` on all
208    ///   members, to avoid creating redundant `Take` wrappers
209    ///   (`Take<Take<...>>`). Failure to do so might result only in a tiny
210    ///   performance hit.
211    #[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        // This method is always strictly less general than, `consensus_decode_partial`,
217        // so it's safe and make sense to default to just calling it. This way
218        // most types, that don't care about protecting against resource
219        // exhaustion due to malicious input, can just ignore it.
220        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        // This method is always strictly less general than, `consensus_decode_partial`,
234        // so it's safe and make sense to default to just calling it. This way
235        // most types, that don't care about protecting against resource
236        // exhaustion due to malicious input, can just ignore it.
237        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    /// Decode an object with a well-defined format.
253    ///
254    /// This is the method that should be implemented for a typical, fixed sized
255    /// type implementing this trait. Default implementation is wrapping the
256    /// reader in [`std::io::Take`] to limit the input size to
257    /// [`MAX_DECODE_SIZE`], and forwards the call to
258    /// [`Self::consensus_decode_partial_from_finite_reader`], which is
259    /// convenient for types that override
260    /// [`Self::consensus_decode_partial_from_finite_reader`] instead.
261    #[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    /// Decode an object from hex
273    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
284/// Encodes a timestamp as the legacy `(seconds, nanoseconds)` `SystemTime`
285/// representation.
286///
287/// Existing encoded types use this only to preserve their stored
288/// representation. It panics when `time` precedes the Unix epoch.
289pub 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
299/// Decodes a timestamp from the legacy `(seconds, nanoseconds)` representation.
300///
301/// Existing encoded types use this only to preserve their stored
302/// representation.
303pub 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
311/// Encodes an optional timestamp in the legacy `SystemTime` representation.
312///
313/// Existing encoded types use this only to preserve their stored
314/// representation.
315pub 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
328/// Decodes an optional timestamp in the legacy `SystemTime` representation.
329///
330/// Existing encoded types use this only to preserve their stored
331/// representation.
332pub 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
347/// Decodes a field from a finite reader and annotates errors with its schema
348/// context.
349pub 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
360/// Adds schema context to an error returned while decoding a field.
361pub 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    // TODO: think about better name
664    #[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/// A type that decodes `module_instance_id`-prefixed `T`s even
707/// when corresponding `Decoder` is not available.
708///
709/// All dyn-module types are encoded as:
710///
711/// ```norust
712/// module_instance_id | len_u64 | data
713/// ```
714///
715/// So clients that don't have a corresponding module, can read
716/// the `len_u64` and skip the amount of data specified in it.
717///
718/// This type makes it more convenient. It's possible to attempt
719/// to retry decoding after more modules become available by using
720/// [`DynRawFallback::redecode_raw`].
721///
722/// Notably this struct does not ignore any errors. It only skips
723/// decoding when the module decoder is not available.
724#[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    /// Get the decoded `T` or `None` if not decoded yet
766    pub fn decoded(self) -> Option<T> {
767        match self {
768            Self::Raw { .. } => None,
769            Self::Decoded(v) => Some(v),
770        }
771    }
772
773    /// Convert into the decoded `T` and panic if not decoded yet
774    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    /// Get the decoded `T` and panic if not decoded yet
784    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    /// Attempt to re-decode raw values with new set of of `modules`
794    ///
795    /// In certain contexts it might be necessary to try again with
796    /// a new set of modules.
797    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                // since the decoder is not available, just read the raw data
853                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        // bitcoin structures are not lexicographically sortable so we cannot
1291        // test them here. in future we may crate a wrapper type that is
1292        // lexicographically sortable to use when needed
1293    }
1294}