Skip to content

Commit a2e4f5d

Browse files
committed
proto: simplify ProtoVisitor depth logic
1 parent 954e53f commit a2e4f5d

File tree

3 files changed

+68
-55
lines changed

3 files changed

+68
-55
lines changed

crates/sui-rpc-api/src/grpc/v2beta/ledger_service/get_object.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,13 @@ fn get_object_impl(
130130
Some((layout, s.contents()))
131131
})
132132
.and_then(|(layout, contents)| {
133-
sui_types::proto_value::ProtoVisitor::new(service.config.max_json_move_value_size())
134-
.deserialize_value(contents, &layout)
135-
.map_err(|e| tracing::debug!("unable to convert to JSON: {e}"))
136-
.ok()
137-
.map(Box::new)
133+
sui_types::proto_value::ProtoVisitorBuilder::new(
134+
service.config.max_json_move_value_size(),
135+
)
136+
.deserialize_value(contents, &layout)
137+
.map_err(|e| tracing::debug!("unable to convert to JSON: {e}"))
138+
.ok()
139+
.map(Box::new)
138140
});
139141
}
140142

crates/sui-rpc-api/src/grpc/v2beta/ledger_service/get_transaction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ fn transaction_to_response(
190190
Some((layout, &event.contents))
191191
})
192192
.and_then(|(layout, contents)| {
193-
sui_types::proto_value::ProtoVisitor::new(
193+
sui_types::proto_value::ProtoVisitorBuilder::new(
194194
service.config.max_json_move_value_size(),
195195
)
196196
.deserialize_value(contents, &layout)

crates/sui-types/src/proto_value.rs

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,22 @@ use prost_types::Value;
2626
/// we'll conservitively cap this to ~80% of that.
2727
const MAX_DEPTH: usize = 80;
2828

29-
pub struct ProtoVisitor {
30-
/// Budget left to spend on visiting.
29+
pub struct ProtoVisitorBuilder {
30+
/// Budget to spend on visiting.
3131
bound: usize,
32+
33+
/// Current level of nesting depth while visiting.
3234
depth: usize,
3335
}
3436

37+
struct ProtoVisitor<'a> {
38+
/// Budget left to spend on visiting.
39+
bound: &'a mut usize,
40+
41+
/// Current level of nesting depth while visiting.
42+
depth: &'a mut usize,
43+
}
44+
3545
#[derive(thiserror::Error, Debug)]
3646
pub enum Error {
3747
#[error(transparent)]
@@ -47,11 +57,15 @@ pub enum Error {
4757
UnexpectedType,
4858
}
4959

50-
impl ProtoVisitor {
60+
impl ProtoVisitorBuilder {
5161
pub fn new(bound: usize) -> Self {
5262
Self { bound, depth: 0 }
5363
}
5464

65+
fn new_visitor(&mut self) -> Result<ProtoVisitor<'_>, Error> {
66+
ProtoVisitor::new(&mut self.bound, &mut self.depth)
67+
}
68+
5569
/// Deserialize `bytes` as a `MoveValue` with layout `layout`. Can fail if the bytes do not
5670
/// represent a value with this layout, or if the deserialized value exceeds the field/type size
5771
/// budget.
@@ -60,7 +74,9 @@ impl ProtoVisitor {
6074
bytes: &[u8],
6175
layout: &A::MoveTypeLayout,
6276
) -> anyhow::Result<Value> {
63-
A::MoveValue::visit_deserialize(bytes, layout, &mut self)
77+
let mut visitor = self.new_visitor()?;
78+
79+
A::MoveValue::visit_deserialize(bytes, layout, &mut visitor)
6480
}
6581

6682
/// Deserialize `bytes` as a `MoveStruct` with layout `layout`. Can fail if the bytes do not
@@ -71,38 +87,54 @@ impl ProtoVisitor {
7187
bytes: &[u8],
7288
layout: &A::MoveStructLayout,
7389
) -> anyhow::Result<Struct> {
90+
let mut visitor = self.new_visitor()?;
91+
7492
let Value {
7593
kind: Some(Kind::StructValue(struct_)),
76-
} = A::MoveStruct::visit_deserialize(bytes, layout, &mut self)?
94+
} = A::MoveStruct::visit_deserialize(bytes, layout, &mut visitor)?
7795
else {
7896
bail!("Expected to deserialize a struct");
7997
};
8098
Ok(struct_)
8199
}
100+
}
101+
102+
impl Drop for ProtoVisitor<'_> {
103+
fn drop(&mut self) {
104+
self.dec_depth();
105+
}
106+
}
82107

83-
fn inc_depth(&mut self) -> Result<(), Error> {
84-
if self.depth > MAX_DEPTH {
108+
impl<'a> ProtoVisitor<'a> {
109+
fn new(bound: &'a mut usize, depth: &'a mut usize) -> Result<Self, Error> {
110+
// Increment the depth since we're creating a new Visitor instance
111+
Self::inc_depth(depth)?;
112+
Ok(Self { bound, depth })
113+
}
114+
115+
fn inc_depth(depth: &mut usize) -> Result<(), Error> {
116+
if *depth > MAX_DEPTH {
85117
Err(Error::TooNested)
86118
} else {
87-
self.depth += 1;
119+
*depth += 1;
88120
Ok(())
89121
}
90122
}
91123

92124
fn dec_depth(&mut self) {
93-
if self.depth == 0 {
125+
if *self.depth == 0 {
94126
panic!("BUG: logic bug in Visitor implementation");
95127
} else {
96-
self.depth -= 1;
128+
*self.depth -= 1;
97129
}
98130
}
99131

100132
/// Deduct `size` from the overall budget. Errors if `size` exceeds the current budget.
101133
fn debit(&mut self, size: usize) -> Result<(), Error> {
102-
if self.bound < size {
134+
if *self.bound < size {
103135
Err(Error::OutOfBudget)
104136
} else {
105-
self.bound -= size;
137+
*self.bound -= size;
106138
Ok(())
107139
}
108140
}
@@ -121,59 +153,45 @@ impl ProtoVisitor {
121153
}
122154
}
123155

124-
impl<'b, 'l> Visitor<'b, 'l> for ProtoVisitor {
156+
impl<'b, 'l> Visitor<'b, 'l> for ProtoVisitor<'_> {
125157
type Value = Value;
126158
type Error = Error;
127159

128160
fn visit_u8(&mut self, _: &ValueDriver<'_, 'b, 'l>, value: u8) -> Result<Value, Error> {
129-
self.inc_depth()?;
130161
self.debit_value()?;
131-
self.dec_depth();
132162
Ok(Value::from(value))
133163
}
134164

135165
fn visit_u16(&mut self, _: &ValueDriver<'_, 'b, 'l>, value: u16) -> Result<Value, Error> {
136-
self.inc_depth()?;
137166
self.debit_value()?;
138-
self.dec_depth();
139167
Ok(Value::from(value))
140168
}
141169

142170
fn visit_u32(&mut self, _: &ValueDriver<'_, 'b, 'l>, value: u32) -> Result<Value, Error> {
143-
self.inc_depth()?;
144171
self.debit_value()?;
145-
self.dec_depth();
146172
Ok(Value::from(value))
147173
}
148174

149175
fn visit_u64(&mut self, _: &ValueDriver<'_, 'b, 'l>, value: u64) -> Result<Value, Error> {
150-
self.inc_depth()?;
151176
let value = value.to_string();
152177
self.debit_string_value(&value)?;
153-
self.dec_depth();
154178
Ok(Value::from(value))
155179
}
156180

157181
fn visit_u128(&mut self, _: &ValueDriver<'_, 'b, 'l>, value: u128) -> Result<Value, Error> {
158-
self.inc_depth()?;
159182
let value = value.to_string();
160183
self.debit_string_value(&value)?;
161-
self.dec_depth();
162184
Ok(Value::from(value))
163185
}
164186

165187
fn visit_u256(&mut self, _: &ValueDriver<'_, 'b, 'l>, value: U256) -> Result<Value, Error> {
166-
self.inc_depth()?;
167188
let value = value.to_string();
168189
self.debit_string_value(&value)?;
169-
self.dec_depth();
170190
Ok(Value::from(value))
171191
}
172192

173193
fn visit_bool(&mut self, _: &ValueDriver<'_, 'b, 'l>, value: bool) -> Result<Value, Error> {
174-
self.inc_depth()?;
175194
self.debit_value()?;
176-
self.dec_depth();
177195
Ok(Value::from(value))
178196
}
179197

@@ -182,10 +200,8 @@ impl<'b, 'l> Visitor<'b, 'l> for ProtoVisitor {
182200
_: &ValueDriver<'_, 'b, 'l>,
183201
value: AccountAddress,
184202
) -> Result<Value, Error> {
185-
self.inc_depth()?;
186203
let value = value.to_canonical_string(true);
187204
self.debit_string_value(&value)?;
188-
self.dec_depth();
189205
Ok(Value::from(value))
190206
}
191207

@@ -194,16 +210,12 @@ impl<'b, 'l> Visitor<'b, 'l> for ProtoVisitor {
194210
_: &ValueDriver<'_, 'b, 'l>,
195211
value: AccountAddress,
196212
) -> Result<Value, Error> {
197-
self.inc_depth()?;
198213
let value = value.to_canonical_string(true);
199214
self.debit_string_value(&value)?;
200-
self.dec_depth();
201215
Ok(Value::from(value))
202216
}
203217

204218
fn visit_vector(&mut self, driver: &mut VecDriver<'_, 'b, 'l>) -> Result<Value, Error> {
205-
self.inc_depth()?;
206-
207219
let value = if driver.element_layout().is_type(&TypeTag::U8) {
208220
// Base64 encode arbitrary bytes
209221
use base64::{engine::general_purpose::STANDARD, Engine};
@@ -221,20 +233,20 @@ impl<'b, 'l> Visitor<'b, 'l> for ProtoVisitor {
221233
} else {
222234
let mut elems = vec![];
223235
self.debit_value()?;
224-
while let Some(elem) = driver.next_element(self)? {
236+
237+
while let Some(elem) =
238+
driver.next_element(&mut ProtoVisitor::new(self.bound, self.depth)?)?
239+
{
225240
elems.push(elem);
226241
}
227242

228243
Value::from(elems)
229244
};
230245

231-
self.dec_depth();
232246
Ok(value)
233247
}
234248

235249
fn visit_struct(&mut self, driver: &mut StructDriver<'_, 'b, 'l>) -> Result<Value, Error> {
236-
self.inc_depth()?;
237-
238250
let ty = &driver.struct_layout().type_;
239251
let layout = driver.struct_layout();
240252

@@ -298,19 +310,17 @@ impl<'b, 'l> Visitor<'b, 'l> for ProtoVisitor {
298310
self.debit_str(field.name.as_str())?;
299311
}
300312

301-
while let Some((field, elem)) = driver.next_field(self)? {
313+
while let Some((field, elem)) =
314+
driver.next_field(&mut ProtoVisitor::new(self.bound, self.depth)?)?
315+
{
302316
map.fields.insert(field.name.as_str().to_owned(), elem);
303317
}
304318
Value::from(Kind::StructValue(map))
305319
};
306-
307-
self.dec_depth();
308320
Ok(value)
309321
}
310322

311323
fn visit_variant(&mut self, driver: &mut VariantDriver<'_, 'b, 'l>) -> Result<Value, Error> {
312-
self.inc_depth()?;
313-
314324
let mut map = Struct::default();
315325
self.debit_value()?;
316326

@@ -324,11 +334,12 @@ impl<'b, 'l> Visitor<'b, 'l> for ProtoVisitor {
324334
self.debit_str(field.name.as_str())?;
325335
}
326336

327-
while let Some((field, elem)) = driver.next_field(self)? {
337+
while let Some((field, elem)) =
338+
driver.next_field(&mut ProtoVisitor::new(self.bound, self.depth)?)?
339+
{
328340
map.fields.insert(field.name.as_str().to_owned(), elem);
329341
}
330342

331-
self.dec_depth();
332343
Ok(Value::from(Kind::StructValue(map)))
333344
}
334345
}
@@ -551,13 +562,13 @@ pub(crate) mod tests {
551562

552563
let bytes = serialize(value.clone());
553564

554-
let deser = ProtoVisitor::new(bound)
565+
let deser = ProtoVisitorBuilder::new(bound)
555566
.deserialize_value(&bytes, &type_layout)
556567
.unwrap();
557568

558569
assert_eq!(expected, proto_value_to_json_value(deser));
559570

560-
ProtoVisitor::new(bound - 1)
571+
ProtoVisitorBuilder::new(bound - 1)
561572
.deserialize_value(&bytes, &type_layout)
562573
.unwrap_err();
563574
}
@@ -580,7 +591,7 @@ pub(crate) mod tests {
580591
let bound = required_budget(&expected);
581592
let bytes = serialize(value.clone());
582593

583-
let deser = ProtoVisitor::new(bound)
594+
let deser = ProtoVisitorBuilder::new(bound)
584595
.deserialize_value(&bytes, &layout)
585596
.unwrap();
586597

@@ -592,7 +603,7 @@ pub(crate) mod tests {
592603

593604
let bytes = serialize(value.clone());
594605

595-
let err = ProtoVisitor::new(bound)
606+
let err = ProtoVisitorBuilder::new(bound)
596607
.deserialize_value(&bytes, &layout)
597608
.unwrap_err();
598609

@@ -643,7 +654,7 @@ pub(crate) mod tests {
643654

644655
fn json<T: serde::Serialize>(layout: A::MoveTypeLayout, data: T) -> serde_json::Value {
645656
let bcs = bcs::to_bytes(&data).unwrap();
646-
let proto_value = ProtoVisitor::new(1024 * 1024)
657+
let proto_value = ProtoVisitorBuilder::new(1024 * 1024)
647658
.deserialize_value(&bcs, &layout)
648659
.unwrap();
649660
proto_value_to_json_value(proto_value)

0 commit comments

Comments
 (0)