Skip to content

Commit cd1527d

Browse files
fix(dpp)!: wrapping overflow issue (#2430)
1 parent fd7ee85 commit cd1527d

File tree

11 files changed

+182
-117
lines changed
  • packages
    • rs-dpp/src/data_contract/document_type
    • rs-drive/src
      • drive/document
        • delete
          • remove_indices_for_index_level_for_contract_operations/v0
          • remove_indices_for_top_index_level_for_contract_operations/v0
        • insert
          • add_indices_for_index_level_for_contract_operations/v0
          • add_indices_for_top_index_level_for_contract_operations/v0
        • insert_contested
          • add_contested_indices_for_contract_operations/v0
          • add_contested_indices_for_index_level_for_contract_operations/v0
      • util/object_size_info

11 files changed

+182
-117
lines changed
Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
11
use crate::data_contract::document_type::v0::DocumentTypeV0;
2-
2+
use crate::ProtocolError;
3+
use platform_version::version::PlatformVersion;
34
// If another document type (like V1) ever were to exist we would need to implement estimated_size_v0 again
45

56
impl DocumentTypeV0 {
67
/// The estimated size uses the middle ceil size of all attributes
7-
pub(in crate::data_contract::document_type) fn estimated_size_v0(&self) -> u16 {
8-
let mut iter = self
9-
.flattened_properties
10-
.iter()
11-
.filter_map(|(_, document_property)| {
12-
document_property.property_type.middle_byte_size_ceil()
13-
});
14-
let first = Some(iter.next().unwrap_or_default());
8+
pub(in crate::data_contract::document_type) fn estimated_size_v0(
9+
&self,
10+
platform_version: &PlatformVersion,
11+
) -> Result<u16, ProtocolError> {
12+
let mut total_size = 0u16;
13+
14+
for (_, document_property) in self.flattened_properties.iter() {
15+
// This call now returns a Result<Option<u16>, ProtocolError>.
16+
let maybe_size = document_property
17+
.property_type
18+
.middle_byte_size_ceil(platform_version)?;
19+
20+
if let Some(size) = maybe_size {
21+
total_size = match total_size.checked_add(size) {
22+
Some(new_total) => new_total,
23+
None => {
24+
return Ok(u16::MAX);
25+
}
26+
};
27+
}
28+
}
1529

16-
iter.fold(first, |acc, item| acc.and_then(|acc| acc.checked_add(item)))
17-
.unwrap_or(u16::MAX)
30+
Ok(total_size)
1831
}
1932
}
Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,30 @@
11
use crate::data_contract::document_type::v0::DocumentTypeV0;
2-
2+
use crate::ProtocolError;
3+
use platform_version::version::PlatformVersion;
34
// If another document type (like V1) ever were to exist we would need to implement max_size_v0 again
45

56
impl DocumentTypeV0 {
6-
pub(in crate::data_contract::document_type) fn max_size_v0(&self) -> u16 {
7-
let mut iter = self
8-
.flattened_properties
9-
.iter()
10-
.filter_map(|(_, document_property)| document_property.property_type.max_byte_size());
11-
let first = Some(iter.next().unwrap_or_default());
7+
pub(in crate::data_contract::document_type) fn max_size_v0(
8+
&self,
9+
platform_version: &PlatformVersion,
10+
) -> Result<u16, ProtocolError> {
11+
let mut total_size = 0u16;
12+
13+
for (_, document_property) in self.flattened_properties.iter() {
14+
let maybe_size = document_property
15+
.property_type
16+
.max_byte_size(platform_version)?;
17+
18+
if let Some(size) = maybe_size {
19+
total_size = match total_size.checked_add(size) {
20+
Some(new_total) => new_total,
21+
None => {
22+
return Ok(u16::MAX);
23+
}
24+
};
25+
}
26+
}
1227

13-
iter.fold(first, |acc, item| acc.and_then(|acc| acc.checked_add(item)))
14-
.unwrap_or(u16::MAX)
28+
Ok(total_size)
1529
}
1630
}

packages/rs-dpp/src/data_contract/document_type/methods/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ impl DocumentTypeV0Methods for DocumentTypeV0 {
222222
.methods
223223
.max_size
224224
{
225-
0 => Ok(self.max_size_v0()),
225+
0 => self.max_size_v0(platform_version),
226226
version => Err(ProtocolError::UnknownVersionMismatch {
227227
method: "max_size".to_string(),
228228
known_versions: vec![0],
@@ -239,7 +239,7 @@ impl DocumentTypeV0Methods for DocumentTypeV0 {
239239
.methods
240240
.estimated_size
241241
{
242-
0 => Ok(self.estimated_size_v0()),
242+
0 => self.estimated_size_v0(platform_version),
243243
version => Err(ProtocolError::UnknownVersionMismatch {
244244
method: "estimated_size".to_string(),
245245
known_versions: vec![0],

packages/rs-dpp/src/data_contract/document_type/property/mod.rs

Lines changed: 113 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
1212
use indexmap::IndexMap;
1313
use integer_encoding::{VarInt, VarIntReader};
1414
use platform_value::{Identifier, Value};
15+
use platform_version::version::PlatformVersion;
1516
use rand::distributions::{Alphanumeric, Standard};
1617
use rand::rngs::StdRng;
1718
use rand::Rng;
@@ -159,69 +160,93 @@ impl DocumentPropertyType {
159160
}
160161
}
161162

162-
pub fn min_byte_size(&self) -> Option<u16> {
163+
pub fn min_byte_size(
164+
&self,
165+
platform_version: &PlatformVersion,
166+
) -> Result<Option<u16>, ProtocolError> {
163167
match self {
164-
DocumentPropertyType::U128 => Some(16),
165-
DocumentPropertyType::I128 => Some(16),
166-
DocumentPropertyType::U64 => Some(8),
167-
DocumentPropertyType::I64 => Some(8),
168-
DocumentPropertyType::U32 => Some(4),
169-
DocumentPropertyType::I32 => Some(4),
170-
DocumentPropertyType::U16 => Some(2),
171-
DocumentPropertyType::I16 => Some(2),
172-
DocumentPropertyType::U8 => Some(1),
173-
DocumentPropertyType::I8 => Some(1),
174-
DocumentPropertyType::F64 => Some(8),
168+
DocumentPropertyType::U128 => Ok(Some(16)),
169+
DocumentPropertyType::I128 => Ok(Some(16)),
170+
DocumentPropertyType::U64 => Ok(Some(8)),
171+
DocumentPropertyType::I64 => Ok(Some(8)),
172+
DocumentPropertyType::U32 => Ok(Some(4)),
173+
DocumentPropertyType::I32 => Ok(Some(4)),
174+
DocumentPropertyType::U16 => Ok(Some(2)),
175+
DocumentPropertyType::I16 => Ok(Some(2)),
176+
DocumentPropertyType::U8 => Ok(Some(1)),
177+
DocumentPropertyType::I8 => Ok(Some(1)),
178+
DocumentPropertyType::F64 => Ok(Some(8)),
175179
DocumentPropertyType::String(sizes) => match sizes.min_length {
176-
None => Some(0),
177-
Some(size) => Some(size * 4),
180+
None => Ok(Some(0)),
181+
Some(size) => {
182+
if platform_version.protocol_version > 8 {
183+
match size.checked_mul(4) {
184+
Some(mul) => Ok(Some(mul)),
185+
None => Err(ProtocolError::Overflow("min_byte_size overflow")),
186+
}
187+
} else {
188+
Ok(Some(size.wrapping_mul(4)))
189+
}
190+
}
178191
},
179192
DocumentPropertyType::ByteArray(sizes) => match sizes.min_size {
180-
None => Some(0),
181-
Some(size) => Some(size),
193+
None => Ok(Some(0)),
194+
Some(size) => Ok(Some(size)),
182195
},
183-
DocumentPropertyType::Boolean => Some(1),
184-
DocumentPropertyType::Date => Some(8),
196+
DocumentPropertyType::Boolean => Ok(Some(1)),
197+
DocumentPropertyType::Date => Ok(Some(8)),
185198
DocumentPropertyType::Object(sub_fields) => sub_fields
186199
.iter()
187-
.map(|(_, sub_field)| sub_field.property_type.min_byte_size())
200+
.map(|(_, sub_field)| sub_field.property_type.min_byte_size(platform_version))
188201
.sum(),
189-
DocumentPropertyType::Array(_) => None,
190-
DocumentPropertyType::VariableTypeArray(_) => None,
191-
DocumentPropertyType::Identifier => Some(32),
202+
DocumentPropertyType::Array(_) => Ok(None),
203+
DocumentPropertyType::VariableTypeArray(_) => Ok(None),
204+
DocumentPropertyType::Identifier => Ok(Some(32)),
192205
}
193206
}
194207

195-
pub fn max_byte_size(&self) -> Option<u16> {
208+
pub fn max_byte_size(
209+
&self,
210+
platform_version: &PlatformVersion,
211+
) -> Result<Option<u16>, ProtocolError> {
196212
match self {
197-
DocumentPropertyType::U128 => Some(16),
198-
DocumentPropertyType::I128 => Some(16),
199-
DocumentPropertyType::U64 => Some(8),
200-
DocumentPropertyType::I64 => Some(8),
201-
DocumentPropertyType::U32 => Some(4),
202-
DocumentPropertyType::I32 => Some(4),
203-
DocumentPropertyType::U16 => Some(2),
204-
DocumentPropertyType::I16 => Some(2),
205-
DocumentPropertyType::U8 => Some(1),
206-
DocumentPropertyType::I8 => Some(1),
207-
DocumentPropertyType::F64 => Some(8),
213+
DocumentPropertyType::U128 => Ok(Some(16)),
214+
DocumentPropertyType::I128 => Ok(Some(16)),
215+
DocumentPropertyType::U64 => Ok(Some(8)),
216+
DocumentPropertyType::I64 => Ok(Some(8)),
217+
DocumentPropertyType::U32 => Ok(Some(4)),
218+
DocumentPropertyType::I32 => Ok(Some(4)),
219+
DocumentPropertyType::U16 => Ok(Some(2)),
220+
DocumentPropertyType::I16 => Ok(Some(2)),
221+
DocumentPropertyType::U8 => Ok(Some(1)),
222+
DocumentPropertyType::I8 => Ok(Some(1)),
223+
DocumentPropertyType::F64 => Ok(Some(8)),
208224
DocumentPropertyType::String(sizes) => match sizes.max_length {
209-
None => Some(u16::MAX),
210-
Some(size) => Some(size * 4),
225+
None => Ok(Some(u16::MAX)),
226+
Some(size) => {
227+
if platform_version.protocol_version > 8 {
228+
match size.checked_mul(4) {
229+
Some(mul) => Ok(Some(mul)),
230+
None => Err(ProtocolError::Overflow("max_byte_size overflow")),
231+
}
232+
} else {
233+
Ok(Some(size.wrapping_mul(4)))
234+
}
235+
}
211236
},
212237
DocumentPropertyType::ByteArray(sizes) => match sizes.max_size {
213-
None => Some(u16::MAX),
214-
Some(size) => Some(size),
238+
None => Ok(Some(u16::MAX)),
239+
Some(size) => Ok(Some(size)),
215240
},
216-
DocumentPropertyType::Boolean => Some(1),
217-
DocumentPropertyType::Date => Some(8),
241+
DocumentPropertyType::Boolean => Ok(Some(1)),
242+
DocumentPropertyType::Date => Ok(Some(8)),
218243
DocumentPropertyType::Object(sub_fields) => sub_fields
219244
.iter()
220-
.map(|(_, sub_field)| sub_field.property_type.max_byte_size())
245+
.map(|(_, sub_field)| sub_field.property_type.max_byte_size(platform_version))
221246
.sum(),
222-
DocumentPropertyType::Array(_) => None,
223-
DocumentPropertyType::VariableTypeArray(_) => None,
224-
DocumentPropertyType::Identifier => Some(32),
247+
DocumentPropertyType::Array(_) => Ok(None),
248+
DocumentPropertyType::VariableTypeArray(_) => Ok(None),
249+
DocumentPropertyType::Identifier => Ok(Some(32)),
225250
}
226251
}
227252

@@ -259,60 +284,66 @@ impl DocumentPropertyType {
259284
}
260285

261286
/// The middle size rounded down halfway between min and max size
262-
pub fn middle_size(&self) -> Option<u16> {
263-
match self {
264-
DocumentPropertyType::Array(_) | DocumentPropertyType::VariableTypeArray(_) => {
265-
return None
266-
}
267-
_ => {}
287+
pub fn middle_size(&self, platform_version: &PlatformVersion) -> Option<u16> {
288+
let min_size = self.min_size()?;
289+
let max_size = self.max_size()?;
290+
if platform_version.protocol_version > 8 {
291+
Some(((min_size as u32 + max_size as u32) / 2) as u16)
292+
} else {
293+
Some(min_size.wrapping_add(max_size) / 2)
268294
}
269-
let min_size = self.min_size().unwrap();
270-
let max_size = self.max_size().unwrap();
271-
Some((min_size + max_size) / 2)
272295
}
273296

274297
/// The middle size rounded up halfway between min and max size
275-
pub fn middle_size_ceil(&self) -> Option<u16> {
276-
match self {
277-
DocumentPropertyType::Array(_) | DocumentPropertyType::VariableTypeArray(_) => {
278-
return None
279-
}
280-
_ => {}
298+
pub fn middle_size_ceil(&self, platform_version: &PlatformVersion) -> Option<u16> {
299+
let min_size = self.min_size()?;
300+
let max_size = self.max_size()?;
301+
if platform_version.protocol_version > 8 {
302+
Some(((min_size as u32 + max_size as u32 + 1) / 2) as u16)
303+
} else {
304+
Some(min_size.wrapping_add(max_size).wrapping_add(1) / 2)
281305
}
282-
let min_size = self.min_size().unwrap();
283-
let max_size = self.max_size().unwrap();
284-
Some((min_size + max_size + 1) / 2)
285306
}
286307

287308
/// The middle size rounded down halfway between min and max byte size
288-
pub fn middle_byte_size(&self) -> Option<u16> {
289-
match self {
290-
DocumentPropertyType::Array(_) | DocumentPropertyType::VariableTypeArray(_) => {
291-
return None
292-
}
293-
_ => {}
309+
pub fn middle_byte_size(
310+
&self,
311+
platform_version: &PlatformVersion,
312+
) -> Result<Option<u16>, ProtocolError> {
313+
let Some(min_size) = self.min_byte_size(platform_version)? else {
314+
return Ok(None);
315+
};
316+
let Some(max_size) = self.max_byte_size(platform_version)? else {
317+
return Ok(None);
318+
};
319+
if platform_version.protocol_version > 8 {
320+
Ok(Some(((min_size as u32 + max_size as u32) / 2) as u16))
321+
} else {
322+
Ok(Some(min_size.wrapping_add(max_size) / 2))
294323
}
295-
let min_size = self.min_byte_size().unwrap();
296-
let max_size = self.max_byte_size().unwrap();
297-
Some((min_size + max_size) / 2)
298324
}
299325

300326
/// The middle size rounded up halfway between min and max byte size
301-
pub fn middle_byte_size_ceil(&self) -> Option<u16> {
302-
match self {
303-
DocumentPropertyType::Array(_) | DocumentPropertyType::VariableTypeArray(_) => {
304-
return None
305-
}
306-
_ => {}
327+
pub fn middle_byte_size_ceil(
328+
&self,
329+
platform_version: &PlatformVersion,
330+
) -> Result<Option<u16>, ProtocolError> {
331+
let Some(min_size) = self.min_byte_size(platform_version)? else {
332+
return Ok(None);
333+
};
334+
let Some(max_size) = self.max_byte_size(platform_version)? else {
335+
return Ok(None);
336+
};
337+
if platform_version.protocol_version > 8 {
338+
Ok(Some(((min_size as u32 + max_size as u32 + 1) / 2) as u16))
339+
} else {
340+
Ok(Some(min_size.wrapping_add(max_size).wrapping_add(1) / 2))
307341
}
308-
let min_size = self.min_byte_size().unwrap() as u32;
309-
let max_size = self.max_byte_size().unwrap() as u32;
310-
Some(((min_size + max_size + 1) / 2) as u16)
311342
}
312343

313344
pub fn random_size(&self, rng: &mut StdRng) -> u16 {
314-
let min_size = self.min_size().unwrap();
315-
let max_size = self.max_size().unwrap();
345+
let min_size = self.min_size().unwrap_or_default();
346+
let max_size = self.max_size().unwrap_or_default();
316347
rng.gen_range(min_size..=max_size)
317348
}
318349

packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/v0/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl Drive {
105105
let document_top_field_estimated_size = document_and_contract_info
106106
.owned_document_info
107107
.document_info
108-
.get_estimated_size_for_document_type(name, document_type)?;
108+
.get_estimated_size_for_document_type(name, document_type, platform_version)?;
109109

110110
if document_top_field_estimated_size > u8::MAX as u16 {
111111
return Err(Error::Fee(FeeError::Overflow(

packages/rs-drive/src/drive/document/delete/remove_indices_for_top_index_level_for_contract_operations/v0/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ impl Drive {
107107
let document_top_field_estimated_size = document_and_contract_info
108108
.owned_document_info
109109
.document_info
110-
.get_estimated_size_for_document_type(name, document_type)?;
110+
.get_estimated_size_for_document_type(name, document_type, platform_version)?;
111111

112112
if document_top_field_estimated_size > u8::MAX as u16 {
113113
return Err(Error::Fee(FeeError::Overflow(

packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ impl Drive {
125125
let document_top_field_estimated_size = document_and_contract_info
126126
.owned_document_info
127127
.document_info
128-
.get_estimated_size_for_document_type(name, document_type)?;
128+
.get_estimated_size_for_document_type(name, document_type, platform_version)?;
129129

130130
if document_top_field_estimated_size > u8::MAX as u16 {
131131
return Err(Error::Fee(FeeError::Overflow(

packages/rs-drive/src/drive/document/insert/add_indices_for_top_index_level_for_contract_operations/v0/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ impl Drive {
134134
let document_top_field_estimated_size = document_and_contract_info
135135
.owned_document_info
136136
.document_info
137-
.get_estimated_size_for_document_type(name, document_type)?;
137+
.get_estimated_size_for_document_type(name, document_type, platform_version)?;
138138

139139
if document_top_field_estimated_size > u8::MAX as u16 {
140140
return Err(Error::Fee(FeeError::Overflow(

packages/rs-drive/src/drive/document/insert_contested/add_contested_indices_for_contract_operations/v0/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ impl Drive {
111111
let document_top_field_estimated_size = document_and_contract_info
112112
.owned_document_info
113113
.document_info
114-
.get_estimated_size_for_document_type(name, document_type)?;
114+
.get_estimated_size_for_document_type(name, document_type, platform_version)?;
115115

116116
if document_top_field_estimated_size > u8::MAX as u16 {
117117
return Err(Error::Fee(FeeError::Overflow(

0 commit comments

Comments
 (0)