sui_types/
sui_serde.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::fmt;
5use std::fmt::Write;
6use std::fmt::{Debug, Display, Formatter};
7use std::marker::PhantomData;
8use std::ops::Deref;
9use std::str::FromStr;
10
11use move_core_types::account_address::AccountAddress;
12use move_core_types::language_storage::{StructTag, TypeTag};
13use schemars::JsonSchema;
14use serde;
15use serde::de::{Deserializer, Error};
16use serde::ser::{Error as SerError, Serializer};
17use serde::{Deserialize, Serialize};
18use serde_with::DisplayFromStr;
19use serde_with::serde_as;
20use serde_with::{Bytes, DeserializeAs, SerializeAs};
21
22use sui_protocol_config::ProtocolVersion;
23
24use crate::governance::MAX_VALIDATOR_COUNT;
25use crate::{
26    DEEPBOOK_ADDRESS, SUI_CLOCK_ADDRESS, SUI_FRAMEWORK_ADDRESS, SUI_SYSTEM_ADDRESS,
27    SUI_SYSTEM_STATE_ADDRESS, parse_sui_struct_tag, parse_sui_type_tag,
28};
29
30#[inline]
31pub(crate) fn to_custom_deser_error<'de, D, E>(e: E) -> D::Error
32where
33    E: Debug,
34    D: Deserializer<'de>,
35{
36    Error::custom(format!("byte deserialization failed, cause by: {:?}", e))
37}
38
39#[inline]
40pub(crate) fn to_custom_ser_error<S, E>(e: E) -> S::Error
41where
42    E: Debug,
43    S: Serializer,
44{
45    S::Error::custom(format!("byte serialization failed, cause by: {:?}", e))
46}
47
48/// Use with serde_as to control serde for human-readable serialization and deserialization
49/// `H` : serde_as SerializeAs/DeserializeAs delegation for human readable in/output
50/// `R` : serde_as SerializeAs/DeserializeAs delegation for non-human readable in/output
51///
52/// # Example:
53///
54/// ```text
55/// #[serde_as]
56/// #[derive(Deserialize, Serialize)]
57/// struct Example(#[serde_as(as = "Readable<DisplayFromStr, _>")] [u8; 20]);
58/// ```
59///
60/// The above example will delegate human-readable serde to `DisplayFromStr`
61/// and array tuple (default) for non-human-readable serializer.
62pub struct Readable<H, R> {
63    human_readable: PhantomData<H>,
64    non_human_readable: PhantomData<R>,
65}
66
67impl<T: ?Sized, H, R> SerializeAs<T> for Readable<H, R>
68where
69    H: SerializeAs<T>,
70    R: SerializeAs<T>,
71{
72    fn serialize_as<S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
73    where
74        S: Serializer,
75    {
76        if serializer.is_human_readable() {
77            H::serialize_as(value, serializer)
78        } else {
79            R::serialize_as(value, serializer)
80        }
81    }
82}
83
84impl<'de, R, H, T> DeserializeAs<'de, T> for Readable<H, R>
85where
86    H: DeserializeAs<'de, T>,
87    R: DeserializeAs<'de, T>,
88{
89    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
90    where
91        D: Deserializer<'de>,
92    {
93        if deserializer.is_human_readable() {
94            H::deserialize_as(deserializer)
95        } else {
96            R::deserialize_as(deserializer)
97        }
98    }
99}
100
101pub struct SuiStructTag;
102
103impl SerializeAs<StructTag> for SuiStructTag {
104    fn serialize_as<S>(value: &StructTag, serializer: S) -> Result<S::Ok, S::Error>
105    where
106        S: Serializer,
107    {
108        let f = to_sui_struct_tag_string(value).map_err(S::Error::custom)?;
109        f.serialize(serializer)
110    }
111}
112
113const SUI_ADDRESSES: [AccountAddress; 7] = [
114    AccountAddress::ZERO,
115    AccountAddress::ONE,
116    SUI_FRAMEWORK_ADDRESS,
117    SUI_SYSTEM_ADDRESS,
118    DEEPBOOK_ADDRESS,
119    SUI_SYSTEM_STATE_ADDRESS,
120    SUI_CLOCK_ADDRESS,
121];
122/// Serialize StructTag as a string, retaining the leading zeros in the address.
123pub fn to_sui_struct_tag_string(value: &StructTag) -> Result<String, fmt::Error> {
124    let mut f = String::new();
125    // trim leading zeros if address is in SUI_ADDRESSES
126    let address = if SUI_ADDRESSES.contains(&value.address) {
127        value.address.short_str_lossless()
128    } else {
129        value.address.to_canonical_string(/* with_prefix */ false)
130    };
131
132    write!(f, "0x{}::{}::{}", address, value.module, value.name)?;
133    if let Some(first_ty) = value.type_params.first() {
134        write!(f, "<")?;
135        write!(f, "{}", to_sui_type_tag_string(first_ty)?)?;
136        for ty in value.type_params.iter().skip(1) {
137            write!(f, ", {}", to_sui_type_tag_string(ty)?)?;
138        }
139        write!(f, ">")?;
140    }
141    Ok(f)
142}
143
144fn to_sui_type_tag_string(value: &TypeTag) -> Result<String, fmt::Error> {
145    match value {
146        TypeTag::Vector(t) => Ok(format!("vector<{}>", to_sui_type_tag_string(t)?)),
147        TypeTag::Struct(s) => to_sui_struct_tag_string(s),
148        _ => Ok(value.to_string()),
149    }
150}
151
152impl<'de> DeserializeAs<'de, StructTag> for SuiStructTag {
153    fn deserialize_as<D>(deserializer: D) -> Result<StructTag, D::Error>
154    where
155        D: Deserializer<'de>,
156    {
157        let s = String::deserialize(deserializer)?;
158        parse_sui_struct_tag(&s).map_err(D::Error::custom)
159    }
160}
161
162pub struct SuiTypeTag;
163
164impl SerializeAs<TypeTag> for SuiTypeTag {
165    fn serialize_as<S>(value: &TypeTag, serializer: S) -> Result<S::Ok, S::Error>
166    where
167        S: Serializer,
168    {
169        let s = to_sui_type_tag_string(value).map_err(S::Error::custom)?;
170        s.serialize(serializer)
171    }
172}
173
174impl<'de> DeserializeAs<'de, TypeTag> for SuiTypeTag {
175    fn deserialize_as<D>(deserializer: D) -> Result<TypeTag, D::Error>
176    where
177        D: Deserializer<'de>,
178    {
179        let s = String::deserialize(deserializer)?;
180        parse_sui_type_tag(&s).map_err(D::Error::custom)
181    }
182}
183
184#[serde_as]
185#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)]
186pub struct BigInt<T>(
187    #[schemars(with = "String")]
188    #[serde_as(as = "DisplayFromStr")]
189    T,
190)
191where
192    T: Display + FromStr,
193    <T as FromStr>::Err: Display;
194
195impl<T> BigInt<T>
196where
197    T: Display + FromStr,
198    <T as FromStr>::Err: Display,
199{
200    pub fn into_inner(self) -> T {
201        self.0
202    }
203}
204
205impl<T> SerializeAs<T> for BigInt<T>
206where
207    T: Display + FromStr + Copy,
208    <T as FromStr>::Err: Display,
209{
210    fn serialize_as<S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
211    where
212        S: Serializer,
213    {
214        BigInt(*value).serialize(serializer)
215    }
216}
217
218impl<'de, T> DeserializeAs<'de, T> for BigInt<T>
219where
220    T: Display + FromStr + Copy,
221    <T as FromStr>::Err: Display,
222{
223    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
224    where
225        D: Deserializer<'de>,
226    {
227        Ok(*BigInt::deserialize(deserializer)?)
228    }
229}
230
231impl<T> From<T> for BigInt<T>
232where
233    T: Display + FromStr,
234    <T as FromStr>::Err: Display,
235{
236    fn from(v: T) -> BigInt<T> {
237        BigInt(v)
238    }
239}
240
241impl<T> Deref for BigInt<T>
242where
243    T: Display + FromStr,
244    <T as FromStr>::Err: Display,
245{
246    type Target = T;
247
248    fn deref(&self) -> &Self::Target {
249        &self.0
250    }
251}
252
253impl<T> Display for BigInt<T>
254where
255    T: Display + FromStr,
256    <T as FromStr>::Err: Display,
257{
258    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
259        write!(f, "{}", self.0)
260    }
261}
262
263#[serde_as]
264#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)]
265pub struct SequenceNumber(#[schemars(with = "BigInt<u64>")] u64);
266
267impl SerializeAs<crate::base_types::SequenceNumber> for SequenceNumber {
268    fn serialize_as<S>(
269        value: &crate::base_types::SequenceNumber,
270        serializer: S,
271    ) -> Result<S::Ok, S::Error>
272    where
273        S: Serializer,
274    {
275        let s = value.value().to_string();
276        s.serialize(serializer)
277    }
278}
279
280impl<'de> DeserializeAs<'de, crate::base_types::SequenceNumber> for SequenceNumber {
281    fn deserialize_as<D>(deserializer: D) -> Result<crate::base_types::SequenceNumber, D::Error>
282    where
283        D: Deserializer<'de>,
284    {
285        let b = BigInt::deserialize(deserializer)?;
286        Ok(crate::base_types::SequenceNumber::from_u64(*b))
287    }
288}
289
290#[serde_as]
291#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy, JsonSchema)]
292#[serde(rename = "ProtocolVersion")]
293pub struct AsProtocolVersion(#[schemars(with = "BigInt<u64>")] u64);
294
295impl SerializeAs<ProtocolVersion> for AsProtocolVersion {
296    fn serialize_as<S>(value: &ProtocolVersion, serializer: S) -> Result<S::Ok, S::Error>
297    where
298        S: Serializer,
299    {
300        let s = value.as_u64().to_string();
301        s.serialize(serializer)
302    }
303}
304
305impl<'de> DeserializeAs<'de, ProtocolVersion> for AsProtocolVersion {
306    fn deserialize_as<D>(deserializer: D) -> Result<ProtocolVersion, D::Error>
307    where
308        D: Deserializer<'de>,
309    {
310        let b = BigInt::<u64>::deserialize(deserializer)?;
311        Ok(ProtocolVersion::from(*b))
312    }
313}
314
315/// Serializes and deserializes a RoaringBitmap with its own on-disk standard.
316/// <https://github.com/RoaringBitmap/RoaringFormatSpec>
317pub(crate) struct SuiBitmap;
318
319impl SerializeAs<roaring::RoaringBitmap> for SuiBitmap {
320    fn serialize_as<S>(source: &roaring::RoaringBitmap, serializer: S) -> Result<S::Ok, S::Error>
321    where
322        S: Serializer,
323    {
324        let mut bytes = vec![];
325
326        source
327            .serialize_into(&mut bytes)
328            .map_err(to_custom_ser_error::<S, _>)?;
329        Bytes::serialize_as(&bytes, serializer)
330    }
331}
332
333impl<'de> DeserializeAs<'de, roaring::RoaringBitmap> for SuiBitmap {
334    fn deserialize_as<D>(deserializer: D) -> Result<roaring::RoaringBitmap, D::Error>
335    where
336        D: Deserializer<'de>,
337    {
338        let bytes: Vec<u8> = Bytes::deserialize_as(deserializer)?;
339        deserialize_sui_bitmap(&bytes).map_err(to_custom_deser_error::<'de, D, _>)
340    }
341}
342
343// RoaringBitmap::deserialize_from() or iter() do not check for duplicates.
344// So this function is needed to sanitize the bitmap to ensure unique entries.
345pub(crate) fn deserialize_sui_bitmap(bytes: &[u8]) -> std::io::Result<roaring::RoaringBitmap> {
346    let orig_bitmap = roaring::RoaringBitmap::deserialize_from(bytes)?;
347
348    // Check cardinality before iteration.
349    if orig_bitmap.len() > MAX_VALIDATOR_COUNT {
350        return Err(std::io::Error::new(
351            std::io::ErrorKind::InvalidData,
352            format!(
353                "bitmap cardinality {} exceeds max {}",
354                orig_bitmap.len(),
355                MAX_VALIDATOR_COUNT
356            ),
357        ));
358    }
359
360    // Ensure there is no duplicated entries in the bitmap.
361    let mut seen = std::collections::BTreeSet::new();
362    let mut new_bitmap = roaring::RoaringBitmap::new();
363    for v in orig_bitmap.iter() {
364        if seen.insert(v) {
365            new_bitmap.insert(v);
366        }
367    }
368    Ok(new_bitmap)
369}
370
371#[cfg(test)]
372mod test {
373    use base64::Engine as _;
374
375    use super::*;
376
377    #[test]
378    fn test_sui_bitmap_unique_deserialize() {
379        let raw = "OjAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAAAFoAAABcAAAAXgAAAGAAAABiAAAAZAAAAGYAAABoAAAAagAAAAEAAQABAAEAAQABAAEAAQABAAEA";
380        let bytes = base64::engine::general_purpose::STANDARD
381            .decode(raw)
382            .unwrap();
383
384        let bitmap = roaring::RoaringBitmap::deserialize_from(&bytes[..]).unwrap();
385        assert_eq!(bitmap.len(), 10);
386        let bitmap_values: Vec<u32> = bitmap.iter().collect();
387        assert_eq!(bitmap_values, vec![1; 10]);
388
389        let sui_bitmap = deserialize_sui_bitmap(&bytes[..]).unwrap();
390        assert_eq!(sui_bitmap.len(), 1);
391        let bitmap_values: Vec<u32> = sui_bitmap.iter().collect();
392        assert_eq!(bitmap_values, vec![1]);
393    }
394}