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 {
428 match proto.kind {
429 Some(Kind::NullValue(_)) | None => serde_json::Value::Null,
430 Some(Kind::NumberValue(n)) => serde_json::Value::from(n as u32),
432 Some(Kind::StringValue(s)) => serde_json::Value::from(s),
433 Some(Kind::BoolValue(b)) => serde_json::Value::from(b),
434 Some(Kind::StructValue(map)) => serde_json::Value::Object(
435 map.fields
436 .into_iter()
437 .map(|(k, v)| (k, proto_value_to_json_value(v)))
438 .collect(),
439 ),
440 Some(Kind::ListValue(list_value)) => serde_json::Value::Array(
441 list_value
442 .values
443 .into_iter()
444 .map(proto_value_to_json_value)
445 .collect(),
446 ),
447 }
448 }
449
450 fn required_budget(json: &serde_json::Value) -> usize {
451 size_of::<Value>()
452 + match json {
453 serde_json::Value::Null => 0,
454 serde_json::Value::Bool(_) => 0,
455 serde_json::Value::Number(_) => 0,
456 serde_json::Value::String(s) => s.len(),
457 serde_json::Value::Array(vec) => vec.iter().map(required_budget).sum(),
458 serde_json::Value::Object(map) => {
459 map.iter().map(|(k, v)| k.len() + required_budget(v)).sum()
460 }
461 }
462 }
463
464 fn json<T: serde::Serialize>(layout: A::MoveTypeLayout, data: T) -> serde_json::Value {
468 let bcs = bcs::to_bytes(&data).unwrap();
469 let proto_value = ProtoVisitorBuilder::new(1024 * 1024)
470 .deserialize_value(&bcs, &layout)
471 .unwrap();
472 proto_value_to_json_value(proto_value)
473 }
474
475 macro_rules! struct_layout {
476 ($type:literal { $($name:literal : $layout:expr),* $(,)?}) => {
477 A::MoveTypeLayout::Struct(Box::new(MoveStructLayout {
478 type_: StructTag::from_str($type).expect("Failed to parse struct"),
479 fields: vec![$(MoveFieldLayout {
480 name: ident_str!($name).to_owned(),
481 layout: $layout,
482 }),*]
483 }))
484 }
485 }
486
487 macro_rules! vector_layout {
488 ($inner:expr) => {
489 A::MoveTypeLayout::Vector(Box::new($inner))
490 };
491 }
492
493 fn address(a: &str) -> iota_sdk_types::Address {
494 iota_sdk_types::Address::from_str(a).unwrap()
495 }
496
497 #[test]
498 fn json_bool() {
499 let actual = json(L::Bool, true);
500 let expect = json!(true);
501 assert_eq!(expect, actual);
502
503 let actual = json(L::Bool, false);
504 let expect = json!(false);
505 assert_eq!(expect, actual);
506 }
507
508 #[test]
509 fn json_u8() {
510 let actual = json(L::U8, 42u8);
511 let expect = json!(42u8);
512 assert_eq!(expect, actual);
513 }
514
515 #[test]
516 fn json_u16() {
517 let actual = json(L::U16, 424u16);
518 let expect = json!(424u16);
519 assert_eq!(expect, actual);
520 }
521
522 #[test]
523 fn json_u32() {
524 let actual = json(L::U32, 432_432u32);
525 let expect = json!(432_432u32);
526 assert_eq!(expect, actual);
527 }
528
529 #[test]
530 fn json_u64() {
531 let actual = json(L::U64, 432_432_432_432u64);
532 let expect = json!(432_432_432_432u64.to_string());
533 assert_eq!(expect, actual);
534 }
535
536 #[test]
537 fn json_u128() {
538 let actual = json(L::U128, 424_242_424_242_424_242_424u128);
539 let expect = json!(424_242_424_242_424_242_424u128.to_string());
540 assert_eq!(expect, actual);
541 }
542
543 #[test]
544 fn json_u256() {
545 let actual = json(
546 L::U256,
547 U256::from_str("42424242424242424242424242424242424242424").unwrap(),
548 );
549 let expect = json!("42424242424242424242424242424242424242424");
550 assert_eq!(expect, actual);
551 }
552
553 #[test]
554 fn json_ascii_string() {
555 let l = struct_layout!("0x1::ascii::String" {
556 "bytes": vector_layout!(L::U8)
557 });
558 let actual = json(l, "The quick brown fox");
559 let expect = json!("The quick brown fox");
560 assert_eq!(expect, actual);
561 }
562
563 #[test]
564 fn json_utf8_string() {
565 let l = struct_layout!("0x1::string::String" {
566 "bytes": vector_layout!(L::U8)
567 });
568 let actual = json(l, "The quick brown fox");
569 let expect = json!("The quick brown fox");
570 assert_eq!(expect, actual);
571 }
572
573 #[test]
574 fn json_url() {
575 let l = struct_layout!("0x2::url::Url" {
576 "url": struct_layout!("0x1::ascii::String" {
577 "bytes": vector_layout!(L::U8)
578 })
579 });
580 let actual = json(l, "https://example.com");
581 let expect = json!("https://example.com");
582 assert_eq!(expect, actual);
583 }
584
585 #[test]
586 fn json_address() {
587 let actual = json(L::Address, address("0x42"));
588 let expect = json!(address("0x42").to_string());
589 assert_eq!(expect, actual);
590 }
591
592 #[test]
593 fn json_signer() {
594 let actual = json(L::Signer, address("0x42"));
595 let expect = json!(address("0x42").to_string());
596 assert_eq!(expect, actual);
597 }
598
599 #[test]
600 fn json_id() {
601 let l = struct_layout!("0x2::object::ID" {
602 "bytes": L::Address,
603 });
604 let actual = json(l, address("0x42"));
605 let expect = json!(address("0x42").to_string());
606 assert_eq!(expect, actual);
607 }
608
609 #[test]
610 fn json_uid() {
611 let l = struct_layout!("0x2::object::UID" {
612 "id": struct_layout!("0x2::object::ID" {
613 "bytes": L::Address,
614 })
615 });
616 let actual = json(l, address("0x42"));
617 let expect = json!(address("0x42").to_string());
618 assert_eq!(expect, actual);
619 }
620
621 #[test]
622 fn json_option() {
623 let l = struct_layout!("0x42::foo::Bar" {
624 "baz": struct_layout!("0x1::option::Option<u8>" { "vec": vector_layout!(L::U8) }),
625 });
626
627 let actual = json(l, Option::<Vec<u8>>::None);
628 let expect = json!({
629 "baz": null,
630 });
631 assert_eq!(expect, actual);
632 }
633
634 #[test]
635 fn json_balance() {
636 let l = struct_layout!("0x2::balance::Balance<0x2::iota::IOTA>" {
637 "value": L::U64,
638 });
639
640 let actual = json(l, 100u64);
641 let expect = json!(100u64.to_string());
642 assert_eq!(expect, actual);
643 }
644
645 #[test]
646 fn json_compound() {
647 let l = struct_layout!("0x42::foo::Bar" {
648 "baz": struct_layout!("0x1::option::Option<u8>" { "vec": vector_layout!(L::U8) }),
649 "qux": vector_layout!(struct_layout!("0x43::xy::Zzy" {
650 "quy": L::U16,
651 "quz": struct_layout!("0x1::option::Option<0x1::ascii::String>" {
652 "vec": vector_layout!(struct_layout!("0x1::ascii::String" {
653 "bytes": vector_layout!(L::U8),
654 }))
655 }),
656 "frob": L::Address,
657 })),
658 });
659
660 let actual = json(
661 l,
662 (
663 Option::<Vec<u8>>::None,
664 vec![
665 (44u16, Some("Hello, world!"), address("0x45")),
666 (46u16, None, address("0x47")),
667 ],
668 ),
669 );
670 let expect = json!({
671 "baz": null,
672 "qux": [{
673 "quy": 44,
674 "quz": "Hello, world!",
675 "frob": address("0x45").to_string(),
676 },
677 {
678 "quy": 46,
679 "quz": null,
680 "frob": address("0x47").to_string(),
681 }
682 ],
683 });
684 assert_eq!(expect, actual);
685 }
686}