1use move_core_types::annotated_value as A;
5use move_core_types::annotated_visitor as AV;
6use prost_types::Struct;
7use prost_types::Value;
8use prost_types::value::Kind;
9
10use crate::object::option_visitor as OV;
11use crate::object::rpc_visitor as RV;
12
13const MAX_DEPTH: usize = 80;
17
18pub struct ProtoVisitor {
19 bound: usize,
21}
22
23pub struct ProtoWriter<'b> {
24 bound: &'b mut usize,
25 depth: usize,
26}
27
28#[derive(thiserror::Error, Debug)]
29pub enum Error {
30 #[error(transparent)]
31 Visitor(#[from] AV::Error),
32
33 #[error("Deserialized value too large")]
34 OutOfBudget,
35
36 #[error("Exceeded maximum depth")]
37 TooNested,
38
39 #[error("Unexpected type")]
40 UnexpectedType,
41}
42
43impl ProtoVisitor {
44 pub fn new(bound: usize) -> Self {
45 Self { bound }
46 }
47
48 pub fn deserialize_value(
52 mut self,
53 bytes: &[u8],
54 layout: &A::MoveTypeLayout,
55 ) -> Result<Value, Error> {
56 A::MoveValue::visit_deserialize(
57 bytes,
58 layout,
59 &mut RV::RpcVisitor::new(ProtoWriter {
60 bound: &mut self.bound,
61 depth: 0,
62 }),
63 )
64 }
65}
66
67impl ProtoWriter<'_> {
68 fn debit(&mut self, size: usize) -> Result<(), Error> {
69 if *self.bound < size {
70 Err(Error::OutOfBudget)
71 } else {
72 *self.bound -= size;
73 Ok(())
74 }
75 }
76
77 fn debit_value(&mut self) -> Result<(), Error> {
78 self.debit(size_of::<Value>())
79 }
80
81 fn debit_str(&mut self, s: &str) -> Result<(), Error> {
82 self.debit(s.len())
83 }
84
85 fn debit_string_value(&mut self, s: &str) -> Result<(), Error> {
86 self.debit_str(s)?;
87 self.debit_value()
88 }
89}
90
91impl<'b> RV::Writer for ProtoWriter<'b> {
92 type Value = Value;
93 type Error = Error;
94
95 type Vec = Vec<Value>;
96 type Map = Struct;
97
98 type Nested<'a>
99 = ProtoWriter<'a>
100 where
101 Self: 'a;
102
103 fn nest(&mut self) -> Result<Self::Nested<'_>, Self::Error> {
104 if self.depth >= MAX_DEPTH {
105 Err(Error::TooNested)
106 } else {
107 Ok(ProtoWriter {
108 bound: self.bound,
109 depth: self.depth + 1,
110 })
111 }
112 }
113
114 fn write_null(&mut self) -> Result<Self::Value, Self::Error> {
115 self.debit_value()?;
116 Ok(Kind::NullValue(0).into())
117 }
118
119 fn write_bool(&mut self, value: bool) -> Result<Self::Value, Self::Error> {
120 self.debit_value()?;
121 Ok(Kind::BoolValue(value).into())
122 }
123
124 fn write_number(&mut self, value: u32) -> Result<Self::Value, Self::Error> {
125 self.debit_value()?;
126 Ok(Value::from(value))
127 }
128
129 fn write_str(&mut self, value: String) -> Result<Self::Value, Self::Error> {
130 self.debit_string_value(&value)?;
131 Ok(Kind::StringValue(value).into())
132 }
133
134 fn write_vec(&mut self, value: Self::Vec) -> Result<Self::Value, Self::Error> {
135 self.debit_value()?;
136 Ok(Value::from(value))
137 }
138
139 fn write_map(&mut self, value: Self::Map) -> Result<Self::Value, Self::Error> {
140 self.debit_value()?;
141 Ok(Value::from(Kind::StructValue(value)))
142 }
143
144 fn vec_push_element(
145 &mut self,
146 vec: &mut Self::Vec,
147 val: Self::Value,
148 ) -> Result<(), Self::Error> {
149 vec.push(val);
150 Ok(())
151 }
152
153 fn map_push_field(
154 &mut self,
155 map: &mut Self::Map,
156 key: String,
157 val: Self::Value,
158 ) -> Result<(), Self::Error> {
159 self.debit_str(&key)?;
160 map.fields.insert(key, val);
161 Ok(())
162 }
163}
164
165impl From<RV::Error> for Error {
166 fn from(RV::Error: RV::Error) -> Self {
167 Error::UnexpectedType
168 }
169}
170
171impl From<OV::Error> for Error {
172 fn from(OV::Error: OV::Error) -> Self {
173 Error::UnexpectedType
174 }
175}
176
177#[cfg(test)]
178pub(crate) mod tests {
179 use super::*;
180
181 use crate::object::bounded_visitor::tests::layout_;
182 use crate::object::bounded_visitor::tests::serialize;
183 use crate::object::bounded_visitor::tests::value_;
184 use expect_test::expect;
185 use serde_json::json;
186
187 use A::MoveTypeLayout as L;
188 use A::MoveValue as V;
189
190 #[test]
191 fn test_simple() {
192 let type_layout = layout_(
193 "0x0::foo::Bar",
194 vec![
195 ("a", L::U64),
196 ("b", L::Vector(Box::new(L::U64))),
197 ("c", layout_("0x0::foo::Baz", vec![("d", L::U64)])),
198 ],
199 );
200
201 let value = value_(
202 "0x0::foo::Bar",
203 vec![
204 ("a", V::U64(42)),
205 ("b", V::Vector(vec![V::U64(43)])),
206 ("c", value_("0x0::foo::Baz", vec![("d", V::U64(44))])),
207 ],
208 );
209
210 let expected = json!({
211 "a": "42",
212 "b": ["43"],
213 "c": {
214 "d": "44"
215 }
216 });
217 let bound = required_budget(&expected);
218
219 let bytes = serialize(value.clone());
220
221 let deser = ProtoVisitor::new(bound)
222 .deserialize_value(&bytes, &type_layout)
223 .unwrap();
224
225 assert_eq!(expected, proto_value_to_json_value(deser));
226
227 ProtoVisitor::new(bound - 1)
228 .deserialize_value(&bytes, &type_layout)
229 .unwrap_err();
230 }
231
232 #[test]
233 fn test_too_deep() {
234 let mut layout = L::U64;
235 let mut value = V::U64(42);
236 let mut expected = serde_json::Value::from("42");
237
238 const DEPTH: usize = MAX_DEPTH;
239 for _ in 0..DEPTH {
240 layout = layout_("0x0::foo::Bar", vec![("f", layout)]);
241 value = value_("0x0::foo::Bar", vec![("f", value)]);
242 expected = json!({
243 "f": expected
244 });
245 }
246
247 let bound = required_budget(&expected);
248 let bytes = serialize(value.clone());
249
250 let deser = ProtoVisitor::new(bound)
251 .deserialize_value(&bytes, &layout)
252 .unwrap();
253
254 assert_eq!(expected, proto_value_to_json_value(deser));
255
256 layout = layout_("0x0::foo::Bar", vec![("f", layout)]);
258 value = value_("0x0::foo::Bar", vec![("f", value)]);
259
260 let bytes = serialize(value.clone());
261
262 let err = ProtoVisitor::new(bound)
263 .deserialize_value(&bytes, &layout)
264 .unwrap_err();
265
266 let expect = expect!["Exceeded maximum depth"];
267 expect.assert_eq(&err.to_string());
268 }
269
270 fn proto_value_to_json_value(proto: Value) -> serde_json::Value {
271 match proto.kind {
272 Some(Kind::NullValue(_)) | None => serde_json::Value::Null,
273 Some(Kind::NumberValue(n)) => serde_json::Value::from(n as u32),
275 Some(Kind::StringValue(s)) => serde_json::Value::from(s),
276 Some(Kind::BoolValue(b)) => serde_json::Value::from(b),
277 Some(Kind::StructValue(map)) => serde_json::Value::Object(
278 map.fields
279 .into_iter()
280 .map(|(k, v)| (k, proto_value_to_json_value(v)))
281 .collect(),
282 ),
283 Some(Kind::ListValue(list_value)) => serde_json::Value::Array(
284 list_value
285 .values
286 .into_iter()
287 .map(proto_value_to_json_value)
288 .collect(),
289 ),
290 }
291 }
292
293 fn required_budget(json: &serde_json::Value) -> usize {
294 size_of::<Value>()
295 + match json {
296 serde_json::Value::Null => 0,
297 serde_json::Value::Bool(_) => 0,
298 serde_json::Value::Number(_) => 0,
299 serde_json::Value::String(s) => s.len(),
300 serde_json::Value::Array(vec) => vec.iter().map(required_budget).sum(),
301 serde_json::Value::Object(map) => {
302 map.iter().map(|(k, v)| k.len() + required_budget(v)).sum()
303 }
304 }
305 }
306}