Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
use crate::data_contract::document_type::v0::DocumentTypeV0;

use crate::ProtocolError;
use platform_version::version::PlatformVersion;
// If another document type (like V1) ever were to exist we would need to implement estimated_size_v0 again

impl DocumentTypeV0 {
/// The estimated size uses the middle ceil size of all attributes
pub(in crate::data_contract::document_type) fn estimated_size_v0(&self) -> u16 {
let mut iter = self
.flattened_properties
.iter()
.filter_map(|(_, document_property)| {
document_property.property_type.middle_byte_size_ceil()
});
let first = Some(iter.next().unwrap_or_default());
pub(in crate::data_contract::document_type) fn estimated_size_v0(
&self,
platform_version: &PlatformVersion,
) -> Result<u16, ProtocolError> {
let mut total_size = 0u16;

for (_, document_property) in self.flattened_properties.iter() {
// This call now returns a Result<Option<u16>, ProtocolError>.
let maybe_size = document_property
.property_type
.middle_byte_size_ceil(platform_version)?;

if let Some(size) = maybe_size {
total_size = match total_size.checked_add(size) {
Some(new_total) => new_total,
None => {
return Ok(u16::MAX);
}
};
}
}

iter.fold(first, |acc, item| acc.and_then(|acc| acc.checked_add(item)))
.unwrap_or(u16::MAX)
Ok(total_size)
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
use crate::data_contract::document_type::v0::DocumentTypeV0;

use crate::ProtocolError;
use platform_version::version::PlatformVersion;
// If another document type (like V1) ever were to exist we would need to implement max_size_v0 again

impl DocumentTypeV0 {
pub(in crate::data_contract::document_type) fn max_size_v0(&self) -> u16 {
let mut iter = self
.flattened_properties
.iter()
.filter_map(|(_, document_property)| document_property.property_type.max_byte_size());
let first = Some(iter.next().unwrap_or_default());
pub(in crate::data_contract::document_type) fn max_size_v0(
&self,
platform_version: &PlatformVersion,
) -> Result<u16, ProtocolError> {
let mut total_size = 0u16;

for (_, document_property) in self.flattened_properties.iter() {
let maybe_size = document_property
.property_type
.max_byte_size(platform_version)?;

if let Some(size) = maybe_size {
total_size = match total_size.checked_add(size) {
Some(new_total) => new_total,
None => {
return Ok(u16::MAX);
}
};
}
}

iter.fold(first, |acc, item| acc.and_then(|acc| acc.checked_add(item)))
.unwrap_or(u16::MAX)
Ok(total_size)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl DocumentTypeV0Methods for DocumentTypeV0 {
.methods
.max_size
{
0 => Ok(self.max_size_v0()),
0 => self.max_size_v0(platform_version),
version => Err(ProtocolError::UnknownVersionMismatch {
method: "max_size".to_string(),
known_versions: vec![0],
Expand All @@ -239,7 +239,7 @@ impl DocumentTypeV0Methods for DocumentTypeV0 {
.methods
.estimated_size
{
0 => Ok(self.estimated_size_v0()),
0 => self.estimated_size_v0(platform_version),
version => Err(ProtocolError::UnknownVersionMismatch {
method: "estimated_size".to_string(),
known_versions: vec![0],
Expand Down
195 changes: 113 additions & 82 deletions packages/rs-dpp/src/data_contract/document_type/property/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use indexmap::IndexMap;
use integer_encoding::{VarInt, VarIntReader};
use platform_value::{Identifier, Value};
use platform_version::version::PlatformVersion;
use rand::distributions::{Alphanumeric, Standard};
use rand::rngs::StdRng;
use rand::Rng;
Expand Down Expand Up @@ -159,69 +160,93 @@ impl DocumentPropertyType {
}
}

pub fn min_byte_size(&self) -> Option<u16> {
pub fn min_byte_size(
&self,
platform_version: &PlatformVersion,
) -> Result<Option<u16>, ProtocolError> {
match self {
DocumentPropertyType::U128 => Some(16),
DocumentPropertyType::I128 => Some(16),
DocumentPropertyType::U64 => Some(8),
DocumentPropertyType::I64 => Some(8),
DocumentPropertyType::U32 => Some(4),
DocumentPropertyType::I32 => Some(4),
DocumentPropertyType::U16 => Some(2),
DocumentPropertyType::I16 => Some(2),
DocumentPropertyType::U8 => Some(1),
DocumentPropertyType::I8 => Some(1),
DocumentPropertyType::F64 => Some(8),
DocumentPropertyType::U128 => Ok(Some(16)),
DocumentPropertyType::I128 => Ok(Some(16)),
DocumentPropertyType::U64 => Ok(Some(8)),
DocumentPropertyType::I64 => Ok(Some(8)),
DocumentPropertyType::U32 => Ok(Some(4)),
DocumentPropertyType::I32 => Ok(Some(4)),
DocumentPropertyType::U16 => Ok(Some(2)),
DocumentPropertyType::I16 => Ok(Some(2)),
DocumentPropertyType::U8 => Ok(Some(1)),
DocumentPropertyType::I8 => Ok(Some(1)),
DocumentPropertyType::F64 => Ok(Some(8)),
DocumentPropertyType::String(sizes) => match sizes.min_length {
None => Some(0),
Some(size) => Some(size * 4),
None => Ok(Some(0)),
Some(size) => {
if platform_version.protocol_version > 8 {
match size.checked_mul(4) {
Some(mul) => Ok(Some(mul)),
None => Err(ProtocolError::Overflow("min_byte_size overflow")),
}
} else {
Ok(Some(size.wrapping_mul(4)))
}
}
},
DocumentPropertyType::ByteArray(sizes) => match sizes.min_size {
None => Some(0),
Some(size) => Some(size),
None => Ok(Some(0)),
Some(size) => Ok(Some(size)),
},
DocumentPropertyType::Boolean => Some(1),
DocumentPropertyType::Date => Some(8),
DocumentPropertyType::Boolean => Ok(Some(1)),
DocumentPropertyType::Date => Ok(Some(8)),
DocumentPropertyType::Object(sub_fields) => sub_fields
.iter()
.map(|(_, sub_field)| sub_field.property_type.min_byte_size())
.map(|(_, sub_field)| sub_field.property_type.min_byte_size(platform_version))
.sum(),
DocumentPropertyType::Array(_) => None,
DocumentPropertyType::VariableTypeArray(_) => None,
DocumentPropertyType::Identifier => Some(32),
DocumentPropertyType::Array(_) => Ok(None),
DocumentPropertyType::VariableTypeArray(_) => Ok(None),
DocumentPropertyType::Identifier => Ok(Some(32)),
}
}

pub fn max_byte_size(&self) -> Option<u16> {
pub fn max_byte_size(
&self,
platform_version: &PlatformVersion,
) -> Result<Option<u16>, ProtocolError> {
match self {
DocumentPropertyType::U128 => Some(16),
DocumentPropertyType::I128 => Some(16),
DocumentPropertyType::U64 => Some(8),
DocumentPropertyType::I64 => Some(8),
DocumentPropertyType::U32 => Some(4),
DocumentPropertyType::I32 => Some(4),
DocumentPropertyType::U16 => Some(2),
DocumentPropertyType::I16 => Some(2),
DocumentPropertyType::U8 => Some(1),
DocumentPropertyType::I8 => Some(1),
DocumentPropertyType::F64 => Some(8),
DocumentPropertyType::U128 => Ok(Some(16)),
DocumentPropertyType::I128 => Ok(Some(16)),
DocumentPropertyType::U64 => Ok(Some(8)),
DocumentPropertyType::I64 => Ok(Some(8)),
DocumentPropertyType::U32 => Ok(Some(4)),
DocumentPropertyType::I32 => Ok(Some(4)),
DocumentPropertyType::U16 => Ok(Some(2)),
DocumentPropertyType::I16 => Ok(Some(2)),
DocumentPropertyType::U8 => Ok(Some(1)),
DocumentPropertyType::I8 => Ok(Some(1)),
DocumentPropertyType::F64 => Ok(Some(8)),
DocumentPropertyType::String(sizes) => match sizes.max_length {
None => Some(u16::MAX),
Some(size) => Some(size * 4),
None => Ok(Some(u16::MAX)),
Some(size) => {
if platform_version.protocol_version > 8 {
match size.checked_mul(4) {
Some(mul) => Ok(Some(mul)),
None => Err(ProtocolError::Overflow("max_byte_size overflow")),
}
} else {
Ok(Some(size.wrapping_mul(4)))
}
}
},
DocumentPropertyType::ByteArray(sizes) => match sizes.max_size {
None => Some(u16::MAX),
Some(size) => Some(size),
None => Ok(Some(u16::MAX)),
Some(size) => Ok(Some(size)),
},
DocumentPropertyType::Boolean => Some(1),
DocumentPropertyType::Date => Some(8),
DocumentPropertyType::Boolean => Ok(Some(1)),
DocumentPropertyType::Date => Ok(Some(8)),
DocumentPropertyType::Object(sub_fields) => sub_fields
.iter()
.map(|(_, sub_field)| sub_field.property_type.max_byte_size())
.map(|(_, sub_field)| sub_field.property_type.max_byte_size(platform_version))
.sum(),
DocumentPropertyType::Array(_) => None,
DocumentPropertyType::VariableTypeArray(_) => None,
DocumentPropertyType::Identifier => Some(32),
DocumentPropertyType::Array(_) => Ok(None),
DocumentPropertyType::VariableTypeArray(_) => Ok(None),
DocumentPropertyType::Identifier => Ok(Some(32)),
}
}

Expand Down Expand Up @@ -259,60 +284,66 @@ impl DocumentPropertyType {
}

/// The middle size rounded down halfway between min and max size
pub fn middle_size(&self) -> Option<u16> {
match self {
DocumentPropertyType::Array(_) | DocumentPropertyType::VariableTypeArray(_) => {
return None
}
_ => {}
pub fn middle_size(&self, platform_version: &PlatformVersion) -> Option<u16> {
let min_size = self.min_size()?;
let max_size = self.max_size()?;
if platform_version.protocol_version > 8 {
Some(((min_size as u32 + max_size as u32) / 2) as u16)
} else {
Some(min_size.wrapping_add(max_size) / 2)
}
let min_size = self.min_size().unwrap();
let max_size = self.max_size().unwrap();
Some((min_size + max_size) / 2)
}

/// The middle size rounded up halfway between min and max size
pub fn middle_size_ceil(&self) -> Option<u16> {
match self {
DocumentPropertyType::Array(_) | DocumentPropertyType::VariableTypeArray(_) => {
return None
}
_ => {}
pub fn middle_size_ceil(&self, platform_version: &PlatformVersion) -> Option<u16> {
let min_size = self.min_size()?;
let max_size = self.max_size()?;
if platform_version.protocol_version > 8 {
Some(((min_size as u32 + max_size as u32 + 1) / 2) as u16)
} else {
Some(min_size.wrapping_add(max_size).wrapping_add(1) / 2)
}
let min_size = self.min_size().unwrap();
let max_size = self.max_size().unwrap();
Some((min_size + max_size + 1) / 2)
}

/// The middle size rounded down halfway between min and max byte size
pub fn middle_byte_size(&self) -> Option<u16> {
match self {
DocumentPropertyType::Array(_) | DocumentPropertyType::VariableTypeArray(_) => {
return None
}
_ => {}
pub fn middle_byte_size(
&self,
platform_version: &PlatformVersion,
) -> Result<Option<u16>, ProtocolError> {
let Some(min_size) = self.min_byte_size(platform_version)? else {
return Ok(None);
};
let Some(max_size) = self.max_byte_size(platform_version)? else {
return Ok(None);
};
if platform_version.protocol_version > 8 {
Ok(Some(((min_size as u32 + max_size as u32) / 2) as u16))
} else {
Ok(Some(min_size.wrapping_add(max_size) / 2))
}
let min_size = self.min_byte_size().unwrap();
let max_size = self.max_byte_size().unwrap();
Some((min_size + max_size) / 2)
}

/// The middle size rounded up halfway between min and max byte size
pub fn middle_byte_size_ceil(&self) -> Option<u16> {
match self {
DocumentPropertyType::Array(_) | DocumentPropertyType::VariableTypeArray(_) => {
return None
}
_ => {}
pub fn middle_byte_size_ceil(
&self,
platform_version: &PlatformVersion,
) -> Result<Option<u16>, ProtocolError> {
let Some(min_size) = self.min_byte_size(platform_version)? else {
return Ok(None);
};
let Some(max_size) = self.max_byte_size(platform_version)? else {
return Ok(None);
};
if platform_version.protocol_version > 8 {
Ok(Some(((min_size as u32 + max_size as u32 + 1) / 2) as u16))
} else {
Ok(Some(min_size.wrapping_add(max_size).wrapping_add(1) / 2))
}
let min_size = self.min_byte_size().unwrap() as u32;
let max_size = self.max_byte_size().unwrap() as u32;
Some(((min_size + max_size + 1) / 2) as u16)
}

pub fn random_size(&self, rng: &mut StdRng) -> u16 {
let min_size = self.min_size().unwrap();
let max_size = self.max_size().unwrap();
let min_size = self.min_size().unwrap_or_default();
let max_size = self.max_size().unwrap_or_default();
rng.gen_range(min_size..=max_size)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl Drive {
let document_top_field_estimated_size = document_and_contract_info
.owned_document_info
.document_info
.get_estimated_size_for_document_type(name, document_type)?;
.get_estimated_size_for_document_type(name, document_type, platform_version)?;

if document_top_field_estimated_size > u8::MAX as u16 {
return Err(Error::Fee(FeeError::Overflow(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl Drive {
let document_top_field_estimated_size = document_and_contract_info
.owned_document_info
.document_info
.get_estimated_size_for_document_type(name, document_type)?;
.get_estimated_size_for_document_type(name, document_type, platform_version)?;

if document_top_field_estimated_size > u8::MAX as u16 {
return Err(Error::Fee(FeeError::Overflow(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ impl Drive {
let document_top_field_estimated_size = document_and_contract_info
.owned_document_info
.document_info
.get_estimated_size_for_document_type(name, document_type)?;
.get_estimated_size_for_document_type(name, document_type, platform_version)?;

if document_top_field_estimated_size > u8::MAX as u16 {
return Err(Error::Fee(FeeError::Overflow(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl Drive {
let document_top_field_estimated_size = document_and_contract_info
.owned_document_info
.document_info
.get_estimated_size_for_document_type(name, document_type)?;
.get_estimated_size_for_document_type(name, document_type, platform_version)?;

if document_top_field_estimated_size > u8::MAX as u16 {
return Err(Error::Fee(FeeError::Overflow(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl Drive {
let document_top_field_estimated_size = document_and_contract_info
.owned_document_info
.document_info
.get_estimated_size_for_document_type(name, document_type)?;
.get_estimated_size_for_document_type(name, document_type, platform_version)?;

if document_top_field_estimated_size > u8::MAX as u16 {
return Err(Error::Fee(FeeError::Overflow(
Expand Down
Loading