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