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