1use crate::{
5 balance::Balance,
6 base_types::{RESOLVED_STD_OPTION, move_ascii_str_layout, move_utf8_str_layout, url_layout},
7 id::{ID, UID},
8 object::option_visitor as OV,
9};
10use move_core_types::{
11 account_address::AccountAddress, annotated_value as A, annotated_visitor as AV,
12 language_storage::TypeTag, u256::U256,
13};
14use prost_types::Struct;
15use prost_types::Value;
16use prost_types::value::Kind;
17
18const MAX_DEPTH: usize = 80;
22
23pub struct ProtoVisitorBuilder {
24 bound: usize,
26
27 depth: usize,
29}
30
31struct ProtoVisitor<'a> {
32 bound: &'a mut usize,
34
35 depth: &'a mut usize,
37}
38
39#[derive(thiserror::Error, Debug)]
40pub enum Error {
41 #[error(transparent)]
42 Visitor(#[from] AV::Error),
43
44 #[error("Deserialized value too large")]
45 OutOfBudget,
46
47 #[error("Exceeded maximum depth")]
48 TooNested,
49
50 #[error("Unexpected type")]
51 UnexpectedType,
52}
53
54impl ProtoVisitorBuilder {
55 pub fn new(bound: usize) -> Self {
56 Self { bound, depth: 0 }
57 }
58
59 fn new_visitor(&mut self) -> Result<ProtoVisitor<'_>, Error> {
60 ProtoVisitor::new(&mut self.bound, &mut self.depth)
61 }
62
63 pub fn deserialize_value(
67 mut self,
68 bytes: &[u8],
69 layout: &A::MoveTypeLayout,
70 ) -> Result<Value, Error> {
71 let mut visitor = self.new_visitor()?;
72 A::MoveValue::visit_deserialize(bytes, layout, &mut visitor)
73 }
74}
75
76impl Drop for ProtoVisitor<'_> {
77 fn drop(&mut self) {
78 self.dec_depth();
79 }
80}
81
82impl<'a> ProtoVisitor<'a> {
83 fn new(bound: &'a mut usize, depth: &'a mut usize) -> Result<Self, Error> {
84 Self::inc_depth(depth)?;
86 Ok(Self { bound, depth })
87 }
88
89 fn inc_depth(depth: &mut usize) -> Result<(), Error> {
90 if *depth > MAX_DEPTH {
91 Err(Error::TooNested)
92 } else {
93 *depth += 1;
94 Ok(())
95 }
96 }
97
98 fn dec_depth(&mut self) {
99 if *self.depth == 0 {
100 panic!("BUG: logic bug in Visitor implementation");
101 } else {
102 *self.depth -= 1;
103 }
104 }
105
106 fn debit(&mut self, size: usize) -> Result<(), Error> {
108 if *self.bound < size {
109 Err(Error::OutOfBudget)
110 } else {
111 *self.bound -= size;
112 Ok(())
113 }
114 }
115
116 fn debit_value(&mut self) -> Result<(), Error> {
117 self.debit(size_of::<Value>())
118 }
119
120 fn debit_string_value(&mut self, s: &str) -> Result<(), Error> {
121 self.debit_str(s)?;
122 self.debit_value()
123 }
124
125 fn debit_str(&mut self, s: &str) -> Result<(), Error> {
126 self.debit(s.len())
127 }
128}
129
130impl<'b, 'l> AV::Visitor<'b, 'l> for ProtoVisitor<'_> {
131 type Value = Value;
132 type Error = Error;
133
134 fn visit_u8(&mut self, _: &AV::ValueDriver<'_, 'b, 'l>, value: u8) -> Result<Value, Error> {
135 self.debit_value()?;
136 Ok(Value::from(value))
137 }
138
139 fn visit_u16(&mut self, _: &AV::ValueDriver<'_, 'b, 'l>, value: u16) -> Result<Value, Error> {
140 self.debit_value()?;
141 Ok(Value::from(value))
142 }
143
144 fn visit_u32(&mut self, _: &AV::ValueDriver<'_, 'b, 'l>, value: u32) -> Result<Value, Error> {
145 self.debit_value()?;
146 Ok(Value::from(value))
147 }
148
149 fn visit_u64(&mut self, _: &AV::ValueDriver<'_, 'b, 'l>, value: u64) -> Result<Value, Error> {
150 let value = value.to_string();
151 self.debit_string_value(&value)?;
152 Ok(Value::from(value))
153 }
154
155 fn visit_u128(&mut self, _: &AV::ValueDriver<'_, 'b, 'l>, value: u128) -> Result<Value, Error> {
156 let value = value.to_string();
157 self.debit_string_value(&value)?;
158 Ok(Value::from(value))
159 }
160
161 fn visit_u256(&mut self, _: &AV::ValueDriver<'_, 'b, 'l>, value: U256) -> Result<Value, Error> {
162 let value = value.to_string();
163 self.debit_string_value(&value)?;
164 Ok(Value::from(value))
165 }
166
167 fn visit_bool(&mut self, _: &AV::ValueDriver<'_, 'b, 'l>, value: bool) -> Result<Value, Error> {
168 self.debit_value()?;
169 Ok(Value::from(value))
170 }
171
172 fn visit_address(
173 &mut self,
174 _: &AV::ValueDriver<'_, 'b, 'l>,
175 value: AccountAddress,
176 ) -> Result<Value, Error> {
177 let value = value.to_canonical_string(true);
178 self.debit_string_value(&value)?;
179 Ok(Value::from(value))
180 }
181
182 fn visit_signer(
183 &mut self,
184 _: &AV::ValueDriver<'_, 'b, 'l>,
185 value: AccountAddress,
186 ) -> Result<Value, Error> {
187 let value = value.to_canonical_string(true);
188 self.debit_string_value(&value)?;
189 Ok(Value::from(value))
190 }
191
192 fn visit_vector(&mut self, driver: &mut AV::VecDriver<'_, 'b, 'l>) -> Result<Value, Error> {
193 let value = if driver.element_layout().is_type(&TypeTag::U8) {
194 use base64::{Engine, engine::general_purpose::STANDARD};
196
197 if let Some(bytes) = driver
198 .bytes()
199 .get(driver.position()..(driver.position() + driver.len() as usize))
200 {
201 let b64 = STANDARD.encode(bytes);
202 self.debit_string_value(&b64)?;
203 Value::from(b64)
204 } else {
205 return Err(AV::Error::UnexpectedEof.into());
206 }
207 } else {
208 let mut elems = vec![];
209 self.debit_value()?;
210
211 while let Some(elem) =
212 driver.next_element(&mut ProtoVisitor::new(self.bound, self.depth)?)?
213 {
214 elems.push(elem);
215 }
216
217 Value::from(elems)
218 };
219
220 Ok(value)
221 }
222
223 fn visit_struct(&mut self, driver: &mut AV::StructDriver<'_, 'b, 'l>) -> Result<Value, Error> {
224 let ty = &driver.struct_layout().type_;
225 let layout = driver.struct_layout();
226
227 let value = if layout == &move_ascii_str_layout()
228 || layout == &move_utf8_str_layout()
229 || layout == &url_layout()
230 {
231 let lo = driver.position();
234 driver.skip_field()?;
235 let hi = driver.position();
236
237 let bytes = &driver.bytes()[lo..hi];
239 let s: &str = bcs::from_bytes(bytes).map_err(|_| Error::UnexpectedType)?;
240 self.debit_string_value(s)?;
241 Value::from(s)
242 } else if layout == &UID::layout() || layout == &ID::layout() {
243 let lo = driver.position();
246 driver.skip_field()?;
247 let hi = driver.position();
248
249 let bytes = &driver.bytes()[lo..hi];
251 let id = AccountAddress::from_bytes(bytes)
252 .map_err(|_| Error::UnexpectedType)?
253 .to_canonical_string(true);
254
255 self.debit_string_value(&id)?;
256 Value::from(id)
257 } else if (&ty.address, ty.module.as_ref(), ty.name.as_ref()) == RESOLVED_STD_OPTION {
258 self.debit_value()?;
260 match OV::OptionVisitor(self).visit_struct(driver)? {
261 Some(value) => value,
262 None => Kind::NullValue(0).into(),
263 }
264 } else if Balance::is_balance_layout(layout) {
265 let lo = driver.position();
268 driver.skip_field()?;
269 let hi = driver.position();
270
271 let bytes = &driver.bytes()[lo..hi];
273 let balance = bcs::from_bytes::<u64>(bytes)
274 .map_err(|_| Error::UnexpectedType)?
275 .to_string();
276 self.debit_string_value(&balance)?;
277 Value::from(balance)
278 } else {
279 let mut map = Struct::default();
281
282 self.debit_value()?;
283 for field in &driver.struct_layout().fields {
284 self.debit_str(field.name.as_str())?;
285 }
286
287 while let Some((field, elem)) =
288 driver.next_field(&mut ProtoVisitor::new(self.bound, self.depth)?)?
289 {
290 map.fields.insert(field.name.as_str().to_owned(), elem);
291 }
292 Value::from(Kind::StructValue(map))
293 };
294 Ok(value)
295 }
296
297 fn visit_variant(
298 &mut self,
299 driver: &mut AV::VariantDriver<'_, 'b, 'l>,
300 ) -> Result<Value, Error> {
301 let mut map = Struct::default();
302 self.debit_value()?;
303
304 self.debit_str("@variant")?;
305 self.debit_string_value(driver.variant_name().as_str())?;
306
307 map.fields
308 .insert("@variant".to_owned(), driver.variant_name().as_str().into());
309
310 for field in driver.variant_layout() {
311 self.debit_str(field.name.as_str())?;
312 }
313
314 while let Some((field, elem)) =
315 driver.next_field(&mut ProtoVisitor::new(self.bound, self.depth)?)?
316 {
317 map.fields.insert(field.name.as_str().to_owned(), elem);
318 }
319
320 Ok(Value::from(Kind::StructValue(map)))
321 }
322}
323
324impl From<OV::Error> for Error {
325 fn from(OV::Error: OV::Error) -> Self {
326 Error::UnexpectedType
327 }
328}
329
330#[cfg(test)]
331pub(crate) mod tests {
332 use std::str::FromStr;
333
334 use super::*;
335
336 use crate::object::bounded_visitor::tests::layout_;
337 use crate::object::bounded_visitor::tests::serialize;
338 use crate::object::bounded_visitor::tests::value_;
339 use expect_test::expect;
340 use move_core_types::annotated_value::MoveFieldLayout;
341 use move_core_types::annotated_value::MoveStructLayout;
342 use move_core_types::{ident_str, language_storage::StructTag};
343 use serde_json::json;
344
345 use A::MoveTypeLayout as L;
346 use A::MoveValue as V;
347
348 #[test]
349 fn test_simple() {
350 let type_layout = layout_(
351 "0x0::foo::Bar",
352 vec![
353 ("a", L::U64),
354 ("b", L::Vector(Box::new(L::U64))),
355 ("c", layout_("0x0::foo::Baz", vec![("d", L::U64)])),
356 ],
357 );
358
359 let value = value_(
360 "0x0::foo::Bar",
361 vec![
362 ("a", V::U64(42)),
363 ("b", V::Vector(vec![V::U64(43)])),
364 ("c", value_("0x0::foo::Baz", vec![("d", V::U64(44))])),
365 ],
366 );
367
368 let expected = json!({
369 "a": "42",
370 "b": ["43"],
371 "c": {
372 "d": "44"
373 }
374 });
375 let bound = required_budget(&expected);
376
377 let bytes = serialize(value.clone());
378
379 let deser = ProtoVisitorBuilder::new(bound)
380 .deserialize_value(&bytes, &type_layout)
381 .unwrap();
382
383 assert_eq!(expected, proto_value_to_json_value(deser));
384
385 ProtoVisitorBuilder::new(bound - 1)
386 .deserialize_value(&bytes, &type_layout)
387 .unwrap_err();
388 }
389
390 #[test]
391 fn test_too_deep() {
392 let mut layout = L::U64;
393 let mut value = V::U64(42);
394 let mut expected = serde_json::Value::from("42");
395
396 const DEPTH: usize = MAX_DEPTH;
397 for _ in 0..DEPTH {
398 layout = layout_("0x0::foo::Bar", vec![("f", layout)]);
399 value = value_("0x0::foo::Bar", vec![("f", value)]);
400 expected = json!({
401 "f": expected
402 });
403 }
404
405 let bound = required_budget(&expected);
406 let bytes = serialize(value.clone());
407
408 let deser = ProtoVisitorBuilder::new(bound)
409 .deserialize_value(&bytes, &layout)
410 .unwrap();
411
412 assert_eq!(expected, proto_value_to_json_value(deser));
413
414 layout = layout_("0x0::foo::Bar", vec![("f", layout)]);
416 value = value_("0x0::foo::Bar", vec![("f", value)]);
417
418 let bytes = serialize(value.clone());
419
420 let err = ProtoVisitorBuilder::new(bound)
421 .deserialize_value(&bytes, &layout)
422 .unwrap_err();
423
424 let expect = expect!["Exceeded maximum depth"];
425 expect.assert_eq(&err.to_string());
426 }
427
428 fn proto_value_to_json_value(proto: Value) -> serde_json::Value {
429 match proto.kind {
430 Some(Kind::NullValue(_)) | None => serde_json::Value::Null,
431 Some(Kind::NumberValue(n)) => serde_json::Value::from(n as u32),
433 Some(Kind::StringValue(s)) => serde_json::Value::from(s),
434 Some(Kind::BoolValue(b)) => serde_json::Value::from(b),
435 Some(Kind::StructValue(map)) => serde_json::Value::Object(
436 map.fields
437 .into_iter()
438 .map(|(k, v)| (k, proto_value_to_json_value(v)))
439 .collect(),
440 ),
441 Some(Kind::ListValue(list_value)) => serde_json::Value::Array(
442 list_value
443 .values
444 .into_iter()
445 .map(proto_value_to_json_value)
446 .collect(),
447 ),
448 }
449 }
450
451 fn required_budget(json: &serde_json::Value) -> usize {
452 size_of::<Value>()
453 + match json {
454 serde_json::Value::Null => 0,
455 serde_json::Value::Bool(_) => 0,
456 serde_json::Value::Number(_) => 0,
457 serde_json::Value::String(s) => s.len(),
458 serde_json::Value::Array(vec) => vec.iter().map(required_budget).sum(),
459 serde_json::Value::Object(map) => {
460 map.iter().map(|(k, v)| k.len() + required_budget(v)).sum()
461 }
462 }
463 }
464
465 fn json<T: serde::Serialize>(layout: A::MoveTypeLayout, data: T) -> serde_json::Value {
470 let bcs = bcs::to_bytes(&data).unwrap();
471 let proto_value = ProtoVisitorBuilder::new(1024 * 1024)
472 .deserialize_value(&bcs, &layout)
473 .unwrap();
474 proto_value_to_json_value(proto_value)
475 }
476
477 macro_rules! struct_layout {
478 ($type:literal { $($name:literal : $layout:expr),* $(,)?}) => {
479 A::MoveTypeLayout::Struct(Box::new(MoveStructLayout {
480 type_: StructTag::from_str($type).expect("Failed to parse struct"),
481 fields: vec![$(MoveFieldLayout {
482 name: ident_str!($name).to_owned(),
483 layout: $layout,
484 }),*]
485 }))
486 }
487 }
488
489 macro_rules! vector_layout {
490 ($inner:expr) => {
491 A::MoveTypeLayout::Vector(Box::new($inner))
492 };
493 }
494
495 fn address(a: &str) -> sui_sdk_types::Address {
496 sui_sdk_types::Address::from_str(a).unwrap()
497 }
498
499 #[test]
500 fn json_bool() {
501 let actual = json(L::Bool, true);
502 let expect = json!(true);
503 assert_eq!(expect, actual);
504
505 let actual = json(L::Bool, false);
506 let expect = json!(false);
507 assert_eq!(expect, actual);
508 }
509
510 #[test]
511 fn json_u8() {
512 let actual = json(L::U8, 42u8);
513 let expect = json!(42u8);
514 assert_eq!(expect, actual);
515 }
516
517 #[test]
518 fn json_u16() {
519 let actual = json(L::U16, 424u16);
520 let expect = json!(424u16);
521 assert_eq!(expect, actual);
522 }
523
524 #[test]
525 fn json_u32() {
526 let actual = json(L::U32, 432_432u32);
527 let expect = json!(432_432u32);
528 assert_eq!(expect, actual);
529 }
530
531 #[test]
532 fn json_u64() {
533 let actual = json(L::U64, 432_432_432_432u64);
534 let expect = json!(432_432_432_432u64.to_string());
535 assert_eq!(expect, actual);
536 }
537
538 #[test]
539 fn json_u128() {
540 let actual = json(L::U128, 424_242_424_242_424_242_424u128);
541 let expect = json!(424_242_424_242_424_242_424u128.to_string());
542 assert_eq!(expect, actual);
543 }
544
545 #[test]
546 fn json_u256() {
547 let actual = json(
548 L::U256,
549 U256::from_str("42424242424242424242424242424242424242424").unwrap(),
550 );
551 let expect = json!("42424242424242424242424242424242424242424");
552 assert_eq!(expect, actual);
553 }
554
555 #[test]
556 fn json_ascii_string() {
557 let l = struct_layout!("0x1::ascii::String" {
558 "bytes": vector_layout!(L::U8)
559 });
560 let actual = json(l, "The quick brown fox");
561 let expect = json!("The quick brown fox");
562 assert_eq!(expect, actual);
563 }
564
565 #[test]
566 fn json_utf8_string() {
567 let l = struct_layout!("0x1::string::String" {
568 "bytes": vector_layout!(L::U8)
569 });
570 let actual = json(l, "The quick brown fox");
571 let expect = json!("The quick brown fox");
572 assert_eq!(expect, actual);
573 }
574
575 #[test]
576 fn json_url() {
577 let l = struct_layout!("0x2::url::Url" {
578 "url": struct_layout!("0x1::ascii::String" {
579 "bytes": vector_layout!(L::U8)
580 })
581 });
582 let actual = json(l, "https://example.com");
583 let expect = json!("https://example.com");
584 assert_eq!(expect, actual);
585 }
586
587 #[test]
588 fn json_address() {
589 let actual = json(L::Address, address("0x42"));
590 let expect = json!(address("0x42").to_string());
591 assert_eq!(expect, actual);
592 }
593
594 #[test]
595 fn json_signer() {
596 let actual = json(L::Signer, address("0x42"));
597 let expect = json!(address("0x42").to_string());
598 assert_eq!(expect, actual);
599 }
600
601 #[test]
602 fn json_id() {
603 let l = struct_layout!("0x2::object::ID" {
604 "bytes": L::Address,
605 });
606 let actual = json(l, address("0x42"));
607 let expect = json!(address("0x42").to_string());
608 assert_eq!(expect, actual);
609 }
610
611 #[test]
612 fn json_uid() {
613 let l = struct_layout!("0x2::object::UID" {
614 "id": struct_layout!("0x2::object::ID" {
615 "bytes": L::Address,
616 })
617 });
618 let actual = json(l, address("0x42"));
619 let expect = json!(address("0x42").to_string());
620 assert_eq!(expect, actual);
621 }
622
623 #[test]
624 fn json_option() {
625 let l = struct_layout!("0x42::foo::Bar" {
626 "baz": struct_layout!("0x1::option::Option<u8>" { "vec": vector_layout!(L::U8) }),
627 });
628
629 let actual = json(l, Option::<Vec<u8>>::None);
630 let expect = json!({
631 "baz": null,
632 });
633 assert_eq!(expect, actual);
634 }
635
636 #[test]
637 fn json_balance() {
638 let l = struct_layout!("0x2::balance::Balance<0x2::sui::SUI>" {
639 "value": L::U64,
640 });
641
642 let actual = json(l, 100u64);
643 let expect = json!(100u64.to_string());
644 assert_eq!(expect, actual);
645 }
646
647 #[test]
648 fn json_compound() {
649 let l = struct_layout!("0x42::foo::Bar" {
650 "baz": struct_layout!("0x1::option::Option<u8>" { "vec": vector_layout!(L::U8) }),
651 "qux": vector_layout!(struct_layout!("0x43::xy::Zzy" {
652 "quy": L::U16,
653 "quz": struct_layout!("0x1::option::Option<0x1::ascii::String>" {
654 "vec": vector_layout!(struct_layout!("0x1::ascii::String" {
655 "bytes": vector_layout!(L::U8),
656 }))
657 }),
658 "frob": L::Address,
659 })),
660 });
661
662 let actual = json(
663 l,
664 (
665 Option::<Vec<u8>>::None,
666 vec![
667 (44u16, Some("Hello, world!"), address("0x45")),
668 (46u16, None, address("0x47")),
669 ],
670 ),
671 );
672 let expect = json!({
673 "baz": null,
674 "qux": [{
675 "quy": 44,
676 "quz": "Hello, world!",
677 "frob": address("0x45").to_string(),
678 },
679 {
680 "quy": 46,
681 "quz": null,
682 "frob": address("0x47").to_string(),
683 }
684 ],
685 });
686 assert_eq!(expect, actual);
687 }
688}