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}