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