iota_types/
iota_serde.rs

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