sui_types/object/
rpc_visitor.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use move_core_types::account_address::AccountAddress;
5use move_core_types::annotated_visitor as AV;
6use move_core_types::language_storage::TypeTag;
7use move_core_types::u256::U256;
8
9use crate::balance::Balance;
10use crate::base_types::RESOLVED_STD_OPTION;
11use crate::base_types::move_ascii_str_layout;
12use crate::base_types::move_utf8_str_layout;
13use crate::base_types::url_layout;
14use crate::id::ID;
15use crate::id::UID;
16use crate::object::option_visitor as OV;
17
18/// A trait for serializing Move values into some nested structured representation that supports
19/// `null`, `bool`, numbers, strings, vectors, and maps (e.g. JSON or Protobuf).
20///
21/// Writers are allowed to fail, e.g. to limit resource usage.
22pub trait Writer {
23    type Value;
24    type Error: std::error::Error
25        + From<Error>
26        + From<OV::Error>
27        + From<AV::Error>
28        + Send
29        + Sync
30        + 'static;
31
32    type Vec: Default;
33    type Map: Default;
34
35    type Nested<'a>: Writer<Value = Self::Value, Error = Self::Error, Vec = Self::Vec, Map = Self::Map>
36    where
37        Self: 'a;
38
39    /// Produce a new writer for writing into nested contexts (e.g. fields of structs or enum
40    /// variants, or elements of vectors).
41    fn nest(&mut self) -> Result<Self::Nested<'_>, Self::Error>;
42
43    /// Write a `null` value.
44    fn write_null(&mut self) -> Result<Self::Value, Self::Error>;
45
46    /// Write a `true` or `false` value.
47    fn write_bool(&mut self, value: bool) -> Result<Self::Value, Self::Error>;
48
49    /// Write a numeric value that fits in a `u32`.
50    fn write_number(&mut self, value: u32) -> Result<Self::Value, Self::Error>;
51
52    /// Write a string value.
53    fn write_str(&mut self, value: String) -> Result<Self::Value, Self::Error>;
54
55    /// Write a completed vector.
56    fn write_vec(&mut self, value: Self::Vec) -> Result<Self::Value, Self::Error>;
57
58    /// Write a completed key-value map.
59    fn write_map(&mut self, value: Self::Map) -> Result<Self::Value, Self::Error>;
60
61    /// Add an element to a vector.
62    fn vec_push_element(
63        &mut self,
64        vec: &mut Self::Vec,
65        val: Self::Value,
66    ) -> Result<(), Self::Error>;
67
68    /// Add a key-value pair to a map.
69    fn map_push_field(
70        &mut self,
71        map: &mut Self::Map,
72        key: String,
73        val: Self::Value,
74    ) -> Result<(), Self::Error>;
75}
76
77/// A visitor that serializes Move values into some representation appropriate for RPC outputs.
78///
79/// The `W: Writer` type parameter determines the output format and how resource limits are
80/// enforced.
81pub struct RpcVisitor<W: Writer> {
82    writer: W,
83}
84
85#[derive(thiserror::Error, Debug)]
86#[error("Unexpected type")]
87pub struct Error;
88
89impl<W: Writer> RpcVisitor<W> {
90    /// Create a new RPC visitor that writes into the given writer.
91    pub fn new(writer: W) -> Self {
92        Self { writer }
93    }
94}
95
96impl<'b, 'l, W: Writer> AV::Visitor<'b, 'l> for RpcVisitor<W> {
97    type Value = <W as Writer>::Value;
98    type Error = <W as Writer>::Error;
99
100    fn visit_u8(
101        &mut self,
102        _: &AV::ValueDriver<'_, 'b, 'l>,
103        value: u8,
104    ) -> Result<Self::Value, Self::Error> {
105        self.writer.write_number(value as u32)
106    }
107
108    fn visit_u16(
109        &mut self,
110        _: &AV::ValueDriver<'_, 'b, 'l>,
111        value: u16,
112    ) -> Result<Self::Value, Self::Error> {
113        self.writer.write_number(value as u32)
114    }
115
116    fn visit_u32(
117        &mut self,
118        _: &AV::ValueDriver<'_, 'b, 'l>,
119        value: u32,
120    ) -> Result<Self::Value, Self::Error> {
121        self.writer.write_number(value)
122    }
123
124    fn visit_u64(
125        &mut self,
126        _: &AV::ValueDriver<'_, 'b, 'l>,
127        value: u64,
128    ) -> Result<Self::Value, Self::Error> {
129        self.writer.write_str(value.to_string())
130    }
131
132    fn visit_u128(
133        &mut self,
134        _: &AV::ValueDriver<'_, 'b, 'l>,
135        value: u128,
136    ) -> Result<Self::Value, Self::Error> {
137        self.writer.write_str(value.to_string())
138    }
139
140    fn visit_u256(
141        &mut self,
142        _: &AV::ValueDriver<'_, 'b, 'l>,
143        value: U256,
144    ) -> Result<Self::Value, Self::Error> {
145        self.writer.write_str(value.to_string())
146    }
147
148    fn visit_bool(
149        &mut self,
150        _: &AV::ValueDriver<'_, 'b, 'l>,
151        value: bool,
152    ) -> Result<Self::Value, Self::Error> {
153        self.writer.write_bool(value)
154    }
155
156    fn visit_address(
157        &mut self,
158        _: &AV::ValueDriver<'_, 'b, 'l>,
159        value: AccountAddress,
160    ) -> Result<Self::Value, Self::Error> {
161        self.writer.write_str(value.to_canonical_string(true))
162    }
163
164    fn visit_signer(
165        &mut self,
166        _: &AV::ValueDriver<'_, 'b, 'l>,
167        value: AccountAddress,
168    ) -> Result<Self::Value, Self::Error> {
169        self.writer.write_str(value.to_canonical_string(true))
170    }
171
172    fn visit_vector(
173        &mut self,
174        driver: &mut AV::VecDriver<'_, 'b, 'l>,
175    ) -> Result<Self::Value, Self::Error> {
176        if driver.element_layout().is_type(&TypeTag::U8) {
177            // Base64 encode arbitrary bytes
178            use base64::{Engine, engine::general_purpose::STANDARD};
179
180            if let Some(bytes) = driver
181                .bytes()
182                .get(driver.position()..(driver.position() + driver.len() as usize))
183            {
184                let b64 = STANDARD.encode(bytes);
185                self.writer.write_str(b64)
186            } else {
187                Err(AV::Error::UnexpectedEof.into())
188            }
189        } else {
190            let mut elems = W::Vec::default();
191            {
192                let nested = self.writer.nest()?;
193                let mut visitor = RpcVisitor { writer: nested };
194
195                while let Some(elem) = driver.next_element(&mut visitor)? {
196                    visitor.writer.vec_push_element(&mut elems, elem)?;
197                }
198            }
199
200            self.writer.write_vec(elems)
201        }
202    }
203
204    fn visit_struct(
205        &mut self,
206        driver: &mut AV::StructDriver<'_, 'b, 'l>,
207    ) -> Result<Self::Value, Self::Error> {
208        let ty = &driver.struct_layout().type_;
209        let layout = driver.struct_layout();
210
211        if layout == &move_ascii_str_layout()
212            || layout == &move_utf8_str_layout()
213            || layout == &url_layout()
214        {
215            // 0x1::ascii::String or 0x1::string::String or 0x2::url::Url
216
217            let lo = driver.position();
218            driver.skip_field()?;
219            let hi = driver.position();
220
221            // HACK: Bypassing the layout to deserialize its bytes as a Rust type.
222            let bytes = &driver.bytes()[lo..hi];
223            let s: String = bcs::from_bytes(bytes).map_err(|_| Error)?;
224            self.writer.write_str(s)
225        } else if layout == &UID::layout() || layout == &ID::layout() {
226            // 0x2::object::UID or 0x2::object::ID
227
228            let lo = driver.position();
229            driver.skip_field()?;
230            let hi = driver.position();
231
232            // HACK: Bypassing the layout to deserialize its bytes as a Rust type.
233            let bytes = &driver.bytes()[lo..hi];
234            let id = AccountAddress::from_bytes(bytes)
235                .map_err(|_| Error)?
236                .to_canonical_string(true);
237
238            self.writer.write_str(id)
239        } else if (&ty.address, ty.module.as_ref(), ty.name.as_ref()) == RESOLVED_STD_OPTION {
240            // 0x1::option::Option
241
242            match OV::OptionVisitor(self).visit_struct(driver)? {
243                Some(value) => Ok(value),
244                None => self.writer.write_null(),
245            }
246        } else if Balance::is_balance_layout(layout) {
247            // 0x2::balance::Balance
248
249            let lo = driver.position();
250            driver.skip_field()?;
251            let hi = driver.position();
252
253            // HACK: Bypassing the layout to deserialize its bytes as a Rust type.
254            let bytes = &driver.bytes()[lo..hi];
255            let balance = bcs::from_bytes::<u64>(bytes)
256                .map_err(|_| Error)?
257                .to_string();
258
259            self.writer.write_str(balance)
260        } else {
261            // Arbitrary structs
262
263            let mut map = W::Map::default();
264            {
265                let nested = self.writer.nest()?;
266                let mut visitor = RpcVisitor { writer: nested };
267
268                while let Some((field, elem)) = driver.next_field(&mut visitor)? {
269                    let name = field.name.to_string();
270                    visitor.writer.map_push_field(&mut map, name, elem)?;
271                }
272            }
273
274            self.writer.write_map(map)
275        }
276    }
277
278    fn visit_variant(
279        &mut self,
280        driver: &mut AV::VariantDriver<'_, 'b, 'l>,
281    ) -> Result<Self::Value, Self::Error> {
282        let mut map = W::Map::default();
283        {
284            let mut nested = self.writer.nest()?;
285
286            let variant = nested.write_str(driver.variant_name().to_string())?;
287            nested.map_push_field(&mut map, "@variant".to_owned(), variant)?;
288
289            let mut visitor = RpcVisitor { writer: nested };
290            while let Some((field, elem)) = driver.next_field(&mut visitor)? {
291                let name = field.name.to_string();
292                visitor.writer.map_push_field(&mut map, name, elem)?;
293            }
294        }
295
296        self.writer.write_map(map)
297    }
298}
299
300#[cfg(test)]
301mod tests {
302    use std::str::FromStr as _;
303
304    use move_core_types::annotated_value as A;
305    use move_core_types::ident_str;
306    use move_core_types::language_storage::StructTag;
307    use serde::Serialize;
308    use serde_json::Value;
309    use serde_json::json;
310
311    use super::*;
312
313    use A::MoveTypeLayout as L;
314
315    macro_rules! struct_ {
316        ($type:literal { $($name:literal : $layout:expr),* $(,)?}) => {
317            A::MoveTypeLayout::Struct(Box::new(A::MoveStructLayout {
318                type_: StructTag::from_str($type).expect("Failed to parse struct"),
319                fields: vec![$(A::MoveFieldLayout {
320                    name: ident_str!($name).to_owned(),
321                    layout: $layout,
322                }),*]
323            }))
324        }
325    }
326
327    macro_rules! vector_ {
328        ($inner:expr) => {
329            A::MoveTypeLayout::Vector(Box::new($inner))
330        };
331    }
332
333    struct JsonWriter;
334
335    #[derive(thiserror::Error, Debug)]
336    enum Error {
337        #[error(transparent)]
338        Visitor(#[from] AV::Error),
339
340        #[error("Unexpected type")]
341        UnexpectedType,
342    }
343
344    impl Writer for JsonWriter {
345        type Value = Value;
346        type Error = Error;
347
348        type Vec = Vec<Value>;
349        type Map = serde_json::Map<String, Value>;
350
351        type Nested<'a> = Self;
352
353        fn nest(&mut self) -> Result<Self::Nested<'_>, Self::Error> {
354            Ok(JsonWriter)
355        }
356
357        fn write_null(&mut self) -> Result<Self::Value, Self::Error> {
358            Ok(Value::Null)
359        }
360
361        fn write_bool(&mut self, value: bool) -> Result<Self::Value, Self::Error> {
362            Ok(Value::Bool(value))
363        }
364
365        fn write_number(&mut self, value: u32) -> Result<Self::Value, Self::Error> {
366            Ok(Value::Number(value.into()))
367        }
368
369        fn write_str(&mut self, value: String) -> Result<Self::Value, Self::Error> {
370            Ok(Value::String(value))
371        }
372
373        fn write_vec(&mut self, value: Self::Vec) -> Result<Self::Value, Self::Error> {
374            Ok(Value::Array(value))
375        }
376
377        fn write_map(&mut self, value: Self::Map) -> Result<Self::Value, Self::Error> {
378            Ok(Value::Object(value))
379        }
380
381        fn vec_push_element(
382            &mut self,
383            vec: &mut Self::Vec,
384            value: Self::Value,
385        ) -> Result<(), Self::Error> {
386            vec.push(value);
387            Ok(())
388        }
389
390        fn map_push_field(
391            &mut self,
392            map: &mut Self::Map,
393            key: String,
394            val: Self::Value,
395        ) -> Result<(), Self::Error> {
396            map.insert(key, val);
397            Ok(())
398        }
399    }
400
401    impl From<OV::Error> for Error {
402        fn from(OV::Error: OV::Error) -> Self {
403            Error::UnexpectedType
404        }
405    }
406
407    impl From<super::Error> for Error {
408        fn from(super::Error: super::Error) -> Self {
409            Error::UnexpectedType
410        }
411    }
412
413    fn json<T: Serialize>(layout: A::MoveTypeLayout, data: T) -> Value {
414        let bcs = bcs::to_bytes(&data).unwrap();
415        let mut visitor = RpcVisitor::new(JsonWriter);
416        A::MoveValue::visit_deserialize(&bcs, &layout, &mut visitor).unwrap()
417    }
418
419    fn address(a: &str) -> sui_sdk_types::Address {
420        sui_sdk_types::Address::from_str(a).unwrap()
421    }
422
423    #[test]
424    fn json_bool() {
425        let actual = json(L::Bool, true);
426        let expect = json!(true);
427        assert_eq!(actual, expect);
428
429        let actual = json(L::Bool, false);
430        let expect = json!(false);
431        assert_eq!(actual, expect);
432    }
433
434    #[test]
435    fn json_u8() {
436        let actual = json(L::U8, 42u8);
437        let expect = json!(42u8);
438        assert_eq!(expect, actual);
439    }
440
441    #[test]
442    fn json_u16() {
443        let actual = json(L::U16, 424u16);
444        let expect = json!(424u16);
445        assert_eq!(expect, actual);
446    }
447
448    #[test]
449    fn json_u32() {
450        let actual = json(L::U32, 432_432u32);
451        let expect = json!(432_432u32);
452        assert_eq!(expect, actual);
453    }
454
455    #[test]
456    fn json_u64() {
457        let actual = json(L::U64, 432_432_432_432u64);
458        let expect = json!(432_432_432_432u64.to_string());
459        assert_eq!(expect, actual);
460    }
461
462    #[test]
463    fn json_u128() {
464        let actual = json(L::U128, 424_242_424_242_424_242_424u128);
465        let expect = json!(424_242_424_242_424_242_424u128.to_string());
466        assert_eq!(expect, actual);
467    }
468
469    #[test]
470    fn json_u256() {
471        let actual = json(
472            L::U256,
473            U256::from_str("42424242424242424242424242424242424242424").unwrap(),
474        );
475        let expect = json!("42424242424242424242424242424242424242424");
476        assert_eq!(expect, actual);
477    }
478
479    #[test]
480    fn json_ascii_string() {
481        let l = struct_!("0x1::ascii::String" {
482            "bytes": vector_!(L::U8)
483        });
484        let actual = json(l, "The quick brown fox");
485        let expect = json!("The quick brown fox");
486        assert_eq!(expect, actual);
487    }
488
489    #[test]
490    fn json_utf8_string() {
491        let l = struct_!("0x1::string::String" {
492            "bytes": vector_!(L::U8)
493        });
494        let actual = json(l, "The quick brown fox");
495        let expect = json!("The quick brown fox");
496        assert_eq!(expect, actual);
497    }
498
499    #[test]
500    fn json_url() {
501        let l = struct_!("0x2::url::Url" {
502            "url": struct_!("0x1::ascii::String" {
503                "bytes": vector_!(L::U8)
504            })
505        });
506        let actual = json(l, "https://example.com");
507        let expect = json!("https://example.com");
508        assert_eq!(expect, actual);
509    }
510
511    #[test]
512    fn json_address() {
513        let actual = json(L::Address, address("0x42"));
514        let expect = json!(address("0x42").to_string());
515        assert_eq!(expect, actual);
516    }
517
518    #[test]
519    fn json_signer() {
520        let actual = json(L::Signer, address("0x42"));
521        let expect = json!(address("0x42").to_string());
522        assert_eq!(expect, actual);
523    }
524
525    #[test]
526    fn json_id() {
527        let l = struct_!("0x2::object::ID" {
528            "bytes": L::Address,
529        });
530        let actual = json(l, address("0x42"));
531        let expect = json!(address("0x42").to_string());
532        assert_eq!(expect, actual);
533    }
534
535    #[test]
536    fn json_uid() {
537        let l = struct_!("0x2::object::UID" {
538            "id": struct_!("0x2::object::ID" {
539                "bytes": L::Address,
540            })
541        });
542        let actual = json(l, address("0x42"));
543        let expect = json!(address("0x42").to_string());
544        assert_eq!(expect, actual);
545    }
546
547    #[test]
548    fn json_option() {
549        let l = struct_!("0x42::foo::Bar" {
550            "baz": struct_!("0x1::option::Option<u8>" { "vec": vector_!(L::U8) }),
551        });
552
553        let actual = json(l, Option::<Vec<u8>>::None);
554        let expect = json!({
555            "baz": null,
556        });
557        assert_eq!(expect, actual);
558    }
559
560    #[test]
561    fn json_balance() {
562        let l = struct_!("0x2::balance::Balance<0x2::sui::SUI>" {
563            "value": L::U64,
564        });
565
566        let actual = json(l, 100u64);
567        let expect = json!(100u64.to_string());
568        assert_eq!(expect, actual);
569    }
570
571    #[test]
572    fn json_compound() {
573        let l = struct_!("0x42::foo::Bar" {
574            "baz": struct_!("0x1::option::Option<u8>" { "vec": vector_!(L::U8) }),
575            "qux": vector_!(struct_!("0x43::xy::Zzy" {
576                "quy": L::U16,
577                "quz": struct_!("0x1::option::Option<0x1::ascii::String>" {
578                    "vec": vector_!(struct_!("0x1::ascii::String" {
579                        "bytes": vector_!(L::U8),
580                    }))
581                }),
582                "frob": L::Address,
583            })),
584        });
585
586        let actual = json(
587            l,
588            (
589                Option::<Vec<u8>>::None,
590                vec![
591                    (44u16, Some("Hello, world!"), address("0x45")),
592                    (46u16, None, address("0x47")),
593                ],
594            ),
595        );
596        let expect = json!({
597            "baz": null,
598            "qux": [{
599                "quy": 44,
600                "quz": "Hello, world!",
601                "frob": address("0x45").to_string(),
602            },
603            {
604                "quy": 46,
605                "quz": null,
606                "frob": address("0x47").to_string(),
607            }
608            ],
609        });
610        assert_eq!(expect, actual);
611    }
612}