From 5a859c14d8dc5306a376027f39d254d499481aff Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 23 Jul 2024 06:34:20 +0700 Subject: [PATCH] work done --- .../class_methods/try_from_schema/v0/mod.rs | 39 +- .../document_type/index_level/mod.rs | 29 +- .../src/data_contract/document_type/mod.rs | 1 + .../rs-dpp/src/document/accessors/v0/mod.rs | 7 + .../src/errors/consensus/basic/basic_error.rs | 14 +- ...ed_unique_index_with_unique_index_error.rs | 10 +- .../consensus/basic/data_contract/mod.rs | 2 +- .../methods/mod.rs | 1 + .../methods/v0/mod.rs | 1 + .../v0/v0_methods.rs | 1 + .../create_genesis_state/v0/mod.rs | 4 +- .../data_contract_create/mod.rs | 130 ++- .../state_transitions/documents_batch/mod.rs | 890 +++++++++++++++++- .../state_transitions/masternode_vote/mod.rs | 428 ++++++--- .../state_transition/state_transitions/mod.rs | 339 ++++++- .../tests/strategy_tests/main.rs | 6 +- .../tests/strategy_tests/voting_tests.rs | 12 +- ...d-unique-index-and-other-unique-index.json | 2 +- ...with-contract-id-null-searchable-true.json | 185 ++++ ...ntested-unique-index-with-contract-id.json | 187 ++++ .../dpns-contract-contested-unique-index.json | 2 +- packages/rs-drive/src/config.rs | 3 +- .../v0/mod.rs | 9 +- .../mod.rs | 2 + .../v0/mod.rs | 4 + .../v0/mod.rs | 2 + .../mod.rs | 6 +- .../v0/mod.rs | 13 +- .../mod.rs | 2 + .../v0/mod.rs | 6 +- .../v0/mod.rs | 2 + .../mod.rs | 6 +- .../v0/mod.rs | 10 +- .../rs-drive/src/drive/document/insert/mod.rs | 4 +- .../mod.rs | 1 - .../v0/mod.rs | 7 +- .../shared/shared_estimation_costs/mod.rs | 2 +- .../rs-drive/src/util/test_helpers/mod.rs | 2 +- packages/rs-drive/tests/query_tests.rs | 50 +- .../dpns-contract-label-not-required.json | 4 +- .../dpns/dpns-contract-update-v2-test.json | 4 +- .../contract/dpns/dpns-contract.json | 4 +- .../src/version/drive_versions.rs | 3 +- 43 files changed, 2184 insertions(+), 252 deletions(-) create mode 100644 packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id-null-searchable-true.json create mode 100644 packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id.json diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs index 8694dd7d00a..cab211ddc31 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs @@ -23,6 +23,8 @@ use std::convert::TryInto; #[cfg(feature = "validation")] use crate::consensus::basic::data_contract::ContestedUniqueIndexOnMutableDocumentTypeError; +#[cfg(feature = "validation")] +use crate::consensus::basic::data_contract::ContestedUniqueIndexWithUniqueIndexError; #[cfg(any(test, feature = "validation"))] use crate::consensus::basic::data_contract::InvalidDocumentTypeNameError; #[cfg(feature = "validation")] @@ -50,7 +52,6 @@ use crate::version::PlatformVersion; use crate::ProtocolError; use platform_value::btreemap_extensions::BTreeValueMapHelper; use platform_value::{Identifier, Value}; -use crate::consensus::basic::data_contract::ContestedUniqueIndexWithUniqueIndexError; const NOT_ALLOWED_SYSTEM_PROPERTIES: [&str; 1] = ["$id"]; @@ -285,10 +286,10 @@ impl DocumentTypeV0 { let mut unique_indices_count = 0; #[cfg(feature = "validation")] - let mut last_non_contested_unique_index_name : Option = None; + let mut last_non_contested_unique_index_name: Option = None; #[cfg(feature = "validation")] - let mut last_contested_unique_index_name : Option = None; + let mut last_contested_unique_index_name: Option = None; #[cfg(feature = "validation")] let mut contested_indices_count = 0; @@ -339,17 +340,17 @@ impl DocumentTypeV0 { ))); } - if let Some(last_contested_unique_index_name) = last_contested_unique_index_name.as_ref() { - + if let Some(last_contested_unique_index_name) = + last_contested_unique_index_name.as_ref() + { return Err(ProtocolError::ConsensusError(Box::new( ContestedUniqueIndexWithUniqueIndexError::new( name.to_string(), last_contested_unique_index_name.clone(), index.name, ) - .into(), + .into(), ))); - } if index.contested_index.is_none() { @@ -379,18 +380,18 @@ impl DocumentTypeV0 { .into(), ))); } - - if let Some(last_unique_index_name) = last_non_contested_unique_index_name.as_ref() { - - return Err(ProtocolError::ConsensusError(Box::new( - ContestedUniqueIndexWithUniqueIndexError::new( - name.to_string(), - index.name, - last_unique_index_name.clone() - ) - .into(), - ))); - + + if let Some(last_unique_index_name) = + last_non_contested_unique_index_name.as_ref() + { + return Err(ProtocolError::ConsensusError(Box::new( + ContestedUniqueIndexWithUniqueIndexError::new( + name.to_string(), + index.name, + last_unique_index_name.clone(), + ) + .into(), + ))); } if documents_mutable { diff --git a/packages/rs-dpp/src/data_contract/document_type/index_level/mod.rs b/packages/rs-dpp/src/data_contract/document_type/index_level/mod.rs index 61548ac3b22..e2c6a132750 100644 --- a/packages/rs-dpp/src/data_contract/document_type/index_level/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/index_level/mod.rs @@ -29,6 +29,14 @@ pub enum IndexType { ContestedResourceIndex, } +#[derive(Debug, PartialEq, Copy, Clone)] +pub struct IndexLevelTypeInfo { + /// should we insert if all fields up to here are null + pub should_insert_with_all_null: bool, + /// The index type + pub index_type: IndexType, +} + impl IndexType { pub fn is_unique(&self) -> bool { match self { @@ -39,12 +47,14 @@ impl IndexType { } } +pub type ShouldInsertWithAllNull = bool; + #[derive(Debug, PartialEq, Clone)] pub struct IndexLevel { /// the lower index levels from this level sub_index_levels: BTreeMap, /// did an index terminate at this level - has_index_with_type: Option, + has_index_with_type: Option, /// unique level identifier level_identifier: u64, } @@ -58,7 +68,7 @@ impl IndexLevel { &self.sub_index_levels } - pub fn has_index_with_type(&self) -> Option { + pub fn has_index_with_type(&self) -> Option { self.has_index_with_type } @@ -199,7 +209,12 @@ impl IndexLevel { NonUniqueIndex }; - current_level.has_index_with_type = Some(index_type); + // if things are null searchable that means we should insert with all null + + current_level.has_index_with_type = Some(IndexLevelTypeInfo { + should_insert_with_all_null: index.null_searchable, + index_type, + }); } } } @@ -305,7 +320,7 @@ mod tests { }], unique: false, null_searchable: true, - contested_index: None, + contested_index: None, }, Index { name: "test2".to_string(), @@ -315,7 +330,7 @@ mod tests { }], unique: false, null_searchable: true, - contested_index: None, + contested_index: None, }, ]; @@ -351,7 +366,7 @@ mod tests { }], unique: false, null_searchable: true, - contested_index: None, + contested_index: None, }, Index { name: "test2".to_string(), @@ -361,7 +376,7 @@ mod tests { }], unique: false, null_searchable: true, - contested_index: None, + contested_index: None, }, ]; diff --git a/packages/rs-dpp/src/data_contract/document_type/mod.rs b/packages/rs-dpp/src/data_contract/document_type/mod.rs index da809c01a15..182bfe881a8 100644 --- a/packages/rs-dpp/src/data_contract/document_type/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/mod.rs @@ -7,6 +7,7 @@ pub mod methods; pub use index::*; mod index_level; pub use index_level::IndexLevel; +pub use index_level::IndexLevelTypeInfo; pub use index_level::IndexType; #[cfg(feature = "random-documents")] diff --git a/packages/rs-dpp/src/document/accessors/v0/mod.rs b/packages/rs-dpp/src/document/accessors/v0/mod.rs index e8274af2219..671ac05c4a6 100644 --- a/packages/rs-dpp/src/document/accessors/v0/mod.rs +++ b/packages/rs-dpp/src/document/accessors/v0/mod.rs @@ -79,6 +79,13 @@ pub trait DocumentV0Setters: DocumentV0Getters { } } + /// Removes the value under the given path. + /// The path supports syntax from the `lodash` JS library. Example: "root.people[0].name". + /// If parents are not present, they will be automatically created. + fn remove(&mut self, path: &str) -> Option { + self.properties_mut().remove(path) + } + /// Sets a `u8` value for the specified property name. fn set_u8(&mut self, property_name: &str, value: u8) { self.properties_mut() diff --git a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs index df501b50391..e2f2f25012e 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -6,7 +6,19 @@ use thiserror::Error; use crate::consensus::basic::data_contract::data_contract_max_depth_exceed_error::DataContractMaxDepthExceedError; #[cfg(feature = "json-schema-validation")] use crate::consensus::basic::data_contract::InvalidJsonSchemaRefError; -use crate::consensus::basic::data_contract::{ContestedUniqueIndexOnMutableDocumentTypeError, DataContractHaveNewUniqueIndexError, DataContractImmutablePropertiesUpdateError, DataContractInvalidIndexDefinitionUpdateError, DataContractUniqueIndicesChangedError, DuplicateIndexError, DuplicateIndexNameError, IncompatibleDataContractSchemaError, IncompatibleDocumentTypeSchemaError, IncompatibleRe2PatternError, InvalidCompoundIndexError, InvalidDataContractIdError, InvalidDataContractVersionError, InvalidDocumentTypeNameError, InvalidDocumentTypeRequiredSecurityLevelError, InvalidIndexPropertyTypeError, InvalidIndexedPropertyConstraintError, SystemPropertyIndexAlreadyPresentError, UndefinedIndexPropertyError, UniqueIndicesLimitReachedError, UnknownDocumentCreationRestrictionModeError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError, ContestedUniqueIndexWithUniqueIndexError}; +use crate::consensus::basic::data_contract::{ + ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, + DataContractHaveNewUniqueIndexError, DataContractImmutablePropertiesUpdateError, + DataContractInvalidIndexDefinitionUpdateError, DataContractUniqueIndicesChangedError, + DuplicateIndexError, DuplicateIndexNameError, IncompatibleDataContractSchemaError, + IncompatibleDocumentTypeSchemaError, IncompatibleRe2PatternError, InvalidCompoundIndexError, + InvalidDataContractIdError, InvalidDataContractVersionError, InvalidDocumentTypeNameError, + InvalidDocumentTypeRequiredSecurityLevelError, InvalidIndexPropertyTypeError, + InvalidIndexedPropertyConstraintError, SystemPropertyIndexAlreadyPresentError, + UndefinedIndexPropertyError, UniqueIndicesLimitReachedError, + UnknownDocumentCreationRestrictionModeError, UnknownSecurityLevelError, + UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError, +}; use crate::consensus::basic::decode::{ ProtocolVersionParsingError, SerializedObjectParsingError, VersionError, }; diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/contested_unique_index_with_unique_index_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/contested_unique_index_with_unique_index_error.rs index dcd1e8cf79a..cfaa8b9fe12 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/data_contract/contested_unique_index_with_unique_index_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/contested_unique_index_with_unique_index_error.rs @@ -24,7 +24,11 @@ pub struct ContestedUniqueIndexWithUniqueIndexError { } impl ContestedUniqueIndexWithUniqueIndexError { - pub fn new(document_type: String, contested_unique_index_name: String, unique_index_name: String) -> Self { + pub fn new( + document_type: String, + contested_unique_index_name: String, + unique_index_name: String, + ) -> Self { Self { document_type, contested_unique_index_name, @@ -47,8 +51,6 @@ impl ContestedUniqueIndexWithUniqueIndexError { impl From for ConsensusError { fn from(err: ContestedUniqueIndexWithUniqueIndexError) -> Self { - Self::BasicError(BasicError::ContestedUniqueIndexWithUniqueIndexError( - err, - )) + Self::BasicError(BasicError::ContestedUniqueIndexWithUniqueIndexError(err)) } } diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs index 14eda176c5d..9e7bedab0d9 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs @@ -1,4 +1,5 @@ mod contested_unique_index_on_mutable_document_type_error; +mod contested_unique_index_with_unique_index_error; mod data_contract_have_new_unique_index_error; mod data_contract_immutable_properties_update_error; mod data_contract_invalid_index_definition_update_error; @@ -27,7 +28,6 @@ mod unknown_security_level_error; mod unknown_storage_key_requirements_error; mod unknown_trade_mode_error; mod unknown_transferable_type_error; -mod contested_unique_index_with_unique_index_error; pub use data_contract_have_new_unique_index_error::*; pub use data_contract_immutable_properties_update_error::*; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/mod.rs index a149b7d0512..96b2654046a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/mod.rs @@ -12,6 +12,7 @@ use crate::identity::Identity; #[cfg(feature = "state-transition-signing")] use crate::identity::core_script::CoreScript; +#[cfg(feature = "state-transition-signing")] use crate::identity::IdentityPublicKey; #[cfg(feature = "state-transition-signing")] use crate::prelude::{IdentityNonce, UserFeeIncrease}; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/v0/mod.rs index 6fd9bbeccec..0341f253f1f 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/methods/v0/mod.rs @@ -4,6 +4,7 @@ use crate::identity::core_script::CoreScript; use crate::identity::signer::Signer; #[cfg(feature = "state-transition-signing")] use crate::identity::Identity; +#[cfg(feature = "state-transition-signing")] use crate::identity::IdentityPublicKey; #[cfg(feature = "state-transition-signing")] use crate::prelude::{IdentityNonce, UserFeeIncrease}; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v0/v0_methods.rs index 65e63b3bd8f..ca9d0ecec96 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_withdrawal_transition/v0/v0_methods.rs @@ -4,6 +4,7 @@ use crate::identity::accessors::IdentityGettersV0; use crate::identity::core_script::CoreScript; #[cfg(feature = "state-transition-signing")] use crate::identity::signer::Signer; +#[cfg(feature = "state-transition-signing")] use crate::identity::IdentityPublicKey; #[cfg(feature = "state-transition-signing")] use crate::identity::{Identity, KeyType, Purpose, SecurityLevel}; diff --git a/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v0/mod.rs index 412ef546372..bdf70d325ee 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v0/mod.rs @@ -295,8 +295,8 @@ mod tests { assert_eq!( root_hash, [ - 37, 162, 178, 238, 218, 180, 162, 24, 34, 199, 191, 38, 43, 39, 197, 101, 133, - 229, 130, 128, 20, 135, 168, 126, 219, 15, 235, 112, 139, 89, 187, 115 + 248, 90, 202, 206, 96, 59, 148, 53, 168, 193, 17, 125, 14, 157, 48, 42, 236, + 180, 135, 136, 12, 89, 15, 254, 72, 134, 239, 246, 242, 126, 239, 52 ] ) } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs index 54b127bdcfe..8805afb60fd 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs @@ -141,20 +141,20 @@ impl StateTransitionStateValidationV0 for DataContractCreateTransition { #[cfg(test)] mod tests { - use assert_matches::assert_matches; use crate::execution::validation::state_transition::state_transitions::tests::setup_identity; + use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; + use crate::test::helpers::setup::TestPlatformBuilder; + use assert_matches::assert_matches; use dpp::block::block_info::BlockInfo; use dpp::consensus::basic::BasicError; use dpp::consensus::ConsensusError; use dpp::dash_to_credits; use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; + use dpp::serialization::PlatformSerializable; + use dpp::state_transition::data_contract_create_transition::methods::DataContractCreateTransitionMethodsV0; use dpp::state_transition::data_contract_create_transition::DataContractCreateTransition; use dpp::tests::json_document::json_document_to_contract_with_ids; use platform_version::version::PlatformVersion; - use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; - use crate::test::helpers::setup::TestPlatformBuilder; - use dpp::state_transition::data_contract_create_transition::methods::DataContractCreateTransitionMethodsV0; - use dpp::serialization::PlatformSerializable; #[test] fn test_data_contract_creation_with_contested_unique_index() { @@ -174,19 +174,79 @@ mod tests { false, //no need to validate the data contracts in tests for drive platform_version, ) - .expect("expected to get json based contract"); + .expect("expected to get json based contract"); + + let data_contract_create_transition = DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); - let data_contract_create_transition = - DataContractCreateTransition::new_from_data_contract( - data_contract, - 1, - &identity.into_partial_identity_info(), - key.id(), - &signer, + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, platform_version, - None, ) - .expect("expect to create documents batch transition"); + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } + + #[test] + fn test_dpns_contract_creation_with_contract_id_non_contested() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + let data_contract_create_transition = DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); let data_contract_create_serialized_transition = data_contract_create_transition .serialize_to_bytes() @@ -206,9 +266,9 @@ mod tests { .expect("expected to process state transition"); assert_matches!( - processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::SuccessfulExecution(_, _)] - ); + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] + ); platform .drive @@ -237,18 +297,17 @@ mod tests { platform_version, ) .expect("expected to get json based contract"); - - let data_contract_create_transition = - DataContractCreateTransition::new_from_data_contract( - data_contract, - 1, - &identity.into_partial_identity_info(), - key.id(), - &signer, - platform_version, - None, - ) - .expect("expect to create documents batch transition"); + + let data_contract_create_transition = DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); let data_contract_create_serialized_transition = data_contract_create_transition .serialize_to_bytes() @@ -266,13 +325,14 @@ mod tests { platform_version, ) .expect("expected to process state transition"); - - assert_matches!( - processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError(ConsensusError::BasicError(BasicError::ContestedUniqueIndexWithUniqueIndexError(_)), _)] - ); + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError(BasicError::ContestedUniqueIndexWithUniqueIndexError(_)), + _ + )] + ); platform .drive diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/mod.rs index 8db100c4dab..fc64b77912b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/mod.rs @@ -292,7 +292,7 @@ mod tests { use drive::query::vote_poll_vote_state_query::ContestedDocumentVotePollDriveQueryResultType::DocumentsAndVoteTally; use drive::query::vote_poll_vote_state_query::ResolvedContestedDocumentVotePollDriveQuery; use drive::util::test_helpers::setup_contract; - use crate::execution::validation::state_transition::state_transitions::tests::{add_contender_to_dpns_name_contest, create_dpns_name_contest, create_dpns_name_contest_give_key_info, fast_forward_to_block, perform_votes_multi}; + use crate::execution::validation::state_transition::state_transitions::tests::{add_contender_to_dpns_name_contest, create_dpns_identity_name_contest, create_dpns_name_contest_give_key_info, fast_forward_to_block, perform_votes_multi}; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult::PaidConsensusError; @@ -954,7 +954,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -1100,7 +1100,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -5420,4 +5420,888 @@ mod tests { ); } } + + mod dpns_tests { + use super::*; + use crate::execution::validation::state_transition::tests::setup_identity; + use crate::test::helpers::setup::TestPlatformBuilder; + use dpp::dash_to_credits; + use dpp::data_contract::document_type::random_document::{ + DocumentFieldFillSize, DocumentFieldFillType, + }; + use dpp::platform_value::Bytes32; + use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; + use dpp::util::hash::hash_double; + use drive::query::{InternalClauses, OrderClause, WhereClause, WhereOperator}; + use drive::util::test_helpers::setup_contract; + use indexmap::IndexMap; + use platform_version::version::PlatformVersion; + use rand::prelude::StdRng; + use rand::Rng; + use std::collections::BTreeMap; + + #[test] + fn test_dpns_contract_references_with_no_contested_unique_index() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity_1, signer_1, key_1) = + setup_identity(&mut platform, 958, dash_to_credits!(0.5)); + + let (identity_2, signer_2, key_2) = + setup_identity(&mut platform, 93, dash_to_credits!(0.5)); + + let (identity_3, signer_3, key_3) = + setup_identity(&mut platform, 98, dash_to_credits!(0.5)); + + let dashpay_contract = setup_contract( + &platform.drive, + "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json", + None, + None, + ); + + let card_game = setup_contract( + &platform.drive, + "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json", + None, + None, + ); + + let dpns_contract = setup_contract( + &platform.drive, + "tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id.json", + None, + None, + ); + + let preorder = dpns_contract + .document_type_for_name("preorder") + .expect("expected a profile document type"); + + assert!(!preorder.documents_mutable()); + assert!(preorder.documents_can_be_deleted()); + assert!(!preorder.documents_transferable().is_transferable()); + + let domain = dpns_contract + .document_type_for_name("domain") + .expect("expected a profile document type"); + + assert!(!domain.documents_mutable()); + // Deletion is disabled with data trigger + assert!(domain.documents_can_be_deleted()); + assert!(domain.documents_transferable().is_transferable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut preorder_document_1 = preorder + .random_document_with_identifier_and_entropy( + &mut rng, + identity_1.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut preorder_document_2 = preorder + .random_document_with_identifier_and_entropy( + &mut rng, + identity_2.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut preorder_document_3 = preorder + .random_document_with_identifier_and_entropy( + &mut rng, + identity_3.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut document_1 = domain + .random_document_with_identifier_and_entropy( + &mut rng, + identity_1.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut document_2 = domain + .random_document_with_identifier_and_entropy( + &mut rng, + identity_2.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut document_3 = domain + .random_document_with_identifier_and_entropy( + &mut rng, + identity_3.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document_1.set("parentDomainName", "dash".into()); + document_1.set("normalizedParentDomainName", "dash".into()); + document_1.set("label", "quantum123".into()); + document_1.set("normalizedLabel", "quantum123".into()); + document_1.set("records.contract", dashpay_contract.id().into()); + document_1.set("subdomainRules.allowSubdomains", false.into()); + + document_2.set("parentDomainName", "dash".into()); + document_2.set("normalizedParentDomainName", "dash".into()); + document_2.set("label", "van89".into()); + document_2.set("normalizedLabel", "van89".into()); + document_2.set("records.contract", card_game.id().into()); + document_2.set("subdomainRules.allowSubdomains", false.into()); + + document_3.set("parentDomainName", "dash".into()); + document_3.set("normalizedParentDomainName", "dash".into()); + document_3.set("label", "jazz65".into()); + document_3.set("normalizedLabel", "jazz65".into()); + document_3.set("records.identity", document_3.owner_id().into()); + document_3.set("subdomainRules.allowSubdomains", false.into()); + + let salt_1: [u8; 32] = rng.gen(); + let salt_2: [u8; 32] = rng.gen(); + let salt_3: [u8; 32] = rng.gen(); + + let mut salted_domain_buffer_1: Vec = vec![]; + salted_domain_buffer_1.extend(salt_1); + salted_domain_buffer_1.extend("quantum123.dash".as_bytes()); + + let salted_domain_hash_1 = hash_double(salted_domain_buffer_1); + + let mut salted_domain_buffer_2: Vec = vec![]; + salted_domain_buffer_2.extend(salt_2); + salted_domain_buffer_2.extend("van89.dash".as_bytes()); + + let salted_domain_hash_2 = hash_double(salted_domain_buffer_2); + + let mut salted_domain_buffer_3: Vec = vec![]; + salted_domain_buffer_3.extend(salt_3); + salted_domain_buffer_3.extend("jazz65.dash".as_bytes()); + + let salted_domain_hash_3 = hash_double(salted_domain_buffer_3); + + preorder_document_1.set("saltedDomainHash", salted_domain_hash_1.into()); + preorder_document_2.set("saltedDomainHash", salted_domain_hash_2.into()); + preorder_document_3.set("saltedDomainHash", salted_domain_hash_3.into()); + + document_1.set("preorderSalt", salt_1.into()); + document_2.set("preorderSalt", salt_2.into()); + document_3.set("preorderSalt", salt_3.into()); + + let documents_batch_create_preorder_transition_1 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + preorder_document_1, + preorder, + entropy.0, + &key_1, + 2, + 0, + &signer_1, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_preorder_transition_1 = + documents_batch_create_preorder_transition_1 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_preorder_transition_2 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + preorder_document_2, + preorder, + entropy.0, + &key_2, + 2, + 0, + &signer_2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_preorder_transition_2 = + documents_batch_create_preorder_transition_2 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_preorder_transition_3 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + preorder_document_3, + preorder, + entropy.0, + &key_3, + 2, + 0, + &signer_3, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_preorder_transition_3 = + documents_batch_create_preorder_transition_3 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_transition_1 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document_1, + domain, + entropy.0, + &key_1, + 3, + 0, + &signer_1, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition_1 = + documents_batch_create_transition_1 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_transition_2 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document_2, + domain, + entropy.0, + &key_2, + 3, + 0, + &signer_2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition_2 = + documents_batch_create_transition_2 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_transition_3 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document_3.clone(), + domain, + entropy.0, + &key_3, + 3, + 0, + &signer_3, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition_3 = + documents_batch_create_transition_3 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![ + documents_batch_create_serialized_preorder_transition_1.clone(), + documents_batch_create_serialized_preorder_transition_2.clone(), + documents_batch_create_serialized_preorder_transition_3.clone(), + ], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_eq!(processing_result.valid_count(), 3); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![ + documents_batch_create_serialized_transition_1.clone(), + documents_batch_create_serialized_transition_2.clone(), + documents_batch_create_serialized_transition_3.clone(), + ], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_eq!(processing_result.valid_count(), 3); + + let mut order_by = IndexMap::new(); + + order_by.insert( + "records.identity".to_string(), + OrderClause { + field: "records.identity".to_string(), + ascending: true, + }, + ); + + let drive_query = DriveDocumentQuery { + contract: &dpns_contract, + document_type: domain, + internal_clauses: InternalClauses { + primary_key_in_clause: None, + primary_key_equal_clause: None, + in_clause: None, + range_clause: Some(WhereClause { + field: "records.identity".to_string(), + operator: WhereOperator::LessThanOrEquals, + value: Value::Bytes32([255; 32]), + }), + equal_clauses: Default::default(), + }, + offset: None, + limit: None, + order_by, + start_at: None, + start_at_included: false, + block_time_ms: None, + }; + + let documents = platform + .drive + .query_documents(drive_query, None, false, None, None) + .expect("expected to get back documents") + .documents_owned(); + + assert!(documents + .get(0) + .expect("expected a document") + .is_equal_ignoring_time_based_fields(&document_3, platform_version) + .expect("expected to run is equal")); + + let drive_query = DriveDocumentQuery { + contract: &dpns_contract, + document_type: domain, + internal_clauses: InternalClauses { + primary_key_in_clause: None, + primary_key_equal_clause: None, + in_clause: None, + range_clause: None, + equal_clauses: BTreeMap::from([( + "records.identity".to_string(), + WhereClause { + field: "records.identity".to_string(), + operator: WhereOperator::Equal, + value: Value::Null, + }, + )]), + }, + offset: None, + limit: None, + order_by: Default::default(), + start_at: None, + start_at_included: false, + block_time_ms: None, + }; + + let documents = platform + .drive + .query_documents(drive_query, None, false, None, None) + .expect("expected to get back documents") + .documents_owned(); + + // This is normal because we set that we could not query on null + assert_eq!(documents.len(), 0); + } + + #[test] + fn test_dpns_contract_references_with_no_contested_unique_index_null_searchable_true() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity_1, signer_1, key_1) = + setup_identity(&mut platform, 958, dash_to_credits!(0.5)); + + let (identity_2, signer_2, key_2) = + setup_identity(&mut platform, 93, dash_to_credits!(0.5)); + + let (identity_3, signer_3, key_3) = + setup_identity(&mut platform, 98, dash_to_credits!(0.5)); + + let dashpay_contract = setup_contract( + &platform.drive, + "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json", + None, + None, + ); + + let card_game = setup_contract( + &platform.drive, + "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json", + None, + None, + ); + + let dpns_contract = setup_contract( + &platform.drive, + "tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id-null-searchable-true.json", + None, + None, + ); + + let preorder = dpns_contract + .document_type_for_name("preorder") + .expect("expected a profile document type"); + + assert!(!preorder.documents_mutable()); + assert!(preorder.documents_can_be_deleted()); + assert!(!preorder.documents_transferable().is_transferable()); + + let domain = dpns_contract + .document_type_for_name("domain") + .expect("expected a profile document type"); + + assert!(!domain.documents_mutable()); + // Deletion is disabled with data trigger + assert!(domain.documents_can_be_deleted()); + assert!(domain.documents_transferable().is_transferable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut preorder_document_1 = preorder + .random_document_with_identifier_and_entropy( + &mut rng, + identity_1.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut preorder_document_2 = preorder + .random_document_with_identifier_and_entropy( + &mut rng, + identity_2.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut preorder_document_3 = preorder + .random_document_with_identifier_and_entropy( + &mut rng, + identity_3.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut document_1 = domain + .random_document_with_identifier_and_entropy( + &mut rng, + identity_1.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut document_2 = domain + .random_document_with_identifier_and_entropy( + &mut rng, + identity_2.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut document_3 = domain + .random_document_with_identifier_and_entropy( + &mut rng, + identity_3.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document_1.set("parentDomainName", "dash".into()); + document_1.set("normalizedParentDomainName", "dash".into()); + document_1.set("label", "quantum123".into()); + document_1.set("normalizedLabel", "quantum123".into()); + document_1.set("records.contract", dashpay_contract.id().into()); + document_1.set("subdomainRules.allowSubdomains", false.into()); + + document_2.set("parentDomainName", "dash".into()); + document_2.set("normalizedParentDomainName", "dash".into()); + document_2.set("label", "van89".into()); + document_2.set("normalizedLabel", "van89".into()); + document_2.set("records.contract", card_game.id().into()); + document_2.set("subdomainRules.allowSubdomains", false.into()); + + document_3.set("parentDomainName", "dash".into()); + document_3.set("normalizedParentDomainName", "dash".into()); + document_3.set("label", "jazz65".into()); + document_3.set("normalizedLabel", "jazz65".into()); + document_3.set("records.identity", document_3.owner_id().into()); + document_3.set("subdomainRules.allowSubdomains", false.into()); + + let salt_1: [u8; 32] = rng.gen(); + let salt_2: [u8; 32] = rng.gen(); + let salt_3: [u8; 32] = rng.gen(); + + let mut salted_domain_buffer_1: Vec = vec![]; + salted_domain_buffer_1.extend(salt_1); + salted_domain_buffer_1.extend("quantum123.dash".as_bytes()); + + let salted_domain_hash_1 = hash_double(salted_domain_buffer_1); + + let mut salted_domain_buffer_2: Vec = vec![]; + salted_domain_buffer_2.extend(salt_2); + salted_domain_buffer_2.extend("van89.dash".as_bytes()); + + let salted_domain_hash_2 = hash_double(salted_domain_buffer_2); + + let mut salted_domain_buffer_3: Vec = vec![]; + salted_domain_buffer_3.extend(salt_3); + salted_domain_buffer_3.extend("jazz65.dash".as_bytes()); + + let salted_domain_hash_3 = hash_double(salted_domain_buffer_3); + + preorder_document_1.set("saltedDomainHash", salted_domain_hash_1.into()); + preorder_document_2.set("saltedDomainHash", salted_domain_hash_2.into()); + preorder_document_3.set("saltedDomainHash", salted_domain_hash_3.into()); + + document_1.set("preorderSalt", salt_1.into()); + document_2.set("preorderSalt", salt_2.into()); + document_3.set("preorderSalt", salt_3.into()); + + let documents_batch_create_preorder_transition_1 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + preorder_document_1, + preorder, + entropy.0, + &key_1, + 2, + 0, + &signer_1, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_preorder_transition_1 = + documents_batch_create_preorder_transition_1 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_preorder_transition_2 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + preorder_document_2, + preorder, + entropy.0, + &key_2, + 2, + 0, + &signer_2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_preorder_transition_2 = + documents_batch_create_preorder_transition_2 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_preorder_transition_3 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + preorder_document_3, + preorder, + entropy.0, + &key_3, + 2, + 0, + &signer_3, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_preorder_transition_3 = + documents_batch_create_preorder_transition_3 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_transition_1 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document_1, + domain, + entropy.0, + &key_1, + 3, + 0, + &signer_1, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition_1 = + documents_batch_create_transition_1 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_transition_2 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document_2, + domain, + entropy.0, + &key_2, + 3, + 0, + &signer_2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition_2 = + documents_batch_create_transition_2 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_transition_3 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document_3.clone(), + domain, + entropy.0, + &key_3, + 3, + 0, + &signer_3, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition_3 = + documents_batch_create_transition_3 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![ + documents_batch_create_serialized_preorder_transition_1.clone(), + documents_batch_create_serialized_preorder_transition_2.clone(), + documents_batch_create_serialized_preorder_transition_3.clone(), + ], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_eq!(processing_result.valid_count(), 3); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![ + documents_batch_create_serialized_transition_1.clone(), + documents_batch_create_serialized_transition_2.clone(), + documents_batch_create_serialized_transition_3.clone(), + ], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_eq!(processing_result.valid_count(), 3); + + let mut order_by = IndexMap::new(); + + order_by.insert( + "records.identity".to_string(), + OrderClause { + field: "records.identity".to_string(), + ascending: true, + }, + ); + + let drive_query = DriveDocumentQuery { + contract: &dpns_contract, + document_type: domain, + internal_clauses: InternalClauses { + primary_key_in_clause: None, + primary_key_equal_clause: None, + in_clause: None, + range_clause: Some(WhereClause { + field: "records.identity".to_string(), + operator: WhereOperator::LessThanOrEquals, + value: Value::Bytes32([255; 32]), + }), + equal_clauses: Default::default(), + }, + offset: None, + limit: None, + order_by, + start_at: None, + start_at_included: false, + block_time_ms: None, + }; + + let documents = platform + .drive + .query_documents(drive_query, None, false, None, None) + .expect("expected to get back documents") + .documents_owned(); + + // here we will get all 3 documents + assert_eq!(documents.len(), 3); + + let drive_query = DriveDocumentQuery { + contract: &dpns_contract, + document_type: domain, + internal_clauses: InternalClauses { + primary_key_in_clause: None, + primary_key_equal_clause: None, + in_clause: None, + range_clause: None, + equal_clauses: BTreeMap::from([( + "records.identity".to_string(), + WhereClause { + field: "records.identity".to_string(), + operator: WhereOperator::Equal, + value: Value::Null, + }, + )]), + }, + offset: None, + limit: None, + order_by: Default::default(), + start_at: None, + start_at_included: false, + block_time_ms: None, + }; + + let documents = platform + .drive + .query_documents(drive_query, None, false, None, None) + .expect("expected to get back documents") + .documents_owned(); + + assert_eq!(documents.len(), 2); + } + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/mod.rs index 6383ac871bc..f2ce1e36626 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/mod.rs @@ -159,7 +159,7 @@ mod tests { }; use dpp::fee::Credits; use drive::drive::Drive; - use crate::execution::validation::state_transition::state_transitions::tests::{create_dpns_name_contest, verify_dpns_name_contest, perform_vote, setup_masternode_identity, get_proved_vote_states, get_vote_states, perform_votes_multi}; + use crate::execution::validation::state_transition::state_transitions::tests::{create_dpns_identity_name_contest, verify_dpns_name_contest, perform_vote, setup_masternode_identity, get_proved_vote_states, get_vote_states, perform_votes_multi}; use dapi_grpc::platform::v0::get_contested_resource_vote_state_response::get_contested_resource_vote_state_response_v0::{finished_vote_info, FinishedVoteInfo}; use dpp::voting::vote_info_storage::contested_document_vote_poll_winner_info::ContestedDocumentVotePollWinnerInfo; use dapi_grpc::platform::v0::get_vote_polls_by_end_date_request::get_vote_polls_by_end_date_request_v0; @@ -179,7 +179,7 @@ mod tests { let platform_state = platform.state.load(); - let (identity_1, identity_2, dpns_contract) = create_dpns_name_contest( + let (identity_1, identity_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -197,7 +197,7 @@ mod tests { platform_version, ); - let (identity_3, identity_4, dpns_contract) = create_dpns_name_contest( + let (identity_3, identity_4, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -280,7 +280,7 @@ mod tests { let platform_state = platform.state.load(); - let (_identity_1, _identity_2, _dpns_contract) = create_dpns_name_contest( + let (_identity_1, _identity_2, _dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -288,7 +288,7 @@ mod tests { platform_version, ); - let (_identity_3, _identity_4, dpns_contract) = create_dpns_name_contest( + let (_identity_3, _identity_4, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -374,7 +374,7 @@ mod tests { let platform_state = platform.state.load(); - let (_contender_1, _contender_2, dpns_contract) = create_dpns_name_contest( + let (_contender_1, _contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -507,7 +507,7 @@ mod tests { let platform_state = platform.state.load(); - let (_contender_1, _contender_2, dpns_contract) = create_dpns_name_contest( + let (_contender_1, _contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -647,7 +647,7 @@ mod tests { let platform_state = platform.state.load(); - let (_contender_1, _contender_2, dpns_contract) = create_dpns_name_contest( + let (_contender_1, _contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -791,7 +791,7 @@ mod tests { let platform_state = platform.state.load(); - let (_contender_1, _contender_2, dpns_contract) = create_dpns_name_contest( + let (_contender_1, _contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -925,7 +925,7 @@ mod tests { let platform_state = platform.state.load(); - let (_contender_1, _contender_2, dpns_contract) = create_dpns_name_contest( + let (_contender_1, _contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -1023,23 +1023,25 @@ mod tests { let platform_state = platform.state.load(); - let (_contender_1, _contender_2, _dpns_contract) = create_dpns_name_contest( - &mut platform, - &platform_state, - 7, - "quantum", - platform_version, - ); + let (_contender_1, _contender_2, _dpns_contract) = + create_dpns_identity_name_contest( + &mut platform, + &platform_state, + 7, + "quantum", + platform_version, + ); - let (_contender_3, _contender_4, _dpns_contract) = create_dpns_name_contest( - &mut platform, - &platform_state, - 8, - "coya", - platform_version, - ); + let (_contender_3, _contender_4, _dpns_contract) = + create_dpns_identity_name_contest( + &mut platform, + &platform_state, + 8, + "coya", + platform_version, + ); - let (_contender_5, _contender_6, dpns_contract) = create_dpns_name_contest( + let (_contender_5, _contender_6, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -1172,23 +1174,25 @@ mod tests { let platform_state = platform.state.load(); - let (_contender_1, _contender_2, _dpns_contract) = create_dpns_name_contest( - &mut platform, - &platform_state, - 7, - "quantum", - platform_version, - ); + let (_contender_1, _contender_2, _dpns_contract) = + create_dpns_identity_name_contest( + &mut platform, + &platform_state, + 7, + "quantum", + platform_version, + ); - let (_contender_3, _contender_4, _dpns_contract) = create_dpns_name_contest( - &mut platform, - &platform_state, - 8, - "coya", - platform_version, - ); + let (_contender_3, _contender_4, _dpns_contract) = + create_dpns_identity_name_contest( + &mut platform, + &platform_state, + 8, + "coya", + platform_version, + ); - let (_contender_5, _contender_6, dpns_contract) = create_dpns_name_contest( + let (_contender_5, _contender_6, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -1351,7 +1355,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -1501,7 +1505,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -1648,7 +1652,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -1903,7 +1907,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -2213,7 +2217,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -2338,7 +2342,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -2478,7 +2482,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, _dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, _dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -2486,7 +2490,7 @@ mod tests { platform_version, ); - let (contender_3, _contender_4, _dpns_contract) = create_dpns_name_contest( + let (contender_3, _contender_4, _dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -2494,7 +2498,7 @@ mod tests { platform_version, ); - let (_contender_5, _contender_6, dpns_contract) = create_dpns_name_contest( + let (_contender_5, _contender_6, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -2638,7 +2642,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, _dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, _dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -2646,7 +2650,7 @@ mod tests { platform_version, ); - let (contender_3, _contender_4, _dpns_contract) = create_dpns_name_contest( + let (contender_3, _contender_4, _dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -2654,7 +2658,7 @@ mod tests { platform_version, ); - let (_contender_5, _contender_6, dpns_contract) = create_dpns_name_contest( + let (_contender_5, _contender_6, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -3001,7 +3005,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -3009,7 +3013,7 @@ mod tests { platform_version, ); - let (contender_3, _, _) = create_dpns_name_contest( + let (contender_3, _, _) = create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -3244,7 +3248,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -3252,7 +3256,7 @@ mod tests { platform_version, ); - let (contender_3, _, _) = create_dpns_name_contest( + let (contender_3, _, _) = create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -3552,7 +3556,7 @@ mod tests { let platform_state = platform.state.load(); let (contender_1_quantum, _contender_2_quantum, _dpns_contract) = - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -3561,7 +3565,7 @@ mod tests { ); let (_contender_1_cooldog, contender_2_cooldog, _dpns_contract) = - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -3570,7 +3574,7 @@ mod tests { ); let (_contender_1_superman, _contender_2_superman, dpns_contract) = - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -3714,7 +3718,7 @@ mod tests { let platform_state = platform.state.load(); let (contender_1_quantum, _contender_2_quantum, _dpns_contract) = - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -3723,7 +3727,7 @@ mod tests { ); let (_contender_1_cooldog, contender_2_cooldog, _dpns_contract) = - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -3732,7 +3736,7 @@ mod tests { ); let (_contender_1_superman, _contender_2_superman, dpns_contract) = - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -3878,7 +3882,7 @@ mod tests { let platform_state = platform.state.load(); - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -3979,7 +3983,7 @@ mod tests { let platform_state = platform.state.load(); - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -4068,7 +4072,7 @@ mod tests { let platform_state = platform.state.load(); let mut platform_state = (**platform_state).clone(); - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -4100,7 +4104,7 @@ mod tests { )); // we create two new contenders, but we are on the same contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -4109,7 +4113,7 @@ mod tests { ); // we create a new contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -4255,7 +4259,7 @@ mod tests { let platform_state = platform.state.load(); let mut platform_state = (**platform_state).clone(); - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -4287,7 +4291,7 @@ mod tests { )); // we create two new contenders, but we are on the same contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -4296,7 +4300,7 @@ mod tests { ); // we create a new contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -4405,7 +4409,7 @@ mod tests { let platform_state = platform.state.load(); let mut platform_state = (**platform_state).clone(); - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -4437,7 +4441,7 @@ mod tests { )); // we create two new contenders, but we are on the same contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -4446,7 +4450,7 @@ mod tests { ); // we create a new contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -4478,7 +4482,7 @@ mod tests { )); // we create a new contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 10, @@ -4661,7 +4665,7 @@ mod tests { let platform_state = platform.state.load(); let mut platform_state = (**platform_state).clone(); - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -4693,7 +4697,7 @@ mod tests { )); // we create two new contenders, but we are on the same contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -4702,7 +4706,7 @@ mod tests { ); // we create a new contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -4734,7 +4738,7 @@ mod tests { )); // we create a new contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 10, @@ -4819,7 +4823,7 @@ mod tests { let platform_state = platform.state.load(); let mut platform_state = (**platform_state).clone(); - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -4851,7 +4855,7 @@ mod tests { )); // we create two new contenders, but we are on the same contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -4860,7 +4864,7 @@ mod tests { ); // we create a new contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -4892,7 +4896,7 @@ mod tests { )); // we create a new contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 10, @@ -4973,7 +4977,7 @@ mod tests { let platform_state = platform.state.load(); let mut platform_state = (**platform_state).clone(); - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -5005,7 +5009,7 @@ mod tests { )); // we create two new contenders, but we are on the same contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -5014,7 +5018,7 @@ mod tests { ); // we create a new contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -5046,7 +5050,7 @@ mod tests { )); // we create a new contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 10, @@ -5144,7 +5148,7 @@ mod tests { let platform_state = platform.state.load(); let mut platform_state = (**platform_state).clone(); - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -5176,7 +5180,7 @@ mod tests { )); // we create two new contenders, but we are on the same contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 8, @@ -5185,7 +5189,7 @@ mod tests { ); // we create a new contest - create_dpns_name_contest( + create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -5512,7 +5516,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -5530,7 +5534,7 @@ mod tests { assert_eq!(start_balance, dash_to_credits!(0.4)); - let (_contender_3, _contender_4, _) = create_dpns_name_contest( + let (_contender_3, _contender_4, _) = create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -5620,7 +5624,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -5638,7 +5642,7 @@ mod tests { assert_eq!(start_balance, dash_to_credits!(0.4)); - let (_contender_3, _contender_4, _) = create_dpns_name_contest( + let (_contender_3, _contender_4, _) = create_dpns_identity_name_contest( &mut platform, &platform_state, 9, @@ -5722,6 +5726,7 @@ mod tests { mod document_distribution { use super::*; + use crate::execution::validation::state_transition::tests::create_dpns_contract_name_contest; #[test] fn test_document_distribution() { @@ -5732,7 +5737,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -5945,7 +5950,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -6158,7 +6163,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -6371,7 +6376,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -6579,7 +6584,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -6778,7 +6783,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -6987,7 +6992,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -7176,7 +7181,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -7355,6 +7360,219 @@ mod tests { assert_eq!(locking, Some(50)); } } + + #[test] + fn test_document_distribution_to_contract() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (contender_1, contender_2, dpns_contract) = create_dpns_contract_name_contest( + &mut platform, + &platform_state, + 600, + "cards", + platform_version, + ); + + perform_votes_multi( + &mut platform, + &dpns_contract, + vec![ + (TowardsIdentity(contender_1.id()), 50), + (TowardsIdentity(contender_2.id()), 5), + (ResourceVoteChoice::Abstain, 10), + (ResourceVoteChoice::Lock, 3), + ], + "cards", + 10, + platform_version, + ); + + let platform_state = platform.state.load(); + + let (contenders, abstaining, locking, finished_vote_info) = get_vote_states( + &platform, + &platform_state, + &dpns_contract, + "cards", + None, + true, + None, + ResultType::DocumentsAndVoteTally, + platform_version, + ); + + assert_eq!(finished_vote_info, None); + + assert_eq!(contenders.len(), 2); + + let first_contender = contenders.first().unwrap(); + + let second_contender = contenders.last().unwrap(); + + assert_ne!(first_contender.document(), second_contender.document()); + + assert_eq!(first_contender.identity_id(), contender_1.id()); + + assert_eq!(second_contender.identity_id(), contender_2.id()); + + assert_eq!(first_contender.vote_tally(), Some(50)); + + assert_eq!(second_contender.vote_tally(), Some(5)); + + assert_eq!(abstaining, Some(10)); + + assert_eq!(locking, Some(3)); + + let mut platform_state = (**platform_state).clone(); + + let block_info = BlockInfo { + time_ms: 1_209_900_000, //2 weeks and 300s + height: 10000, + core_height: 42, + epoch: Default::default(), + }; + + platform_state.set_last_committed_block_info(Some( + ExtendedBlockInfoV0 { + basic_info: block_info, + app_hash: platform + .drive + .grove + .root_hash(None, &platform_version.drive.grove_version) + .unwrap() + .unwrap(), + quorum_hash: [0u8; 32], + block_id_hash: [0u8; 32], + proposer_pro_tx_hash: [0u8; 32], + signature: [0u8; 96], + round: 0, + } + .into(), + )); + + platform.state.store(Arc::new(platform_state)); + + let platform_state = platform.state.load(); + + let transaction = platform.drive.grove.start_transaction(); + + platform + .check_for_ended_vote_polls( + &platform_state, + &block_info, + Some(&transaction), + platform_version, + ) + .expect("expected to check for ended vote polls"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + // At this point the document should have been awarded to contender 1. + + { + let (contenders, abstaining, locking, finished_vote_info) = get_vote_states( + &platform, + &platform_state, + &dpns_contract, + "cards", + None, + true, + None, + ResultType::DocumentsAndVoteTally, + platform_version, + ); + + assert_eq!( + finished_vote_info, + Some(FinishedVoteInfo { + finished_vote_outcome: + finished_vote_info::FinishedVoteOutcome::TowardsIdentity as i32, + won_by_identity_id: Some(contender_1.id().to_vec()), + finished_at_block_height: 10000, + finished_at_core_block_height: 42, + finished_at_block_time_ms: 1209900000, + finished_at_epoch: 0 + }) + ); + + assert_eq!(contenders.len(), 2); + + let first_contender = contenders.first().unwrap(); + + let second_contender = contenders.last().unwrap(); + + assert_eq!(first_contender.document(), &None); + + assert_eq!(second_contender.document(), &None); + + assert_eq!(first_contender.identity_id(), contender_1.id()); + + assert_eq!(second_contender.identity_id(), contender_2.id()); + + assert_eq!(first_contender.vote_tally(), Some(50)); + + assert_eq!(second_contender.vote_tally(), Some(5)); + + assert_eq!(abstaining, Some(10)); + + assert_eq!(locking, Some(3)); + } + + { + let (contenders, abstaining, locking, finished_vote_info) = + get_proved_vote_states( + &platform, + &platform_state, + &dpns_contract, + "cards", + None, + true, + None, + ResultType::DocumentsAndVoteTally, + platform_version, + ); + + assert_eq!( + finished_vote_info, + Some(( + ContestedDocumentVotePollWinnerInfo::WonByIdentity(contender_1.id()), + block_info + )) + ); + + assert_eq!(contenders.len(), 2); + + let first_contender = contenders.first().unwrap(); + + let second_contender = contenders.last().unwrap(); + + assert_eq!(first_contender.document(), &None); + + assert_eq!(second_contender.document(), &None); + + assert_eq!(first_contender.identity_id(), contender_1.id()); + + assert_eq!(second_contender.identity_id(), contender_2.id()); + + assert_eq!(first_contender.vote_tally(), Some(50)); + + assert_eq!(second_contender.vote_tally(), Some(5)); + + assert_eq!(abstaining, Some(10)); + + assert_eq!(locking, Some(3)); + } + } } mod changing_vote { use super::*; @@ -7368,7 +7586,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, _contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, _contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -7419,7 +7637,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -7500,7 +7718,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, @@ -7611,7 +7829,7 @@ mod tests { let platform_state = platform.state.load(); - let (contender_1, contender_2, dpns_contract) = create_dpns_name_contest( + let (contender_1, contender_2, dpns_contract) = create_dpns_identity_name_contest( &mut platform, &platform_state, 7, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs index f5a8f6005a3..490b5821530 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs @@ -96,6 +96,7 @@ pub(crate) mod tests { use dpp::state_transition::masternode_vote_transition::MasternodeVoteTransition; use dpp::state_transition::masternode_vote_transition::methods::MasternodeVoteTransitionMethodsV0; use dpp::state_transition::StateTransition; + use dpp::tests::json_document::json_document_to_contract_with_ids; use dpp::util::hash::hash_double; use dpp::util::strings::convert_to_homograph_safe_chars; use dpp::voting::contender_structs::{Contender, ContenderV0}; @@ -110,6 +111,7 @@ pub(crate) mod tests { use drive::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed; use drive::query::vote_poll_vote_state_query::ContestedDocumentVotePollDriveQueryResultType::DocumentsAndVoteTally; use drive::query::vote_poll_vote_state_query::{ContestedDocumentVotePollDriveQueryResultType, ResolvedContestedDocumentVotePollDriveQuery}; + use drive::util::test_helpers::setup_contract; use crate::execution::types::block_execution_context::BlockExecutionContext; use crate::execution::types::block_execution_context::v0::BlockExecutionContextV0; use crate::expect_match; @@ -540,7 +542,7 @@ pub(crate) mod tests { ) } - pub(crate) fn create_dpns_name_contest( + pub(crate) fn create_dpns_identity_name_contest( platform: &mut TempPlatform, platform_state: &PlatformState, seed: u64, @@ -573,6 +575,55 @@ pub(crate) mod tests { (identity_1_info.0, identity_2_info.0, dpns_contract) } + pub(crate) fn create_dpns_contract_name_contest( + platform: &mut TempPlatform, + platform_state: &PlatformState, + seed: u64, + name: &str, + platform_version: &PlatformVersion, + ) -> (Identity, Identity, DataContract) { + let mut rng = StdRng::seed_from_u64(seed); + + let identity_1_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5)); + + let identity_2_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5)); + + // Flip them if needed so identity 1 id is always smaller than identity 2 id + let (identity_1_info, identity_2_info) = if identity_1_info.0.id() < identity_2_info.0.id() + { + (identity_1_info, identity_2_info) + } else { + (identity_2_info, identity_1_info) + }; + + let dashpay_contract = setup_contract( + &platform.drive, + "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json", + None, + None, + ); + + let card_game = setup_contract( + &platform.drive, + "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json", + None, + None, + ); + + let (_, _, dpns_contract) = create_dpns_name_contest_on_identities_for_contract_records( + platform, + &identity_1_info, + &identity_2_info, + &dashpay_contract, + &card_game, + platform_state, + rng, + name, + platform_version, + ); + (identity_1_info.0, identity_2_info.0, dpns_contract) + } + fn create_dpns_name_contest_on_identities( platform: &mut TempPlatform, identity_1: &(Identity, SimpleSigner, IdentityPublicKey), @@ -845,6 +896,286 @@ pub(crate) mod tests { ) } + fn create_dpns_name_contest_on_identities_for_contract_records( + platform: &mut TempPlatform, + identity_1: &(Identity, SimpleSigner, IdentityPublicKey), + identity_2: &(Identity, SimpleSigner, IdentityPublicKey), + contract_1: &DataContract, + contract_2: &DataContract, + platform_state: &PlatformState, + mut rng: StdRng, + name: &str, + platform_version: &PlatformVersion, + ) -> ( + ((Document, Bytes32), (Document, Bytes32)), + ((Document, Bytes32), (Document, Bytes32)), + DataContract, + ) { + let (identity_1, signer_1, key_1) = identity_1; + + let (identity_2, signer_2, key_2) = identity_2; + + let dpns_contract = setup_contract( + &platform.drive, + "tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id.json", + None, + None, + ); + + let preorder = dpns_contract + .document_type_for_name("preorder") + .expect("expected a profile document type"); + + assert!(!preorder.documents_mutable()); + assert!(preorder.documents_can_be_deleted()); + assert!(!preorder.documents_transferable().is_transferable()); + + let domain = dpns_contract + .document_type_for_name("domain") + .expect("expected a profile document type"); + + assert!(!domain.documents_mutable()); + // Deletion is disabled with data trigger + assert!(domain.documents_can_be_deleted()); + assert!(domain.documents_transferable().is_transferable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut preorder_document_1 = preorder + .random_document_with_identifier_and_entropy( + &mut rng, + identity_1.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut preorder_document_2 = preorder + .random_document_with_identifier_and_entropy( + &mut rng, + identity_2.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut document_1 = domain + .random_document_with_identifier_and_entropy( + &mut rng, + identity_1.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + let mut document_2 = domain + .random_document_with_identifier_and_entropy( + &mut rng, + identity_2.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document_1.set("parentDomainName", "dash".into()); + document_1.set("normalizedParentDomainName", "dash".into()); + document_1.set("label", name.into()); + document_1.set( + "normalizedLabel", + convert_to_homograph_safe_chars(name).into(), + ); + document_1.remove("records.identity"); + document_1.set("records.contract", contract_1.id().into()); + document_1.set("subdomainRules.allowSubdomains", false.into()); + + document_2.set("parentDomainName", "dash".into()); + document_2.set("normalizedParentDomainName", "dash".into()); + document_2.set("label", name.into()); + document_2.set( + "normalizedLabel", + convert_to_homograph_safe_chars(name).into(), + ); + document_2.remove("records.identity"); + document_2.set("records.contract", contract_2.id().into()); + document_2.set("subdomainRules.allowSubdomains", false.into()); + + let salt_1: [u8; 32] = rng.gen(); + let salt_2: [u8; 32] = rng.gen(); + + let mut salted_domain_buffer_1: Vec = vec![]; + salted_domain_buffer_1.extend(salt_1); + salted_domain_buffer_1.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes()); + + let salted_domain_hash_1 = hash_double(salted_domain_buffer_1); + + let mut salted_domain_buffer_2: Vec = vec![]; + salted_domain_buffer_2.extend(salt_2); + salted_domain_buffer_2.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes()); + + let salted_domain_hash_2 = hash_double(salted_domain_buffer_2); + + preorder_document_1.set("saltedDomainHash", salted_domain_hash_1.into()); + preorder_document_2.set("saltedDomainHash", salted_domain_hash_2.into()); + + document_1.set("preorderSalt", salt_1.into()); + document_2.set("preorderSalt", salt_2.into()); + + let documents_batch_create_preorder_transition_1 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + preorder_document_1.clone(), + preorder, + entropy.0, + key_1, + 2, + 0, + signer_1, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_preorder_transition_1 = + documents_batch_create_preorder_transition_1 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_preorder_transition_2 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + preorder_document_2.clone(), + preorder, + entropy.0, + key_2, + 2, + 0, + signer_2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_preorder_transition_2 = + documents_batch_create_preorder_transition_2 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_transition_1 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document_1.clone(), + domain, + entropy.0, + key_1, + 3, + 0, + signer_1, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition_1 = documents_batch_create_transition_1 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let documents_batch_create_transition_2 = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document_2.clone(), + domain, + entropy.0, + key_2, + 3, + 0, + signer_2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition_2 = documents_batch_create_transition_2 + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![ + documents_batch_create_serialized_preorder_transition_1.clone(), + documents_batch_create_serialized_preorder_transition_2.clone(), + ], + platform_state, + &BlockInfo::default_with_time( + platform_state + .last_committed_block_time_ms() + .unwrap_or_default() + + 3000, + ), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_eq!(processing_result.valid_count(), 2); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![ + documents_batch_create_serialized_transition_1.clone(), + documents_batch_create_serialized_transition_2.clone(), + ], + platform_state, + &BlockInfo::default_with_time( + platform_state + .last_committed_block_time_ms() + .unwrap_or_default() + + 3000, + ), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_eq!(processing_result.valid_count(), 2); + ( + ((preorder_document_1, entropy), (document_1, entropy)), + ((preorder_document_2, entropy), (document_2, entropy)), + dpns_contract, + ) + } + pub(crate) fn add_contender_to_dpns_name_contest( platform: &mut TempPlatform, platform_state: &PlatformState, @@ -1506,7 +1837,7 @@ pub(crate) mod tests { let dash_encoded = bincode::encode_to_vec(Value::Text("dash".to_string()), config) .expect("expected to encode the word dash"); - let quantum_encoded = + let name_encoded = bincode::encode_to_vec(Value::Text(convert_to_homograph_safe_chars(name)), config) .expect("expected to encode the word quantum"); @@ -1520,7 +1851,7 @@ pub(crate) mod tests { contract_id: dpns_contract.id().to_vec(), document_type_name: domain.name().clone(), index_name: index_name.clone(), - index_values: vec![dash_encoded.clone(), quantum_encoded.clone()], + index_values: vec![dash_encoded.clone(), name_encoded.clone()], result_type: result_type as i32, allow_include_locked_and_abstaining_vote_tally, start_at_identifier_info, @@ -1556,7 +1887,7 @@ pub(crate) mod tests { index_name: index_name.clone(), index_values: vec![ Value::Text("dash".to_string()), - Value::Text("quantum".to_string()), + Value::Text(convert_to_homograph_safe_chars(name)), ], }, result_type: ContestedDocumentVotePollDriveQueryResultType::try_from( diff --git a/packages/rs-drive-abci/tests/strategy_tests/main.rs b/packages/rs-drive-abci/tests/strategy_tests/main.rs index 4584ad5c8b9..907dd784962 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/main.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/main.rs @@ -1194,7 +1194,7 @@ mod tests { .unwrap() .unwrap() ), - "2b735bf737d33272ab6c7df267000ab5c7930a5dea324fc9f43af78f916a6dd6".to_string() + "15eba9098bb5223511924906ec9293647b98ee8362eff3e605d0efd631a7216f".to_string() ) } @@ -1915,7 +1915,7 @@ mod tests { .unwrap() .unwrap() ), - "de74b89f6af1e11da2428395f19a8c5892f104fbd23d34b5a35f98f9a41f8f9a".to_string() + "2bbbaeff219ed40262753a460cfb8f64930ff43c653c5c392c96f8603f654282".to_string() ) } @@ -2050,7 +2050,7 @@ mod tests { .unwrap() .unwrap() ), - "d820f18b4aeb732c328f1cd2cbf851fcc090941710d721a2432110618bf8262a".to_string() + "9325c86b2ed374b1585706b289d5d4ab9f82fceab094764b6a21474b37307f74".to_string() ) } diff --git a/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs index 09d5e4a6b6a..0244fe3f132 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs @@ -116,8 +116,7 @@ mod tests { ("normalizedParentDomainName".into(), "dash".into()), ( "records".into(), - BTreeMap::from([("identity", Value::from(identity1_id))]) - .into(), + BTreeMap::from([("identity", Value::from(identity1_id))]).into(), ), ]), Some(start_identities.first().unwrap().0.id()), @@ -393,8 +392,7 @@ mod tests { ("normalizedParentDomainName".into(), "dash".into()), ( "records".into(), - BTreeMap::from([("identity", Value::from(identity1_id))]) - .into(), + BTreeMap::from([("identity", Value::from(identity1_id))]).into(), ), ]), Some(start_identities.first().unwrap().0.id()), @@ -750,8 +748,7 @@ mod tests { ("normalizedParentDomainName".into(), "dash".into()), ( "records".into(), - BTreeMap::from([("identity", Value::from(identity1_id))]) - .into(), + BTreeMap::from([("identity", Value::from(identity1_id))]).into(), ), ]), Some(start_identities.first().unwrap().0.id()), @@ -1119,8 +1116,7 @@ mod tests { ("normalizedParentDomainName".into(), "dash".into()), ( "records".into(), - BTreeMap::from([("identity", Value::from(identity1_id))]) - .into(), + BTreeMap::from([("identity", Value::from(identity1_id))]).into(), ), ]), Some(start_identities.first().unwrap().0.id()), diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-and-other-unique-index.json b/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-and-other-unique-index.json index 8c9d921bfc6..07ceec6a4fb 100644 --- a/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-and-other-unique-index.json +++ b/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-and-other-unique-index.json @@ -1,6 +1,6 @@ { "$format_version": "0", - "id": "8MjTnX7JUbGfYYswyuCtHU7ZqcYU9s1fUaNiqD9s5tEw", + "id": "DWBXe9EXFPHxvbArQgT45uQR5gMmi8dfMpLhR5KSbwnZ", "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", "version": 1, "documentSchemas": { diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id-null-searchable-true.json b/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id-null-searchable-true.json new file mode 100644 index 00000000000..c3135f6aa50 --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id-null-searchable-true.json @@ -0,0 +1,185 @@ +{ + "$format_version": "0", + "id": "DWBXe9EXFPHxvbArQgT45uQR5gMmi8dfMpLhR5KSbwnZ", + "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", + "version": 1, + "documentSchemas": { + "domain": { + "documentsMutable": false, + "canBeDeleted": true, + "transferable": 1, + "tradeMode": 1, + "type": "object", + "indices": [ + { + "name": "parentNameAndLabel", + "properties": [ + { + "normalizedParentDomainName": "asc" + }, + { + "normalizedLabel": "asc" + } + ], + "unique": true, + "contested": { + "fieldMatches": [ + { + "field": "normalizedLabel", + "regexPattern": "^[a-zA-Z01]{3,19}$" + } + ], + "resolution": 0, + "description": "If the normalized label part of this index is less than 20 characters (all alphabet a-z and 0 and 1) then this index is non unique while contest resolution takes place." + } + }, + { + "name": "identityId", + "properties": [ + { + "records.identity": "asc" + } + ] + }, + { + "name": "contractId", + "properties": [ + { + "records.contract": "asc" + } + ] + } + ], + "properties": { + "label": { + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$", + "minLength": 3, + "maxLength": 63, + "position": 0, + "description": "Domain label. e.g. 'Bob'." + }, + "normalizedLabel": { + "type": "string", + "pattern": "^[a-hj-km-np-z0-9][a-hj-km-np-z0-9-]{0,61}[a-hj-km-np-z0-9]$", + "maxLength": 63, + "position": 1, + "description": "Domain label converted to lowercase for case-insensitive uniqueness validation. \"o\", \"i\" and \"l\" replaced with \"0\" and \"1\" to mitigate homograph attack. e.g. 'b0b'", + "$comment": "Must be equal to the label in lowercase. \"o\", \"i\" and \"l\" must be replaced with \"0\" and \"1\"." + }, + "parentDomainName": { + "type": "string", + "pattern": "^$|^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$", + "minLength": 0, + "maxLength": 63, + "position": 2, + "description": "A full parent domain name. e.g. 'dash'." + }, + "normalizedParentDomainName": { + "type": "string", + "pattern": "^$|^[a-hj-km-np-z0-9][a-hj-km-np-z0-9-\\.]{0,61}[a-hj-km-np-z0-9]$", + "minLength": 0, + "maxLength": 63, + "position": 3, + "description": "A parent domain name in lowercase for case-insensitive uniqueness validation. \"o\", \"i\" and \"l\" replaced with \"0\" and \"1\" to mitigate homograph attack. e.g. 'dash'", + "$comment": "Must either be equal to an existing domain or empty to create a top level domain. \"o\", \"i\" and \"l\" must be replaced with \"0\" and \"1\". Only the data contract owner can create top level domains." + }, + "preorderSalt": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 4, + "description": "Salt used in the preorder document" + }, + "records": { + "type": "object", + "properties": { + "identity": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 1, + "contentMediaType": "application/x.dash.dpp.identifier", + "description": "Identifier name record that refers to an Identity" + }, + "contract": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 1, + "contentMediaType": "application/x.dash.dpp.identifier", + "description": "Identifier name record that refers to a Contract" + } + }, + "minProperties": 1, + "position": 5, + "additionalProperties": false + }, + "subdomainRules": { + "type": "object", + "properties": { + "allowSubdomains": { + "type": "boolean", + "description": "This option defines who can create subdomains: true - anyone; false - only the domain owner", + "$comment": "Only the domain owner is allowed to create subdomains for non top-level domains", + "position": 0 + } + }, + "position": 6, + "description": "Subdomain rules allow domain owners to define rules for subdomains", + "additionalProperties": false, + "required": [ + "allowSubdomains" + ] + } + }, + "required": [ + "$createdAt", + "$updatedAt", + "$transferredAt", + "label", + "normalizedLabel", + "normalizedParentDomainName", + "preorderSalt", + "records", + "subdomainRules" + ], + "additionalProperties": false, + "$comment": "In order to register a domain you need to create a preorder. The preorder step is needed to prevent man-in-the-middle attacks. normalizedLabel + '.' + normalizedParentDomain must not be longer than 253 chars length as defined by RFC 1035. Domain documents are immutable: modification and deletion are restricted" + }, + "preorder": { + "documentsMutable": false, + "canBeDeleted": true, + "type": "object", + "indices": [ + { + "name": "saltedHash", + "properties": [ + { + "saltedDomainHash": "asc" + } + ], + "unique": true + } + ], + "properties": { + "saltedDomainHash": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 0, + "description": "Double sha-256 of the concatenation of a 32 byte random salt and a normalized domain name" + } + }, + "required": [ + "saltedDomainHash" + ], + "additionalProperties": false, + "$comment": "Preorder documents are immutable: modification and deletion are restricted" + } + } +} \ No newline at end of file diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id.json b/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id.json new file mode 100644 index 00000000000..238c1ad59ee --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id.json @@ -0,0 +1,187 @@ +{ + "$format_version": "0", + "id": "DWBXe9EXFPHxvbArQgT45uQR5gMmi8dfMpLhR5KSbwnZ", + "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", + "version": 1, + "documentSchemas": { + "domain": { + "documentsMutable": false, + "canBeDeleted": true, + "transferable": 1, + "tradeMode": 1, + "type": "object", + "indices": [ + { + "name": "parentNameAndLabel", + "properties": [ + { + "normalizedParentDomainName": "asc" + }, + { + "normalizedLabel": "asc" + } + ], + "unique": true, + "contested": { + "fieldMatches": [ + { + "field": "normalizedLabel", + "regexPattern": "^[a-zA-Z01]{3,19}$" + } + ], + "resolution": 0, + "description": "If the normalized label part of this index is less than 20 characters (all alphabet a-z and 0 and 1) then this index is non unique while contest resolution takes place." + } + }, + { + "name": "identityId", + "nullSearchable": false, + "properties": [ + { + "records.identity": "asc" + } + ] + }, + { + "name": "contractId", + "nullSearchable": false, + "properties": [ + { + "records.contract": "asc" + } + ] + } + ], + "properties": { + "label": { + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$", + "minLength": 3, + "maxLength": 63, + "position": 0, + "description": "Domain label. e.g. 'Bob'." + }, + "normalizedLabel": { + "type": "string", + "pattern": "^[a-hj-km-np-z0-9][a-hj-km-np-z0-9-]{0,61}[a-hj-km-np-z0-9]$", + "maxLength": 63, + "position": 1, + "description": "Domain label converted to lowercase for case-insensitive uniqueness validation. \"o\", \"i\" and \"l\" replaced with \"0\" and \"1\" to mitigate homograph attack. e.g. 'b0b'", + "$comment": "Must be equal to the label in lowercase. \"o\", \"i\" and \"l\" must be replaced with \"0\" and \"1\"." + }, + "parentDomainName": { + "type": "string", + "pattern": "^$|^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$", + "minLength": 0, + "maxLength": 63, + "position": 2, + "description": "A full parent domain name. e.g. 'dash'." + }, + "normalizedParentDomainName": { + "type": "string", + "pattern": "^$|^[a-hj-km-np-z0-9][a-hj-km-np-z0-9-\\.]{0,61}[a-hj-km-np-z0-9]$", + "minLength": 0, + "maxLength": 63, + "position": 3, + "description": "A parent domain name in lowercase for case-insensitive uniqueness validation. \"o\", \"i\" and \"l\" replaced with \"0\" and \"1\" to mitigate homograph attack. e.g. 'dash'", + "$comment": "Must either be equal to an existing domain or empty to create a top level domain. \"o\", \"i\" and \"l\" must be replaced with \"0\" and \"1\". Only the data contract owner can create top level domains." + }, + "preorderSalt": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 4, + "description": "Salt used in the preorder document" + }, + "records": { + "type": "object", + "properties": { + "identity": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 1, + "contentMediaType": "application/x.dash.dpp.identifier", + "description": "Identifier name record that refers to an Identity" + }, + "contract": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 1, + "contentMediaType": "application/x.dash.dpp.identifier", + "description": "Identifier name record that refers to a Contract" + } + }, + "minProperties": 1, + "position": 5, + "additionalProperties": false + }, + "subdomainRules": { + "type": "object", + "properties": { + "allowSubdomains": { + "type": "boolean", + "description": "This option defines who can create subdomains: true - anyone; false - only the domain owner", + "$comment": "Only the domain owner is allowed to create subdomains for non top-level domains", + "position": 0 + } + }, + "position": 6, + "description": "Subdomain rules allow domain owners to define rules for subdomains", + "additionalProperties": false, + "required": [ + "allowSubdomains" + ] + } + }, + "required": [ + "$createdAt", + "$updatedAt", + "$transferredAt", + "label", + "normalizedLabel", + "normalizedParentDomainName", + "preorderSalt", + "records", + "subdomainRules" + ], + "additionalProperties": false, + "$comment": "In order to register a domain you need to create a preorder. The preorder step is needed to prevent man-in-the-middle attacks. normalizedLabel + '.' + normalizedParentDomain must not be longer than 253 chars length as defined by RFC 1035. Domain documents are immutable: modification and deletion are restricted" + }, + "preorder": { + "documentsMutable": false, + "canBeDeleted": true, + "type": "object", + "indices": [ + { + "name": "saltedHash", + "properties": [ + { + "saltedDomainHash": "asc" + } + ], + "unique": true + } + ], + "properties": { + "saltedDomainHash": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 0, + "description": "Double sha-256 of the concatenation of a 32 byte random salt and a normalized domain name" + } + }, + "required": [ + "saltedDomainHash" + ], + "additionalProperties": false, + "$comment": "Preorder documents are immutable: modification and deletion are restricted" + } + } +} \ No newline at end of file diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index.json b/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index.json index ada9effef56..8e05c7829fc 100644 --- a/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index.json +++ b/packages/rs-drive-abci/tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index.json @@ -1,6 +1,6 @@ { "$format_version": "0", - "id": "8MjTnX7JUbGfYYswyuCtHU7ZqcYU9s1fUaNiqD9s5tEw", + "id": "DWBXe9EXFPHxvbArQgT45uQR5gMmi8dfMpLhR5KSbwnZ", "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", "version": 1, "documentSchemas": { diff --git a/packages/rs-drive/src/config.rs b/packages/rs-drive/src/config.rs index 620b9514b8e..b65fc7ec8ef 100644 --- a/packages/rs-drive/src/config.rs +++ b/packages/rs-drive/src/config.rs @@ -162,7 +162,8 @@ fn default_data_contracts_cache_size() -> u64 { DEFAULT_DATA_CONTRACTS_CACHE_SIZE } -fn default_grovedb_visualizer_address() -> std::net::SocketAddr { +/// The default grovedb visualizer_address +pub fn default_grovedb_visualizer_address() -> std::net::SocketAddr { "127.0.0.1:8083".parse().unwrap() } diff --git a/packages/rs-drive/src/drive/contract/estimation_costs/add_estimation_costs_for_contract_insertion/v0/mod.rs b/packages/rs-drive/src/drive/contract/estimation_costs/add_estimation_costs_for_contract_insertion/v0/mod.rs index e41ad6ff785..ba04d65bc61 100644 --- a/packages/rs-drive/src/drive/contract/estimation_costs/add_estimation_costs_for_contract_insertion/v0/mod.rs +++ b/packages/rs-drive/src/drive/contract/estimation_costs/add_estimation_costs_for_contract_insertion/v0/mod.rs @@ -11,6 +11,7 @@ use dpp::data_contract::DataContract; use dpp::serialization::PlatformSerializableWithPlatformVersion; +use crate::drive::votes::paths::vote_contested_resource_active_polls_contract_document_tree_path; use crate::util::type_constants::{DEFAULT_FLOAT_SIZE, DEFAULT_FLOAT_SIZE_U8}; use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; @@ -19,7 +20,6 @@ use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllSubtrees, Mix}; use grovedb::EstimatedSumTrees::NoSumTrees; use std::collections::HashMap; -use crate::drive::votes::paths::{vote_contested_resource_active_polls_contract_document_tree_path, vote_contested_resource_contract_documents_indexes_path}; impl Drive { /// Adds the estimation costs for a contract insertion @@ -41,9 +41,10 @@ impl Drive { } else { None }; - - let document_types_with_contested_unique_indexes = contract.document_types_with_contested_indexes(); - + + let document_types_with_contested_unique_indexes = + contract.document_types_with_contested_indexes(); + if !document_types_with_contested_unique_indexes.is_empty() { Self::add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded( contract, diff --git a/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/mod.rs b/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/mod.rs index ef843873c91..a10973b5714 100644 --- a/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/mod.rs @@ -39,6 +39,7 @@ impl Drive { index_path_info: PathInfo<0>, index_level: &IndexLevel, any_fields_null: bool, + all_fields_null: bool, storage_flags: &Option<&StorageFlags>, previous_batch_operations: &Option<&mut Vec>, estimated_costs_only_with_layer_info: &mut Option< @@ -61,6 +62,7 @@ impl Drive { index_path_info, index_level, any_fields_null, + all_fields_null, storage_flags, previous_batch_operations, estimated_costs_only_with_layer_info, diff --git a/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/v0/mod.rs index 7d3799088fd..6ad033a0f41 100644 --- a/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/v0/mod.rs @@ -33,6 +33,7 @@ impl Drive { index_path_info: PathInfo<0>, index_level: &IndexLevel, mut any_fields_null: bool, + mut all_fields_null: bool, storage_flags: &Option<&StorageFlags>, previous_batch_operations: &Option<&mut Vec>, estimated_costs_only_with_layer_info: &mut Option< @@ -67,6 +68,7 @@ impl Drive { index_path_info.clone(), index_type, any_fields_null, + all_fields_null, storage_flags, previous_batch_operations, estimated_costs_only_with_layer_info, @@ -129,6 +131,7 @@ impl Drive { // Iteration 2. the index path is now something likeDataContracts/ContractID/Documents(1)/$ownerId//toUserId//accountReference any_fields_null |= document_index_field.is_empty(); + all_fields_null &= document_index_field.is_empty(); // we push the actual value of the index path sub_level_index_path_info.push(document_index_field)?; @@ -139,6 +142,7 @@ impl Drive { sub_level_index_path_info, sub_level, any_fields_null, + all_fields_null, storage_flags, previous_batch_operations, estimated_costs_only_with_layer_info, diff --git a/packages/rs-drive/src/drive/document/delete/remove_indices_for_top_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/delete/remove_indices_for_top_index_level_for_contract_operations/v0/mod.rs index 3b714588e27..332e9214519 100644 --- a/packages/rs-drive/src/drive/document/delete/remove_indices_for_top_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/remove_indices_for_top_index_level_for_contract_operations/v0/mod.rs @@ -131,6 +131,7 @@ impl Drive { } let any_fields_null = document_top_field.is_empty(); + let all_fields_null = document_top_field.is_empty(); let mut index_path_info = if document_and_contract_info .owned_document_info @@ -152,6 +153,7 @@ impl Drive { index_path_info, sub_level, any_fields_null, + all_fields_null, &storage_flags, previous_batch_operations, estimated_costs_only_with_layer_info, diff --git a/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/mod.rs b/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/mod.rs index 0dfc00efc54..bf35d3504cf 100644 --- a/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/mod.rs @@ -11,7 +11,7 @@ use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; -use dpp::data_contract::document_type::IndexType; +use dpp::data_contract::document_type::IndexLevelTypeInfo; use grovedb::{EstimatedLayerInformation, TransactionArg}; use std::collections::HashMap; @@ -38,8 +38,9 @@ impl Drive { &self, document_and_contract_info: &DocumentAndContractInfo, index_path_info: PathInfo<0>, - index_type: IndexType, + index_type: IndexLevelTypeInfo, any_fields_null: bool, + all_fields_null: bool, storage_flags: &Option<&StorageFlags>, previous_batch_operations: &Option<&mut Vec>, estimated_costs_only_with_layer_info: &mut Option< @@ -62,6 +63,7 @@ impl Drive { index_path_info, index_type, any_fields_null, + all_fields_null, storage_flags, previous_batch_operations, estimated_costs_only_with_layer_info, diff --git a/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/v0/mod.rs index 2ebd38f356c..0ee9619ac03 100644 --- a/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/v0/mod.rs @@ -5,7 +5,7 @@ use grovedb::EstimatedLayerCount::PotentiallyAtMaxElements; use grovedb::EstimatedLayerSizes::{AllReference, AllSubtrees}; use grovedb::{EstimatedLayerInformation, TransactionArg}; -use dpp::data_contract::document_type::IndexType; +use dpp::data_contract::document_type::IndexLevelTypeInfo; use dpp::data_contract::document_type::IndexType::{ContestedResourceIndex, NonUniqueIndex}; use grovedb::EstimatedSumTrees::NoSumTrees; use std::collections::HashMap; @@ -30,8 +30,9 @@ impl Drive { &self, document_and_contract_info: &DocumentAndContractInfo, index_path_info: PathInfo<0>, - index_type: IndexType, + index_type: IndexLevelTypeInfo, any_fields_null: bool, + all_fields_null: bool, storage_flags: &Option<&StorageFlags>, previous_batch_operations: &Option<&mut Vec>, estimated_costs_only_with_layer_info: &mut Option< @@ -42,13 +43,19 @@ impl Drive { batch_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result<(), Error> { + if all_fields_null && !index_type.should_insert_with_all_null { + return Ok(()); + } let mut key_info_path = index_path_info.convert_to_key_info_path(); let document_type = document_and_contract_info.document_type; // unique indexes will be stored under key "0" // non unique indices should have a tree at key "0" that has all elements based off of primary key - if index_type == NonUniqueIndex || index_type == ContestedResourceIndex || any_fields_null { + if index_type.index_type == NonUniqueIndex + || index_type.index_type == ContestedResourceIndex + || any_fields_null + { key_info_path.push(KnownKey(vec![0])); if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info diff --git a/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/mod.rs b/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/mod.rs index 19463c7ce7e..b7b2ac40608 100644 --- a/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/mod.rs @@ -24,6 +24,7 @@ impl Drive { index_path_info: PathInfo<0>, index_level: &IndexLevel, any_fields_null: bool, + all_fields_null: bool, previous_batch_operations: &mut Option<&mut Vec>, storage_flags: &Option<&StorageFlags>, estimated_costs_only_with_layer_info: &mut Option< @@ -46,6 +47,7 @@ impl Drive { index_path_info, index_level, any_fields_null, + all_fields_null, previous_batch_operations, storage_flags, estimated_costs_only_with_layer_info, diff --git a/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs index a3347d7302c..2725cc80b1c 100644 --- a/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs @@ -26,6 +26,7 @@ impl Drive { index_path_info: PathInfo<0>, index_level: &IndexLevel, mut any_fields_null: bool, + mut all_fields_null: bool, previous_batch_operations: &mut Option<&mut Vec>, storage_flags: &Option<&StorageFlags>, estimated_costs_only_with_layer_info: &mut Option< @@ -42,6 +43,7 @@ impl Drive { index_path_info.clone(), index_type, any_fields_null, + all_fields_null, previous_batch_operations, storage_flags, estimated_costs_only_with_layer_info, @@ -165,16 +167,18 @@ impl Drive { )?; any_fields_null |= document_index_field.is_empty(); + all_fields_null &= document_index_field.is_empty(); // we push the actual value of the index path sub_level_index_path_info.push(document_index_field)?; // Iteration 1. the index path is now something likeDataContracts/ContractID/Documents(1)/$ownerId//toUserId// // Iteration 2. the index path is now something likeDataContracts/ContractID/Documents(1)/$ownerId//toUserId//accountReference/ - self.add_indices_for_index_level_for_contract_operations( + self.add_indices_for_index_level_for_contract_operations_v0( document_and_contract_info, sub_level_index_path_info, sub_level, any_fields_null, + all_fields_null, previous_batch_operations, storage_flags, estimated_costs_only_with_layer_info, diff --git a/packages/rs-drive/src/drive/document/insert/add_indices_for_top_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/insert/add_indices_for_top_index_level_for_contract_operations/v0/mod.rs index f178fad0317..c21146a1832 100644 --- a/packages/rs-drive/src/drive/document/insert/add_indices_for_top_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/add_indices_for_top_index_level_for_contract_operations/v0/mod.rs @@ -158,6 +158,7 @@ impl Drive { } let any_fields_null = document_top_field.is_empty(); + let all_fields_null = document_top_field.is_empty(); let mut index_path_info = if document_and_contract_info .owned_document_info @@ -179,6 +180,7 @@ impl Drive { index_path_info, sub_level, any_fields_null, + all_fields_null, previous_batch_operations, &storage_flags, estimated_costs_only_with_layer_info, diff --git a/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/mod.rs b/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/mod.rs index 12192298cf9..bb95aa19332 100644 --- a/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/mod.rs @@ -11,7 +11,7 @@ use dpp::version::drive_versions::DriveVersion; use grovedb::batch::KeyInfoPath; -use dpp::data_contract::document_type::IndexType; +use dpp::data_contract::document_type::IndexLevelTypeInfo; use grovedb::{EstimatedLayerInformation, TransactionArg}; use std::collections::HashMap; @@ -21,8 +21,9 @@ impl Drive { &self, document_and_contract_info: &DocumentAndContractInfo, index_path_info: PathInfo<0>, - index_type: IndexType, + index_type: IndexLevelTypeInfo, any_fields_null: bool, + all_fields_null: bool, previous_batch_operations: &mut Option<&mut Vec>, storage_flags: &Option<&StorageFlags>, estimated_costs_only_with_layer_info: &mut Option< @@ -43,6 +44,7 @@ impl Drive { index_path_info, index_type, any_fields_null, + all_fields_null, previous_batch_operations, storage_flags, estimated_costs_only_with_layer_info, diff --git a/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/v0/mod.rs index c4847e1cb5e..be2ec0515d1 100644 --- a/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/v0/mod.rs @@ -16,7 +16,7 @@ use crate::util::object_size_info::{DocumentAndContractInfo, PathInfo, PathKeyEl use crate::util::storage_flags::StorageFlags; use crate::util::type_constants::DEFAULT_HASH_SIZE_U8; use dpp::data_contract::document_type::methods::DocumentTypeV0Methods; -use dpp::data_contract::document_type::IndexType; +use dpp::data_contract::document_type::IndexLevelTypeInfo; use dpp::document::DocumentV0Getters; use dpp::version::drive_versions::DriveVersion; use grovedb::batch::key_info::KeyInfo; @@ -33,8 +33,9 @@ impl Drive { &self, document_and_contract_info: &DocumentAndContractInfo, mut index_path_info: PathInfo<0>, - index_type: IndexType, + index_type: IndexLevelTypeInfo, any_fields_null: bool, + all_fields_null: bool, previous_batch_operations: &mut Option<&mut Vec>, storage_flags: &Option<&StorageFlags>, estimated_costs_only_with_layer_info: &mut Option< @@ -44,9 +45,12 @@ impl Drive { batch_operations: &mut Vec, drive_version: &DriveVersion, ) -> Result<(), Error> { + if all_fields_null && !index_type.should_insert_with_all_null { + return Ok(()); + } // unique indexes will be stored under key "0" // non-unique indices should have a tree at key "0" that has all elements based off of primary key - if !index_type.is_unique() || any_fields_null { + if !index_type.index_type.is_unique() || any_fields_null { // Tree generation, this happens for both non unique indexes, unique indexes with a null inside // a member of the path let key_path_info = KeyRef(&[0]); diff --git a/packages/rs-drive/src/drive/document/insert/mod.rs b/packages/rs-drive/src/drive/document/insert/mod.rs index bd87b1aab58..e2e2f378900 100644 --- a/packages/rs-drive/src/drive/document/insert/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/mod.rs @@ -671,12 +671,12 @@ mod tests { assert_eq!( fee_result, FeeResult { - storage_fee: 1761 + storage_fee: 1840 * Epoch::new(0).unwrap().cost_for_known_cost_item( &EPOCH_CHANGE_FEE_VERSION_TEST, StorageDiskUsageCreditPerByte, ), - processing_fee: 1227900, + processing_fee: 1264300, ..Default::default() } ); diff --git a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/mod.rs b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/mod.rs index 8f047cff323..ccb294ad2ba 100644 --- a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/mod.rs +++ b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/mod.rs @@ -8,7 +8,6 @@ use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerInformation; -use dpp::data_contract::document_type::DocumentTypeRef; use dpp::data_contract::DataContract; use std::collections::HashMap; diff --git a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs index b226cfb15ec..83f8c8dbc50 100644 --- a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs +++ b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs @@ -1,6 +1,4 @@ -use crate::drive::constants::{ - ESTIMATED_AVERAGE_DOCUMENT_TYPE_NAME_SIZE, -}; +use crate::drive::constants::ESTIMATED_AVERAGE_DOCUMENT_TYPE_NAME_SIZE; use crate::drive::Drive; @@ -11,8 +9,7 @@ use grovedb::EstimatedLayerSizes::AllSubtrees; use crate::drive::votes::paths::{ vote_contested_resource_active_polls_contract_tree_path, - vote_contested_resource_active_polls_tree_path, - vote_contested_resource_tree_path, + vote_contested_resource_active_polls_tree_path, vote_contested_resource_tree_path, vote_root_path, }; use crate::util::type_constants::DEFAULT_HASH_SIZE_U8; diff --git a/packages/rs-drive/src/drive/shared/shared_estimation_costs/mod.rs b/packages/rs-drive/src/drive/shared/shared_estimation_costs/mod.rs index 9140053bac4..d0d2bb88ca1 100644 --- a/packages/rs-drive/src/drive/shared/shared_estimation_costs/mod.rs +++ b/packages/rs-drive/src/drive/shared/shared_estimation_costs/mod.rs @@ -1,4 +1,4 @@ mod add_estimation_costs_for_contested_document_tree_levels_up_to_contract; +mod add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded; mod add_estimation_costs_for_levels_up_to_contract; mod add_estimation_costs_for_levels_up_to_contract_document_type_excluded; -mod add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded; diff --git a/packages/rs-drive/src/util/test_helpers/mod.rs b/packages/rs-drive/src/util/test_helpers/mod.rs index b92848fd1df..81447b46915 100644 --- a/packages/rs-drive/src/util/test_helpers/mod.rs +++ b/packages/rs-drive/src/util/test_helpers/mod.rs @@ -35,7 +35,7 @@ pub mod setup; pub mod test_utils; #[cfg(feature = "fixtures-and-mocks")] -/// Serializes to CBOR and applies to Drive a JSON contract from the file system. +/// Applies to Drive a JSON contract from the file system. pub fn setup_contract( drive: &Drive, path: &str, diff --git a/packages/rs-drive/tests/query_tests.rs b/packages/rs-drive/tests/query_tests.rs index c62c347bf43..f29741e83d1 100644 --- a/packages/rs-drive/tests/query_tests.rs +++ b/packages/rs-drive/tests/query_tests.rs @@ -3167,8 +3167,8 @@ fn test_dpns_query() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 244, 146, 123, 117, 189, 33, 121, 197, 170, 145, 77, 125, 25, 189, 87, 118, 50, 94, 170, 7, - 21, 208, 63, 241, 89, 4, 243, 50, 118, 21, 49, 24, + 142, 246, 25, 166, 52, 184, 158, 102, 192, 111, 173, 255, 155, 125, 53, 233, 98, 241, 201, + 233, 2, 58, 47, 90, 209, 207, 147, 204, 83, 68, 183, 143, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -3439,9 +3439,9 @@ fn test_dpns_query() { .expect("we should be able to get the records"); let map_records_value = records_value.as_map().expect("this should be a map"); let record_dash_unique_identity_id = - Value::inner_optional_bytes_value(map_records_value, "identity") + Value::inner_optional_bytes_value(map_records_value, "dashUniqueIdentityId") .unwrap() - .expect("there should be a identity"); + .expect("there should be a dashUniqueIdentityId"); bs58::encode(record_dash_unique_identity_id).into_string() }) .collect(); @@ -3454,11 +3454,11 @@ fn test_dpns_query() { let query_value = json!({ "where": [ - ["records.identity", "<=", "5hXRj1xmmnNQ7RN1ATYym4x6bQugxcKn7FWiMnkQTQpF"], + ["records.dashUniqueIdentityId", "<=", "5hXRj1xmmnNQ7RN1ATYym4x6bQugxcKn7FWiMnkQTQpF"], ], "limit": 10, "orderBy": [ - ["records.identity", "desc"] + ["records.dashUniqueIdentityId", "desc"] ] }); let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) @@ -3510,11 +3510,11 @@ fn test_dpns_query() { let query_value = json!({ "where": [ - ["records.identity", "<=", "5hXRj1xmmnNQ7RN1ATYym4x6bQugxcKn7FWiMnkQTQpF"], + ["records.dashUniqueIdentityId", "<=", "5hXRj1xmmnNQ7RN1ATYym4x6bQugxcKn7FWiMnkQTQpF"], ], "limit": 2, "orderBy": [ - ["records.identity", "asc"] + ["records.dashUniqueIdentityId", "asc"] ] }); let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) @@ -3562,7 +3562,7 @@ fn test_dpns_query() { let query_value = json!({ "orderBy": [ - ["records.identity", "desc"] + ["records.dashUniqueIdentityId", "desc"] ] }); let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) @@ -3602,7 +3602,7 @@ fn test_dpns_insertion_no_aliases() { let db_transaction = drive.grove.start_transaction(); let query_value = json!({ - "orderBy": [["records.identity", "desc"]], + "orderBy": [["records.dashUniqueIdentityId", "desc"]], }); let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) @@ -3658,7 +3658,7 @@ fn test_dpns_insertion_with_aliases() { let db_transaction = drive.grove.start_transaction(); let query_value = json!({ - "orderBy": [["records.identity", "desc"]], + "orderBy": [["records.dashUniqueIdentityId", "desc"]], }); let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) @@ -3719,8 +3719,8 @@ fn test_dpns_query_start_at() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 244, 146, 123, 117, 189, 33, 121, 197, 170, 145, 77, 125, 25, 189, 87, 118, 50, 94, 170, 7, - 21, 208, 63, 241, 89, 4, 243, 50, 118, 21, 49, 24, + 142, 246, 25, 166, 52, 184, 158, 102, 192, 111, 173, 255, 155, 125, 53, 233, 98, 241, 201, + 233, 2, 58, 47, 90, 209, 207, 147, 204, 83, 68, 183, 143, ]; assert_eq!(root_hash.as_slice(), expected_app_hash,); @@ -3813,8 +3813,8 @@ fn test_dpns_query_start_after() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 244, 146, 123, 117, 189, 33, 121, 197, 170, 145, 77, 125, 25, 189, 87, 118, 50, 94, 170, 7, - 21, 208, 63, 241, 89, 4, 243, 50, 118, 21, 49, 24, + 142, 246, 25, 166, 52, 184, 158, 102, 192, 111, 173, 255, 155, 125, 53, 233, 98, 241, 201, + 233, 2, 58, 47, 90, 209, 207, 147, 204, 83, 68, 183, 143, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -3907,8 +3907,8 @@ fn test_dpns_query_start_at_desc() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 244, 146, 123, 117, 189, 33, 121, 197, 170, 145, 77, 125, 25, 189, 87, 118, 50, 94, 170, 7, - 21, 208, 63, 241, 89, 4, 243, 50, 118, 21, 49, 24, + 142, 246, 25, 166, 52, 184, 158, 102, 192, 111, 173, 255, 155, 125, 53, 233, 98, 241, 201, + 233, 2, 58, 47, 90, 209, 207, 147, 204, 83, 68, 183, 143, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4001,8 +4001,8 @@ fn test_dpns_query_start_after_desc() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 244, 146, 123, 117, 189, 33, 121, 197, 170, 145, 77, 125, 25, 189, 87, 118, 50, 94, 170, 7, - 21, 208, 63, 241, 89, 4, 243, 50, 118, 21, 49, 24, + 142, 246, 25, 166, 52, 184, 158, 102, 192, 111, 173, 255, 155, 125, 53, 233, 98, 241, 201, + 233, 2, 58, 47, 90, 209, 207, 147, 204, 83, 68, 183, 143, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4195,8 +4195,8 @@ fn test_dpns_query_start_at_with_null_id() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 217, 196, 25, 2, 88, 47, 16, 244, 117, 34, 65, 18, 208, 158, 14, 207, 158, 105, 191, 62, - 108, 124, 189, 159, 196, 137, 212, 243, 65, 230, 231, 95, + 72, 138, 172, 70, 225, 95, 64, 122, 142, 96, 131, 223, 154, 119, 132, 79, 182, 97, 202, 63, + 120, 116, 39, 217, 25, 208, 176, 49, 242, 138, 67, 112, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4398,8 +4398,8 @@ fn test_dpns_query_start_after_with_null_id() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 217, 196, 25, 2, 88, 47, 16, 244, 117, 34, 65, 18, 208, 158, 14, 207, 158, 105, 191, 62, - 108, 124, 189, 159, 196, 137, 212, 243, 65, 230, 231, 95, + 72, 138, 172, 70, 225, 95, 64, 122, 142, 96, 131, 223, 154, 119, 132, 79, 182, 97, 202, 63, + 120, 116, 39, 217, 25, 208, 176, 49, 242, 138, 67, 112, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4605,8 +4605,8 @@ fn test_dpns_query_start_after_with_null_id_desc() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 217, 196, 25, 2, 88, 47, 16, 244, 117, 34, 65, 18, 208, 158, 14, 207, 158, 105, 191, 62, - 108, 124, 189, 159, 196, 137, 212, 243, 65, 230, 231, 95, + 72, 138, 172, 70, 225, 95, 64, 122, 142, 96, 131, 223, 154, 119, 132, 79, 182, 97, 202, 63, + 120, 116, 39, 217, 25, 208, 176, 49, 242, 138, 67, 112, ]; assert_eq!(root_hash.as_slice(), expected_app_hash,); diff --git a/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract-label-not-required.json b/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract-label-not-required.json index f833e1da0cf..020255c4d40 100644 --- a/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract-label-not-required.json +++ b/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract-label-not-required.json @@ -23,7 +23,7 @@ "name": "dashIdentityId", "properties": [ { - "records.identity": "asc" + "records.dashUniqueIdentityId": "asc" } ], "unique": true @@ -74,7 +74,7 @@ "records": { "type": "object", "properties": { - "identity": { + "dashUniqueIdentityId": { "type": "array", "byteArray": true, "minItems": 32, diff --git a/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract-update-v2-test.json b/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract-update-v2-test.json index 1b0c645a9cf..ab68c409449 100644 --- a/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract-update-v2-test.json +++ b/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract-update-v2-test.json @@ -23,7 +23,7 @@ "name": "dashIdentityId", "properties": [ { - "records.identity": "asc" + "records.dashUniqueIdentityId": "asc" } ], "unique": true @@ -74,7 +74,7 @@ "records": { "type": "object", "properties": { - "identity": { + "dashUniqueIdentityId": { "type": "array", "byteArray": true, "minItems": 32, diff --git a/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract.json b/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract.json index 805cfb19002..852bf5b0317 100644 --- a/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract.json +++ b/packages/rs-drive/tests/supporting_files/contract/dpns/dpns-contract.json @@ -23,7 +23,7 @@ "name": "dashIdentityId", "properties": [ { - "records.identity": "asc" + "records.dashUniqueIdentityId": "asc" } ], "unique": true @@ -74,7 +74,7 @@ "records": { "type": "object", "properties": { - "identity": { + "dashUniqueIdentityId": { "type": "array", "byteArray": true, "minItems": 32, diff --git a/packages/rs-platform-version/src/version/drive_versions.rs b/packages/rs-platform-version/src/version/drive_versions.rs index 18ab0b82ddf..41a0061a791 100644 --- a/packages/rs-platform-version/src/version/drive_versions.rs +++ b/packages/rs-platform-version/src/version/drive_versions.rs @@ -733,5 +733,6 @@ pub struct DriveEstimatedCostsMethodVersions { pub add_estimation_costs_for_levels_up_to_contract: FeatureVersion, pub add_estimation_costs_for_levels_up_to_contract_document_type_excluded: FeatureVersion, pub add_estimation_costs_for_contested_document_tree_levels_up_to_contract: FeatureVersion, - pub add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded: FeatureVersion, + pub add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded: + FeatureVersion, }