Skip to content

Commit

Permalink
fix: contested unique indexes can only be on non mutable document types
Browse files Browse the repository at this point in the history
  • Loading branch information
QuantumExplorer committed Jun 16, 2024
1 parent 4dd34e2 commit d82025a
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use std::collections::HashSet;
use std::collections::{BTreeMap, BTreeSet};
use std::convert::TryInto;

use crate::consensus::basic::data_contract::ContestedUniqueIndexOnMutableDocumentTypeError;
#[cfg(any(test, feature = "validation"))]
use crate::consensus::basic::data_contract::InvalidDocumentTypeNameError;
#[cfg(feature = "validation")]
Expand Down Expand Up @@ -51,8 +52,6 @@ use crate::version::PlatformVersion;
use crate::ProtocolError;
use platform_value::btreemap_extensions::BTreeValueMapHelper;
use platform_value::{Identifier, Value};

const UNIQUE_INDEX_LIMIT_V0: usize = 16;
const NOT_ALLOWED_SYSTEM_PROPERTIES: [&str; 1] = ["$id"];

const SYSTEM_PROPERTIES: [&str; 11] = [
Expand Down Expand Up @@ -307,6 +306,9 @@ impl DocumentTypeV0 {
#[cfg(feature = "validation")]
let mut unique_indices_count = 0;

#[cfg(feature = "validation")]
let mut contested_indices_count = 0;

let indices: BTreeMap<String, Index> = index_values
.map(|index_values| {
index_values
Expand All @@ -332,11 +334,56 @@ impl DocumentTypeV0 {
// so we need to limit their number to prevent of spikes and DoS attacks
if index.unique {
unique_indices_count += 1;
if unique_indices_count > UNIQUE_INDEX_LIMIT_V0 {
if unique_indices_count
> platform_version
.dpp
.validation
.document_type
.unique_index_limit
{
return Err(ProtocolError::ConsensusError(Box::new(
UniqueIndicesLimitReachedError::new(
name.to_string(),
UNIQUE_INDEX_LIMIT_V0,
platform_version
.dpp
.validation
.document_type
.unique_index_limit,
false,
)
.into(),
)));
}
}

if index.contested_index.is_some() {
contested_indices_count += 1;
if contested_indices_count
> platform_version
.dpp
.validation
.document_type
.contested_index_limit
{
return Err(ProtocolError::ConsensusError(Box::new(
UniqueIndicesLimitReachedError::new(
name.to_string(),
platform_version
.dpp
.validation
.document_type
.contested_index_limit,
true,
)
.into(),
)));
}

if documents_mutable {
return Err(ProtocolError::ConsensusError(Box::new(
ContestedUniqueIndexOnMutableDocumentTypeError::new(
name.to_string(),
index.name,
)
.into(),
)));
Expand Down
14 changes: 9 additions & 5 deletions packages/rs-dpp/src/errors/consensus/basic/basic_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ use crate::consensus::basic::data_contract::data_contract_max_depth_exceed_error
#[cfg(feature = "json-schema-validation")]
use crate::consensus::basic::data_contract::InvalidJsonSchemaRefError;
use crate::consensus::basic::data_contract::{
DataContractHaveNewUniqueIndexError, DataContractImmutablePropertiesUpdateError,
DataContractInvalidIndexDefinitionUpdateError, DataContractUniqueIndicesChangedError,
DuplicateIndexError, DuplicateIndexNameError, IncompatibleDataContractSchemaError,
IncompatibleDocumentTypeSchemaError, IncompatibleRe2PatternError, InvalidCompoundIndexError,
InvalidDataContractIdError, InvalidDataContractVersionError, InvalidDocumentTypeNameError,
ContestedUniqueIndexOnMutableDocumentTypeError, DataContractHaveNewUniqueIndexError,
DataContractImmutablePropertiesUpdateError, DataContractInvalidIndexDefinitionUpdateError,
DataContractUniqueIndicesChangedError, DuplicateIndexError, DuplicateIndexNameError,
IncompatibleDataContractSchemaError, IncompatibleDocumentTypeSchemaError,
IncompatibleRe2PatternError, InvalidCompoundIndexError, InvalidDataContractIdError,
InvalidDataContractVersionError, InvalidDocumentTypeNameError,
InvalidDocumentTypeRequiredSecurityLevelError, InvalidIndexPropertyTypeError,
InvalidIndexedPropertyConstraintError, SystemPropertyIndexAlreadyPresentError,
UndefinedIndexPropertyError, UniqueIndicesLimitReachedError,
Expand Down Expand Up @@ -376,6 +377,9 @@ pub enum BasicError {
#[error(transparent)]
IncompatibleDocumentTypeSchemaError(IncompatibleDocumentTypeSchemaError),

#[error(transparent)]
ContestedUniqueIndexOnMutableDocumentTypeError(ContestedUniqueIndexOnMutableDocumentTypeError),

#[error(transparent)]
OverflowError(OverflowError),
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use crate::consensus::basic::BasicError;
use crate::consensus::ConsensusError;
use crate::errors::ProtocolError;
use bincode::{Decode, Encode};
use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
use thiserror::Error;

#[derive(
Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize,
)]
#[error(
"Document type '{document_type}' has a contested unique index '{contested_unique_index_name}'"
)]
#[platform_serialize(unversioned)]
pub struct ContestedUniqueIndexOnMutableDocumentTypeError {
/*
DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION
*/
document_type: String,
contested_unique_index_name: String,
}

impl ContestedUniqueIndexOnMutableDocumentTypeError {
pub fn new(document_type: String, contested_unique_index_name: String) -> Self {
Self {
document_type,
contested_unique_index_name,
}
}

pub fn document_type(&self) -> &str {
&self.document_type
}

pub fn contested_unique_index_name(&self) -> &str {
&self.contested_unique_index_name
}
}

impl From<ContestedUniqueIndexOnMutableDocumentTypeError> for ConsensusError {
fn from(err: ContestedUniqueIndexOnMutableDocumentTypeError) -> Self {
Self::BasicError(BasicError::ContestedUniqueIndexOnMutableDocumentTypeError(
err,
))
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod contested_unique_index_on_mutable_document_type_error;
mod data_contract_have_new_unique_index_error;
mod data_contract_immutable_properties_update_error;
mod data_contract_invalid_index_definition_update_error;
Expand Down Expand Up @@ -49,6 +50,7 @@ pub use system_property_index_already_present_error::*;
pub use undefined_index_property_error::*;
pub use unique_indices_limit_reached_error::*;

pub use contested_unique_index_on_mutable_document_type_error::*;
pub use incompatible_document_type_schema_error::*;
pub use invalid_document_type_name_error::*;
pub use unknown_document_creation_restriction_mode_error::*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use thiserror::Error;
#[derive(
Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize,
)]
#[error("'{document_type}' document has more than '{index_limit}' unique indexes")]
#[error("'{document_type}' document has more than '{index_limit}' unique indexes (contested is {is_contested_limit})")]
#[platform_serialize(unversioned)]
pub struct UniqueIndicesLimitReachedError {
/*
Expand All @@ -17,23 +17,29 @@ pub struct UniqueIndicesLimitReachedError {
*/
document_type: String,
index_limit: usize,
index_limit: u16,
is_contested_limit: bool,
}

impl UniqueIndicesLimitReachedError {
pub fn new(document_type: String, index_limit: usize) -> Self {
pub fn new(document_type: String, index_limit: u16, is_contested_limit: bool) -> Self {
Self {
document_type,
index_limit,
is_contested_limit,
}
}

pub fn document_type(&self) -> &str {
&self.document_type
}
pub fn index_limit(&self) -> usize {
pub fn index_limit(&self) -> u16 {
self.index_limit
}

pub fn is_contested_limit(&self) -> bool {
self.is_contested_limit
}
}

impl From<UniqueIndicesLimitReachedError> for ConsensusError {
Expand Down
2 changes: 2 additions & 0 deletions packages/rs-platform-version/src/version/dpp_versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ pub struct VotingValidationVersions {
#[derive(Clone, Debug, Default)]
pub struct DocumentTypeValidationVersions {
pub validate_update: FeatureVersion,
pub unique_index_limit: u16,
pub contested_index_limit: u16,
}

#[derive(Clone, Debug, Default)]
Expand Down

0 comments on commit d82025a

Please sign in to comment.