diff --git a/packages/rs-dpp/src/data_contract/methods/validate_update/mod.rs b/packages/rs-dpp/src/data_contract/methods/validate_update/mod.rs index e40ea1cb625..2a40b26459f 100644 --- a/packages/rs-dpp/src/data_contract/methods/validate_update/mod.rs +++ b/packages/rs-dpp/src/data_contract/methods/validate_update/mod.rs @@ -1,3 +1,4 @@ +use crate::block::block_info::BlockInfo; use crate::prelude::DataContract; use platform_version::version::PlatformVersion; @@ -10,6 +11,7 @@ impl DataContractUpdateValidationMethodsV0 for DataContract { fn validate_update( &self, data_contract: &DataContract, + block_info: &BlockInfo, platform_version: &PlatformVersion, ) -> Result { match platform_version @@ -18,7 +20,7 @@ impl DataContractUpdateValidationMethodsV0 for DataContract { .methods .validate_update { - 0 => self.validate_update_v0(data_contract, platform_version), + 0 => self.validate_update_v0(data_contract, block_info, platform_version), version => Err(ProtocolError::UnknownVersionMismatch { method: "DataContract::validate_update".to_string(), known_versions: vec![0], diff --git a/packages/rs-dpp/src/data_contract/methods/validate_update/v0/mod.rs b/packages/rs-dpp/src/data_contract/methods/validate_update/v0/mod.rs index b1b9b2b1578..0ce43249224 100644 --- a/packages/rs-dpp/src/data_contract/methods/validate_update/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/methods/validate_update/v0/mod.rs @@ -1,3 +1,6 @@ +use crate::block::block_info::BlockInfo; +use crate::consensus::state::state_error::StateError; +use crate::consensus::state::token::PreProgrammedDistributionTimestampInPastError; use crate::data_contract::accessors::v0::DataContractV0Getters; use crate::consensus::basic::data_contract::{ @@ -7,6 +10,9 @@ use crate::consensus::state::data_contract::data_contract_update_action_not_allo use crate::consensus::state::data_contract::data_contract_update_permission_error::DataContractUpdatePermissionError; use crate::consensus::state::data_contract::document_type_update_error::DocumentTypeUpdateError; use crate::data_contract::accessors::v1::DataContractV1Getters; +use crate::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use crate::data_contract::associated_token::token_distribution_rules::accessors::v0::TokenDistributionRulesV0Getters; +use crate::data_contract::associated_token::token_pre_programmed_distribution::accessors::v0::TokenPreProgrammedDistributionV0Methods; use crate::data_contract::document_type::schema::validate_schema_compatibility; use crate::data_contract::schema::DataContractSchemaMethodsV0; use crate::data_contract::DataContract; @@ -20,6 +26,7 @@ pub trait DataContractUpdateValidationMethodsV0 { fn validate_update( &self, data_contract: &DataContract, + block_info: &BlockInfo, platform_version: &PlatformVersion, ) -> Result; } @@ -29,6 +36,7 @@ impl DataContract { pub(super) fn validate_update_v0( &self, new_data_contract: &DataContract, + block_info: &BlockInfo, platform_version: &PlatformVersion, ) -> Result { // Check if the contract is owned by the same identity @@ -199,12 +207,6 @@ impl DataContract { } } } - - let valid = - DataContract::validate_groups(new_data_contract.groups(), platform_version)?; - if !valid.is_valid() { - return Ok(valid); - } } if self.tokens() != new_data_contract.tokens() { @@ -234,16 +236,29 @@ impl DataContract { } } - // Check if a token has been added - for token_position in new_data_contract.tokens().keys() { - if !self.tokens().contains_key(token_position) { - return Ok(SimpleConsensusValidationResult::new_with_error( - DataContractUpdateActionNotAllowedError::new( - self.id(), - format!("add token at position {}", token_position), - ) - .into(), - )); + // Validate any newly added tokens + for (token_contract_position, token_configuration) in new_data_contract.tokens() { + if !self.tokens().contains_key(token_contract_position) { + if let Some(distribution) = token_configuration + .distribution_rules() + .pre_programmed_distribution() + { + if let Some((timestamp, _)) = distribution.distributions().iter().next() { + if timestamp < &block_info.time_ms { + return Ok(SimpleConsensusValidationResult::new_with_error( + StateError::PreProgrammedDistributionTimestampInPastError( + PreProgrammedDistributionTimestampInPastError::new( + new_data_contract.id(), + *token_contract_position, + *timestamp, + block_info.time_ms, + ), + ) + .into(), + )); + } + } + } } } } @@ -275,6 +290,13 @@ mod tests { TokenConfigurationV0Getters, TokenConfigurationV0Setters, }; use crate::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; + use crate::data_contract::associated_token::token_configuration_convention::v0::TokenConfigurationConventionV0; + use crate::data_contract::associated_token::token_configuration_convention::TokenConfigurationConvention; + use crate::data_contract::associated_token::token_configuration_localization::v0::TokenConfigurationLocalizationV0; + use crate::data_contract::associated_token::token_configuration_localization::TokenConfigurationLocalization; + use crate::data_contract::associated_token::token_distribution_rules::accessors::v0::TokenDistributionRulesV0Setters; + use crate::data_contract::associated_token::token_pre_programmed_distribution::v0::TokenPreProgrammedDistributionV0; + use crate::data_contract::associated_token::token_pre_programmed_distribution::TokenPreProgrammedDistribution; use crate::data_contract::document_type::DocumentTypeMutRef; use crate::data_contract::group::accessors::v0::{GroupV0Getters, GroupV0Setters}; use crate::data_contract::group::v0::GroupV0; @@ -295,7 +317,7 @@ mod tests { new_data_contract.as_v0_mut().unwrap().owner_id = Identifier::random(); let result = old_data_contract - .validate_update(&new_data_contract, platform_version) + .validate_update(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert_matches!( @@ -316,7 +338,7 @@ mod tests { let new_data_contract = old_data_contract.clone(); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert_matches!( @@ -340,7 +362,7 @@ mod tests { new_data_contract.config_mut().set_readonly(true); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert_matches!( @@ -366,7 +388,7 @@ mod tests { .remove("niceDocument"); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert_matches!( @@ -399,7 +421,7 @@ mod tests { new_document_type.documents_mutable = false; let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert_matches!( @@ -430,7 +452,7 @@ mod tests { .expect("failed to set schema defs"); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert_matches!( @@ -470,7 +492,7 @@ mod tests { .expect("failed to set schema defs"); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert_matches!( @@ -493,7 +515,7 @@ mod tests { new_data_contract.set_version(old_data_contract.version() + 1); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert!(result.is_valid()); @@ -542,7 +564,7 @@ mod tests { .remove(&first_group_pos); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert_matches!( @@ -598,7 +620,7 @@ mod tests { .insert(first_group_pos, altered_group); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert_matches!( @@ -644,7 +666,7 @@ mod tests { .remove(&first_token_pos); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert_matches!( @@ -688,7 +710,7 @@ mod tests { .insert(first_token_pos, altered_token_cfg); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert_matches!( @@ -700,21 +722,32 @@ mod tests { } #[test] - fn should_return_invalid_result_when_new_token_is_added() { + fn should_return_invalid_result_when_token_is_added_with_past_timestamp() { let platform_version = PlatformVersion::latest(); let mut old_data_contract = get_data_contract_fixture(None, IdentityNonce::default(), 9).data_contract_owned(); - old_data_contract.set_tokens(BTreeMap::from([( - 0, - TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), - )])); + let mut token_cfg = + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()); + token_cfg.set_conventions(TokenConfigurationConvention::V0( + TokenConfigurationConventionV0 { + localizations: BTreeMap::from([( + "en".to_string(), + TokenConfigurationLocalization::V0(TokenConfigurationLocalizationV0 { + should_capitalize: false, + singular_form: "test".to_string(), + plural_form: "tests".to_string(), + }), + )]), + decimals: 8, + }, + )); + old_data_contract.set_tokens(BTreeMap::from([(0, token_cfg)])); let mut new_data_contract = old_data_contract.clone(); new_data_contract.set_version(old_data_contract.version() + 1); - // Create a new token by cloning an existing config but - // inserting it at an unused position. + // Create a new token with a past timestamp let existing_cfg = new_data_contract .tokens() .values() @@ -727,23 +760,85 @@ mod tests { .max() .expect("fixture must have at least one token") + 1; + let mut new_token_cfg = existing_cfg.clone(); + new_token_cfg + .distribution_rules_mut() + .set_pre_programmed_distribution(Some(TokenPreProgrammedDistribution::V0( + TokenPreProgrammedDistributionV0 { + distributions: BTreeMap::from([( + 0, + BTreeMap::from([(new_data_contract.owner_id(), 100)]), + )]), + }, + ))); new_data_contract .tokens_mut() .unwrap() - .insert(new_position, existing_cfg); + .insert(new_position, new_token_cfg); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0( + &new_data_contract, + &BlockInfo::default_with_time(100000), + platform_version, + ) .expect("failed validate update"); assert_matches!( result.errors.as_slice(), [ConsensusError::StateError( - StateError::DataContractUpdateActionNotAllowedError(e) - )] if e.action() == format!("add token at position {}", new_position) + StateError::PreProgrammedDistributionTimestampInPastError(e) + )] if e.token_position() == new_position ); } + #[test] + fn should_pass_when_a_well_formed_new_token_is_added() { + let platform_version = PlatformVersion::latest(); + + let old_data_contract = + get_data_contract_fixture(None, IdentityNonce::default(), 9).data_contract_owned(); + + let mut new_data_contract = old_data_contract.clone(); + new_data_contract.set_version(old_data_contract.version() + 1); + + // build a fully valid token configuration + let valid_token_cfg = { + let mut cfg = + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()); + + cfg.set_base_supply(1_000_000); // within limits + + cfg.set_conventions(TokenConfigurationConvention::V0( + TokenConfigurationConventionV0 { + localizations: BTreeMap::from([( + "en".to_string(), + TokenConfigurationLocalization::V0(TokenConfigurationLocalizationV0 { + should_capitalize: true, + singular_form: "credit".to_string(), + plural_form: "credits".to_string(), + }), + )]), + decimals: 8, + }, + )); + + cfg + }; + + // insert at contiguous position 0 (old contract had no tokens) + new_data_contract + .tokens_mut() + .unwrap() + .insert(0, valid_token_cfg); + + let result = old_data_contract + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) + .expect("failed validate update"); + + assert!(result.is_valid(), "well‑formed token should be accepted"); + } + // // ────────────────────────────────────────────────────────────────────────── // Happy‑path check: no token / group changes @@ -761,7 +856,7 @@ mod tests { new_data_contract.set_version(old_data_contract.version() + 1); let result = old_data_contract - .validate_update_v0(&new_data_contract, platform_version) + .validate_update_v0(&new_data_contract, &BlockInfo::default(), platform_version) .expect("failed validate update"); assert!(result.is_valid()); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs index c27387ebaac..7595b74e84d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs @@ -64,7 +64,7 @@ pub(super) fn state_transition_to_execution_event_for_check_tx_v0<'a, C: CoreRPC } // Only Data contract update does not have basic structure validation - if state_transition.has_basic_structure_validation() { + if state_transition.has_basic_structure_validation(platform_version) { // First we validate the basic structure let result = state_transition.validate_basic_structure(platform_version)?; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs index 12d7bdd4e06..419fcffcca9 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs @@ -21,9 +21,9 @@ use drive::grovedb::TransactionArg; use drive::state_transition_action::StateTransitionAction; use std::collections::BTreeMap; -use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext}; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::execution::validation::state_transition::common::validate_simple_pre_check_balance::ValidateSimplePreCheckBalance; -use crate::execution::validation::state_transition::common::validate_state_transition_identity_signed::{ValidateStateTransitionIdentitySignature}; +use crate::execution::validation::state_transition::common::validate_state_transition_identity_signed::ValidateStateTransitionIdentitySignature; use crate::execution::validation::state_transition::identity_create::{StateTransitionStateValidationForIdentityCreateTransitionV0, StateTransitionStructureKnownInStateValidationForIdentityCreateTransitionV0}; use crate::execution::validation::state_transition::identity_top_up::StateTransitionIdentityTopUpTransitionActionTransformer; use crate::execution::validation::state_transition::state_transitions::identity_update::advanced_structure::v0::IdentityUpdateStateTransitionIdentityAndSignaturesValidationV0; @@ -105,7 +105,7 @@ pub(super) fn process_state_transition_v0<'a, C: CoreRPCLike>( } // Only Data contract state transitions and Masternode vote do not have basic structure validation - if state_transition.has_basic_structure_validation() { + if state_transition.has_basic_structure_validation(platform_version) { // We validate basic structure validation after verifying the identity, // this is structure validation that does not require state and is already checked on check_tx let consensus_result = state_transition.validate_basic_structure(platform_version)?; @@ -333,7 +333,7 @@ pub(crate) trait StateTransitionBasicStructureValidationV0 { /// True if the state transition has basic structure validation. /// Currently only data contract update does not - fn has_basic_structure_validation(&self) -> bool { + fn has_basic_structure_validation(&self, _platform_version: &PlatformVersion) -> bool { true } } @@ -516,9 +516,7 @@ impl StateTransitionBasicStructureValidationV0 for StateTransition { platform_version: &PlatformVersion, ) -> Result { match self { - StateTransition::DataContractCreate(_) - | StateTransition::DataContractUpdate(_) - | StateTransition::MasternodeVote(_) => { + StateTransition::MasternodeVote(_) => { // no basic structure validation Ok(SimpleConsensusValidationResult::new()) } @@ -532,15 +530,66 @@ impl StateTransitionBasicStructureValidationV0 for StateTransition { StateTransition::IdentityCreditTransfer(st) => { st.validate_basic_structure(platform_version) } + StateTransition::DataContractCreate(st) => { + if platform_version + .drive_abci + .validation_and_processing + .state_transitions + .contract_create_state_transition + .basic_structure + .is_some() + { + st.validate_basic_structure(platform_version) + } else { + Ok(SimpleConsensusValidationResult::new()) + } + } + StateTransition::DataContractUpdate(st) => { + if platform_version + .drive_abci + .validation_and_processing + .state_transitions + .contract_update_state_transition + .basic_structure + .is_some() + { + st.validate_basic_structure(platform_version) + } else { + Ok(SimpleConsensusValidationResult::new()) + } + } } } - fn has_basic_structure_validation(&self) -> bool { - !matches!( - self, - StateTransition::DataContractCreate(_) - | StateTransition::DataContractUpdate(_) - | StateTransition::MasternodeVote(_) - ) + fn has_basic_structure_validation(&self, platform_version: &PlatformVersion) -> bool { + match self { + StateTransition::DataContractCreate(_) => { + // Added in protocol version 9 (version 2.0) + platform_version + .drive_abci + .validation_and_processing + .state_transitions + .contract_create_state_transition + .basic_structure + .is_some() + } + StateTransition::DataContractUpdate(_) => { + // Added in protocol version 9 (version 2.0) + platform_version + .drive_abci + .validation_and_processing + .state_transitions + .contract_update_state_transition + .basic_structure + .is_some() + } + StateTransition::Batch(_) + | StateTransition::IdentityCreate(_) + | StateTransition::IdentityTopUp(_) + | StateTransition::IdentityCreditWithdrawal(_) + | StateTransition::IdentityUpdate(_) + | StateTransition::IdentityCreditTransfer(_) => true, + StateTransition::MasternodeVote(_) => false, + } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/mod.rs index 9a1925de7fc..008be12cc67 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/mod.rs @@ -1 +1,2 @@ pub(crate) mod v0; +pub(crate) mod v1; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs index 5f2db600793..625392ee141 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs @@ -1,25 +1,16 @@ use crate::error::Error; -use crate::execution::types::execution_operation::ValidationOperation; -use crate::execution::types::state_transition_execution_context::{ - StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, -}; -use dpp::consensus::basic::data_contract::{ - InvalidDataContractIdError, InvalidDataContractVersionError, InvalidTokenBaseSupplyError, - NonContiguousContractTokenPositionsError, -}; -use dpp::consensus::basic::BasicError; -use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; -use dpp::data_contract::{TokenContractPosition, INITIAL_DATA_CONTRACT_VERSION}; -use dpp::prelude::DataContract; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::execution::validation::state_transition::data_contract_create::advanced_structure::v1::DataContractCreatedStateTransitionAdvancedStructureValidationV1; +use dpp::consensus::basic::data_contract::InvalidDataContractVersionError; +use dpp::data_contract::INITIAL_DATA_CONTRACT_VERSION; use dpp::state_transition::data_contract_create_transition::accessors::DataContractCreateTransitionAccessorsV0; use dpp::state_transition::data_contract_create_transition::DataContractCreateTransition; use dpp::validation::ConsensusValidationResult; -use dpp::version::PlatformVersion; use drive::state_transition_action::system::bump_identity_nonce_action::BumpIdentityNonceAction; use drive::state_transition_action::StateTransitionAction; pub(in crate::execution::validation::state_transition::state_transitions::data_contract_create) trait DataContractCreatedStateTransitionAdvancedStructureValidationV0 { - fn validate_advanced_structure_v0(&self, execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion) -> Result, Error>; + fn validate_advanced_structure_v0(&self, execution_context: &mut StateTransitionExecutionContext) -> Result, Error>; } impl DataContractCreatedStateTransitionAdvancedStructureValidationV0 @@ -28,8 +19,8 @@ impl DataContractCreatedStateTransitionAdvancedStructureValidationV0 fn validate_advanced_structure_v0( &self, execution_context: &mut StateTransitionExecutionContext, - platform_version: &PlatformVersion, ) -> Result, Error> { + // Moved this to basic structure validation in protocol version 9 if self.data_contract().version() != INITIAL_DATA_CONTRACT_VERSION { let bump_action = StateTransitionAction::BumpIdentityNonceAction( BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), @@ -45,230 +36,77 @@ impl DataContractCreatedStateTransitionAdvancedStructureValidationV0 )); } - // Validate data contract id - let generated_id = DataContract::generate_data_contract_id_v0( - self.data_contract().owner_id(), - self.identity_nonce(), - ); - - // This hash will only take 1 block (64 bytes) - execution_context.add_operation(ValidationOperation::DoubleSha256(1)); - - if generated_id != self.data_contract().id() { - let bump_action = StateTransitionAction::BumpIdentityNonceAction( - BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - vec![ - BasicError::InvalidDataContractIdError(InvalidDataContractIdError::new( - generated_id.to_vec(), - self.data_contract().id().to_vec(), - )) - .into(), - ], - )); - } - - let groups = self.data_contract().groups(); - if !groups.is_empty() { - let validation_result = DataContract::validate_groups(groups, platform_version)?; - - if !validation_result.is_valid() { - let bump_action = StateTransitionAction::BumpIdentityNonceAction( - BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - validation_result.errors, - )); - } - } - - for (expected_position, (token_contract_position, token_configuration)) in - self.data_contract().tokens().iter().enumerate() - { - if expected_position as TokenContractPosition != *token_contract_position { - let bump_action = StateTransitionAction::BumpIdentityNonceAction( - BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - vec![NonContiguousContractTokenPositionsError::new( - expected_position as TokenContractPosition, - *token_contract_position, - ) - .into()], - )); - } - - if token_configuration.base_supply() > i64::MAX as u64 { - let bump_action = StateTransitionAction::BumpIdentityNonceAction( - BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - vec![ - InvalidTokenBaseSupplyError::new(token_configuration.base_supply()).into(), - ], - )); - } - - let validation_result = token_configuration - .conventions() - .validate_localizations(platform_version)?; - if !validation_result.is_valid() { - let bump_action = StateTransitionAction::BumpIdentityNonceAction( - BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - validation_result.errors, - )); - } - - let validation_result = token_configuration.validate_token_config_groups_exist( - self.data_contract().groups(), - platform_version, - )?; - if !validation_result.is_valid() { - let bump_action = StateTransitionAction::BumpIdentityNonceAction( - BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - validation_result.errors, - )); - } - } - - Ok(ConsensusValidationResult::default()) + self.validate_advanced_structure_v1(execution_context) } } #[cfg(test)] mod tests { use super::*; + use crate::execution::types::execution_operation::ValidationOperation; + use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContextMethodsV0; use assert_matches::assert_matches; - - mod validate_advanced_structure { - use super::*; - use dpp::consensus::ConsensusError; - use dpp::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; - use dpp::prelude::{Identifier, IdentityNonce}; - use dpp::state_transition::data_contract_create_transition::DataContractCreateTransitionV0; - use dpp::tests::fixtures::get_data_contract_fixture; - use drive::state_transition_action::system::bump_identity_nonce_action::BumpIdentityNonceActionAccessorsV0; - use platform_version::version::PlatformVersion; - use platform_version::{DefaultForPlatformVersion, TryIntoPlatformVersioned}; - - #[test] - fn should_return_invalid_result_if_contract_version_is_not_initial() { - let platform_version = PlatformVersion::latest(); - let identity_nonce = IdentityNonce::default(); - - let mut data_contract = - get_data_contract_fixture(None, identity_nonce, platform_version.protocol_version) - .data_contract_owned(); - - data_contract.set_version(6); - - let identity_id = data_contract.owner_id(); - - let data_contract_for_serialization = data_contract - .try_into_platform_versioned(platform_version) - .expect("failed to convert data contract"); - - let transition: DataContractCreateTransition = DataContractCreateTransitionV0 { - data_contract: data_contract_for_serialization, - identity_nonce, - user_fee_increase: 0, - signature_public_key_id: 0, - signature: Default::default(), - } - .into(); - - let mut execution_context = - StateTransitionExecutionContext::default_for_platform_version(platform_version) - .expect("failed to create execution context"); - - let result = transition - .validate_advanced_structure_v0(&mut execution_context, platform_version) - .expect("failed to validate advanced structure"); - - assert_matches!(execution_context.operations_slice(), []); - - assert_matches!( - result.data, - Some(StateTransitionAction::BumpIdentityNonceAction(action)) - if action.identity_id() == identity_id && action.identity_nonce() == identity_nonce - ); - - assert_matches!( - result.errors.as_slice(), - [ConsensusError::BasicError(BasicError::InvalidDataContractVersionError(e))] if e.expected_version() == INITIAL_DATA_CONTRACT_VERSION && e.version() == 6 - ); + use dpp::consensus::basic::BasicError; + use dpp::consensus::ConsensusError; + use dpp::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; + use dpp::prelude::{Identifier, IdentityNonce}; + use dpp::state_transition::data_contract_create_transition::DataContractCreateTransitionV0; + use dpp::tests::fixtures::get_data_contract_fixture; + use drive::state_transition_action::system::bump_identity_nonce_action::BumpIdentityNonceActionAccessorsV0; + use platform_version::version::PlatformVersion; + use platform_version::{DefaultForPlatformVersion, TryIntoPlatformVersioned}; + + #[test] + fn should_return_invalid_result_if_contract_id_is_not_valid() { + let platform_version = PlatformVersion::latest(); + let identity_nonce = IdentityNonce::default(); + + let mut data_contract = + get_data_contract_fixture(None, identity_nonce, platform_version.protocol_version) + .data_contract_owned(); + + let identity_id = data_contract.owner_id(); + let original_id = data_contract.id(); + let invalid_id = Identifier::default(); + + data_contract.set_id(invalid_id); + + let data_contract_for_serialization = data_contract + .try_into_platform_versioned(platform_version) + .expect("failed to convert data contract"); + + let transition: DataContractCreateTransition = DataContractCreateTransitionV0 { + data_contract: data_contract_for_serialization, + identity_nonce, + user_fee_increase: 0, + signature_public_key_id: 0, + signature: Default::default(), } + .into(); + + let mut execution_context = + StateTransitionExecutionContext::default_for_platform_version(platform_version) + .expect("failed to create execution context"); + + let result = transition + .validate_advanced_structure_v0(&mut execution_context) + .expect("failed to validate advanced structure"); + assert_matches!( + execution_context.operations_slice(), + [ValidationOperation::DoubleSha256(1)] + ); - #[test] - fn should_return_invalid_result_if_contract_id_is_not_valid() { - let platform_version = PlatformVersion::latest(); - let identity_nonce = IdentityNonce::default(); - - let mut data_contract = - get_data_contract_fixture(None, identity_nonce, platform_version.protocol_version) - .data_contract_owned(); - - let identity_id = data_contract.owner_id(); - let original_id = data_contract.id(); - let invalid_id = Identifier::default(); - - data_contract.set_id(invalid_id); - - let data_contract_for_serialization = data_contract - .try_into_platform_versioned(platform_version) - .expect("failed to convert data contract"); - - let transition: DataContractCreateTransition = DataContractCreateTransitionV0 { - data_contract: data_contract_for_serialization, - identity_nonce, - user_fee_increase: 0, - signature_public_key_id: 0, - signature: Default::default(), - } - .into(); - - let mut execution_context = - StateTransitionExecutionContext::default_for_platform_version(platform_version) - .expect("failed to create execution context"); - - let result = transition - .validate_advanced_structure_v0(&mut execution_context, platform_version) - .expect("failed to validate advanced structure"); - - assert_matches!( - execution_context.operations_slice(), - [ValidationOperation::DoubleSha256(1)] - ); - - assert_matches!( - result.data, - Some(StateTransitionAction::BumpIdentityNonceAction(action)) - if action.identity_id() == identity_id && action.identity_nonce() == identity_nonce - ); + assert_matches!( + result.data, + Some(StateTransitionAction::BumpIdentityNonceAction(action)) + if action.identity_id() == identity_id && action.identity_nonce() == identity_nonce + ); - assert_matches!( - result.errors.as_slice(), - [ConsensusError::BasicError(BasicError::InvalidDataContractIdError(e))] - if Identifier::try_from(e.expected_id()).unwrap() == original_id - && Identifier::try_from(e.invalid_id()).unwrap() == invalid_id - ); - } + assert_matches!( + result.errors.as_slice(), + [ConsensusError::BasicError(BasicError::InvalidDataContractIdError(e))] + if Identifier::try_from(e.expected_id()).unwrap() == original_id + && Identifier::try_from(e.invalid_id()).unwrap() == invalid_id + ); } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v1/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v1/mod.rs new file mode 100644 index 00000000000..7cd0bb8027a --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v1/mod.rs @@ -0,0 +1,127 @@ +use crate::error::Error; +use crate::execution::types::execution_operation::ValidationOperation; +use crate::execution::types::state_transition_execution_context::{ + StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, +}; +use dpp::consensus::basic::data_contract::InvalidDataContractIdError; +use dpp::consensus::basic::BasicError; +use dpp::prelude::DataContract; +use dpp::state_transition::data_contract_create_transition::accessors::DataContractCreateTransitionAccessorsV0; +use dpp::state_transition::data_contract_create_transition::DataContractCreateTransition; +use dpp::validation::ConsensusValidationResult; +use drive::state_transition_action::system::bump_identity_nonce_action::BumpIdentityNonceAction; +use drive::state_transition_action::StateTransitionAction; + +pub(in crate::execution::validation::state_transition::state_transitions::data_contract_create) trait DataContractCreatedStateTransitionAdvancedStructureValidationV1 { + fn validate_advanced_structure_v1(&self, execution_context: &mut StateTransitionExecutionContext) -> Result, Error>; +} + +impl DataContractCreatedStateTransitionAdvancedStructureValidationV1 + for DataContractCreateTransition +{ + fn validate_advanced_structure_v1( + &self, + execution_context: &mut StateTransitionExecutionContext, + ) -> Result, Error> { + // Validate data contract id + let generated_id = DataContract::generate_data_contract_id_v0( + self.data_contract().owner_id(), + self.identity_nonce(), + ); + + // This hash will only take 1 block (64 bytes) + execution_context.add_operation(ValidationOperation::DoubleSha256(1)); + + if generated_id != self.data_contract().id() { + let bump_action = StateTransitionAction::BumpIdentityNonceAction( + BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + vec![ + BasicError::InvalidDataContractIdError(InvalidDataContractIdError::new( + generated_id.to_vec(), + self.data_contract().id().to_vec(), + )) + .into(), + ], + )); + } + + Ok(ConsensusValidationResult::default()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use assert_matches::assert_matches; + + mod validate_advanced_structure { + use super::*; + use dpp::consensus::ConsensusError; + use dpp::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; + use dpp::prelude::{Identifier, IdentityNonce}; + use dpp::state_transition::data_contract_create_transition::DataContractCreateTransitionV0; + use dpp::tests::fixtures::get_data_contract_fixture; + use drive::state_transition_action::system::bump_identity_nonce_action::BumpIdentityNonceActionAccessorsV0; + use platform_version::version::PlatformVersion; + use platform_version::{DefaultForPlatformVersion, TryIntoPlatformVersioned}; + + #[test] + fn should_return_invalid_result_if_contract_id_is_not_valid() { + let platform_version = PlatformVersion::latest(); + let identity_nonce = IdentityNonce::default(); + + let mut data_contract = + get_data_contract_fixture(None, identity_nonce, platform_version.protocol_version) + .data_contract_owned(); + + let identity_id = data_contract.owner_id(); + let original_id = data_contract.id(); + let invalid_id = Identifier::default(); + + data_contract.set_id(invalid_id); + + let data_contract_for_serialization = data_contract + .try_into_platform_versioned(platform_version) + .expect("failed to convert data contract"); + + let transition: DataContractCreateTransition = DataContractCreateTransitionV0 { + data_contract: data_contract_for_serialization, + identity_nonce, + user_fee_increase: 0, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + + let mut execution_context = + StateTransitionExecutionContext::default_for_platform_version(platform_version) + .expect("failed to create execution context"); + + let result = transition + .validate_advanced_structure_v1(&mut execution_context) + .expect("failed to validate advanced structure"); + + assert_matches!( + execution_context.operations_slice(), + [ValidationOperation::DoubleSha256(1)] + ); + + assert_matches!( + result.data, + Some(StateTransitionAction::BumpIdentityNonceAction(action)) + if action.identity_id() == identity_id && action.identity_nonce() == identity_nonce + ); + + assert_matches!( + result.errors.as_slice(), + [ConsensusError::BasicError(BasicError::InvalidDataContractIdError(e))] + if Identifier::try_from(e.expected_id()).unwrap() == original_id + && Identifier::try_from(e.invalid_id()).unwrap() == invalid_id + ); + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/basic_structure/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/basic_structure/mod.rs new file mode 100644 index 00000000000..9a1925de7fc --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/basic_structure/mod.rs @@ -0,0 +1 @@ +pub(crate) mod v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/basic_structure/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/basic_structure/v0/mod.rs new file mode 100644 index 00000000000..39876ba7724 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/basic_structure/v0/mod.rs @@ -0,0 +1,136 @@ +use crate::error::Error; +use dpp::consensus::basic::data_contract::{ + InvalidDataContractVersionError, InvalidTokenBaseSupplyError, + NonContiguousContractTokenPositionsError, +}; +use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use dpp::data_contract::{TokenContractPosition, INITIAL_DATA_CONTRACT_VERSION}; +use dpp::prelude::DataContract; +use dpp::state_transition::data_contract_create_transition::accessors::DataContractCreateTransitionAccessorsV0; +use dpp::state_transition::data_contract_create_transition::DataContractCreateTransition; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; + +pub(in crate::execution::validation::state_transition::state_transitions::data_contract_create) trait DataContractCreateStateTransitionBasicStructureValidationV0 +{ + fn validate_basic_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl DataContractCreateStateTransitionBasicStructureValidationV0 for DataContractCreateTransition { + fn validate_basic_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result { + if self.data_contract().version() != INITIAL_DATA_CONTRACT_VERSION { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidDataContractVersionError::new( + INITIAL_DATA_CONTRACT_VERSION, + self.data_contract().version(), + ) + .into(), + )); + } + + let groups = self.data_contract().groups(); + if !groups.is_empty() { + let validation_result = DataContract::validate_groups(groups, platform_version)?; + + if !validation_result.is_valid() { + return Ok(validation_result); + } + } + + for (expected_position, (token_contract_position, token_configuration)) in + self.data_contract().tokens().iter().enumerate() + { + if expected_position as TokenContractPosition != *token_contract_position { + return Ok(SimpleConsensusValidationResult::new_with_error( + NonContiguousContractTokenPositionsError::new( + expected_position as TokenContractPosition, + *token_contract_position, + ) + .into(), + )); + } + + if token_configuration.base_supply() > i64::MAX as u64 { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidTokenBaseSupplyError::new(token_configuration.base_supply()).into(), + )); + } + + let validation_result = token_configuration + .conventions() + .validate_localizations(platform_version)?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + + let validation_result = token_configuration.validate_token_config_groups_exist( + self.data_contract().groups(), + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + } + + Ok(SimpleConsensusValidationResult::new()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use assert_matches::assert_matches; + + mod validate_basic_structure { + use super::*; + use dpp::consensus::basic::BasicError; + use dpp::consensus::ConsensusError; + use dpp::data_contract::accessors::v0::DataContractV0Setters; + use dpp::data_contract::INITIAL_DATA_CONTRACT_VERSION; + use dpp::prelude::IdentityNonce; + use dpp::state_transition::data_contract_create_transition::DataContractCreateTransitionV0; + use dpp::tests::fixtures::get_data_contract_fixture; + use platform_version::version::PlatformVersion; + use platform_version::TryIntoPlatformVersioned; + + #[test] + fn should_return_invalid_result_if_contract_version_is_not_initial() { + let platform_version = PlatformVersion::latest(); + let identity_nonce = IdentityNonce::default(); + + let mut data_contract = + get_data_contract_fixture(None, identity_nonce, platform_version.protocol_version) + .data_contract_owned(); + + data_contract.set_version(6); + + let data_contract_for_serialization = data_contract + .try_into_platform_versioned(platform_version) + .expect("failed to convert data contract"); + + let transition: DataContractCreateTransition = DataContractCreateTransitionV0 { + data_contract: data_contract_for_serialization, + identity_nonce, + user_fee_increase: 0, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + + let result = transition + .validate_basic_structure_v0(&platform_version) + .expect("failed to validate advanced structure"); + + assert_matches!( + result.errors.as_slice(), + [ConsensusError::BasicError(BasicError::InvalidDataContractVersionError(e))] if e.expected_version() == INITIAL_DATA_CONTRACT_VERSION && e.version() == 6 + ); + } + } +} 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 bf837f815ca..574d097abad 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 @@ -1,11 +1,15 @@ mod advanced_structure; +mod basic_structure; mod identity_nonce; mod state; +use advanced_structure::v1::DataContractCreatedStateTransitionAdvancedStructureValidationV1; +use basic_structure::v0::DataContractCreateStateTransitionBasicStructureValidationV0; use dpp::block::block_info::BlockInfo; use dpp::identity::PartialIdentity; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::data_contract_create_transition::DataContractCreateTransition; +use dpp::validation::SimpleConsensusValidationResult; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; @@ -21,7 +25,8 @@ use crate::platform_types::platform::PlatformRef; use crate::rpc::core::CoreRPCLike; use crate::execution::validation::state_transition::processor::v0::{ - StateTransitionAdvancedStructureValidationV0, StateTransitionStateValidationV0, + StateTransitionAdvancedStructureValidationV0, StateTransitionBasicStructureValidationV0, + StateTransitionStateValidationV0, }; use crate::execution::validation::state_transition::transformer::StateTransitionActionTransformerV0; use crate::execution::validation::state_transition::ValidationMode; @@ -72,6 +77,32 @@ impl StateTransitionActionTransformerV0 for DataContractCreateTransition { } } +impl StateTransitionBasicStructureValidationV0 for DataContractCreateTransition { + fn validate_basic_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .contract_create_state_transition + .basic_structure + { + Some(0) => self.validate_basic_structure_v0(platform_version), + Some(version) => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "data contract create transition: validate_basic_structure".to_string(), + known_versions: vec![0], + received: version, + })), + None => Err(Error::Execution(ExecutionError::VersionNotActive { + method: "data contract create transition: validate_basic_structure".to_string(), + known_versions: vec![0], + })), + } + } +} + impl StateTransitionAdvancedStructureValidationV0 for DataContractCreateTransition { fn validate_advanced_structure( &self, @@ -86,15 +117,16 @@ impl StateTransitionAdvancedStructureValidationV0 for DataContractCreateTransiti .contract_create_state_transition .advanced_structure { - Some(0) => self.validate_advanced_structure_v0(execution_context, platform_version), + Some(0) => self.validate_advanced_structure_v0(execution_context), + Some(1) => self.validate_advanced_structure_v1(execution_context), Some(version) => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "data contract create transition: validate_advanced_structure".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), None => Err(Error::Execution(ExecutionError::VersionNotActive { method: "data contract create transition: validate_advanced_structure".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], })), } } @@ -1283,9 +1315,8 @@ mod tests { .expect("expected to process state transition"); assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError( + [StateTransitionExecutionResult::UnpaidConsensusError( ConsensusError::BasicError(BasicError::InvalidTokenBaseSupplyError(_)), - _ )] ); @@ -1396,9 +1427,8 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError( + [StateTransitionExecutionResult::UnpaidConsensusError( ConsensusError::BasicError(BasicError::GroupPositionDoesNotExistError(_)), - _ )] ); @@ -1511,9 +1541,8 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError( + [StateTransitionExecutionResult::UnpaidConsensusError( ConsensusError::BasicError(BasicError::GroupPositionDoesNotExistError(_)), - _ )] ); @@ -1772,11 +1801,10 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError( + [StateTransitionExecutionResult::UnpaidConsensusError( ConsensusError::BasicError( BasicError::NonContiguousContractGroupPositionsError(_) ), - _ )] ); @@ -1903,9 +1931,8 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError( + [StateTransitionExecutionResult::UnpaidConsensusError( ConsensusError::BasicError(BasicError::GroupMemberHasPowerOfZeroError(_)), - _ )] ); @@ -2032,9 +2059,8 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError( + [StateTransitionExecutionResult::UnpaidConsensusError( ConsensusError::BasicError(BasicError::GroupMemberHasPowerOverLimitError(_)), - _ )] ); @@ -2162,9 +2188,8 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError( + [StateTransitionExecutionResult::UnpaidConsensusError( ConsensusError::BasicError(BasicError::GroupMemberHasPowerOverLimitError(_)), - _ )] ); @@ -2291,9 +2316,8 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError( + [StateTransitionExecutionResult::UnpaidConsensusError( ConsensusError::BasicError(BasicError::GroupTotalPowerLessThanRequiredError(_)), - _ )] ); @@ -2420,11 +2444,10 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError( + [StateTransitionExecutionResult::UnpaidConsensusError( ConsensusError::BasicError( BasicError::GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError(_) ), - _ )] ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/basic_structure/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/basic_structure/mod.rs new file mode 100644 index 00000000000..9a1925de7fc --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/basic_structure/mod.rs @@ -0,0 +1 @@ +pub(crate) mod v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/basic_structure/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/basic_structure/v0/mod.rs new file mode 100644 index 00000000000..d59cee74b55 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/basic_structure/v0/mod.rs @@ -0,0 +1,72 @@ +use crate::error::Error; +use dpp::consensus::basic::data_contract::{ + InvalidTokenBaseSupplyError, NonContiguousContractTokenPositionsError, +}; +use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use dpp::data_contract::TokenContractPosition; +use dpp::prelude::DataContract; +use dpp::state_transition::data_contract_update_transition::accessors::DataContractUpdateTransitionAccessorsV0; +use dpp::state_transition::data_contract_update_transition::DataContractUpdateTransition; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; + +pub(in crate::execution::validation::state_transition::state_transitions::data_contract_update) trait DataContractUpdateStateTransitionBasicStructureValidationV0 +{ + fn validate_basic_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl DataContractUpdateStateTransitionBasicStructureValidationV0 for DataContractUpdateTransition { + fn validate_basic_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result { + let groups = self.data_contract().groups(); + if !groups.is_empty() { + let validation_result = DataContract::validate_groups(groups, platform_version)?; + + if !validation_result.is_valid() { + return Ok(validation_result); + } + } + + for (expected_position, (token_contract_position, token_configuration)) in + self.data_contract().tokens().iter().enumerate() + { + if expected_position as TokenContractPosition != *token_contract_position { + return Ok(SimpleConsensusValidationResult::new_with_error( + NonContiguousContractTokenPositionsError::new( + expected_position as TokenContractPosition, + *token_contract_position, + ) + .into(), + )); + } + + if token_configuration.base_supply() > i64::MAX as u64 { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidTokenBaseSupplyError::new(token_configuration.base_supply()).into(), + )); + } + + let validation_result = token_configuration + .conventions() + .validate_localizations(platform_version)?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + + let validation_result = token_configuration.validate_token_config_groups_exist( + self.data_contract().groups(), + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + } + + Ok(SimpleConsensusValidationResult::new()) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs index ab99794aeb2..31f77fc9aec 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs @@ -1,16 +1,20 @@ +mod basic_structure; mod identity_contract_nonce; mod state; +use basic_structure::v0::DataContractUpdateStateTransitionBasicStructureValidationV0; use dpp::block::block_info::BlockInfo; use dpp::state_transition::data_contract_update_transition::DataContractUpdateTransition; -use dpp::validation::ConsensusValidationResult; +use dpp::validation::{ConsensusValidationResult, SimpleConsensusValidationResult}; +use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; use crate::error::execution::ExecutionError; use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::execution::validation::state_transition::processor::v0::StateTransitionBasicStructureValidationV0; use drive::state_transition_action::StateTransitionAction; @@ -21,6 +25,32 @@ use crate::platform_types::platform::PlatformRef; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::rpc::core::CoreRPCLike; +impl StateTransitionBasicStructureValidationV0 for DataContractUpdateTransition { + fn validate_basic_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .contract_update_state_transition + .basic_structure + { + Some(0) => self.validate_basic_structure_v0(platform_version), + Some(version) => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "data contract update transition: validate_basic_structure".to_string(), + known_versions: vec![0], + received: version, + })), + None => Err(Error::Execution(ExecutionError::VersionNotActive { + method: "data contract update transition: validate_basic_structure".to_string(), + known_versions: vec![0], + })), + } + } +} + impl StateTransitionActionTransformerV0 for DataContractUpdateTransition { fn transform_into_action( &self, @@ -676,6 +706,8 @@ mod tests { mod group_tests { use super::*; + use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult::UnpaidConsensusError; + #[test] fn test_data_contract_update_can_not_remove_groups() { let mut platform = TestPlatformBuilder::new() @@ -1029,12 +1061,9 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError( - ConsensusError::BasicError( - BasicError::NonContiguousContractGroupPositionsError(_) - ), - _ - )] + [UnpaidConsensusError(ConsensusError::BasicError( + BasicError::NonContiguousContractGroupPositionsError(_) + ))] ); platform @@ -1179,13 +1208,19 @@ mod tests { mod token_tests { use super::*; + use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult::UnpaidConsensusError; use dpp::data_contract::accessors::v1::DataContractV1Setters; - use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; + use dpp::data_contract::associated_token::token_configuration::accessors::v0::{TokenConfigurationV0Getters, TokenConfigurationV0Setters}; use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; - use dpp::data_contract::associated_token::token_distribution_rules::accessors::v0::TokenDistributionRulesV0Setters; + use dpp::data_contract::associated_token::token_configuration_convention::accessors::v0::TokenConfigurationConventionV0Getters; + use dpp::data_contract::associated_token::token_configuration_convention::v0::TokenConfigurationConventionV0; + use dpp::data_contract::associated_token::token_configuration_convention::TokenConfigurationConvention; + use dpp::data_contract::associated_token::token_configuration_localization::v0::TokenConfigurationLocalizationV0; + use dpp::data_contract::associated_token::token_configuration_localization::TokenConfigurationLocalization; + #[test] - fn test_data_contract_update_can_not_add_new_token() { + fn test_data_contract_update_can_add_new_token() { let mut platform = TestPlatformBuilder::new() .build_with_mock_rpc() .set_initial_state_structure(); @@ -1197,31 +1232,132 @@ mod tests { .current_platform_version() .expect("expected to get current platform version"); - // Create an initial data contract with groups + // ── original contract (no tokens) ───────────────────────────────── let mut data_contract = get_data_contract_fixture(None, 0, platform_version.protocol_version) .data_contract_owned(); - data_contract.set_owner_id(identity.id()); - { - // Add groups to the contract - let groups = data_contract.groups_mut().expect("expected groups"); - groups.insert( + platform + .drive + .apply_contract( + &data_contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + // ── updated contract: add a well‑formed token at position 0 ────── + let mut updated_data_contract = data_contract.clone(); + updated_data_contract.set_version(2); + + let valid_token_cfg = { + let mut cfg = + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()); + cfg.set_base_supply(1_000_000); + + cfg.set_conventions(TokenConfigurationConvention::V0( + TokenConfigurationConventionV0 { + localizations: BTreeMap::from([( + "en".to_string(), + TokenConfigurationLocalization::V0(TokenConfigurationLocalizationV0 { + should_capitalize: true, + singular_form: "credit".to_string(), + plural_form: "credits".to_string(), + }), + )]), + decimals: 8, + }, + )); + cfg + }; + + updated_data_contract.add_token(0, valid_token_cfg); + + let data_contract_update_transition = + DataContractUpdateTransition::new_from_data_contract( + updated_data_contract, + &identity.into_partial_identity_info(), + key.id(), + 2, 0, - Group::V0(GroupV0 { - members: [(identity.id(), 1)].into(), - required_power: 1, - }), - ); - groups.insert( - 1, - Group::V0(GroupV0 { - members: [(identity.id(), 1)].into(), - required_power: 1, + &signer, + platform_version, + None, + ) + .expect("expect to create data contract update transition"); + + let tx_bytes = data_contract_update_transition + .serialize_to_bytes() + .expect("expected serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![tx_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .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_data_contract_update_can_not_add_new_token_with_gap() { + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let platform_state = platform.state.load(); + let platform_version = platform_state + .current_platform_version() + .expect("expected to get current platform version"); + + // ── original contract with token at position 0 ─────────────────── + let mut data_contract = + get_data_contract_fixture(None, 0, platform_version.protocol_version) + .data_contract_owned(); + data_contract.set_owner_id(identity.id()); + data_contract.add_token( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ); + data_contract + .tokens_mut() + .expect("expected tokens") + .get_mut(&0) + .expect("expected token") + .conventions_mut() + .localizations_mut() + .insert( + "en".to_string(), + TokenConfigurationLocalization::V0(TokenConfigurationLocalizationV0 { + should_capitalize: true, + singular_form: "test".to_string(), + plural_form: "tests".to_string(), }), ); - } platform .drive @@ -1235,12 +1371,12 @@ mod tests { ) .expect("expected to apply contract successfully"); - // Create an updated contract with one group removed + // ── updated contract: try to add token at position 2 (gap) ─────── let mut updated_data_contract = data_contract.clone(); updated_data_contract.set_version(2); updated_data_contract.add_token( - 0, + 2, // <‑‑ non‑contiguous TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), ); @@ -1257,16 +1393,15 @@ mod tests { ) .expect("expect to create data contract update transition"); - let data_contract_update_serialized_transition = data_contract_update_transition + let tx_bytes = data_contract_update_transition .serialize_to_bytes() .expect("expected serialized state transition"); let transaction = platform.drive.grove.start_transaction(); - let processing_result = platform .platform .process_raw_state_transitions( - &vec![data_contract_update_serialized_transition.clone()], + &vec![tx_bytes], &platform_state, &BlockInfo::default(), &transaction, @@ -1276,27 +1411,12 @@ mod tests { ) .expect("expected to process state transition"); - // Extract the error and check the message - if let [StateTransitionExecutionResult::PaidConsensusError( - ConsensusError::StateError(StateError::DataContractUpdateActionNotAllowedError( - error, - )), - _, - )] = processing_result.execution_results().as_slice() - { - assert_eq!( - error.action(), - "add token at position 0", - "expected error message to match 'add token at position 0'" - ); - assert_eq!( - error.data_contract_id(), - data_contract.id(), - "expected the error to reference the correct data contract ID" - ); - } else { - panic!("Expected a DataContractUpdateActionNotAllowedError"); - } + assert_matches!( + processing_result.execution_results().as_slice(), + [UnpaidConsensusError(ConsensusError::BasicError( + BasicError::NonContiguousContractTokenPositionsError(_) + ))] + ); platform .drive @@ -1307,7 +1427,7 @@ mod tests { } #[test] - fn test_data_contract_update_can_not_remove_token() { + fn test_data_contract_update_can_not_add_new_token_with_large_base_supply() { let mut platform = TestPlatformBuilder::new() .build_with_mock_rpc() .set_initial_state_structure(); @@ -1319,21 +1439,12 @@ mod tests { .current_platform_version() .expect("expected to get current platform version"); + // ── original contract (no tokens) ──────────────────────────────── let mut data_contract = get_data_contract_fixture(None, 0, platform_version.protocol_version) .data_contract_owned(); - data_contract.set_owner_id(identity.id()); - { - // Add a token to the contract - let tokens = data_contract.tokens_mut().expect("expected tokens"); - tokens.insert( - 0, - TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), - ); - } - platform .drive .apply_contract( @@ -1346,11 +1457,15 @@ mod tests { ) .expect("expected to apply contract successfully"); - // Create an updated contract with the token removed + // ── updated contract: token with base_supply > i64::MAX ────────── let mut updated_data_contract = data_contract.clone(); updated_data_contract.set_version(2); - updated_data_contract.tokens_mut().unwrap().remove(&0); + let mut huge_supply_cfg = + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()); + huge_supply_cfg.set_base_supply(i64::MAX as u64 + 1); + + updated_data_contract.add_token(0, huge_supply_cfg); let data_contract_update_transition = DataContractUpdateTransition::new_from_data_contract( @@ -1365,16 +1480,15 @@ mod tests { ) .expect("expect to create data contract update transition"); - let data_contract_update_serialized_transition = data_contract_update_transition + let tx_bytes = data_contract_update_transition .serialize_to_bytes() .expect("expected serialized state transition"); let transaction = platform.drive.grove.start_transaction(); - let processing_result = platform .platform .process_raw_state_transitions( - &vec![data_contract_update_serialized_transition.clone()], + &vec![tx_bytes], &platform_state, &BlockInfo::default(), &transaction, @@ -1384,26 +1498,12 @@ mod tests { ) .expect("expected to process state transition"); - if let [StateTransitionExecutionResult::PaidConsensusError( - ConsensusError::StateError(StateError::DataContractUpdateActionNotAllowedError( - error, - )), - _, - )] = processing_result.execution_results().as_slice() - { - assert_eq!( - error.action(), - "remove token at position 0", - "expected error message to match 'remove token at position 0'" - ); - assert_eq!( - error.data_contract_id(), - data_contract.id(), - "expected the error to reference the correct data contract ID" - ); - } else { - panic!("Expected a DataContractUpdateActionNotAllowedError"); - } + assert_matches!( + processing_result.execution_results().as_slice(), + [UnpaidConsensusError(ConsensusError::BasicError( + BasicError::InvalidTokenBaseSupplyError(_) + ))] + ); platform .drive @@ -1414,7 +1514,7 @@ mod tests { } #[test] - fn test_data_contract_update_can_not_modify_token() { + fn test_data_contract_update_can_not_add_new_token_with_invalid_localization() { let mut platform = TestPlatformBuilder::new() .build_with_mock_rpc() .set_initial_state_structure(); @@ -1426,21 +1526,12 @@ mod tests { .current_platform_version() .expect("expected to get current platform version"); + // ── original contract (no tokens) ──────────────────────────────── let mut data_contract = get_data_contract_fixture(None, 0, platform_version.protocol_version) .data_contract_owned(); - data_contract.set_owner_id(identity.id()); - { - // Add a token to the contract - let tokens = data_contract.tokens_mut().expect("expected tokens"); - tokens.insert( - 0, - TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), - ); - } - platform .drive .apply_contract( @@ -1453,17 +1544,23 @@ mod tests { ) .expect("expected to apply contract successfully"); - // Create an updated contract with the token modified + // ── updated contract: token with empty localization map ────────── let mut updated_data_contract = data_contract.clone(); updated_data_contract.set_version(2); - if let Some(TokenConfiguration::V0(config)) = - updated_data_contract.tokens_mut().unwrap().get_mut(&0) - { - config - .distribution_rules_mut() - .set_minting_allow_choosing_destination(false); //originally true - } + let empty_localization_cfg = { + let mut cfg = + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()); + cfg.set_conventions(TokenConfigurationConvention::V0( + TokenConfigurationConventionV0 { + localizations: BTreeMap::new(), // <‑‑ invalid + decimals: 8, + }, + )); + cfg + }; + + updated_data_contract.add_token(0, empty_localization_cfg); let data_contract_update_transition = DataContractUpdateTransition::new_from_data_contract( @@ -1478,16 +1575,15 @@ mod tests { ) .expect("expect to create data contract update transition"); - let data_contract_update_serialized_transition = data_contract_update_transition + let tx_bytes = data_contract_update_transition .serialize_to_bytes() .expect("expected serialized state transition"); let transaction = platform.drive.grove.start_transaction(); - let processing_result = platform .platform .process_raw_state_transitions( - &vec![data_contract_update_serialized_transition.clone()], + &vec![tx_bytes], &platform_state, &BlockInfo::default(), &transaction, @@ -1497,26 +1593,12 @@ mod tests { ) .expect("expected to process state transition"); - if let [StateTransitionExecutionResult::PaidConsensusError( - ConsensusError::StateError(StateError::DataContractUpdateActionNotAllowedError( - error, - )), - _, - )] = processing_result.execution_results().as_slice() - { - assert_eq!( - error.action(), - "update token at position 0", - "expected error message to match 'update token at position 0'" - ); - assert_eq!( - error.data_contract_id(), - data_contract.id(), - "expected the error to reference the correct data contract ID" - ); - } else { - panic!("Expected a DataContractUpdateActionNotAllowedError"); - } + assert_matches!( + processing_result.execution_results().as_slice(), + [UnpaidConsensusError(ConsensusError::BasicError( + BasicError::MissingDefaultLocalizationError(_) + ))] + ); platform .drive diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/state/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/state/v0/mod.rs index 7f97d3a8f4b..ab66daf9500 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/state/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/state/v0/mod.rs @@ -5,17 +5,11 @@ use dpp::block::block_info::BlockInfo; use dpp::consensus::basic::document::DataContractNotPresentError; use dpp::consensus::basic::BasicError; -use dpp::consensus::state::state_error::StateError; -use dpp::consensus::state::token::PreProgrammedDistributionTimestampInPastError; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::accessors::v1::{DataContractV1Getters, DataContractV1Setters}; -use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; -use dpp::data_contract::associated_token::token_distribution_rules::accessors::v0::TokenDistributionRulesV0Getters; -use dpp::data_contract::associated_token::token_pre_programmed_distribution::accessors::v0::TokenPreProgrammedDistributionV0Methods; use dpp::data_contract::validate_update::DataContractUpdateValidationMethodsV0; use dpp::prelude::ConsensusValidationResult; -use dpp::state_transition::data_contract_update_transition::accessors::DataContractUpdateTransitionAccessorsV0; use dpp::state_transition::data_contract_update_transition::DataContractUpdateTransition; use dpp::version::PlatformVersion; use dpp::ProtocolError; @@ -73,25 +67,6 @@ impl DataContractUpdateStateTransitionStateValidationV0 for DataContractUpdateTr return Ok(action); } - // Validate token distribution rules - for (position, config) in self.data_contract().tokens() { - if let Some(distribution) = config.distribution_rules().pre_programmed_distribution() { - if let Some((timestamp, _)) = distribution.distributions().iter().next() { - if timestamp < &block_info.time_ms { - return Ok(ConsensusValidationResult::new_with_data_and_errors( - StateTransitionAction::BumpIdentityDataContractNonceAction( - BumpIdentityDataContractNonceAction::from_borrowed_data_contract_update_transition(self), - ), - vec![StateError::PreProgrammedDistributionTimestampInPastError( - PreProgrammedDistributionTimestampInPastError::new(self.data_contract().id(), *position, *timestamp, block_info.time_ms), - ) - .into()], - )); - } - } - } - } - let state_transition_action = action.data.as_mut().ok_or(Error::Execution( ExecutionError::CorruptedCodeExecution( "we should always have an action at this point in data contract update", @@ -156,8 +131,9 @@ impl DataContractUpdateStateTransitionStateValidationV0 for DataContractUpdateTr let old_data_contract = &contract_fetch_info.contract; + // Here we do validations that consider the old data contract let validation_result = - old_data_contract.validate_update(new_data_contract, platform_version)?; + old_data_contract.validate_update(new_data_contract, block_info, platform_version)?; if !validation_result.is_valid() { let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs index 439ac18d51e..970f7d89adc 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs @@ -3,6 +3,7 @@ pub mod v2; pub mod v3; pub mod v4; pub mod v5; +pub mod v6; use versioned_feature_core::{FeatureVersion, OptionalFeatureVersion}; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs new file mode 100644 index 00000000000..dfb9921ef2b --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs @@ -0,0 +1,180 @@ +use crate::version::drive_abci_versions::drive_abci_validation_versions::{ + DriveAbciAssetLockValidationVersions, DriveAbciDocumentsStateTransitionValidationVersions, + DriveAbciStateTransitionCommonValidationVersions, DriveAbciStateTransitionValidationVersion, + DriveAbciStateTransitionValidationVersions, DriveAbciValidationConstants, + DriveAbciValidationDataTriggerAndBindingVersions, DriveAbciValidationDataTriggerVersions, + DriveAbciValidationVersions, PenaltyAmounts, +}; + +// In this version we introduce basic structure validation for DataContractCreate and DataContractUpdate. +// In order for tests that used the first protocol version to pass, we needed to change the contract_create +// and contract_update state transition validation basic_structure to Some(0) for all previous versions. +// Also, we needed to change contract_create advanced_structure to Some(0) for all previous versions. +// There were some things in validate_advanced_structure for Create that should've been in basic. +// There were also some things in validate_update for that should've been in basic. +// We were also matching to basic_structure version for advanced_structure before too for Create. +pub const DRIVE_ABCI_VALIDATION_VERSIONS_V6: DriveAbciValidationVersions = + DriveAbciValidationVersions { + state_transitions: DriveAbciStateTransitionValidationVersions { + common_validation_methods: DriveAbciStateTransitionCommonValidationVersions { + asset_locks: DriveAbciAssetLockValidationVersions { + fetch_asset_lock_transaction_output_sync: 0, + verify_asset_lock_is_not_spent_and_has_enough_balance: 0, + }, + validate_identity_public_key_contract_bounds: 0, + validate_identity_public_key_ids_dont_exist_in_state: 0, + validate_identity_public_key_ids_exist_in_state: 0, + validate_state_transition_identity_signed: 0, + validate_unique_identity_public_key_hashes_in_state: 0, + validate_master_key_uniqueness: 0, + validate_simple_pre_check_balance: 0, + }, + max_asset_lock_usage_attempts: 16, + identity_create_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: Some(0), + identity_signatures: Some(0), + advanced_minimum_balance_pre_check: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + identity_update_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: Some(0), + identity_signatures: Some(0), + advanced_minimum_balance_pre_check: None, + nonce: Some(0), + state: 0, + transform_into_action: 0, + }, + identity_top_up_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + advanced_minimum_balance_pre_check: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + identity_credit_withdrawal_state_transition: + DriveAbciStateTransitionValidationVersion { + basic_structure: Some(1), + advanced_structure: None, + identity_signatures: None, + advanced_minimum_balance_pre_check: Some(0), + nonce: Some(0), + state: 0, + transform_into_action: 0, + }, + identity_credit_withdrawal_state_transition_purpose_matches_requirements: 0, + identity_credit_transfer_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + advanced_minimum_balance_pre_check: Some(0), + nonce: Some(0), + state: 0, + transform_into_action: 0, + }, + masternode_vote_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: Some(0), + identity_signatures: None, + advanced_minimum_balance_pre_check: Some(0), + nonce: Some(1), + state: 0, + transform_into_action: 0, + }, + contract_create_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: Some(1), + identity_signatures: None, + advanced_minimum_balance_pre_check: None, + nonce: Some(0), + state: 0, + transform_into_action: 0, + }, + contract_update_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + advanced_minimum_balance_pre_check: None, + nonce: Some(0), + state: 0, + transform_into_action: 0, + }, + batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { + balance_pre_check: 0, + basic_structure: 0, + advanced_structure: 0, + state: 0, + revision: 0, + transform_into_action: 0, + data_triggers: DriveAbciValidationDataTriggerAndBindingVersions { + bindings: 0, + triggers: DriveAbciValidationDataTriggerVersions { + create_contact_request_data_trigger: 0, + create_domain_data_trigger: 0, + create_identity_data_trigger: 0, + create_feature_flag_data_trigger: 0, + create_masternode_reward_shares_data_trigger: 0, + delete_withdrawal_data_trigger: 0, + reject_data_trigger: 0, + }, + }, + is_allowed: 0, + document_create_transition_structure_validation: 0, + document_delete_transition_structure_validation: 0, + document_replace_transition_structure_validation: 0, + document_transfer_transition_structure_validation: 0, + document_purchase_transition_structure_validation: 0, + document_update_price_transition_structure_validation: 0, + document_base_transition_state_validation: 0, + document_create_transition_state_validation: 1, + document_delete_transition_state_validation: 0, + document_replace_transition_state_validation: 0, + document_transfer_transition_state_validation: 0, + document_purchase_transition_state_validation: 0, + document_update_price_transition_state_validation: 0, + token_mint_transition_structure_validation: 0, + token_burn_transition_structure_validation: 0, + token_transfer_transition_structure_validation: 0, + token_mint_transition_state_validation: 0, + token_burn_transition_state_validation: 0, + token_transfer_transition_state_validation: 0, + token_base_transition_structure_validation: 0, + token_base_transition_state_validation: 0, + token_freeze_transition_structure_validation: 0, + token_unfreeze_transition_structure_validation: 0, + token_freeze_transition_state_validation: 0, + token_unfreeze_transition_state_validation: 0, + token_destroy_frozen_funds_transition_structure_validation: 0, + token_destroy_frozen_funds_transition_state_validation: 0, + token_emergency_action_transition_structure_validation: 0, + token_emergency_action_transition_state_validation: 0, + token_config_update_transition_structure_validation: 0, + token_config_update_transition_state_validation: 0, + token_base_transition_group_action_validation: 0, + token_claim_transition_structure_validation: 0, + token_claim_transition_state_validation: 0, + token_direct_purchase_transition_structure_validation: 0, + token_direct_purchase_transition_state_validation: 0, + token_set_price_for_direct_purchase_transition_structure_validation: 0, + token_set_price_for_direct_purchase_transition_state_validation: 0, + }, + }, + has_nonce_validation: 1, + process_state_transition: 0, + state_transition_to_execution_event_for_check_tx: 0, + penalties: PenaltyAmounts { + identity_id_not_correct: 50000000, + unique_key_already_present: 10000000, + validation_of_added_keys_structure_failure: 10000000, + validation_of_added_keys_proof_of_possession_failure: 50000000, + }, + event_constants: DriveAbciValidationConstants { + maximum_vote_polls_to_process: 2, + maximum_contenders_to_consider: 100, + }, + }; diff --git a/packages/rs-platform-version/src/version/v9.rs b/packages/rs-platform-version/src/version/v9.rs index abcc4fa5a54..f990d75ed09 100644 --- a/packages/rs-platform-version/src/version/v9.rs +++ b/packages/rs-platform-version/src/version/v9.rs @@ -17,8 +17,7 @@ use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v6::DRIVE_ABCI_METHOD_VERSIONS_V6; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; -use crate::version::drive_abci_versions::drive_abci_validation_versions::v4::DRIVE_ABCI_VALIDATION_VERSIONS_V4; -use crate::version::drive_abci_versions::drive_abci_validation_versions::v5::DRIVE_ABCI_VALIDATION_VERSIONS_V5; +use crate::version::drive_abci_versions::drive_abci_validation_versions::v6::DRIVE_ABCI_VALIDATION_VERSIONS_V6; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v2::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2; use crate::version::drive_abci_versions::DriveAbciVersion; use crate::version::drive_versions::v4::DRIVE_VERSION_V4; @@ -38,7 +37,7 @@ pub const PLATFORM_V9: PlatformVersion = PlatformVersion { drive_abci: DriveAbciVersion { structs: DRIVE_ABCI_STRUCTURE_VERSIONS_V1, methods: DRIVE_ABCI_METHOD_VERSIONS_V6, // changed because of the genesis state - validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V5, + validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V6, // changed withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2, query: DRIVE_ABCI_QUERY_VERSIONS_V1, },