sov_state/codec/
mod.rs

1//! Serialization and deserialization -related logic.
2
3mod bcs_codec;
4mod borsh_codec;
5mod json_codec;
6mod split_codec;
7
8pub use bcs_codec::BcsCodec;
9use borsh::BorshSerialize;
10pub use borsh_codec::BorshCodec;
11pub use json_codec::JsonCodec;
12
13/// A trait for types that can serialize and deserialize values for storage
14/// access.
15pub trait StateValueCodec<V> {
16    /// Error type that can arise during deserialization.
17    type Error: std::fmt::Debug;
18
19    /// Serializes a value into a bytes vector.
20    ///
21    /// This method **must** not panic as all instances of the value type are
22    /// supposed to be serializable.
23    fn encode_value(&self, value: &V) -> Vec<u8>;
24
25    /// Tries to deserialize a value from a bytes slice, and returns a
26    /// [`Result`] with either the deserialized value or an error.
27    fn try_decode_value(&self, bytes: &[u8]) -> Result<V, Self::Error>;
28
29    /// Deserializes a value from a bytes slice.
30    ///
31    /// # Panics
32    /// Panics if the call to [`StateValueCodec::try_decode_value`] fails. Use
33    /// [`StateValueCodec::try_decode_value`] if you need to gracefully handle
34    /// errors.
35    fn decode_value_unwrap(&self, bytes: &[u8]) -> V {
36        self.try_decode_value(bytes)
37            .map_err(|err| {
38                format!(
39                    "Failed to decode value 0x{}, error: {:?}",
40                    hex::encode(bytes),
41                    err
42                )
43            })
44            .unwrap()
45    }
46}
47
48/// A trait for types that can serialize keys for storage
49/// access.
50///
51/// Note that, unlike [`StateValueCodec`], this trait does not provide
52/// deserialization logic as it's not needed nor supported.
53pub trait StateKeyCodec<K> {
54    /// Serializes a key into a bytes vector.
55    ///
56    /// # Determinism
57    ///
58    /// All implementations of this trait method **MUST** provide deterministic
59    /// serialization behavior:
60    ///
61    /// 1. Equal (as defined by [`Eq`]) values **MUST** be serialized to the same
62    ///    byte sequence.
63    /// 2. The serialization result **MUST NOT** depend on the compilation target
64    ///    and other runtime environment parameters. If that were the case, zkVM
65    ///    code and native code wouldn't produce the same keys.
66    fn encode_key(&self, key: &K) -> Vec<u8>;
67}
68
69/// A trait for types that can serialize keys and values, as well
70/// as deserializing values for storage access.
71///
72/// # Type bounds
73/// There are no type bounds on [`StateCodec::KeyCodec`] and
74/// [`StateCodec::ValueCodec`], so they can be any type at well. That said,
75/// you'll find many APIs require these two to implement [`StateKeyCodec`] and
76/// [`StateValueCodec`] respectively.
77pub trait StateCodec {
78    /// The codec used to serialize keys. See [`StateKeyCodec`].
79    type KeyCodec;
80    /// The codec used to serialize and deserialize values. See
81    /// [`StateValueCodec`].
82    type ValueCodec;
83
84    /// Returns a reference to the type's key codec.
85    fn key_codec(&self) -> &Self::KeyCodec;
86    /// Returns a reference to the type's value codec.
87    fn value_codec(&self) -> &Self::ValueCodec;
88}
89
90/// A trait for codecs which know how to serialize a type `Ref` as if it were
91/// some other type `Target`.
92///
93/// A good example of this is [`BorshCodec`], which knows how to serialize a
94/// `[T;N]` as if it were a `Vec<T>` even though the two types have different
95/// encodings by default.
96pub trait EncodeKeyLike<Ref: ?Sized, Target> {
97    /// Encodes a reference to `Ref` as if it were a reference to `Target`.
98    fn encode_key_like(&self, borrowed: &Ref) -> Vec<u8>;
99}
100
101// All items can be encoded like themselves by all codecs
102impl<C, T> EncodeKeyLike<T, T> for C
103where
104    C: StateKeyCodec<T>,
105{
106    fn encode_key_like(&self, borrowed: &T) -> Vec<u8> {
107        self.encode_key(borrowed)
108    }
109}
110
111// In borsh, a slice is encoded the same way as a vector except in edge case where
112// T is zero-sized, in which case Vec<T> is not borsh encodable.
113impl<T> EncodeKeyLike<[T], Vec<T>> for BorshCodec
114where
115    T: BorshSerialize,
116{
117    fn encode_key_like(&self, borrowed: &[T]) -> Vec<u8> {
118        borrowed.try_to_vec().unwrap()
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use proptest::collection::vec;
125    use proptest::prelude::any;
126    use proptest::strategy::Strategy;
127
128    use super::*;
129
130    fn arb_vec_i32() -> impl Strategy<Value = Vec<i32>> {
131        vec(any::<i32>(), 0..2048)
132    }
133
134    proptest::proptest! {
135        #[test]
136        fn test_borsh_slice_encode_alike(vec in arb_vec_i32()) {
137            let codec = BorshCodec;
138            assert_eq!(
139                <BorshCodec as EncodeKeyLike<[i32], Vec<i32>>>::encode_key_like(&codec, &vec[..]),
140                codec.encode_value(&vec)
141            );
142        }
143    }
144}