diff --git a/Cargo.lock b/Cargo.lock index 60afac71eab..0da514223e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1876,7 +1876,7 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "grovedb" version = "1.0.0-rc.2" -source = "git+https://github.com/dashpay/grovedb?rev=f5a3382c5537de7417e983cdf2132792aa9fdc9d#f5a3382c5537de7417e983cdf2132792aa9fdc9d" +source = "git+https://github.com/dashpay/grovedb?rev=941dd86d70c86e7a236541919e789dba078abae6#941dd86d70c86e7a236541919e789dba078abae6" dependencies = [ "bincode", "grovedb-costs", @@ -1897,7 +1897,7 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "1.0.0-rc.2" -source = "git+https://github.com/dashpay/grovedb?rev=f5a3382c5537de7417e983cdf2132792aa9fdc9d#f5a3382c5537de7417e983cdf2132792aa9fdc9d" +source = "git+https://github.com/dashpay/grovedb?rev=941dd86d70c86e7a236541919e789dba078abae6#941dd86d70c86e7a236541919e789dba078abae6" dependencies = [ "integer-encoding", "intmap", @@ -1907,7 +1907,7 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "1.0.0-rc.2" -source = "git+https://github.com/dashpay/grovedb?rev=f5a3382c5537de7417e983cdf2132792aa9fdc9d#f5a3382c5537de7417e983cdf2132792aa9fdc9d" +source = "git+https://github.com/dashpay/grovedb?rev=941dd86d70c86e7a236541919e789dba078abae6#941dd86d70c86e7a236541919e789dba078abae6" dependencies = [ "blake3", "byteorder", @@ -1930,12 +1930,12 @@ dependencies = [ [[package]] name = "grovedb-path" version = "1.0.0-rc.2" -source = "git+https://github.com/dashpay/grovedb?rev=f5a3382c5537de7417e983cdf2132792aa9fdc9d#f5a3382c5537de7417e983cdf2132792aa9fdc9d" +source = "git+https://github.com/dashpay/grovedb?rev=941dd86d70c86e7a236541919e789dba078abae6#941dd86d70c86e7a236541919e789dba078abae6" [[package]] name = "grovedb-storage" version = "1.0.0-rc.2" -source = "git+https://github.com/dashpay/grovedb?rev=f5a3382c5537de7417e983cdf2132792aa9fdc9d#f5a3382c5537de7417e983cdf2132792aa9fdc9d" +source = "git+https://github.com/dashpay/grovedb?rev=941dd86d70c86e7a236541919e789dba078abae6#941dd86d70c86e7a236541919e789dba078abae6" dependencies = [ "blake3", "grovedb-costs", @@ -1954,7 +1954,7 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "1.0.0-rc.2" -source = "git+https://github.com/dashpay/grovedb?rev=f5a3382c5537de7417e983cdf2132792aa9fdc9d#f5a3382c5537de7417e983cdf2132792aa9fdc9d" +source = "git+https://github.com/dashpay/grovedb?rev=941dd86d70c86e7a236541919e789dba078abae6#941dd86d70c86e7a236541919e789dba078abae6" dependencies = [ "hex", "itertools 0.12.1", @@ -4403,18 +4403,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", diff --git a/packages/dashpay-contract/schema/v1/dashpay.schema.json b/packages/dashpay-contract/schema/v1/dashpay.schema.json index d4281468ed9..016d40db73c 100644 --- a/packages/dashpay-contract/schema/v1/dashpay.schema.json +++ b/packages/dashpay-contract/schema/v1/dashpay.schema.json @@ -132,6 +132,7 @@ }, "contactRequest": { "documentsMutable": false, + "canBeDeleted": false, "requiresIdentityEncryptionBoundedKey": 2, "requiresIdentityDecryptionBoundedKey": 2, "type": "object", diff --git a/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json b/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json index c5067f16e1f..e25b17af3d8 100644 --- a/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json +++ b/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json @@ -481,6 +481,18 @@ ], "description": "Public key security level. 0 - Master, 1 - Critical, 2 - High, 3 - Medium. If none specified, High level is used" }, + "documentsKeepHistory": { + "type": "boolean", + "description": "True if the documents keep all their history, default is false" + }, + "documentsMutable": { + "type": "boolean", + "description": "True if the documents are mutable, default is true" + }, + "canBeDeleted": { + "type": "boolean", + "description": "True if the documents can be deleted, default is true" + }, "transferable": { "type": "integer", "enum": [ @@ -489,6 +501,23 @@ ], "description": "Transferable without a marketplace sell. 0 - Never, 1 - Always" }, + "tradeMode": { + "type": "integer", + "enum": [ + 0, + 1 + ], + "description": "Built in marketplace system. 0 - None, 1 - Direct purchase (The user can buy the item without the need for an approval)" + }, + "creationRestrictionMode": { + "type": "integer", + "enum": [ + 0, + 1, + 2 + ], + "description": "Restrictions of document creation. 0 - No restrictions, 1 - Owner only, 2 - No creation (System Only)" + }, "requiresIdentityEncryptionBoundedKey": { "type": "integer", "enum": [ diff --git a/packages/rs-dpp/src/data_contract/config/fields.rs b/packages/rs-dpp/src/data_contract/config/fields.rs index 33ced8f00f7..200c0402e07 100644 --- a/packages/rs-dpp/src/data_contract/config/fields.rs +++ b/packages/rs-dpp/src/data_contract/config/fields.rs @@ -3,6 +3,7 @@ pub const DEFAULT_CONTRACT_CAN_BE_DELETED: bool = false; pub const DEFAULT_CONTRACT_MUTABILITY: bool = true; pub const DEFAULT_CONTRACT_DOCUMENTS_KEEPS_HISTORY: bool = false; pub const DEFAULT_CONTRACT_DOCUMENT_MUTABILITY: bool = true; +pub const DEFAULT_CONTRACT_DOCUMENTS_CAN_BE_DELETED: bool = true; pub mod property { pub const CAN_BE_DELETED: &str = "canBeDeleted"; @@ -10,6 +11,8 @@ pub mod property { pub const KEEPS_HISTORY: &str = "keepsHistory"; pub const DOCUMENTS_KEEP_HISTORY_CONTRACT_DEFAULT: &str = "documentsKeepHistoryContractDefault"; pub const DOCUMENTS_MUTABLE_CONTRACT_DEFAULT: &str = "documentsMutableContractDefault"; + pub const DOCUMENTS_CAN_BE_DELETED_CONTRACT_DEFAULT: &str = + "documentsCanBeDeletedContractDefault"; pub const REQUIRES_IDENTITY_ENCRYPTION_BOUNDED_KEY: &str = "requiresIdentityEncryptionBoundedKey"; pub const REQUIRES_IDENTITY_DECRYPTION_BOUNDED_KEY: &str = diff --git a/packages/rs-dpp/src/data_contract/config/methods/validate_config_update/v0/mod.rs b/packages/rs-dpp/src/data_contract/config/methods/validate_config_update/v0/mod.rs index 0003e220b1b..90cc1ef73cd 100644 --- a/packages/rs-dpp/src/data_contract/config/methods/validate_config_update/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/config/methods/validate_config_update/v0/mod.rs @@ -92,6 +92,20 @@ impl DataContractConfig { ); } + // Validate: Documents can be deleted contract default did not change + + if new_config.documents_can_be_deleted_contract_default() + != self.documents_can_be_deleted_contract_default() + { + return SimpleConsensusValidationResult::new_with_error( + DataContractConfigUpdateError::new( + contract_id, + "contract can not change the default of whether documents can be deleted", + ) + .into(), + ); + } + // Validate: Requires identity encryption bounded key did not change if new_config.requires_identity_encryption_bounded_key() diff --git a/packages/rs-dpp/src/data_contract/config/mod.rs b/packages/rs-dpp/src/data_contract/config/mod.rs index 26aaba3636b..aa4a4ef036b 100644 --- a/packages/rs-dpp/src/data_contract/config/mod.rs +++ b/packages/rs-dpp/src/data_contract/config/mod.rs @@ -117,6 +117,12 @@ impl DataContractConfigGettersV0 for DataContractConfig { } } + fn documents_can_be_deleted_contract_default(&self) -> bool { + match self { + DataContractConfig::V0(v0) => v0.documents_can_be_deleted_contract_default, + } + } + /// Encryption key storage requirements fn requires_identity_encryption_bounded_key(&self) -> Option { match self { @@ -157,6 +163,12 @@ impl DataContractConfigSettersV0 for DataContractConfig { } } + fn set_documents_can_be_deleted_contract_default(&mut self, value: bool) { + match self { + DataContractConfig::V0(v0) => v0.documents_can_be_deleted_contract_default = value, + } + } + fn set_documents_mutable_contract_default(&mut self, value: bool) { match self { DataContractConfig::V0(v0) => v0.documents_mutable_contract_default = value, diff --git a/packages/rs-dpp/src/data_contract/config/v0/mod.rs b/packages/rs-dpp/src/data_contract/config/v0/mod.rs index 35734a01e59..329361befe4 100644 --- a/packages/rs-dpp/src/data_contract/config/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/config/v0/mod.rs @@ -1,8 +1,8 @@ use crate::data_contract::config; use crate::data_contract::config::{ - DataContractConfig, DEFAULT_CONTRACT_CAN_BE_DELETED, DEFAULT_CONTRACT_DOCUMENTS_KEEPS_HISTORY, - DEFAULT_CONTRACT_DOCUMENT_MUTABILITY, DEFAULT_CONTRACT_KEEPS_HISTORY, - DEFAULT_CONTRACT_MUTABILITY, + DataContractConfig, DEFAULT_CONTRACT_CAN_BE_DELETED, DEFAULT_CONTRACT_DOCUMENTS_CAN_BE_DELETED, + DEFAULT_CONTRACT_DOCUMENTS_KEEPS_HISTORY, DEFAULT_CONTRACT_DOCUMENT_MUTABILITY, + DEFAULT_CONTRACT_KEEPS_HISTORY, DEFAULT_CONTRACT_MUTABILITY, }; use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements; use crate::ProtocolError; @@ -27,10 +27,14 @@ pub struct DataContractConfigV0 { /// Do documents in the contract keep history. This is a default for all documents in /// the contract, but can be overridden by the document itself pub documents_keep_history_contract_default: bool, - /// Are documents in the contract mutable. This specifies whether the document can be - /// changed or deleted. This is a default for all documents in the contract, but can be - /// overridden by the document itself + /// Are documents in the contract mutable? This specifies whether the documents can be + /// changed. This is a default for all document types in the contract, but can be + /// overridden by the document type config. pub documents_mutable_contract_default: bool, + /// Can documents in the contract be deleted? This specifies whether the documents can be + /// deleted. This is a default for all document types in the contract, but can be + /// overridden by the document types itself. + pub documents_can_be_deleted_contract_default: bool, /// Encryption key storage requirements pub requires_identity_encryption_bounded_key: Option, /// Decryption key storage requirements @@ -53,6 +57,7 @@ pub trait DataContractConfigGettersV0 { /// Returns whether documents in the contract are mutable by default. fn documents_mutable_contract_default(&self) -> bool; + fn documents_can_be_deleted_contract_default(&self) -> bool; /// Encryption key storage requirements fn requires_identity_encryption_bounded_key(&self) -> Option; @@ -78,6 +83,9 @@ pub trait DataContractConfigSettersV0 { /// Sets whether documents in the contract are mutable by default. fn set_documents_mutable_contract_default(&mut self, value: bool); + /// Sets whether documents in the contract can be deleted by default. + fn set_documents_can_be_deleted_contract_default(&mut self, value: bool); + /// Sets Encryption key storage requirements. fn set_requires_identity_encryption_bounded_key( &mut self, @@ -99,6 +107,7 @@ impl std::default::Default for DataContractConfigV0 { keeps_history: DEFAULT_CONTRACT_KEEPS_HISTORY, documents_keep_history_contract_default: DEFAULT_CONTRACT_DOCUMENTS_KEEPS_HISTORY, documents_mutable_contract_default: DEFAULT_CONTRACT_DOCUMENT_MUTABILITY, + documents_can_be_deleted_contract_default: DEFAULT_CONTRACT_DOCUMENTS_CAN_BE_DELETED, requires_identity_encryption_bounded_key: None, requires_identity_decryption_bounded_key: None, } @@ -157,6 +166,10 @@ impl DataContractConfigV0 { .get_optional_bool(config::property::DOCUMENTS_MUTABLE_CONTRACT_DEFAULT)? .unwrap_or(DEFAULT_CONTRACT_DOCUMENT_MUTABILITY); + let documents_can_be_deleted_contract_default = contract + .get_optional_bool(config::property::DOCUMENTS_CAN_BE_DELETED_CONTRACT_DEFAULT)? + .unwrap_or(DEFAULT_CONTRACT_DOCUMENTS_CAN_BE_DELETED); + let requires_identity_encryption_bounded_key = contract .get_optional_integer::(config::property::REQUIRES_IDENTITY_ENCRYPTION_BOUNDED_KEY)? .map(|int| int.try_into()) @@ -173,6 +186,7 @@ impl DataContractConfigV0 { keeps_history, documents_keep_history_contract_default, documents_mutable_contract_default, + documents_can_be_deleted_contract_default, requires_identity_encryption_bounded_key, requires_identity_decryption_bounded_key, }) diff --git a/packages/rs-dpp/src/data_contract/document_type/accessors/mod.rs b/packages/rs-dpp/src/data_contract/document_type/accessors/mod.rs index 3b4aef6b3c7..3dea66c6915 100644 --- a/packages/rs-dpp/src/data_contract/document_type/accessors/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/accessors/mod.rs @@ -7,9 +7,11 @@ use crate::data_contract::document_type::{DocumentType, DocumentTypeMutRef, Docu use platform_value::{Identifier, Value}; +use crate::data_contract::document_type::restricted_creation::CreationRestrictionMode; use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements; use crate::document::transfer::Transferable; use crate::identity::SecurityLevel; +use crate::nft::TradeMode; use indexmap::IndexMap; use std::collections::BTreeSet; pub use v0::*; @@ -87,6 +89,24 @@ impl DocumentTypeV0Getters for DocumentType { } } + fn documents_can_be_deleted(&self) -> bool { + match self { + DocumentType::V0(v0) => v0.documents_can_be_deleted(), + } + } + + fn trade_mode(&self) -> TradeMode { + match self { + DocumentType::V0(v0) => v0.trade_mode(), + } + } + + fn creation_restriction_mode(&self) -> CreationRestrictionMode { + match self { + DocumentType::V0(v0) => v0.creation_restriction_mode(), + } + } + fn documents_transferable(&self) -> Transferable { match self { DocumentType::V0(v0) => v0.documents_transferable(), @@ -191,12 +211,30 @@ impl<'a> DocumentTypeV0Getters for DocumentTypeRef<'a> { } } + fn documents_can_be_deleted(&self) -> bool { + match self { + DocumentTypeRef::V0(v0) => v0.documents_can_be_deleted(), + } + } + fn documents_transferable(&self) -> Transferable { match self { DocumentTypeRef::V0(v0) => v0.documents_transferable(), } } + fn trade_mode(&self) -> TradeMode { + match self { + DocumentTypeRef::V0(v0) => v0.trade_mode(), + } + } + + fn creation_restriction_mode(&self) -> CreationRestrictionMode { + match self { + DocumentTypeRef::V0(v0) => v0.creation_restriction_mode(), + } + } + fn data_contract_id(&self) -> Identifier { match self { DocumentTypeRef::V0(v0) => v0.data_contract_id(), @@ -295,12 +333,30 @@ impl<'a> DocumentTypeV0Getters for DocumentTypeMutRef<'a> { } } + fn documents_can_be_deleted(&self) -> bool { + match self { + DocumentTypeMutRef::V0(v0) => v0.documents_can_be_deleted(), + } + } + fn documents_transferable(&self) -> Transferable { match self { DocumentTypeMutRef::V0(v0) => v0.documents_transferable(), } } + fn trade_mode(&self) -> TradeMode { + match self { + DocumentTypeMutRef::V0(v0) => v0.trade_mode(), + } + } + + fn creation_restriction_mode(&self) -> CreationRestrictionMode { + match self { + DocumentTypeMutRef::V0(v0) => v0.creation_restriction_mode(), + } + } + fn data_contract_id(&self) -> Identifier { match self { DocumentTypeMutRef::V0(v0) => v0.data_contract_id(), diff --git a/packages/rs-dpp/src/data_contract/document_type/accessors/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/accessors/v0/mod.rs index b297b3dd9b1..c5770296685 100644 --- a/packages/rs-dpp/src/data_contract/document_type/accessors/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/accessors/v0/mod.rs @@ -4,9 +4,11 @@ use crate::data_contract::document_type::property::DocumentProperty; use platform_value::{Identifier, Value}; +use crate::data_contract::document_type::restricted_creation::CreationRestrictionMode; use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements; use crate::document::transfer::Transferable; use crate::identity::SecurityLevel; +use crate::nft::TradeMode; use indexmap::IndexMap; use std::collections::BTreeSet; @@ -45,9 +47,18 @@ pub trait DocumentTypeV0Getters { /// Returns the documents mutable flag of the document type. fn documents_mutable(&self) -> bool; + /// Returns the documents can be deleted flag of the document type. + fn documents_can_be_deleted(&self) -> bool; + /// Returns the documents transferable flag of the document type. fn documents_transferable(&self) -> Transferable; + /// Returns the documents trade mode flag of the document type. + fn trade_mode(&self) -> TradeMode; + + /// Returns the creation restriction mode. + fn creation_restriction_mode(&self) -> CreationRestrictionMode; + /// Returns the data contract id of the document type. fn data_contract_id(&self) -> Identifier; diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/mod.rs index a2d6e2fe63c..b767891bfb0 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/mod.rs @@ -39,6 +39,7 @@ impl DocumentType { schema_defs: Option<&BTreeMap>, documents_keep_history_contract_default: bool, documents_mutable_contract_default: bool, + documents_can_be_deleted_contract_default: bool, validate: bool, validation_operations: &mut Vec, platform_version: &PlatformVersion, @@ -56,6 +57,7 @@ impl DocumentType { schema_defs, documents_keep_history_contract_default, documents_mutable_contract_default, + documents_can_be_deleted_contract_default, validate, validation_operations, platform_version, @@ -85,6 +87,7 @@ mod test { false, false, false, + false, &mut vec![], crate::version::PlatformVersion::latest(), ); diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v0/mod.rs index 12177daec65..1bc7ae36619 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v0/mod.rs @@ -15,6 +15,7 @@ impl DocumentTypeV0 { schema_defs: Option<&BTreeMap>, documents_keep_history_contract_default: bool, documents_mutable_contract_default: bool, + documents_can_be_deleted_contract_default: bool, validate: bool, validation_operations: &mut Vec, platform_version: &PlatformVersion, @@ -41,6 +42,7 @@ impl DocumentTypeV0 { schema_defs, documents_keep_history_contract_default, documents_mutable_contract_default, + documents_can_be_deleted_contract_default, validate, validation_operations, platform_version, diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/mod.rs index 023291dc5ba..6a0bc14fc38 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/mod.rs @@ -16,6 +16,7 @@ impl DocumentType { schema_defs: Option<&BTreeMap>, default_keeps_history: bool, default_mutability: bool, + default_can_be_deleted: bool, validate: bool, validation_operations: &mut Vec, platform_version: &PlatformVersion, @@ -34,6 +35,7 @@ impl DocumentType { schema_defs, default_keeps_history, default_mutability, + default_can_be_deleted, validate, validation_operations, platform_version, 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 2571ff0cf68..00d16d6fcfa 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 @@ -32,6 +32,10 @@ use crate::consensus::basic::data_contract::InvalidDocumentTypeRequiredSecurityL use crate::consensus::basic::document::MissingPositionsInDocumentTypePropertiesError; #[cfg(feature = "validation")] use crate::consensus::basic::BasicError; +use crate::data_contract::document_type::property_names::{ + CAN_BE_DELETED, CREATION_RESTRICTION_MODE, DOCUMENTS_KEEP_HISTORY, DOCUMENTS_MUTABLE, + TRADE_MODE, TRANSFERABLE, +}; use crate::data_contract::document_type::{property_names, DocumentType}; use crate::data_contract::errors::DataContractError; use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements; @@ -106,6 +110,7 @@ impl DocumentTypeV0 { schema_defs: Option<&BTreeMap>, default_keeps_history: bool, default_mutability: bool, + default_can_be_deleted: bool, validate: bool, // we don't need to validate if loaded from state validation_operations: &mut Vec, platform_version: &PlatformVersion, @@ -208,27 +213,48 @@ impl DocumentTypeV0 { )) })?; - // TODO: These properties aren't defined in JSON meta schema // Do documents of this type keep history? (Overrides contract value) let documents_keep_history: bool = - Value::inner_optional_bool_value(schema_map, "documentsKeepHistory") + Value::inner_optional_bool_value(schema_map, DOCUMENTS_KEEP_HISTORY) .map_err(consensus_or_protocol_value_error)? .unwrap_or(default_keeps_history); // Are documents of this type mutable? (Overrides contract value) let documents_mutable: bool = - Value::inner_optional_bool_value(schema_map, "documentsMutable") + Value::inner_optional_bool_value(schema_map, DOCUMENTS_MUTABLE) .map_err(consensus_or_protocol_value_error)? .unwrap_or(default_mutability); - // Are documents of this type transferable? (Overrides contract value) + // Can documents of this type be deleted? (Overrides contract value) + let documents_can_be_deleted: bool = + Value::inner_optional_bool_value(schema_map, CAN_BE_DELETED) + .map_err(consensus_or_protocol_value_error)? + .unwrap_or(default_can_be_deleted); + + // Are documents of this type transferable? let documents_transferable_u8: u8 = - Value::inner_optional_integer_value(schema_map, "transferable") + Value::inner_optional_integer_value(schema_map, TRANSFERABLE) .map_err(consensus_or_protocol_value_error)? .unwrap_or_default(); let documents_transferable = documents_transferable_u8.try_into()?; + // What is the trade mode of these documents + let documents_trade_mode_u8: u8 = + Value::inner_optional_integer_value(schema_map, TRADE_MODE) + .map_err(consensus_or_protocol_value_error)? + .unwrap_or_default(); + + let trade_mode = documents_trade_mode_u8.try_into()?; + + // What is the creation restriction mode of this document type? + let documents_creation_restriction_mode_u8: u8 = + Value::inner_optional_integer_value(schema_map, CREATION_RESTRICTION_MODE) + .map_err(consensus_or_protocol_value_error)? + .unwrap_or_default(); + + let creation_restriction_mode = documents_creation_restriction_mode_u8.try_into()?; + // Extract the properties let property_values = Value::inner_optional_index_map::( schema_map, @@ -511,7 +537,10 @@ impl DocumentTypeV0 { required_fields, documents_keep_history, documents_mutable, + documents_can_be_deleted, documents_transferable, + trade_mode, + creation_restriction_mode, data_contract_id, requires_identity_encryption_bounded_key, requires_identity_decryption_bounded_key, @@ -809,6 +838,7 @@ mod tests { None, false, false, + false, true, &mut vec![], platform_version, @@ -838,6 +868,7 @@ mod tests { None, false, false, + false, true, &mut vec![], platform_version, @@ -876,6 +907,7 @@ mod tests { None, false, false, + false, true, &mut vec![], platform_version, @@ -914,6 +946,7 @@ mod tests { None, false, false, + false, true, &mut vec![], platform_version, @@ -936,6 +969,7 @@ mod tests { None, false, false, + false, true, &mut vec![], platform_version, diff --git a/packages/rs-dpp/src/data_contract/document_type/methods/mod.rs b/packages/rs-dpp/src/data_contract/document_type/methods/mod.rs index 240e1d96681..47df2fd0f4d 100644 --- a/packages/rs-dpp/src/data_contract/document_type/methods/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/methods/mod.rs @@ -18,7 +18,6 @@ use crate::prelude::{BlockHeight, CoreBlockHeight, Revision}; use crate::version::PlatformVersion; use crate::ProtocolError; -use crate::document::transfer::Transferable; use platform_value::{Identifier, Value}; // TODO: Some of those methods are only for tests. Hide under feature @@ -216,7 +215,9 @@ impl DocumentTypeV0Methods for DocumentTypeV0 { } fn requires_revision(&self) -> bool { - self.documents_mutable || self.documents_transferable != Transferable::Never + self.documents_mutable + || self.documents_transferable.is_transferable() + || self.trade_mode.seller_sets_price() } fn top_level_indices(&self) -> Vec<&IndexProperty> { 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 eed70afb856..c37c7fc252b 100644 --- a/packages/rs-dpp/src/data_contract/document_type/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/mod.rs @@ -10,6 +10,7 @@ pub use index_level::IndexLevel; #[cfg(feature = "random-documents")] pub mod random_document; +pub mod restricted_creation; pub mod schema; pub mod v0; @@ -26,6 +27,12 @@ use std::collections::BTreeMap; mod property_names { pub const DOCUMENTS_KEEP_HISTORY: &str = "documentsKeepHistory"; pub const DOCUMENTS_MUTABLE: &str = "documentsMutable"; + + pub const CAN_BE_DELETED: &str = "canBeDeleted"; + pub const TRANSFERABLE: &str = "transferable"; + pub const TRADE_MODE: &str = "tradeMode"; + + pub const CREATION_RESTRICTION_MODE: &str = "creationRestrictionMode"; pub const SECURITY_LEVEL_REQUIREMENT: &str = "signatureSecurityLevelRequirement"; pub const REQUIRES_IDENTITY_ENCRYPTION_BOUNDED_KEY: &str = "requiresIdentityEncryptionBoundedKey"; diff --git a/packages/rs-dpp/src/data_contract/document_type/restricted_creation/mod.rs b/packages/rs-dpp/src/data_contract/document_type/restricted_creation/mod.rs new file mode 100644 index 00000000000..81194382f46 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/document_type/restricted_creation/mod.rs @@ -0,0 +1,44 @@ +use crate::consensus::basic::data_contract::UnknownDocumentCreationRestrictionModeError; +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use crate::ProtocolError; +use std::fmt; +use std::fmt::{Display, Formatter}; + +#[derive(Debug, PartialEq, Clone, Copy, Eq, Encode, Decode)] +pub enum CreationRestrictionMode { + NoRestrictions, + OwnerOnly, + NoCreationAllowed, +} + +impl Display for CreationRestrictionMode { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + CreationRestrictionMode::NoRestrictions => write!(f, "No Restrictions"), + CreationRestrictionMode::OwnerOnly => write!(f, "Owner Only"), + CreationRestrictionMode::NoCreationAllowed => write!(f, "No Creation Allowed"), + } + } +} + +impl TryFrom for CreationRestrictionMode { + type Error = ProtocolError; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::NoRestrictions), + 1 => Ok(Self::OwnerOnly), + 2 => Ok(Self::NoCreationAllowed), + value => Err(ProtocolError::ConsensusError( + ConsensusError::BasicError( + BasicError::UnknownDocumentCreationRestrictionModeError( + UnknownDocumentCreationRestrictionModeError::new(vec![0, 1, 2], value), + ), + ) + .into(), + )), + } + } +} diff --git a/packages/rs-dpp/src/data_contract/document_type/v0/accessors.rs b/packages/rs-dpp/src/data_contract/document_type/v0/accessors.rs index b3b875ba577..ad0cb272b3e 100644 --- a/packages/rs-dpp/src/data_contract/document_type/v0/accessors.rs +++ b/packages/rs-dpp/src/data_contract/document_type/v0/accessors.rs @@ -6,9 +6,11 @@ use crate::data_contract::document_type::v0::DocumentTypeV0; use platform_value::{Identifier, Value}; +use crate::data_contract::document_type::restricted_creation::CreationRestrictionMode; use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements; use crate::document::transfer::Transferable; use crate::identity::SecurityLevel; +use crate::nft::TradeMode; use indexmap::IndexMap; use std::collections::BTreeSet; @@ -61,10 +63,22 @@ impl DocumentTypeV0Getters for DocumentTypeV0 { self.documents_mutable } + fn documents_can_be_deleted(&self) -> bool { + self.documents_can_be_deleted + } + fn documents_transferable(&self) -> Transferable { self.documents_transferable } + fn trade_mode(&self) -> TradeMode { + self.trade_mode + } + + fn creation_restriction_mode(&self) -> CreationRestrictionMode { + self.creation_restriction_mode + } + fn data_contract_id(&self) -> Identifier { self.data_contract_id } diff --git a/packages/rs-dpp/src/data_contract/document_type/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/v0/mod.rs index 7d8c6f990b6..147614713ca 100644 --- a/packages/rs-dpp/src/data_contract/document_type/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/v0/mod.rs @@ -9,8 +9,10 @@ use crate::data_contract::storage_requirements::keys_for_document_type::StorageK #[cfg(feature = "validation")] pub(in crate::data_contract) use validator::StatelessJsonSchemaLazyValidator; +use crate::data_contract::document_type::restricted_creation::CreationRestrictionMode; use crate::document::transfer::Transferable; use crate::identity::SecurityLevel; +use crate::nft::TradeMode; use platform_value::{Identifier, Value}; mod accessors; @@ -54,8 +56,15 @@ pub struct DocumentTypeV0 { pub(in crate::data_contract) documents_keep_history: bool, /// Are documents mutable? pub(in crate::data_contract) documents_mutable: bool, - /// Are documents transferable? + /// Can documents of this type be deleted? + pub(in crate::data_contract) documents_can_be_deleted: bool, + /// Can documents be transferred without a trade? pub(in crate::data_contract) documents_transferable: Transferable, + /// How are these documents traded? + pub(in crate::data_contract) trade_mode: TradeMode, + /// Is document creation restricted? + pub(in crate::data_contract) creation_restriction_mode: CreationRestrictionMode, + /// The data contract id pub(in crate::data_contract) data_contract_id: Identifier, /// Encryption key storage requirements pub(in crate::data_contract) requires_identity_encryption_bounded_key: diff --git a/packages/rs-dpp/src/data_contract/document_type/v0/random_document_type.rs b/packages/rs-dpp/src/data_contract/document_type/v0/random_document_type.rs index 5a977161c45..3e46c291ea1 100644 --- a/packages/rs-dpp/src/data_contract/document_type/v0/random_document_type.rs +++ b/packages/rs-dpp/src/data_contract/document_type/v0/random_document_type.rs @@ -72,6 +72,7 @@ pub struct RandomDocumentTypeParameters { pub field_bounds: FieldMinMaxBounds, pub keep_history_chance: f64, pub documents_mutable_chance: f64, + pub documents_can_be_deleted_chance: f64, } impl RandomDocumentTypeParameters { @@ -99,6 +100,7 @@ impl RandomDocumentTypeParameters { use crate::data_contract::document_type::array::ArrayItemType; use crate::data_contract::document_type::index_level::IndexLevel; +use crate::data_contract::document_type::restricted_creation::CreationRestrictionMode; #[cfg(feature = "validation")] use crate::data_contract::document_type::v0::StatelessJsonSchemaLazyValidator; use crate::data_contract::document_type::{ @@ -106,6 +108,7 @@ use crate::data_contract::document_type::{ }; use crate::document::transfer::Transferable; use crate::identity::SecurityLevel; +use crate::nft::TradeMode; use crate::version::PlatformVersion; use crate::ProtocolError; use bincode::{Decode, Encode}; @@ -242,6 +245,7 @@ impl DocumentTypeV0 { let documents_keep_history = rng.gen_bool(parameters.keep_history_chance); let documents_mutable = rng.gen_bool(parameters.documents_mutable_chance); + let documents_can_be_deleted = rng.gen_bool(parameters.documents_can_be_deleted_chance); let name = format!("doc_type_{}", rng.gen::()); @@ -423,7 +427,10 @@ impl DocumentTypeV0 { required_fields, documents_keep_history, documents_mutable, + documents_can_be_deleted, documents_transferable: Transferable::Never, + trade_mode: TradeMode::None, + creation_restriction_mode: CreationRestrictionMode::NoRestrictions, data_contract_id, requires_identity_encryption_bounded_key: None, requires_identity_decryption_bounded_key: None, @@ -556,6 +563,7 @@ impl DocumentTypeV0 { let documents_keep_history = rng.gen_bool(parameters.keep_history_chance); let documents_mutable = rng.gen_bool(parameters.documents_mutable_chance); + let documents_can_be_deleted = rng.gen_bool(parameters.documents_can_be_deleted_chance); let name = format!("doc_type_{}", rng.gen::()); @@ -587,7 +595,10 @@ impl DocumentTypeV0 { required_fields, documents_keep_history, documents_mutable, + documents_can_be_deleted, documents_transferable: Transferable::Never, + trade_mode: TradeMode::None, + creation_restriction_mode: CreationRestrictionMode::NoRestrictions, data_contract_id, requires_identity_encryption_bounded_key: None, requires_identity_decryption_bounded_key: None, diff --git a/packages/rs-dpp/src/data_contract/extra/drive_api_tests.rs b/packages/rs-dpp/src/data_contract/extra/drive_api_tests.rs index cdf5f9b2266..e1cd6308ce0 100644 --- a/packages/rs-dpp/src/data_contract/extra/drive_api_tests.rs +++ b/packages/rs-dpp/src/data_contract/extra/drive_api_tests.rs @@ -217,6 +217,9 @@ mod test { contract .config .set_documents_mutable_contract_default(false); + contract + .config + .set_documents_can_be_deleted_contract_default(false); contract .config .set_documents_keep_history_contract_default(true); @@ -235,6 +238,7 @@ mod test { keeps_history: true, documents_mutable_contract_default: false, documents_keep_history_contract_default: true, + documents_can_be_deleted_contract_default: false, requires_identity_encryption_bounded_key: None, requires_identity_decryption_bounded_key: None, }) @@ -264,6 +268,9 @@ mod test { contract_v0 .config .set_documents_mutable_contract_default(false); + contract_v0 + .config + .set_documents_can_be_deleted_contract_default(false); contract_v0 .config .set_documents_keep_history_contract_default(true); @@ -285,6 +292,7 @@ mod test { documents_keep_history_contract_default: true, requires_identity_encryption_bounded_key: None, requires_identity_decryption_bounded_key: None, + documents_can_be_deleted_contract_default: false, }) ); } diff --git a/packages/rs-dpp/src/data_contract/v0/methods/schema.rs b/packages/rs-dpp/src/data_contract/v0/methods/schema.rs index 03bf8f8f5b3..23bbbb106eb 100644 --- a/packages/rs-dpp/src/data_contract/v0/methods/schema.rs +++ b/packages/rs-dpp/src/data_contract/v0/methods/schema.rs @@ -25,6 +25,7 @@ impl DataContractSchemaMethodsV0 for DataContractV0 { defs.as_ref(), self.config.documents_keep_history_contract_default(), self.config.documents_mutable_contract_default(), + self.config.documents_can_be_deleted_contract_default(), validate, validation_operations, platform_version, @@ -48,6 +49,7 @@ impl DataContractSchemaMethodsV0 for DataContractV0 { self.schema_defs.as_ref(), self.config.documents_keep_history_contract_default(), self.config.documents_mutable_contract_default(), + self.config.documents_mutable_contract_default(), validate, validation_operations, platform_version, diff --git a/packages/rs-dpp/src/data_contract/v0/serialization/mod.rs b/packages/rs-dpp/src/data_contract/v0/serialization/mod.rs index b1992eba7bb..87aa2680b7f 100644 --- a/packages/rs-dpp/src/data_contract/v0/serialization/mod.rs +++ b/packages/rs-dpp/src/data_contract/v0/serialization/mod.rs @@ -97,6 +97,7 @@ impl DataContractV0 { schema_defs.as_ref(), config.documents_keep_history_contract_default(), config.documents_mutable_contract_default(), + config.documents_can_be_deleted_contract_default(), validate, validation_operations, platform_version, diff --git a/packages/rs-dpp/src/document/accessors/mod.rs b/packages/rs-dpp/src/document/accessors/mod.rs index ce005efd62d..2ba6d883103 100644 --- a/packages/rs-dpp/src/document/accessors/mod.rs +++ b/packages/rs-dpp/src/document/accessors/mod.rs @@ -137,6 +137,12 @@ impl DocumentV0Setters for Document { } } + fn bump_revision(&mut self) { + match self { + Document::V0(v0) => v0.bump_revision(), + } + } + fn set_created_at(&mut self, created_at: Option) { match self { Document::V0(v0) => v0.created_at = created_at, diff --git a/packages/rs-dpp/src/document/accessors/v0/mod.rs b/packages/rs-dpp/src/document/accessors/v0/mod.rs index 7717ee02f5e..e8274af2219 100644 --- a/packages/rs-dpp/src/document/accessors/v0/mod.rs +++ b/packages/rs-dpp/src/document/accessors/v0/mod.rs @@ -142,4 +142,5 @@ pub trait DocumentV0Setters: DocumentV0Getters { ); fn set_transferred_at_block_height(&mut self, transferred_at_block_height: Option); fn set_transferred_at(&mut self, transferred_at: Option); + fn bump_revision(&mut self); } diff --git a/packages/rs-dpp/src/document/extended_document/mod.rs b/packages/rs-dpp/src/document/extended_document/mod.rs index ae9e23e6069..c97b4b588b1 100644 --- a/packages/rs-dpp/src/document/extended_document/mod.rs +++ b/packages/rs-dpp/src/document/extended_document/mod.rs @@ -75,7 +75,7 @@ impl ExtendedDocument { /// Returns a `ProtocolError` if the document type is not found in the data contract. pub fn needs_revision(&self) -> Result { match self { - ExtendedDocument::V0(v0) => v0.needs_revision(), + ExtendedDocument::V0(v0) => v0.requires_revision(), } } diff --git a/packages/rs-dpp/src/document/extended_document/v0/mod.rs b/packages/rs-dpp/src/document/extended_document/v0/mod.rs index 918d190e145..a5cf0ec4765 100644 --- a/packages/rs-dpp/src/document/extended_document/v0/mod.rs +++ b/packages/rs-dpp/src/document/extended_document/v0/mod.rs @@ -32,6 +32,7 @@ use std::collections::BTreeMap; use crate::data_contract::accessors::v0::DataContractV0Getters; use crate::data_contract::document_type::accessors::DocumentTypeV0Getters; +use crate::data_contract::document_type::methods::DocumentTypeV0Methods; #[cfg(feature = "validation")] use crate::data_contract::validation::DataContractValidationMethodsV0; #[cfg(feature = "document-json-conversion")] @@ -161,9 +162,9 @@ impl ExtendedDocumentV0 { .map(|document_type| document_type.documents_mutable()) } - pub fn needs_revision(&self) -> Result { + pub fn requires_revision(&self) -> Result { self.document_type() - .map(|document_type| document_type.documents_mutable()) + .map(|document_type| document_type.requires_revision()) } pub fn revision(&self) -> Option { diff --git a/packages/rs-dpp/src/document/fields.rs b/packages/rs-dpp/src/document/fields.rs index f4d7afee699..452b7f7c3ef 100644 --- a/packages/rs-dpp/src/document/fields.rs +++ b/packages/rs-dpp/src/document/fields.rs @@ -5,6 +5,7 @@ pub mod property_names { pub const DATA_CONTRACT_ID: &str = "$dataContractId"; pub const REVISION: &str = "$revision"; pub const OWNER_ID: &str = "$ownerId"; + pub const PRICE: &str = "$price"; pub const CREATED_AT: &str = "$createdAt"; pub const UPDATED_AT: &str = "$updatedAt"; pub const TRANSFERRED_AT: &str = "$transferredAt"; diff --git a/packages/rs-dpp/src/document/v0/accessors.rs b/packages/rs-dpp/src/document/v0/accessors.rs index 4a14bea18a5..63d056b2d12 100644 --- a/packages/rs-dpp/src/document/v0/accessors.rs +++ b/packages/rs-dpp/src/document/v0/accessors.rs @@ -188,6 +188,15 @@ impl DocumentV0Setters for DocumentV0 { self.revision = revision; } + /// Bumps the document's revision if it has one. This is applicable if the document's schema indicates + /// the document type as mutable. + /// + fn bump_revision(&mut self) { + if let Some(revision) = self.revision { + self.revision = Some(revision.saturating_add(1)) + } + } + /// Sets the timestamp of when the document was created. This is applicable if the document's /// schema requires a creation timestamp. /// diff --git a/packages/rs-dpp/src/document/v0/serialize.rs b/packages/rs-dpp/src/document/v0/serialize.rs index 259258fa4d4..a26879d9ff9 100644 --- a/packages/rs-dpp/src/document/v0/serialize.rs +++ b/packages/rs-dpp/src/document/v0/serialize.rs @@ -2,7 +2,7 @@ use crate::data_contract::document_type::DocumentTypeRef; use crate::data_contract::errors::DataContractError; use crate::document::property_names::{ - CREATED_AT, CREATED_AT_BLOCK_HEIGHT, CREATED_AT_CORE_BLOCK_HEIGHT, TRANSFERRED_AT, + CREATED_AT, CREATED_AT_BLOCK_HEIGHT, CREATED_AT_CORE_BLOCK_HEIGHT, PRICE, TRANSFERRED_AT, TRANSFERRED_AT_BLOCK_HEIGHT, TRANSFERRED_AT_CORE_BLOCK_HEIGHT, UPDATED_AT, UPDATED_AT_BLOCK_HEIGHT, UPDATED_AT_CORE_BLOCK_HEIGHT, }; @@ -193,6 +193,18 @@ impl DocumentPlatformSerializationMethodsV0 for DocumentV0 { buffer.extend(bitwise_exists_flag.to_be_bytes().as_slice()); buffer.append(&mut time_fields_data_buffer); + // Now we serialize the price which might not be necessary unless called for by the document type + + if document_type.trade_mode().seller_sets_price() { + if let Some(price) = self.properties.get(PRICE) { + buffer.push(1); + let price_as_u64: u64 = price.to_integer().map_err(ProtocolError::ValueError)?; + buffer.append(&mut price_as_u64.to_be_bytes().to_vec()); + } else { + buffer.push(0); + } + } + // User defined properties document_type .properties() @@ -397,6 +409,18 @@ impl DocumentPlatformSerializationMethodsV0 for DocumentV0 { buffer.extend(bitwise_exists_flag.to_be_bytes().as_slice()); buffer.append(&mut time_fields_data_buffer); + // Now we serialize the price which might not be necessary unless called for by the document type + + if document_type.trade_mode().seller_sets_price() { + if let Some(price) = self.properties.get(PRICE) { + buffer.push(1); + let price_as_u64: u64 = price.to_integer().map_err(ProtocolError::ValueError)?; + buffer.append(&mut price_as_u64.to_be_bytes().to_vec()); + } else { + buffer.push(0); + } + } + // User defined properties document_type .properties() @@ -591,9 +615,31 @@ impl DocumentPlatformDeserializationMethodsV0 for DocumentV0 { None }; + // Now we deserialize the price which might not be necessary unless called for by the document type + + let price = if document_type.trade_mode().seller_sets_price() { + let has_price = buf.read_u8().map_err(|_| { + DataContractError::CorruptedSerialization( + "error reading has price bool from serialized document".to_string(), + ) + })?; + if has_price > 0 { + let price = buf.read_u64::().map_err(|_| { + DataContractError::CorruptedSerialization( + "error reading price u64 from serialized document".to_string(), + ) + })?; + Some(price) + } else { + None + } + } else { + None + }; + let mut finished_buffer = false; - let properties = document_type + let mut properties = document_type .properties() .iter() .filter_map(|(key, property)| { @@ -620,6 +666,10 @@ impl DocumentPlatformDeserializationMethodsV0 for DocumentV0 { }) .collect::, DataContractError>>()?; + if let Some(price) = price { + properties.insert(PRICE.to_string(), price.into()); + } + Ok(DocumentV0 { id: Identifier::new(id), properties, 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 65ad96ade7a..f78903696a6 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -14,20 +14,22 @@ use crate::consensus::basic::data_contract::{ InvalidDataContractIdError, InvalidDataContractVersionError, InvalidDocumentTypeNameError, InvalidDocumentTypeRequiredSecurityLevelError, InvalidIndexPropertyTypeError, InvalidIndexedPropertyConstraintError, SystemPropertyIndexAlreadyPresentError, - UndefinedIndexPropertyError, UniqueIndicesLimitReachedError, UnknownSecurityLevelError, - UnknownStorageKeyRequirementsError, UnknownTransferableTypeError, + UndefinedIndexPropertyError, UniqueIndicesLimitReachedError, + UnknownDocumentCreationRestrictionModeError, UnknownSecurityLevelError, + UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError, }; use crate::consensus::basic::decode::{ ProtocolVersionParsingError, SerializedObjectParsingError, VersionError, }; use crate::consensus::basic::document::{ - DataContractNotPresentError, DocumentTransitionsAreAbsentError, - DuplicateDocumentTransitionsWithIdsError, DuplicateDocumentTransitionsWithIndicesError, - InconsistentCompoundIndexDataError, InvalidDocumentTransitionActionError, - InvalidDocumentTransitionIdError, InvalidDocumentTypeError, - MaxDocumentsTransitionsExceededError, MissingDataContractIdBasicError, - MissingDocumentTransitionActionError, MissingDocumentTransitionTypeError, - MissingDocumentTypeError, MissingPositionsInDocumentTypePropertiesError, NonceOutOfBoundsError, + DataContractNotPresentError, DocumentCreationNotAllowedError, + DocumentTransitionsAreAbsentError, DuplicateDocumentTransitionsWithIdsError, + DuplicateDocumentTransitionsWithIndicesError, InconsistentCompoundIndexDataError, + InvalidDocumentTransitionActionError, InvalidDocumentTransitionIdError, + InvalidDocumentTypeError, MaxDocumentsTransitionsExceededError, + MissingDataContractIdBasicError, MissingDocumentTransitionActionError, + MissingDocumentTransitionTypeError, MissingDocumentTypeError, + MissingPositionsInDocumentTypePropertiesError, NonceOutOfBoundsError, }; use crate::consensus::basic::identity::{ DataContractBoundsNotPresentError, DisablingKeyIdAlsoBeingAddedInSameTransitionError, @@ -93,6 +95,12 @@ pub enum BasicError { #[error(transparent)] UnknownTransferableTypeError(UnknownTransferableTypeError), + #[error(transparent)] + UnknownTradeModeError(UnknownTradeModeError), + + #[error(transparent)] + UnknownDocumentCreationRestrictionModeError(UnknownDocumentCreationRestrictionModeError), + #[error(transparent)] SerializedObjectParsingError(SerializedObjectParsingError), @@ -183,6 +191,9 @@ pub enum BasicError { #[error(transparent)] DataContractNotPresentError(DataContractNotPresentError), + #[error(transparent)] + DocumentCreationNotAllowedError(DocumentCreationNotAllowedError), + #[error(transparent)] DataContractBoundsNotPresentError(DataContractBoundsNotPresentError), diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/incompatible_data_contract_schema_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/incompatible_data_contract_schema_error.rs index 444662dfd88..9a75c009495 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/data_contract/incompatible_data_contract_schema_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/incompatible_data_contract_schema_error.rs @@ -11,7 +11,7 @@ use bincode::{Decode, Encode}; #[derive( Error, Debug, Clone, PartialEq, Encode, Decode, PlatformSerialize, PlatformDeserialize, )] -#[error("Data Contract updated schema is not backward compatible with one defined in Data Contract wid id {data_contract_id}. Field: '{field_path}', Operation: '{operation}'" +#[error("Data Contract updated schema is not backward compatible with one defined in Data Contract with id {data_contract_id}. Field: '{field_path}', Operation: '{operation}'" )] #[platform_serialize(unversioned)] pub struct IncompatibleDataContractSchemaError { 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 30fa795b1f3..4e79e023acd 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 @@ -20,8 +20,10 @@ mod invalid_json_schema_ref_error; mod system_property_index_already_present_error; mod undefined_index_property_error; mod unique_indices_limit_reached_error; +mod unknown_document_creation_restriction_mode_error; mod unknown_security_level_error; mod unknown_storage_key_requirements_error; +mod unknown_trade_mode_error; mod unknown_transferable_type_error; pub use data_contract_empty_schema_error::*; @@ -47,6 +49,8 @@ pub use undefined_index_property_error::*; pub use unique_indices_limit_reached_error::*; pub use invalid_document_type_name_error::*; +pub use unknown_document_creation_restriction_mode_error::*; pub use unknown_security_level_error::*; pub use unknown_storage_key_requirements_error::*; +pub use unknown_trade_mode_error::*; pub use unknown_transferable_type_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_document_creation_restriction_mode_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_document_creation_restriction_mode_error.rs new file mode 100644 index 00000000000..2d55df7e397 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_document_creation_restriction_mode_error.rs @@ -0,0 +1,47 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error( + "Unrecognized document creation restriction mode: allowed {:?}, got {}", + allowed_values, + received +)] +#[platform_serialize(unversioned)] +pub struct UnknownDocumentCreationRestrictionModeError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + allowed_values: Vec, + received: u8, +} + +impl UnknownDocumentCreationRestrictionModeError { + pub fn new(allowed_values: Vec, received: u8) -> Self { + Self { + allowed_values, + received, + } + } + + pub fn allowed_values(&self) -> Vec { + self.allowed_values.clone() + } + pub fn received(&self) -> u8 { + self.received + } +} + +impl From for ConsensusError { + fn from(err: UnknownDocumentCreationRestrictionModeError) -> Self { + Self::BasicError(BasicError::UnknownDocumentCreationRestrictionModeError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_trade_mode_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_trade_mode_error.rs new file mode 100644 index 00000000000..bbf57f33351 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/unknown_trade_mode_error.rs @@ -0,0 +1,47 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error( + "Unrecognized trade mode: allowed {:?}, got {}", + allowed_values, + received +)] +#[platform_serialize(unversioned)] +pub struct UnknownTradeModeError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + allowed_values: Vec, + received: u8, +} + +impl UnknownTradeModeError { + pub fn new(allowed_values: Vec, received: u8) -> Self { + Self { + allowed_values, + received, + } + } + + pub fn allowed_values(&self) -> Vec { + self.allowed_values.clone() + } + pub fn received(&self) -> u8 { + self.received + } +} + +impl From for ConsensusError { + fn from(err: UnknownTradeModeError) -> Self { + Self::BasicError(BasicError::UnknownTradeModeError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/document/document_creation_not_allowed_error.rs b/packages/rs-dpp/src/errors/consensus/basic/document/document_creation_not_allowed_error.rs new file mode 100644 index 00000000000..5ad1732dddc --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/document/document_creation_not_allowed_error.rs @@ -0,0 +1,58 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::data_contract::document_type::restricted_creation::CreationRestrictionMode; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Document Creation on {data_contract_id}:{document_type_name} is not allowed because of the document type's creation restriction mode {creation_restriction_mode}")] +#[platform_serialize(unversioned)] +pub struct DocumentCreationNotAllowedError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + data_contract_id: Identifier, + + document_type_name: String, + + creation_restriction_mode: CreationRestrictionMode, +} + +impl DocumentCreationNotAllowedError { + pub fn new( + data_contract_id: Identifier, + document_type_name: String, + creation_restriction_mode: CreationRestrictionMode, + ) -> Self { + Self { + data_contract_id, + document_type_name, + creation_restriction_mode, + } + } + + pub fn data_contract_id(&self) -> Identifier { + self.data_contract_id + } + + pub fn document_type_name(&self) -> &str { + self.document_type_name.as_str() + } + + pub fn creation_restriction_mode(&self) -> CreationRestrictionMode { + self.creation_restriction_mode + } +} + +impl From for ConsensusError { + fn from(err: DocumentCreationNotAllowedError) -> Self { + Self::BasicError(BasicError::DocumentCreationNotAllowedError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/document/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/document/mod.rs index 7cc323f4fa3..9c011e12b59 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/document/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/document/mod.rs @@ -1,4 +1,5 @@ mod data_contract_not_present_error; +mod document_creation_not_allowed_error; mod document_transitions_are_absent_error; mod duplicate_document_transitions_with_ids_error; mod duplicate_document_transitions_with_indices_error; @@ -15,6 +16,7 @@ mod missing_document_type_error; mod missing_positions_in_document_type_properties_error; pub use data_contract_not_present_error::*; +pub use document_creation_not_allowed_error::*; pub use document_transitions_are_absent_error::*; pub use duplicate_document_transitions_with_ids_error::*; pub use duplicate_document_transitions_with_indices_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index 07f19201fa5..93544fc1d3f 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -91,6 +91,8 @@ impl ErrorWithCode for BasicError { Self::ContractError(DataContractError::KeyWrongBounds(_)) => 10241, Self::ContractError(DataContractError::KeyValueMustExist(_)) => 10242, Self::UnknownTransferableTypeError { .. } => 10243, + Self::UnknownTradeModeError { .. } => 10244, + Self::UnknownDocumentCreationRestrictionModeError { .. } => 10245, // Document Errors: 10400-10499 Self::DataContractNotPresentError { .. } => 10400, @@ -109,6 +111,7 @@ impl ErrorWithCode for BasicError { Self::DocumentTransitionsAreAbsentError { .. } => 10413, Self::NonceOutOfBoundsError(_) => 10414, Self::InvalidDocumentTypeNameError(_) => 10415, + Self::DocumentCreationNotAllowedError(_) => 10416, // Identity Errors: 10500-10599 Self::DuplicatedIdentityPublicKeyBasicError(_) => 10500, @@ -196,6 +199,8 @@ impl ErrorWithCode for StateError { Self::DuplicateUniqueIndexError { .. } => 40105, Self::InvalidDocumentRevisionError { .. } => 40106, Self::DocumentTimestampsAreEqualError(_) => 40107, + Self::DocumentNotForSaleError(_) => 40108, + Self::DocumentIncorrectPurchasePriceError(_) => 40109, // Identity Errors: 40200-40299 Self::IdentityAlreadyExistsError(_) => 40200, diff --git a/packages/rs-dpp/src/errors/consensus/state/document/document_incorrect_purchase_price_error.rs b/packages/rs-dpp/src/errors/consensus/state/document/document_incorrect_purchase_price_error.rs new file mode 100644 index 00000000000..5e726c5cbef --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/document/document_incorrect_purchase_price_error.rs @@ -0,0 +1,58 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use crate::fee::Credits; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("{document_id} document can not be purchased for {trying_to_purchase_at_price}, it's sale price is {actual_price} (in credits)")] +#[platform_serialize(unversioned)] +pub struct DocumentIncorrectPurchasePriceError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + document_id: Identifier, + + trying_to_purchase_at_price: Credits, + + actual_price: Credits, +} + +impl DocumentIncorrectPurchasePriceError { + pub fn new( + document_id: Identifier, + trying_to_purchase_at_price: Credits, + actual_price: Credits, + ) -> Self { + Self { + document_id, + trying_to_purchase_at_price, + actual_price, + } + } + + pub fn document_id(&self) -> &Identifier { + &self.document_id + } + + pub fn trying_to_purchase_at_price(&self) -> Credits { + self.trying_to_purchase_at_price + } + + pub fn actual_price(&self) -> Credits { + self.actual_price + } +} + +impl From for ConsensusError { + fn from(err: DocumentIncorrectPurchasePriceError) -> Self { + Self::StateError(StateError::DocumentIncorrectPurchasePriceError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/document/document_not_for_sale_error.rs b/packages/rs-dpp/src/errors/consensus/state/document/document_not_for_sale_error.rs new file mode 100644 index 00000000000..1304477355f --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/document/document_not_for_sale_error.rs @@ -0,0 +1,37 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("{document_id} document not for sale")] +#[platform_serialize(unversioned)] +pub struct DocumentNotForSaleError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + document_id: Identifier, +} + +impl DocumentNotForSaleError { + pub fn new(document_id: Identifier) -> Self { + Self { document_id } + } + + pub fn document_id(&self) -> &Identifier { + &self.document_id + } +} + +impl From for ConsensusError { + fn from(err: DocumentNotForSaleError) -> Self { + Self::StateError(StateError::DocumentNotForSaleError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/document/mod.rs b/packages/rs-dpp/src/errors/consensus/state/document/mod.rs index 2469345323f..36621070ab8 100644 --- a/packages/rs-dpp/src/errors/consensus/state/document/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/document/mod.rs @@ -1,4 +1,6 @@ pub mod document_already_present_error; +pub mod document_incorrect_purchase_price_error; +pub mod document_not_for_sale_error; pub mod document_not_found_error; pub mod document_owner_id_mismatch_error; pub mod document_timestamp_window_violation_error; diff --git a/packages/rs-dpp/src/errors/consensus/state/state_error.rs b/packages/rs-dpp/src/errors/consensus/state/state_error.rs index a8379044b93..a71511e45ba 100644 --- a/packages/rs-dpp/src/errors/consensus/state/state_error.rs +++ b/packages/rs-dpp/src/errors/consensus/state/state_error.rs @@ -28,6 +28,8 @@ use crate::consensus::state::identity::{ }; use crate::consensus::ConsensusError; use crate::consensus::state::data_contract::document_type_update_error::DocumentTypeUpdateError; +use crate::consensus::state::document::document_incorrect_purchase_price_error::DocumentIncorrectPurchasePriceError; +use crate::consensus::state::document::document_not_for_sale_error::DocumentNotForSaleError; use crate::consensus::state::identity::identity_public_key_already_exists_for_unique_contract_bounds_error::IdentityPublicKeyAlreadyExistsForUniqueContractBoundsError; use crate::consensus::state::identity::invalid_identity_contract_nonce_error::InvalidIdentityNonceError; @@ -55,6 +57,12 @@ pub enum StateError { #[error(transparent)] DocumentNotFoundError(DocumentNotFoundError), + #[error(transparent)] + DocumentNotForSaleError(DocumentNotForSaleError), + + #[error(transparent)] + DocumentIncorrectPurchasePriceError(DocumentIncorrectPurchasePriceError), + #[error(transparent)] DocumentOwnerIdMismatchError(DocumentOwnerIdMismatchError), diff --git a/packages/rs-dpp/src/fee/fee_result/mod.rs b/packages/rs-dpp/src/fee/fee_result/mod.rs index c58e7b97c25..749cc834267 100644 --- a/packages/rs-dpp/src/fee/fee_result/mod.rs +++ b/packages/rs-dpp/src/fee/fee_result/mod.rs @@ -90,7 +90,7 @@ impl TryFrom>> for FeeResult { } /// The balance change for an identity -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum BalanceChange { /// Add Balance AddToBalance(Credits), diff --git a/packages/rs-dpp/src/lib.rs b/packages/rs-dpp/src/lib.rs index cef2d9f3e77..c9eb000abb4 100644 --- a/packages/rs-dpp/src/lib.rs +++ b/packages/rs-dpp/src/lib.rs @@ -39,6 +39,7 @@ pub mod asset_lock; pub mod balances; pub mod block; pub mod fee; +pub mod nft; pub mod serialization; #[cfg(any( feature = "message-signing", diff --git a/packages/rs-dpp/src/nft/mod.rs b/packages/rs-dpp/src/nft/mod.rs new file mode 100644 index 00000000000..884906fb1e8 --- /dev/null +++ b/packages/rs-dpp/src/nft/mod.rs @@ -0,0 +1,55 @@ +use crate::consensus::basic::data_contract::UnknownTradeModeError; +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::ProtocolError; +use std::fmt; +use std::fmt::{Display, Formatter}; + +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum TradeMode { + None = 0, + DirectPurchase = 1, + // PublicOffer = 2, + // PrivateOffer = 3, +} + +impl TradeMode { + pub fn seller_sets_price(&self) -> bool { + match self { + TradeMode::None => false, + TradeMode::DirectPurchase => true, + // TradeMode::PublicOffer => true, //min price + // TradeMode::PrivateOffer => true, //min price + } + } +} + +impl Display for TradeMode { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + TradeMode::None => write!(f, "No Trading"), + TradeMode::DirectPurchase => write!(f, "Direct Purchase"), + // TradeMode::PublicOffer => write!(f, "Public Offer"), + // TradeMode::PrivateOffer => write!(f, "Private Offer"), + } + } +} + +impl TryFrom for TradeMode { + type Error = ProtocolError; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::None), + 1 => Ok(Self::DirectPurchase), + // 2 => Ok(Self::PublicOffer), + // 3 => Ok(Self::PrivateOffer), + value => Err(ProtocolError::ConsensusError( + ConsensusError::BasicError(BasicError::UnknownTradeModeError( + UnknownTradeModeError::new(vec![0, 1], value), + )) + .into(), + )), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/action_type.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/action_type.rs index 9052109dca2..fd7c376f7b9 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/action_type.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/action_type.rs @@ -8,6 +8,8 @@ pub enum DocumentTransitionActionType { Replace, Delete, Transfer, + Purchase, + UpdatePrice, IgnoreWhileBumpingRevision, } @@ -22,6 +24,8 @@ impl TransitionActionTypeGetter for DocumentTransition { DocumentTransition::Delete(_) => DocumentTransitionActionType::Delete, DocumentTransition::Replace(_) => DocumentTransitionActionType::Replace, DocumentTransition::Transfer(_) => DocumentTransitionActionType::Transfer, + DocumentTransition::UpdatePrice(_) => DocumentTransitionActionType::UpdatePrice, + DocumentTransition::Purchase(_) => DocumentTransitionActionType::Purchase, } } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/from_document.rs new file mode 100644 index 00000000000..d4b913405f0 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/from_document.rs @@ -0,0 +1,45 @@ +use crate::data_contract::document_type::DocumentTypeRef; +use crate::document::Document; +use crate::fee::Credits; +use crate::prelude::IdentityNonce; +use crate::ProtocolError; +use platform_version::version::{FeatureVersion, PlatformVersion}; + +use crate::state_transition::documents_batch_transition::document_transition::{DocumentPurchaseTransition}; +use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::DocumentPurchaseTransitionV0; + +impl DocumentPurchaseTransition { + pub fn from_document( + document: Document, + document_type: DocumentTypeRef, + price: Credits, + identity_contract_nonce: IdentityNonce, + platform_version: &PlatformVersion, + feature_version: Option, + base_feature_version: Option, + ) -> Result { + match feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .document_purchase_state_transition + .bounds + .default_current_version, + ) { + 0 => Ok(DocumentPurchaseTransitionV0::from_document( + document, + document_type, + price, + identity_contract_nonce, + platform_version, + base_feature_version, + )? + .into()), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentPurchaseTransition::from_document".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/mod.rs new file mode 100644 index 00000000000..9a5664cfaae --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/mod.rs @@ -0,0 +1,19 @@ +mod from_document; +pub mod v0; +pub mod v0_methods; + +use bincode::{Decode, Encode}; +use derive_more::{Display, From}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +pub use v0::*; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum DocumentPurchaseTransition { + #[display(fmt = "V0({})", "_0")] + V0(DocumentPurchaseTransitionV0), +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/from_document.rs new file mode 100644 index 00000000000..80bfc2115c5 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/from_document.rs @@ -0,0 +1,40 @@ +use platform_version::version::{FeatureVersion, PlatformVersion}; +use crate::data_contract::document_type::{DocumentTypeRef}; +use crate::document::{Document, DocumentV0Getters}; +use crate::document::errors::DocumentError; +use crate::fee::Credits; +use crate::prelude::IdentityNonce; +use crate::ProtocolError; +use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::DocumentPurchaseTransitionV0; + +impl DocumentPurchaseTransitionV0 { + pub(crate) fn from_document( + document: Document, + document_type: DocumentTypeRef, + price: Credits, + identity_contract_nonce: IdentityNonce, + platform_version: &PlatformVersion, + base_feature_version: Option, + ) -> Result { + let Some(revision) = document.revision() else { + return Err(ProtocolError::Document(Box::new( + DocumentError::DocumentNoRevisionError { + document: Box::new(document.clone()), + }, + ))); + }; + + Ok(DocumentPurchaseTransitionV0 { + base: DocumentBaseTransition::from_document( + &document, + document_type, + identity_contract_nonce, + platform_version, + base_feature_version, + )?, + revision, + price, + }) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/mod.rs new file mode 100644 index 00000000000..255310c394c --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/mod.rs @@ -0,0 +1,33 @@ +mod from_document; +pub mod v0_methods; + +use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; + +use bincode::{Decode, Encode}; +use derive_more::Display; + +use crate::fee::Credits; +use crate::prelude::Revision; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +pub use super::super::document_base_transition::IDENTIFIER_FIELDS; + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[display(fmt = "Base: {}", "base")] +pub struct DocumentPurchaseTransitionV0 { + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub base: DocumentBaseTransition, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$revision") + )] + pub revision: Revision, + #[cfg_attr(feature = "state-transition-serde-conversion", serde(rename = "price"))] + pub price: Credits, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/v0_methods.rs new file mode 100644 index 00000000000..95333296e41 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/v0_methods.rs @@ -0,0 +1,50 @@ +use crate::fee::Credits; +use crate::prelude::Revision; +use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::DocumentPurchaseTransitionV0; + +pub trait DocumentPurchaseTransitionV0Methods { + /// Returns a reference to the `base` field of the `DocumentCreateTransitionV0`. + fn base(&self) -> &DocumentBaseTransition; + fn base_mut(&mut self) -> &mut DocumentBaseTransition; + + /// Sets the value of the `base` field in the `DocumentCreateTransitionV0`. + /// + /// # Arguments + /// + /// * `base` - A value of type `DocumentBaseTransition` to set. + fn set_base(&mut self, base: DocumentBaseTransition); + + /// Returns a reference to the `revision` field of the `DocumentReplaceTransitionV0`. + fn revision(&self) -> Revision; + + /// Sets the value of the `revision` field in the `DocumentReplaceTransitionV0`. + fn set_revision(&mut self, revision: Revision); + fn price(&self) -> Credits; +} + +impl DocumentPurchaseTransitionV0Methods for DocumentPurchaseTransitionV0 { + fn base(&self) -> &DocumentBaseTransition { + &self.base + } + + fn base_mut(&mut self) -> &mut DocumentBaseTransition { + &mut self.base + } + + fn set_base(&mut self, base: DocumentBaseTransition) { + self.base = base + } + + fn revision(&self) -> Revision { + self.revision + } + + fn set_revision(&mut self, revision: Revision) { + self.revision = revision; + } + + fn price(&self) -> Credits { + self.price + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0_methods.rs new file mode 100644 index 00000000000..86c2fe8f193 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0_methods.rs @@ -0,0 +1,43 @@ +use crate::fee::Credits; +use crate::prelude::Revision; +use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; +use crate::state_transition::documents_batch_transition::document_transition::DocumentPurchaseTransition; + +impl DocumentPurchaseTransitionV0Methods for DocumentPurchaseTransition { + fn base(&self) -> &DocumentBaseTransition { + match self { + DocumentPurchaseTransition::V0(v0) => &v0.base, + } + } + + fn base_mut(&mut self) -> &mut DocumentBaseTransition { + match self { + DocumentPurchaseTransition::V0(v0) => &mut v0.base, + } + } + + fn set_base(&mut self, base: DocumentBaseTransition) { + match self { + DocumentPurchaseTransition::V0(v0) => v0.base = base, + } + } + + fn revision(&self) -> Revision { + match self { + DocumentPurchaseTransition::V0(v0) => v0.revision, + } + } + + fn set_revision(&mut self, revision: Revision) { + match self { + DocumentPurchaseTransition::V0(v0) => v0.revision = revision, + } + } + + fn price(&self) -> Credits { + match self { + DocumentPurchaseTransition::V0(v0) => v0.price, + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/from_document.rs new file mode 100644 index 00000000000..4f26ff90bd7 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/from_document.rs @@ -0,0 +1,44 @@ +use platform_version::version::{FeatureVersion, PlatformVersion}; +use crate::data_contract::document_type::{DocumentTypeRef}; +use crate::document::{Document}; +use crate::fee::Credits; +use crate::prelude::IdentityNonce; +use crate::ProtocolError; +use crate::state_transition::documents_batch_transition::document_transition::DocumentUpdatePriceTransition; +use crate::state_transition::documents_batch_transition::document_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; + +impl DocumentUpdatePriceTransition { + pub fn from_document( + document: Document, + document_type: DocumentTypeRef, + price: Credits, + identity_contract_nonce: IdentityNonce, + platform_version: &PlatformVersion, + feature_version: Option, + base_feature_version: Option, + ) -> Result { + match feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .document_update_price_state_transition + .bounds + .default_current_version, + ) { + 0 => Ok(DocumentUpdatePriceTransitionV0::from_document( + document, + document_type, + price, + identity_contract_nonce, + platform_version, + base_feature_version, + )? + .into()), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentUpdatePriceTransition::from_document".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/mod.rs new file mode 100644 index 00000000000..25a16a09ae3 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/mod.rs @@ -0,0 +1,19 @@ +mod from_document; +pub mod v0; +pub mod v0_methods; + +use bincode::{Decode, Encode}; +use derive_more::{Display, From}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +pub use v0::*; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum DocumentUpdatePriceTransition { + #[display(fmt = "V0({})", "_0")] + V0(DocumentUpdatePriceTransitionV0), +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/from_document.rs new file mode 100644 index 00000000000..570a3fb5610 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/from_document.rs @@ -0,0 +1,36 @@ +use platform_version::version::{FeatureVersion, PlatformVersion}; +use crate::data_contract::document_type::{DocumentTypeRef}; +use crate::document::{Document, DocumentV0Getters}; +use crate::document::errors::DocumentError; +use crate::fee::Credits; +use crate::prelude::IdentityNonce; +use crate::ProtocolError; +use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::documents_batch_transition::document_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; + +impl DocumentUpdatePriceTransitionV0 { + pub(crate) fn from_document( + document: Document, + document_type: DocumentTypeRef, + price: Credits, + identity_contract_nonce: IdentityNonce, + platform_version: &PlatformVersion, + base_feature_version: Option, + ) -> Result { + Ok(DocumentUpdatePriceTransitionV0 { + base: DocumentBaseTransition::from_document( + &document, + document_type, + identity_contract_nonce, + platform_version, + base_feature_version, + )?, + revision: document.revision().ok_or_else(|| { + ProtocolError::Document(Box::new(DocumentError::DocumentNoRevisionError { + document: Box::new(document.clone()), + })) + })?, + price, + }) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/mod.rs new file mode 100644 index 00000000000..fe1e11cae18 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/mod.rs @@ -0,0 +1,277 @@ +mod from_document; +pub mod v0_methods; + +use crate::prelude::Revision; +use bincode::{Decode, Encode}; +use derive_more::Display; + +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +use crate::fee::Credits; + +pub use super::super::document_base_transition::IDENTIFIER_FIELDS; +use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; + +mod property_names { + pub const REVISION: &str = "$revision"; +} + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[display(fmt = "Base: {}, Revision: {}, Price: {}", "base", "revision", "price")] +pub struct DocumentUpdatePriceTransitionV0 { + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub base: DocumentBaseTransition, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$revision") + )] + pub revision: Revision, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$price") + )] + pub price: Credits, +} +// +// /// document from update_price transition v0 +// pub trait DocumentFromUpdatePriceTransitionV0 { +// /// Attempts to create a new `Document` from the given `DocumentUpdatePriceTransitionV0` reference. This operation is typically used to update_price or update an existing document with new information. +// /// +// /// # Arguments +// /// +// /// * `value` - A reference to the `DocumentUpdatePriceTransitionV0` containing the new information for the document. +// /// * `owner_id` - The `Identifier` of the document's owner. +// /// * `created_at` - An optional timestamp representing when the original document was created. This is preserved during update_pricement. +// /// * `created_at_block_height` - An optional height of the block at which the original document was created. This is preserved during update_pricement. +// /// * `created_at_core_block_height` - An optional core block height at which the original document was created. This is preserved during update_pricement. +// /// * `block_info` - Information about the current block at the time of this update_price transition. +// /// * `document_type` - A reference to the `DocumentTypeRef` indicating the type of the document being update_priced. +// /// * `platform_version` - A reference to the `PlatformVersion` indicating the version of the platform under which the document is being update_priced. +// /// +// /// # Returns +// /// +// /// * `Result` - On successful update_pricement, returns a new `Document` object populated with the provided data. Returns a `ProtocolError` if the update_pricement fails due to validation errors or other issues. +// /// +// /// # Errors +// /// +// /// This function may return a `ProtocolError` if validation fails, required fields are missing, or if there are mismatches between field types and the schema defined in the data contract. +// fn try_from_update_price_transition_v0( +// value: &DocumentUpdatePriceTransitionV0, +// owner_id: Identifier, +// created_at: Option, +// created_at_block_height: Option, +// created_at_core_block_height: Option, +// transferred_at: Option, +// transferred_at_block_height: Option, +// transferred_at_core_block_height: Option, +// block_info: &BlockInfo, +// document_type: &DocumentTypeRef, +// platform_version: &PlatformVersion, +// ) -> Result +// where +// Self: Sized; +// /// Attempts to create a new `Document` from the given `DocumentUpdatePriceTransitionV0` instance. This function is similar to `try_from_update_price_transition_v0` but consumes the `DocumentUpdatePriceTransitionV0` instance, making it suitable for scenarios where the transition is owned and should not be reused after document creation. +// /// +// /// # Arguments +// /// +// /// * `value` - An owned `DocumentUpdatePriceTransitionV0` instance containing the new information for the document. +// /// * `owner_id` - The `Identifier` of the document's owner. +// /// * `created_at` - An optional timestamp representing when the original document was created. This is preserved during update_pricement. +// /// * `created_at_block_height` - An optional height of the block at which the original document was created. This is preserved during update_pricement. +// /// * `created_at_core_block_height` - An optional core block height at which the original document was created. This is preserved during update_pricement. +// /// * `block_info` - Information about the current block at the time of this update_price transition. +// /// * `document_type` - A reference to the `DocumentTypeRef` indicating the type of the document being update_priced. +// /// * `platform_version` - A reference to the `PlatformVersion` indicating the version of the platform under which the document is being update_priced. +// /// +// /// # Returns +// /// +// /// * `Result` - On successful update_pricement, returns a new `Document` object populated with the provided data. Returns a `ProtocolError` if the update_pricement fails due to validation errors or other issues. +// /// +// /// # Errors +// /// +// /// This function may return a `ProtocolError` for the same reasons as `try_from_update_price_transition_v0`, including validation failures, missing required fields, or schema mismatches. +// fn try_from_owned_update_price_transition_v0( +// value: DocumentUpdatePriceTransitionV0, +// owner_id: Identifier, +// created_at: Option, +// created_at_block_height: Option, +// created_at_core_block_height: Option, +// transferred_at: Option, +// transferred_at_block_height: Option, +// transferred_at_core_block_height: Option, +// block_info: &BlockInfo, +// document_type: &DocumentTypeRef, +// platform_version: &PlatformVersion, +// ) -> Result +// where +// Self: Sized; +// } +// +// impl DocumentFromUpdatePriceTransitionV0 for Document { +// fn try_from_update_price_transition_v0( +// value: &DocumentUpdatePriceTransitionV0, +// owner_id: Identifier, +// created_at: Option, +// created_at_block_height: Option, +// created_at_core_block_height: Option, +// transferred_at: Option, +// transferred_at_block_height: Option, +// transferred_at_core_block_height: Option, +// block_info: &BlockInfo, +// document_type: &DocumentTypeRef, +// platform_version: &PlatformVersion, +// ) -> Result { +// let DocumentUpdatePriceTransitionV0 { +// base, +// revision, +// price, +// } = value; +// +// let id = base.id(); +// +// let requires_updated_at = document_type +// .required_fields() +// .contains(document::property_names::UPDATED_AT); +// +// let requires_updated_at_block_height = document_type +// .required_fields() +// .contains(document::property_names::UPDATED_AT_BLOCK_HEIGHT); +// +// let requires_updated_at_core_block_height = document_type +// .required_fields() +// .contains(document::property_names::UPDATED_AT_CORE_BLOCK_HEIGHT); +// +// let updated_at = if requires_updated_at { +// Some(block_info.time_ms) +// } else { +// None +// }; +// +// let updated_at_block_height = if requires_updated_at_block_height { +// Some(block_info.height) +// } else { +// None +// }; +// +// let updated_at_core_block_height = if requires_updated_at_core_block_height { +// Some(block_info.core_height) +// } else { +// None +// }; +// +// data +// +// match platform_version +// .dpp +// .document_versions +// .document_structure_version +// { +// 0 => Ok(DocumentV0 { +// id, +// owner_id, +// properties: data.clone(), +// revision: Some(*revision), +// created_at, +// updated_at, +// transferred_at, +// created_at_block_height, +// updated_at_block_height, +// transferred_at_block_height, +// created_at_core_block_height, +// updated_at_core_block_height, +// transferred_at_core_block_height, +// } +// .into()), +// version => Err(ProtocolError::UnknownVersionMismatch { +// method: "Document::try_from_update_price_transition".to_string(), +// known_versions: vec![0], +// received: version, +// }), +// } +// } +// +// fn try_from_owned_update_price_transition_v0( +// value: DocumentUpdatePriceTransitionV0, +// owner_id: Identifier, +// created_at: Option, +// created_at_block_height: Option, +// created_at_core_block_height: Option, +// transferred_at: Option, +// transferred_at_block_height: Option, +// transferred_at_core_block_height: Option, +// block_info: &BlockInfo, +// document_type: &DocumentTypeRef, +// platform_version: &PlatformVersion, +// ) -> Result { +// let DocumentUpdatePriceTransitionV0 { +// base, +// revision, +// price, +// } = value; +// +// let id = base.id(); +// +// let requires_updated_at = document_type +// .required_fields() +// .contains(document::property_names::UPDATED_AT); +// +// let requires_updated_at_block_height = document_type +// .required_fields() +// .contains(document::property_names::UPDATED_AT_BLOCK_HEIGHT); +// +// let requires_updated_at_core_block_height = document_type +// .required_fields() +// .contains(document::property_names::UPDATED_AT_CORE_BLOCK_HEIGHT); +// +// let updated_at = if requires_updated_at { +// Some(block_info.time_ms) +// } else { +// None +// }; +// +// let updated_at_block_height = if requires_updated_at_block_height { +// Some(block_info.height) +// } else { +// None +// }; +// +// let updated_at_core_block_height = if requires_updated_at_core_block_height { +// Some(block_info.core_height) +// } else { +// None +// }; +// match platform_version +// .dpp +// .document_versions +// .document_structure_version +// { +// 0 => Ok(DocumentV0 { +// id, +// owner_id, +// properties: data, +// revision: Some(revision), +// created_at, +// updated_at, +// transferred_at, +// created_at_block_height, +// updated_at_block_height, +// transferred_at_block_height, +// created_at_core_block_height, +// updated_at_core_block_height, +// transferred_at_core_block_height, +// } +// .into()), +// version => Err(ProtocolError::UnknownVersionMismatch { +// method: "Document::try_from_update_price_transition".to_string(), +// known_versions: vec![0], +// received: version, +// }), +// } +// } +// } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/v0_methods.rs new file mode 100644 index 00000000000..74b27a3589d --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/v0_methods.rs @@ -0,0 +1,58 @@ +use crate::fee::Credits; +use crate::prelude::Revision; + +use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; + +use crate::state_transition::documents_batch_transition::document_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; + +pub trait DocumentUpdatePriceTransitionV0Methods { + /// Returns a reference to the `base` field of the `DocumentUpdatePriceTransitionV0`. + fn base(&self) -> &DocumentBaseTransition; + /// Returns a mut reference to the `base` field of the `DocumentUpdatePriceTransitionV0`. + fn base_mut(&mut self) -> &mut DocumentBaseTransition; + + /// Sets the value of the `base` field in the `DocumentUpdatePriceTransitionV0`. + fn set_base(&mut self, base: DocumentBaseTransition); + + /// Returns a reference to the `revision` field of the `DocumentUpdatePriceTransitionV0`. + fn revision(&self) -> Revision; + + /// Sets the value of the `revision` field in the `DocumentUpdatePriceTransitionV0`. + fn set_revision(&mut self, revision: Revision); + + /// Returns a reference to the `price` field of the `DocumentUpdatePriceTransitionV0`. + fn price(&self) -> Credits; + + /// Sets the value of the `price` field in the `DocumentUpdatePriceTransitionV0`. + fn set_price(&mut self, price: Credits); +} + +impl DocumentUpdatePriceTransitionV0Methods for DocumentUpdatePriceTransitionV0 { + fn base(&self) -> &DocumentBaseTransition { + &self.base + } + + fn base_mut(&mut self) -> &mut DocumentBaseTransition { + &mut self.base + } + + fn set_base(&mut self, base: DocumentBaseTransition) { + self.base = base; + } + + fn revision(&self) -> Revision { + self.revision + } + + fn set_revision(&mut self, revision: Revision) { + self.revision = revision; + } + + fn price(&self) -> Credits { + self.price + } + + fn set_price(&mut self, price: Credits) { + self.price = price; + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0_methods.rs new file mode 100644 index 00000000000..3b605d7431c --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0_methods.rs @@ -0,0 +1,49 @@ +use crate::fee::Credits; +use crate::prelude::Revision; +use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::documents_batch_transition::document_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; +use crate::state_transition::documents_batch_transition::document_transition::DocumentUpdatePriceTransition; + +impl DocumentUpdatePriceTransitionV0Methods for DocumentUpdatePriceTransition { + fn base(&self) -> &DocumentBaseTransition { + match self { + DocumentUpdatePriceTransition::V0(v0) => &v0.base, + } + } + + fn base_mut(&mut self) -> &mut DocumentBaseTransition { + match self { + DocumentUpdatePriceTransition::V0(v0) => &mut v0.base, + } + } + + fn set_base(&mut self, base: DocumentBaseTransition) { + match self { + DocumentUpdatePriceTransition::V0(v0) => v0.base = base, + } + } + + fn revision(&self) -> Revision { + match self { + DocumentUpdatePriceTransition::V0(v0) => v0.revision, + } + } + + fn set_revision(&mut self, revision: Revision) { + match self { + DocumentUpdatePriceTransition::V0(v0) => v0.revision = revision, + } + } + + fn price(&self) -> Credits { + match self { + DocumentUpdatePriceTransition::V0(v0) => v0.price, + } + } + + fn set_price(&mut self, price: Credits) { + match self { + DocumentUpdatePriceTransition::V0(v0) => v0.price = price, + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/mod.rs index 9ff8246a8ef..00e566b2a80 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/mod.rs @@ -12,8 +12,10 @@ pub mod action_type; pub mod document_base_transition; pub mod document_create_transition; pub mod document_delete_transition; +pub mod document_purchase_transition; pub mod document_replace_transition; pub mod document_transfer_transition; +pub mod document_update_price_transition; use crate::prelude::Revision; use crate::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; @@ -22,7 +24,11 @@ pub use document_create_transition::DocumentCreateTransition; pub use document_delete_transition::DocumentDeleteTransition; pub use document_replace_transition::DocumentReplaceTransition; pub use document_transfer_transition::DocumentTransferTransition; +pub use document_purchase_transition::DocumentPurchaseTransition; +pub use document_update_price_transition::DocumentUpdatePriceTransition; use platform_value::Value; +use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; +use crate::state_transition::documents_batch_transition::document_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; use crate::state_transition::state_transitions::document::documents_batch_transition::document_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; use crate::state_transition::state_transitions::document::documents_batch_transition::document_transition::document_replace_transition::v0::v0_methods::DocumentReplaceTransitionV0Methods; @@ -81,6 +87,12 @@ pub enum DocumentTransition { #[display(fmt = "TransferDocumentTransition({})", "_0")] Transfer(DocumentTransferTransition), + + #[display(fmt = "UpdatePriceDocumentTransition({})", "_0")] + UpdatePrice(DocumentUpdatePriceTransition), + + #[display(fmt = "PurchaseDocumentTransition({})", "_0")] + Purchase(DocumentPurchaseTransition), } impl DocumentTransition { @@ -106,6 +118,22 @@ impl DocumentTransition { None } } + + pub fn as_transition_transfer(&self) -> Option<&DocumentTransferTransition> { + if let Self::Transfer(ref t) = self { + Some(t) + } else { + None + } + } + + pub fn as_transition_purchase(&self) -> Option<&DocumentPurchaseTransition> { + if let Self::Purchase(ref t) = self { + Some(t) + } else { + None + } + } } impl DocumentTransitionV0Methods for DocumentTransition { @@ -115,6 +143,8 @@ impl DocumentTransitionV0Methods for DocumentTransition { DocumentTransition::Replace(t) => t.base(), DocumentTransition::Delete(t) => t.base(), DocumentTransition::Transfer(t) => t.base(), + DocumentTransition::UpdatePrice(t) => t.base(), + DocumentTransition::Purchase(t) => t.base(), } } @@ -124,6 +154,8 @@ impl DocumentTransitionV0Methods for DocumentTransition { DocumentTransition::Replace(t) => t.data().get(path), DocumentTransition::Delete(_) => None, DocumentTransition::Transfer(_) => None, + DocumentTransition::UpdatePrice(_) => None, + DocumentTransition::Purchase(_) => None, } } @@ -145,6 +177,8 @@ impl DocumentTransitionV0Methods for DocumentTransition { DocumentTransition::Replace(t) => Some(t.data()), DocumentTransition::Delete(_) => None, DocumentTransition::Transfer(_) => None, + DocumentTransition::UpdatePrice(_) => None, + DocumentTransition::Purchase(_) => None, } } @@ -154,6 +188,8 @@ impl DocumentTransitionV0Methods for DocumentTransition { DocumentTransition::Replace(t) => Some(t.revision()), DocumentTransition::Delete(_) => None, DocumentTransition::Transfer(t) => Some(t.revision()), + DocumentTransition::UpdatePrice(t) => Some(t.revision()), + DocumentTransition::Purchase(t) => Some(t.revision()), } } @@ -163,6 +199,8 @@ impl DocumentTransitionV0Methods for DocumentTransition { DocumentTransition::Replace(t) => t.base().identity_contract_nonce(), DocumentTransition::Delete(t) => t.base().identity_contract_nonce(), DocumentTransition::Transfer(t) => t.base().identity_contract_nonce(), + DocumentTransition::UpdatePrice(t) => t.base().identity_contract_nonce(), + DocumentTransition::Purchase(t) => t.base().identity_contract_nonce(), } } @@ -181,6 +219,8 @@ impl DocumentTransitionV0Methods for DocumentTransition { } DocumentTransition::Delete(_) => {} DocumentTransition::Transfer(_) => {} + DocumentTransition::UpdatePrice(_) => {} + DocumentTransition::Purchase(_) => {} } } @@ -194,6 +234,8 @@ impl DocumentTransitionV0Methods for DocumentTransition { DocumentTransition::Replace(t) => t.base_mut(), DocumentTransition::Delete(t) => t.base_mut(), DocumentTransition::Transfer(t) => t.base_mut(), + DocumentTransition::UpdatePrice(t) => t.base_mut(), + DocumentTransition::Purchase(t) => t.base_mut(), } } @@ -203,6 +245,8 @@ impl DocumentTransitionV0Methods for DocumentTransition { DocumentTransition::Replace(t) => Some(t.data_mut()), DocumentTransition::Delete(_) => None, DocumentTransition::Transfer(_) => None, + DocumentTransition::UpdatePrice(_) => None, + DocumentTransition::Purchase(_) => None, } } @@ -211,7 +255,9 @@ impl DocumentTransitionV0Methods for DocumentTransition { DocumentTransition::Create(_) => {} DocumentTransition::Replace(ref mut t) => t.set_revision(revision), DocumentTransition::Delete(_) => {} - DocumentTransition::Transfer(_) => {} + DocumentTransition::Transfer(ref mut t) => t.set_revision(revision), + DocumentTransition::UpdatePrice(ref mut t) => t.set_revision(revision), + DocumentTransition::Purchase(ref mut t) => t.set_revision(revision), } } @@ -221,6 +267,8 @@ impl DocumentTransitionV0Methods for DocumentTransition { DocumentTransition::Replace(t) => t.base_mut().set_identity_contract_nonce(nonce), DocumentTransition::Delete(t) => t.base_mut().set_identity_contract_nonce(nonce), DocumentTransition::Transfer(t) => t.base_mut().set_identity_contract_nonce(nonce), + DocumentTransition::UpdatePrice(t) => t.base_mut().set_identity_contract_nonce(nonce), + DocumentTransition::Purchase(t) => t.base_mut().set_identity_contract_nonce(nonce), } } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/mod.rs index 27ae53c2a0a..6d2b9a451a8 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/mod.rs @@ -2,6 +2,7 @@ use crate::data_contract::document_type::DocumentTypeRef; #[cfg(feature = "state-transition-signing")] use crate::document::Document; +use crate::fee::Credits; #[cfg(feature = "state-transition-signing")] use crate::identity::signer::Signer; #[cfg(feature = "state-transition-signing")] @@ -26,6 +27,12 @@ use platform_version::version::{FeatureVersion, PlatformVersion}; pub mod v0; impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransition { + fn all_purchases_amount(&self) -> Option { + match self { + DocumentsBatchTransition::V0(v0) => v0.all_purchases_amount(), + } + } + fn set_transitions(&mut self, transitions: Vec) { match self { DocumentsBatchTransition::V0(v0) => v0.set_transitions(transitions), @@ -94,7 +101,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransition { signer: &S, platform_version: &PlatformVersion, batch_feature_version: Option, - update_feature_version: Option, + replace_feature_version: Option, base_feature_version: Option, ) -> Result { match batch_feature_version.unwrap_or( @@ -114,7 +121,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransition { signer, platform_version, batch_feature_version, - update_feature_version, + replace_feature_version, base_feature_version, )?, ), @@ -139,7 +146,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransition { signer: &S, platform_version: &PlatformVersion, batch_feature_version: Option, - update_feature_version: Option, + transfer_feature_version: Option, base_feature_version: Option, ) -> Result { match batch_feature_version.unwrap_or( @@ -160,7 +167,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransition { signer, platform_version, batch_feature_version, - update_feature_version, + transfer_feature_version, base_feature_version, )?, ), @@ -216,4 +223,97 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransition { }), } } + + #[cfg(feature = "state-transition-signing")] + fn new_document_update_price_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + price: Credits, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + update_price_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .documents_batch_state_transition + .default_current_version, + ) { + 0 => Ok( + DocumentsBatchTransitionV0::new_document_update_price_transition_from_document( + document, + document_type, + price, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + update_price_feature_version, + base_feature_version, + )?, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: + "DocumentsBatchTransition::new_document_update_price_transition_from_document" + .to_string(), + known_versions: vec![0], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_purchase_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + new_owner_id: Identifier, + price: Credits, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + purchase_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .documents_batch_state_transition + .default_current_version, + ) { + 0 => Ok( + DocumentsBatchTransitionV0::new_document_purchase_transition_from_document( + document, + document_type, + new_owner_id, + price, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + purchase_feature_version, + base_feature_version, + )?, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentsBatchTransition::new_document_purchase_transition_from_document" + .to_string(), + known_versions: vec![0], + received: version, + }), + } + } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/v0/mod.rs index 8c48bce89cd..a21448ea48c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/v0/mod.rs @@ -2,6 +2,7 @@ use crate::data_contract::document_type::DocumentTypeRef; #[cfg(feature = "state-transition-signing")] use crate::document::Document; +use crate::fee::Credits; #[cfg(feature = "state-transition-signing")] use crate::identity::signer::Signer; #[cfg(feature = "state-transition-signing")] @@ -49,7 +50,7 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, - update_feature_version: Option, + replace_feature_version: Option, base_feature_version: Option, ) -> Result; @@ -78,7 +79,38 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, - delete_feature_version: Option, + transfer_feature_version: Option, + base_feature_version: Option, + ) -> Result; + + #[cfg(feature = "state-transition-signing")] + fn new_document_update_price_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + price: Credits, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + update_price_feature_version: Option, + base_feature_version: Option, + ) -> Result; + + #[cfg(feature = "state-transition-signing")] + fn new_document_purchase_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + new_owner_id: Identifier, + price: Credits, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + purchase_feature_version: Option, base_feature_version: Option, ) -> Result; @@ -123,4 +155,6 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 fn set_transitions(&mut self, transitions: Vec); fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce); + + fn all_purchases_amount(&self) -> Option; } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/v0_methods.rs index 3029f033e43..397de6c5e57 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/v0_methods.rs @@ -2,6 +2,7 @@ use crate::data_contract::document_type::DocumentTypeRef; #[cfg(feature = "state-transition-signing")] use crate::document::{Document, DocumentV0Getters}; +use crate::fee::Credits; #[cfg(feature = "state-transition-signing")] use crate::identity::signer::Signer; #[cfg(feature = "state-transition-signing")] @@ -14,12 +15,12 @@ use crate::prelude::UserFeeIncrease; use crate::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; #[cfg(feature = "state-transition-signing")] use crate::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransition; -#[cfg(feature = "state-transition-signing")] use crate::state_transition::documents_batch_transition::document_transition::{ - DocumentReplaceTransition, DocumentTransferTransition, + DocumentTransition, DocumentTransitionV0Methods, }; +#[cfg(feature = "state-transition-signing")] use crate::state_transition::documents_batch_transition::document_transition::{ - DocumentTransition, DocumentTransitionV0Methods, + DocumentReplaceTransition, DocumentTransferTransition, DocumentPurchaseTransition, DocumentUpdatePriceTransition, }; use crate::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; use crate::state_transition::documents_batch_transition::DocumentsBatchTransitionV0; @@ -35,6 +36,7 @@ use crate::ProtocolError; use platform_value::Identifier; #[cfg(feature = "state-transition-signing")] use platform_version::version::{FeatureVersion, PlatformVersion}; +use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; impl DocumentsBatchTransitionAccessorsV0 for DocumentsBatchTransitionV0 { fn transitions(&self) -> &Vec { @@ -98,7 +100,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, - update_feature_version: Option, + replace_feature_version: Option, base_feature_version: Option, ) -> Result { let owner_id = document.owner_id(); @@ -107,7 +109,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { document_type, identity_contract_nonce, platform_version, - update_feature_version, + replace_feature_version, base_feature_version, )?; let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { @@ -138,7 +140,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { signer: &S, platform_version: &PlatformVersion, _batch_feature_version: Option, - delete_feature_version: Option, + transfer_feature_version: Option, base_feature_version: Option, ) -> Result { let owner_id = document.owner_id(); @@ -148,7 +150,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { identity_contract_nonce, recipient_owner_id, platform_version, - delete_feature_version, + transfer_feature_version, base_feature_version, )?; let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { @@ -207,6 +209,88 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { Ok(state_transition) } + #[cfg(feature = "state-transition-signing")] + fn new_document_update_price_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + price: Credits, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + _batch_feature_version: Option, + update_price_feature_version: Option, + base_feature_version: Option, + ) -> Result { + let owner_id = document.owner_id(); + let transfer_transition = DocumentUpdatePriceTransition::from_document( + document, + document_type, + price, + identity_contract_nonce, + platform_version, + update_price_feature_version, + base_feature_version, + )?; + let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { + owner_id, + transitions: vec![transfer_transition.into()], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_purchase_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + new_owner_id: Identifier, + price: Credits, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + _batch_feature_version: Option, + purchase_feature_version: Option, + base_feature_version: Option, + ) -> Result { + let purchase_transition = DocumentPurchaseTransition::from_document( + document, + document_type, + price, + identity_contract_nonce, + platform_version, + purchase_feature_version, + base_feature_version, + )?; + let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { + owner_id: new_owner_id, + transitions: vec![purchase_transition.into()], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + fn set_transitions(&mut self, transitions: Vec) { self.transitions = transitions; } @@ -216,4 +300,22 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { .iter_mut() .for_each(|transition| transition.set_identity_contract_nonce(identity_contract_nonce)); } + + fn all_purchases_amount(&self) -> Option { + let (total, any_purchases) = self + .transitions + .iter() + .filter_map(|transition| { + transition + .as_transition_purchase() + .map(|purchase| purchase.price()) + }) + .fold((0, false), |(acc, _), price| (acc + price, true)); + + if any_purchases { + Some(total) // Return the sum as Some(Credits) if there were any purchases + } else { + None // Return None if no purchases were found + } + } } diff --git a/packages/rs-dpp/src/util/json_schema.rs b/packages/rs-dpp/src/util/json_schema.rs index 24ba0b584b3..0e6459083dd 100644 --- a/packages/rs-dpp/src/util/json_schema.rs +++ b/packages/rs-dpp/src/util/json_schema.rs @@ -213,6 +213,7 @@ mod test { false, false, false, + false, &mut vec![], LATEST_PLATFORM_VERSION, ) diff --git a/packages/rs-dpp/src/util/mod.rs b/packages/rs-dpp/src/util/mod.rs index a4ae012dca4..2dee13be293 100644 --- a/packages/rs-dpp/src/util/mod.rs +++ b/packages/rs-dpp/src/util/mod.rs @@ -13,4 +13,5 @@ pub mod json_value; pub mod protocol_data; pub mod strings; +pub mod units; pub mod vec; diff --git a/packages/rs-dpp/src/util/units.rs b/packages/rs-dpp/src/util/units.rs new file mode 100644 index 00000000000..ca00561cf05 --- /dev/null +++ b/packages/rs-dpp/src/util/units.rs @@ -0,0 +1,29 @@ +#[macro_export] +macro_rules! dash_to_credits { + // The macro takes a string literal representing the Dash amount. + ($dash:expr) => {{ + let dash_str = stringify!($dash); + + // Parsing the input string to separate the whole and fractional parts. + let parts: Vec<&str> = dash_str.split('.').collect(); + let mut credits: u128 = 0; + + // Process the whole number part if it exists. + if let Some(whole) = parts.get(0) { + if let Ok(whole_number) = whole.parse::() { + credits += whole_number * 100_000_000_000; // Whole Dash amount to credits + } + } + + // Process the fractional part if it exists. + if let Some(fraction) = parts.get(1) { + let fraction_length = fraction.len(); + let fraction_number = fraction.parse::().unwrap_or(0); + // Calculate the multiplier based on the number of digits in the fraction. + let multiplier = 10u128.pow(11 - fraction_length as u32); + credits += fraction_number * multiplier; // Fractional Dash to credits + } + + credits as u64 + }}; +} diff --git a/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs b/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs index 1bd5aff5212..a7c6a1739dc 100644 --- a/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs @@ -434,7 +434,7 @@ mod tests { ) .expect("expected to process state transition"); - assert_eq!(processing_result.aggregated_fees().processing_fee, 2978520); + assert_eq!(processing_result.aggregated_fees().processing_fee, 2985330); let check_result = platform .check_tx( @@ -549,6 +549,7 @@ mod tests { }, keep_history_chance: 0.0, documents_mutable_chance: 0.0, + documents_can_be_deleted_chance: 0.0, }; let mut rng = StdRng::seed_from_u64(6); @@ -625,7 +626,7 @@ mod tests { // We have one invalid paid for state transition assert_eq!(processing_result.invalid_paid_count(), 1); - assert_eq!(processing_result.aggregated_fees().processing_fee, 909510); + assert_eq!(processing_result.aggregated_fees().processing_fee, 909520); let check_result = platform .check_tx( @@ -767,7 +768,7 @@ mod tests { // since a fee multiplier of 100 means 100% more of 1 (gives 2) assert_eq!( processing_result.aggregated_fees().processing_fee, - 2978520 * 2 + 2985330 * 2 ); let check_result = platform @@ -1005,7 +1006,7 @@ mod tests { ) .expect("expected to process state transition"); - assert_eq!(processing_result.aggregated_fees().processing_fee, 2978520); + assert_eq!(processing_result.aggregated_fees().processing_fee, 2985330); platform .drive @@ -1089,7 +1090,7 @@ mod tests { assert_eq!( update_processing_result.aggregated_fees().processing_fee, - 7098500 + 7125710 ); let check_result = platform @@ -1201,7 +1202,7 @@ mod tests { ) .expect("expected to process state transition"); - assert_eq!(processing_result.aggregated_fees().processing_fee, 2978520); + assert_eq!(processing_result.aggregated_fees().processing_fee, 2985330); platform .drive @@ -1250,6 +1251,7 @@ mod tests { }, keep_history_chance: 0.0, documents_mutable_chance: 0.0, + documents_can_be_deleted_chance: 0.0, }; let mut rng = StdRng::seed_from_u64(6); @@ -1320,7 +1322,7 @@ mod tests { // We have one invalid paid for state transition assert_eq!(processing_result.invalid_paid_count(), 1); - assert_eq!(processing_result.aggregated_fees().processing_fee, 1231120); + assert_eq!(processing_result.aggregated_fees().processing_fee, 1231130); let check_result = platform .check_tx( 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 20a540e4f39..d3f23b70ebb 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 @@ -317,8 +317,8 @@ mod tests { assert_eq!( root_hash, [ - 123, 106, 97, 8, 95, 223, 24, 44, 147, 229, 106, 103, 31, 32, 29, 97, 198, 204, - 237, 215, 138, 194, 34, 107, 129, 234, 97, 250, 155, 104, 75, 210 + 162, 81, 50, 217, 246, 11, 77, 233, 231, 192, 228, 176, 197, 102, 24, 18, 160, + 5, 182, 75, 119, 174, 75, 155, 86, 92, 88, 197, 201, 60, 60, 157 ] ) } diff --git a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs index 4caa4413db8..a5b011522ba 100644 --- a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs +++ b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs @@ -155,6 +155,25 @@ impl<'a> ExecutionEvent<'a> { ))) } } + StateTransitionAction::DocumentsBatchAction(document_batch_action) => { + let user_fee_increase = action.user_fee_increase(); + let removed_balance = document_batch_action.all_purchases_amount(); + let operations = + action.into_high_level_drive_operations(epoch, platform_version)?; + if let Some(identity) = identity { + Ok(ExecutionEvent::Paid { + identity, + removed_balance, + operations, + execution_operations: execution_context.operations_consume(), + user_fee_increase, + }) + } else { + Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "partial identity should be present for other state transitions", + ))) + } + } _ => { let user_fee_increase = action.user_fee_increase(); let operations = diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_simple_pre_check_balance/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_simple_pre_check_balance/v0/mod.rs index 99ad4d4795e..07c2895c251 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_simple_pre_check_balance/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_simple_pre_check_balance/v0/mod.rs @@ -37,7 +37,7 @@ impl ValidateSimplePreCheckBalanceV0 for StateTransition { platform_version .fee_version .state_transition_min_fees - .document_batch_transition + .document_batch_sub_transition } StateTransition::IdentityCreate(_) | StateTransition::IdentityTopUp(_) => 0, StateTransition::IdentityCreditWithdrawal(_) => { 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 3a6acb90d02..2b98dd8b1ce 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 @@ -549,9 +549,11 @@ impl StateTransitionBalanceValidationV0 for StateTransition { StateTransition::IdentityCreditWithdrawal(st) => { st.validate_minimum_balance_pre_check(identity, platform_version) } + StateTransition::DocumentsBatch(st) => { + st.validate_minimum_balance_pre_check(identity, platform_version) + } StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) - | StateTransition::DocumentsBatch(_) | StateTransition::IdentityUpdate(_) => { self.validate_simple_pre_check_minimum_balance(identity, platform_version) } 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 ae9be56b215..4215a4ce699 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 @@ -57,19 +57,95 @@ mod tests { use crate::rpc::core::MockCoreRPCLike; use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder}; use dpp::block::block_info::BlockInfo; + use dpp::dash_to_credits; + use dpp::data_contract::accessors::v0::DataContractV0Setters; + use rand::prelude::StdRng; + use rand::SeedableRng; + use std::collections::BTreeMap; use dpp::data_contract::DataContract; + use dpp::fee::Credits; + use dpp::identifier::Identifier; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; + use dpp::identity::{Identity, IdentityPublicKey, IdentityV0}; use dpp::platform_value::BinaryData; - use dpp::state_transition::data_contract_update_transition::DataContractUpdateTransitionV0; + use dpp::serialization::PlatformSerializable; + use dpp::state_transition::data_contract_update_transition::methods::DataContractUpdateTransitionMethodsV0; + use dpp::state_transition::data_contract_update_transition::{ + DataContractUpdateTransition, DataContractUpdateTransitionV0, + }; + use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; use dpp::tests::fixtures::get_data_contract_fixture; + use dpp::tests::json_document::json_document_to_contract; use dpp::version::PlatformVersion; + use drive::drive::flags::StorageFlags; + use simple_signer::signer::SimpleSigner; struct TestData { data_contract: DataContract, platform: TempPlatform, } + fn setup_identity( + platform: &mut TempPlatform, + seed: u64, + credits: Credits, + ) -> (Identity, SimpleSigner, IdentityPublicKey) { + let platform_version = PlatformVersion::latest(); + let mut signer = SimpleSigner::default(); + + let mut rng = StdRng::seed_from_u64(seed); + + let (master_key, master_private_key) = + IdentityPublicKey::random_ecdsa_master_authentication_key_with_rng( + 0, + &mut rng, + platform_version, + ) + .expect("expected to get key pair"); + + signer.add_key(master_key.clone(), master_private_key.clone()); + + let (critical_public_key, private_key) = + IdentityPublicKey::random_ecdsa_critical_level_authentication_key_with_rng( + 1, + &mut rng, + platform_version, + ) + .expect("expected to get key pair"); + + signer.add_key(critical_public_key.clone(), private_key.clone()); + + let identity: Identity = IdentityV0 { + id: Identifier::random_with_rng(&mut rng), + public_keys: BTreeMap::from([ + (0, master_key.clone()), + (1, critical_public_key.clone()), + ]), + balance: credits, + revision: 0, + } + .into(); + + // We just add this identity to the system first + + platform + .drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add a new identity"); + + (identity, signer, critical_public_key) + } + fn apply_contract( platform: &TempPlatform, data_contract: &DataContract, @@ -484,4 +560,99 @@ mod tests { ); } } + + #[test] + fn test_data_contract_update_changing_various_document_type_options() { + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let card_game_path = "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase-creation-restricted-to-owner.json"; + + let platform_version = platform + .state + .load() + .current_platform_version() + .expect("expected to get current platform version"); + + // let's construct the grovedb structure for the card game data contract + let mut contract = json_document_to_contract(card_game_path, true, platform_version) + .expect("expected to get data contract"); + + contract.set_owner_id(identity.id()); + + platform + .drive + .apply_contract( + &contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + let updated_card_game_path = "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json"; + + // let's construct the grovedb structure for the card game data contract + let mut contract_not_restricted_to_owner = + json_document_to_contract(updated_card_game_path, true, platform_version) + .expect("expected to get data contract"); + + contract_not_restricted_to_owner.set_owner_id(identity.id()); + + contract_not_restricted_to_owner.set_version(2); + + let data_contract_update_transition = DataContractUpdateTransition::new_from_data_contract( + contract_not_restricted_to_owner, + &identity.into_partial_identity_info(), + key.id(), + 2, + 0, + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); + + let data_contract_update_serialized_transition = data_contract_update_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_update_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + // There is no issue because the creator of the contract made the document + + assert_eq!(processing_result.invalid_paid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let result = processing_result.into_execution_results().remove(0); + + let StateTransitionExecutionResult::PaidConsensusError(consensus_error, _) = result else { + panic!("expected a paid consensus error"); + }; + assert_eq!(consensus_error.to_string(), "Data Contract updated schema is not backward compatible with one defined in Data Contract with id 86LHvdC1Tqx5P97LQUSibGFqf2vnKFpB6VkqQ7oso86e. Field: '/creationRestrictionMode', Operation: 'remove'"); + } } 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 eacae1bdd34..8eb26952765 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 @@ -173,6 +173,7 @@ impl DataContractUpdateStateTransitionStateValidationV0 for DataContractUpdateTr // - Keeps history did not change // - Can be deleted did not change // - Documents keep history did not change + // - Documents can be deleted contract default did not change // - Documents mutable contract default did not change // - Requires identity encryption bounded key did not change // - Requires identity decryption bounded key did not change diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/mod.rs index 713d82c1292..2d5e116aa85 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/mod.rs @@ -17,6 +17,7 @@ mod structure_v0; pub trait DocumentCreateTransitionActionValidation { fn validate_structure( &self, + owner_id: Identifier, platform_version: &PlatformVersion, ) -> Result; @@ -34,6 +35,7 @@ pub trait DocumentCreateTransitionActionValidation { impl DocumentCreateTransitionActionValidation for DocumentCreateTransitionAction { fn validate_structure( &self, + owner_id: Identifier, platform_version: &PlatformVersion, ) -> Result { match platform_version @@ -43,7 +45,7 @@ impl DocumentCreateTransitionActionValidation for DocumentCreateTransitionAction .documents_batch_state_transition .document_create_transition_structure_validation { - 0 => self.validate_structure_v0(platform_version), + 0 => self.validate_structure_v0(owner_id, platform_version), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "DocumentCreateTransitionAction::validate_structure".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/state_v0/mod.rs index f266d18c763..aff96c03378 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/state_v0/mod.rs @@ -4,6 +4,7 @@ use dpp::consensus::ConsensusError; use dpp::consensus::state::document::document_already_present_error::DocumentAlreadyPresentError; use dpp::consensus::state::state_error::StateError; use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::prelude::{ConsensusValidationResult, Identifier}; use dpp::validation::SimpleConsensusValidationResult; use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; @@ -70,16 +71,21 @@ impl DocumentCreateTransitionActionStateValidationV0 for DocumentCreateTransitio // we also need to validate that the new document wouldn't conflict with any other document // this means for example having overlapping unique indexes - platform - .drive - .validate_document_create_transition_action_uniqueness( - contract, - document_type, - self, - owner_id, - transaction, - platform_version, - ) - .map_err(Error::Drive) + + if document_type.indices().iter().any(|index| index.unique) { + platform + .drive + .validate_document_create_transition_action_uniqueness( + contract, + document_type, + self, + owner_id, + transaction, + platform_version, + ) + .map_err(Error::Drive) + } else { + Ok(SimpleConsensusValidationResult::new()) + } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/structure_v0/mod.rs index bda10d4b2c0..3ddc152f088 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_create_transition_action/structure_v0/mod.rs @@ -1,6 +1,9 @@ -use dpp::consensus::basic::document::InvalidDocumentTypeError; +use dpp::consensus::basic::document::{DocumentCreationNotAllowedError, InvalidDocumentTypeError}; use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; +use dpp::data_contract::document_type::restricted_creation::CreationRestrictionMode; use dpp::data_contract::validation::DataContractValidationMethodsV0; +use dpp::identifier::Identifier; use dpp::validation::{SimpleConsensusValidationResult}; use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0}; @@ -10,12 +13,14 @@ use crate::error::Error; pub(super) trait DocumentCreateTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, + owner_id: Identifier, platform_version: &PlatformVersion, ) -> Result; } impl DocumentCreateTransitionActionStructureValidationV0 for DocumentCreateTransitionAction { fn validate_structure_v0( &self, + owner_id: Identifier, platform_version: &PlatformVersion, ) -> Result { let contract_fetch_info = self.base().data_contract_fetch_info(); @@ -23,16 +28,40 @@ impl DocumentCreateTransitionActionStructureValidationV0 for DocumentCreateTrans // Make sure that the document type is defined in the contract let document_type_name = self.base().document_type_name(); - if data_contract - .document_type_optional_for_name(document_type_name) - .is_none() - { + let Some(document_type) = data_contract.document_type_optional_for_name(document_type_name) + else { return Ok(SimpleConsensusValidationResult::new_with_error( InvalidDocumentTypeError::new(document_type_name.clone(), data_contract.id()) .into(), )); }; + match document_type.creation_restriction_mode() { + CreationRestrictionMode::NoRestrictions => {} + CreationRestrictionMode::OwnerOnly => { + if owner_id != data_contract.owner_id() { + return Ok(SimpleConsensusValidationResult::new_with_error( + DocumentCreationNotAllowedError::new( + self.base().data_contract_id(), + document_type_name.clone(), + document_type.creation_restriction_mode(), + ) + .into(), + )); + } + } + CreationRestrictionMode::NoCreationAllowed => { + return Ok(SimpleConsensusValidationResult::new_with_error( + DocumentCreationNotAllowedError::new( + self.base().data_contract_id(), + document_type_name.clone(), + document_type.creation_restriction_mode(), + ) + .into(), + )); + } + } + // Validate user defined properties data_contract diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_delete_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_delete_transition_action/structure_v0/mod.rs index d0891ffe9b5..3813405201c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_delete_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_delete_transition_action/structure_v0/mod.rs @@ -26,10 +26,10 @@ impl DocumentDeleteTransitionActionStructureValidationV0 for DocumentDeleteTrans )); }; - if !document_type.documents_mutable() { + if !document_type.documents_can_be_deleted() { Ok(SimpleConsensusValidationResult::new_with_error( InvalidDocumentTransitionActionError::new(format!( - "{} is not mutable and can not be deleted", + "documents of type {} can not be deleted", document_type_name )) .into(), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_purchase_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_purchase_transition_action/mod.rs new file mode 100644 index 00000000000..c72f4ea28db --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_purchase_transition_action/mod.rs @@ -0,0 +1,87 @@ +use dpp::block::epoch::Epoch; +use dpp::identifier::Identifier; + +use dpp::validation::SimpleConsensusValidationResult; +use drive::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionAction; +use dpp::version::PlatformVersion; +use drive::grovedb::TransactionArg; +use crate::error::Error; +use crate::error::execution::ExecutionError; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::execution::validation::state_transition::documents_batch::action_validation::document_purchase_transition_action::state_v0::DocumentPurchaseTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::documents_batch::action_validation::document_purchase_transition_action::structure_v0::DocumentPurchaseTransitionActionStructureValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; +mod structure_v0; + +pub trait DocumentPurchaseTransitionActionValidation { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result; + + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + epoch: &Epoch, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl DocumentPurchaseTransitionActionValidation for DocumentPurchaseTransitionAction { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .documents_batch_state_transition + .document_purchase_transition_structure_validation + { + 0 => self.validate_structure_v0(platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "DocumentPurchaseTransitionAction::validate_structure".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + epoch: &Epoch, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .documents_batch_state_transition + .document_purchase_transition_state_validation + { + 0 => self.validate_state_v0( + platform, + owner_id, + epoch, + execution_context, + transaction, + platform_version, + ), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "DocumentPurchaseTransitionAction::validate_state".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_purchase_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_purchase_transition_action/state_v0/mod.rs new file mode 100644 index 00000000000..e4a59552eb6 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_purchase_transition_action/state_v0/mod.rs @@ -0,0 +1,70 @@ +use dpp::block::epoch::Epoch; +use dpp::consensus::basic::document::InvalidDocumentTypeError; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; +use dpp::identifier::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use drive::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; +use dpp::version::PlatformVersion; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::error::Error; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::platform_types::platform::PlatformStateRef; + +pub(super) trait DocumentPurchaseTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + epoch: &Epoch, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl DocumentPurchaseTransitionActionStateValidationV0 for DocumentPurchaseTransitionAction { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + _epoch: &Epoch, + _execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let contract_fetch_info = self.base().data_contract_fetch_info(); + + let contract = &contract_fetch_info.contract; + + let document_type_name = self.base().document_type_name(); + + let Some(document_type) = contract.document_type_optional_for_name(document_type_name) + else { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidDocumentTypeError::new(document_type_name.clone(), contract.id()).into(), + )); + }; + + // There is no need to verify that the document already existed, since this is done when + // transforming into an action + + // We need to verify that the resultant document doesn't violate any unique properties + + if document_type.indices().iter().any(|index| index.unique) { + platform + .drive + .validate_document_purchase_transition_action_uniqueness( + contract, + document_type, + self, + owner_id, + transaction, + platform_version, + ) + .map_err(Error::Drive) + } else { + Ok(SimpleConsensusValidationResult::new()) + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_purchase_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_purchase_transition_action/structure_v0/mod.rs new file mode 100644 index 00000000000..afbe3ae28b2 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_purchase_transition_action/structure_v0/mod.rs @@ -0,0 +1,61 @@ +use dpp::consensus::basic::document::{InvalidDocumentTransitionActionError, InvalidDocumentTypeError}; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; +use dpp::document::DocumentV0Getters; +use dpp::nft::TradeMode; +use dpp::validation::SimpleConsensusValidationResult; +use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; +use dpp::version::PlatformVersion; +use crate::error::Error; + +pub(super) trait DocumentPurchaseTransitionActionStructureValidationV0 { + fn validate_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} +impl DocumentPurchaseTransitionActionStructureValidationV0 for DocumentPurchaseTransitionAction { + fn validate_structure_v0( + &self, + _platform_version: &PlatformVersion, + ) -> Result { + let contract_fetch_info = self.base().data_contract_fetch_info(); + let data_contract = &contract_fetch_info.contract; + let document_type_name = self.base().document_type_name(); + + // Make sure that the document type is defined in the contract + let Some(document_type) = data_contract.document_type_optional_for_name(document_type_name) + else { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidDocumentTypeError::new(document_type_name.clone(), data_contract.id()) + .into(), + )); + }; + + // We can not purchase from ourselves + // The document owner id is already our owner id, as the action we want to take is to + // insert this document into the state (with our owner id) + if self.original_owner_id() == self.document().owner_id() { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidDocumentTransitionActionError::new(format!( + "on document type: {} identity trying to purchase a document that is already owned by the purchaser", + document_type_name + )) + .into(), + )); + } + + if document_type.trade_mode() != TradeMode::DirectPurchase { + Ok(SimpleConsensusValidationResult::new_with_error( + InvalidDocumentTransitionActionError::new(format!( + "{} trade mode is not direct purchase but we are trying to purchase directly", + document_type_name + )) + .into(), + )) + } else { + Ok(SimpleConsensusValidationResult::default()) + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_replace_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_replace_transition_action/state_v0/mod.rs index 1329b35eae1..ea9e1529e8e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_replace_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_replace_transition_action/state_v0/mod.rs @@ -1,6 +1,7 @@ use dpp::block::epoch::Epoch; use dpp::consensus::basic::document::InvalidDocumentTypeError; use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; use drive::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; @@ -48,19 +49,20 @@ impl DocumentReplaceTransitionActionStateValidationV0 for DocumentReplaceTransit // There is no need to verify that the document already existed, since this is done when // transforming into an action - // The rest of state validation is actually happening in documents batch transition transformer - // TODO: Think more about this architecture - - platform - .drive - .validate_document_replace_transition_action_uniqueness( - contract, - document_type, - self, - owner_id, - transaction, - platform_version, - ) - .map_err(Error::Drive) + if document_type.indices().iter().any(|index| index.unique) { + platform + .drive + .validate_document_replace_transition_action_uniqueness( + contract, + document_type, + self, + owner_id, + transaction, + platform_version, + ) + .map_err(Error::Drive) + } else { + Ok(SimpleConsensusValidationResult::new()) + } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_transfer_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_transfer_transition_action/state_v0/mod.rs index 2eaada0c4fd..7e1e64bab40 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_transfer_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_transfer_transition_action/state_v0/mod.rs @@ -1,6 +1,7 @@ use dpp::block::epoch::Epoch; use dpp::consensus::basic::document::InvalidDocumentTypeError; use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; use drive::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; @@ -48,19 +49,20 @@ impl DocumentTransferTransitionActionStateValidationV0 for DocumentTransferTrans // There is no need to verify that the document already existed, since this is done when // transforming into an action - // The rest of state validation is actually happening in documents batch transition transformer - // TODO: Think more about this architecture - - platform - .drive - .validate_document_transfer_transition_action_uniqueness( - contract, - document_type, - self, - owner_id, - transaction, - platform_version, - ) - .map_err(Error::Drive) + if document_type.indices().iter().any(|index| index.unique) { + platform + .drive + .validate_document_transfer_transition_action_uniqueness( + contract, + document_type, + self, + owner_id, + transaction, + platform_version, + ) + .map_err(Error::Drive) + } else { + Ok(SimpleConsensusValidationResult::new()) + } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_update_price_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_update_price_transition_action/mod.rs new file mode 100644 index 00000000000..18876a8fe83 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_update_price_transition_action/mod.rs @@ -0,0 +1,87 @@ +use dpp::block::epoch::Epoch; +use dpp::identifier::Identifier; + +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionAction; +use crate::error::Error; +use crate::error::execution::ExecutionError; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::execution::validation::state_transition::documents_batch::action_validation::document_update_price_transition_action::state_v0::DocumentUpdatePriceTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::documents_batch::action_validation::document_update_price_transition_action::structure_v0::DocumentUpdatePriceTransitionActionStructureValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; +mod structure_v0; + +pub trait DocumentUpdatePriceTransitionActionValidation { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result; + + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + epoch: &Epoch, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl DocumentUpdatePriceTransitionActionValidation for DocumentUpdatePriceTransitionAction { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .documents_batch_state_transition + .document_transfer_transition_structure_validation + { + 0 => self.validate_structure_v0(platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "DocumentUpdatePriceTransitionAction::validate_structure".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + epoch: &Epoch, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .documents_batch_state_transition + .document_transfer_transition_state_validation + { + 0 => self.validate_state_v0( + platform, + owner_id, + epoch, + execution_context, + transaction, + platform_version, + ), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "DocumentUpdatePriceTransitionAction::validate_state".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_update_price_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_update_price_transition_action/state_v0/mod.rs new file mode 100644 index 00000000000..4f622331b52 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_update_price_transition_action/state_v0/mod.rs @@ -0,0 +1,68 @@ +use dpp::block::epoch::Epoch; +use dpp::consensus::basic::document::InvalidDocumentTypeError; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; +use dpp::identifier::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use drive::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; +use dpp::version::PlatformVersion; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::error::Error; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::platform_types::platform::PlatformStateRef; + +pub(super) trait DocumentUpdatePriceTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + epoch: &Epoch, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl DocumentUpdatePriceTransitionActionStateValidationV0 for DocumentUpdatePriceTransitionAction { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + _epoch: &Epoch, + _execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let contract_fetch_info = self.base().data_contract_fetch_info(); + + let contract = &contract_fetch_info.contract; + + let document_type_name = self.base().document_type_name(); + + let Some(document_type) = contract.document_type_optional_for_name(document_type_name) + else { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidDocumentTypeError::new(document_type_name.clone(), contract.id()).into(), + )); + }; + + // There is no need to verify that the document already existed, since this is done when + // transforming into an action + + if document_type.indices().iter().any(|index| index.unique) { + platform + .drive + .validate_document_update_price_transition_action_uniqueness( + contract, + document_type, + self, + owner_id, + transaction, + platform_version, + ) + .map_err(Error::Drive) + } else { + Ok(SimpleConsensusValidationResult::new()) + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_update_price_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_update_price_transition_action/structure_v0/mod.rs new file mode 100644 index 00000000000..f8b66fe3746 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/document_update_price_transition_action/structure_v0/mod.rs @@ -0,0 +1,49 @@ +use dpp::consensus::basic::document::{InvalidDocumentTransitionActionError, InvalidDocumentTypeError}; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; +use dpp::validation::SimpleConsensusValidationResult; +use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; +use dpp::version::PlatformVersion; +use crate::error::Error; + +pub(super) trait DocumentUpdatePriceTransitionActionStructureValidationV0 { + fn validate_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} +impl DocumentUpdatePriceTransitionActionStructureValidationV0 + for DocumentUpdatePriceTransitionAction +{ + fn validate_structure_v0( + &self, + _platform_version: &PlatformVersion, + ) -> Result { + let contract_fetch_info = self.base().data_contract_fetch_info(); + let data_contract = &contract_fetch_info.contract; + let document_type_name = self.base().document_type_name(); + + // Make sure that the document type is defined in the contract + let Some(document_type) = data_contract.document_type_optional_for_name(document_type_name) + else { + return Ok(SimpleConsensusValidationResult::new_with_error( + InvalidDocumentTypeError::new(document_type_name.clone(), data_contract.id()) + .into(), + )); + }; + + if !document_type.trade_mode().seller_sets_price() { + Ok(SimpleConsensusValidationResult::new_with_error( + InvalidDocumentTransitionActionError::new(format!( + "{} is in trade mode {} that does not support the seller setting the price", + document_type_name, + document_type.trade_mode(), + )) + .into(), + )) + } else { + Ok(SimpleConsensusValidationResult::default()) + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/mod.rs index 152a7612984..32c28c43faa 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/mod.rs @@ -1,4 +1,6 @@ pub(crate) mod document_create_transition_action; pub(crate) mod document_delete_transition_action; +pub(crate) mod document_purchase_transition_action; pub(crate) mod document_replace_transition_action; pub(crate) mod document_transfer_transition_action; +pub(crate) mod document_update_price_transition_action; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/v0/mod.rs index 1e0163bfd44..6c9f7b93b42 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/v0/mod.rs @@ -28,7 +28,9 @@ use drive::state_transition_action::system::bump_identity_data_contract_nonce_ac use crate::error::execution::ExecutionError; use crate::execution::types::execution_operation::ValidationOperation; use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0}; +use crate::execution::validation::state_transition::documents_batch::action_validation::document_purchase_transition_action::DocumentPurchaseTransitionActionValidation; use crate::execution::validation::state_transition::documents_batch::action_validation::document_transfer_transition_action::DocumentTransferTransitionActionValidation; +use crate::execution::validation::state_transition::documents_batch::action_validation::document_update_price_transition_action::DocumentUpdatePriceTransitionActionValidation; pub(in crate::execution::validation::state_transition::state_transitions::documents_batch) trait DocumentsBatchStateTransitionStructureValidationV0 { @@ -117,7 +119,7 @@ impl DocumentsBatchStateTransitionStructureValidationV0 for DocumentsBatchTransi for transition in action.transitions() { match transition { DocumentTransitionAction::CreateAction(create_action) => { - let result = create_action.validate_structure(platform_version)?; + let result = create_action.validate_structure(identity.id, platform_version)?; if !result.is_valid() { let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(transition.base().expect("there is always a base for the create action"), self.owner_id(), self.user_fee_increase()), @@ -168,6 +170,32 @@ impl DocumentsBatchStateTransitionStructureValidationV0 for DocumentsBatchTransi )); } } + DocumentTransitionAction::UpdatePriceAction(update_price_action) => { + let result = update_price_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(transition.base().expect("there is always a base for the update price action"), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + DocumentTransitionAction::PurchaseAction(purchase_action) => { + let result = purchase_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(transition.base().expect("there is always a base for the purchase action"), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } DocumentTransitionAction::BumpIdentityDataContractNonce(_) => { return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( "we should not have a bump identity contract nonce at this stage", diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/mod.rs new file mode 100644 index 00000000000..4ca24ddc1cb --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/mod.rs @@ -0,0 +1,33 @@ +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::execution::validation::state_transition::documents_batch::balance::v0::DocumentsBatchTransitionBalanceValidationV0; +use crate::execution::validation::state_transition::processor::v0::StateTransitionBalanceValidationV0; +use dpp::identity::PartialIdentity; +use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; + +pub(crate) mod v0; +impl StateTransitionBalanceValidationV0 for DocumentsBatchTransition { + fn validate_minimum_balance_pre_check( + &self, + identity: &PartialIdentity, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .documents_batch_state_transition + .balance_pre_check + { + 0 => self.validate_advanced_minimum_balance_pre_check_v0(identity, platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "documents batch transition: validate_minimum_balance_pre_check" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/v0/mod.rs new file mode 100644 index 00000000000..a46b1aad9b0 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/v0/mod.rs @@ -0,0 +1,54 @@ +use crate::error::Error; +use dpp::consensus::state::identity::IdentityInsufficientBalanceError; +use dpp::identity::PartialIdentity; +use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; + +use dpp::validation::SimpleConsensusValidationResult; + +use crate::error::execution::ExecutionError; +use dpp::version::PlatformVersion; + +pub(in crate::execution::validation::state_transition::state_transitions) trait DocumentsBatchTransitionBalanceValidationV0 +{ + fn validate_advanced_minimum_balance_pre_check_v0( + &self, + identity: &PartialIdentity, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl DocumentsBatchTransitionBalanceValidationV0 for DocumentsBatchTransition { + fn validate_advanced_minimum_balance_pre_check_v0( + &self, + identity: &PartialIdentity, + platform_version: &PlatformVersion, + ) -> Result { + let balance = + identity + .balance + .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( + "expected to have a balance on identity for documents batch transition", + )))?; + + let purchases_amount = self.all_purchases_amount().unwrap_or_default(); + + let base_fees = platform_version.fee_version.state_transition_min_fees.document_batch_sub_transition.checked_mul(self.transitions().len() as u64).ok_or(Error::Execution(ExecutionError::Overflow("overflow when multiplying base fee and amount of sub transitions in documents batch transition")))?; + + // This is just the needed balance to pass this validation step, most likely the actual fees are smaller + let needed_balance = purchases_amount + .checked_add(base_fees) + .ok_or(Error::Execution(ExecutionError::Overflow( + "overflow when adding all purchases amount and base fees in documents batch transition", + )))?; + + if balance < needed_balance { + return Ok(SimpleConsensusValidationResult::new_with_error( + IdentityInsufficientBalanceError::new(identity.id, balance, needed_balance).into(), + )); + } + + Ok(SimpleConsensusValidationResult::new()) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/list/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/list/v0/mod.rs index c96ec40cdf0..05ede54a775 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/list/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/list/v0/mod.rs @@ -62,18 +62,6 @@ pub(super) fn data_trigger_bindings_list_v0() -> Result, seed: u64, + credits: Credits, ) -> (Identity, SimpleSigner, IdentityPublicKey) { let platform_version = PlatformVersion::latest(); let mut signer = SimpleSigner::default(); @@ -295,7 +305,7 @@ mod tests { (0, master_key.clone()), (1, critical_public_key.clone()), ]), - balance: 10000000000, + balance: credits, revision: 0, } .into(); @@ -317,1699 +327,4349 @@ mod tests { (identity, signer, critical_public_key) } - #[test] - fn test_document_replace_on_document_type_that_is_mutable() { - let platform_version = PlatformVersion::latest(); - let mut platform = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_genesis_state(); + mod creation_tests { + use super::*; + use dpp::data_contract::accessors::v0::DataContractV0Setters; + use dpp::data_contract::document_type::restricted_creation::CreationRestrictionMode; - let mut rng = StdRng::seed_from_u64(433); + #[test] + fn test_document_creation() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); - let platform_state = platform.state.load(); + let mut rng = StdRng::seed_from_u64(433); - let (identity, signer, key) = setup_identity(&mut platform, 958); + let platform_state = platform.state.load(); - let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); - let dashpay_contract = dashpay.clone(); + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); - let profile = dashpay_contract - .document_type_for_name("profile") - .expect("expected a profile document type"); + let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); + let dashpay_contract = dashpay.clone(); - assert!(profile.documents_mutable()); + let profile = dashpay_contract + .document_type_for_name("profile") + .expect("expected a profile document type"); - let entropy = Bytes32::random_with_rng(&mut rng); + assert!(profile.documents_mutable()); - let mut document = profile - .random_document_with_identifier_and_entropy( - &mut rng, - identity.id(), - entropy, - DocumentFieldFillType::FillIfNotRequired, - DocumentFieldFillSize::AnyDocumentFillSize, - platform_version, - ) - .expect("expected a random document"); + let entropy = Bytes32::random_with_rng(&mut rng); - document.set("avatarUrl", "http://test.com/bob.jpg".into()); + let mut document = profile + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); - let mut altered_document = document.clone(); + document.set("avatarUrl", "http://test.com/bob.jpg".into()); - altered_document.increment_revision().unwrap(); - altered_document.set("displayName", "Samuel".into()); - altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); + let mut altered_document = document.clone(); - let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( - document, - profile, - entropy.0, - &key, - 2, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + altered_document.increment_revision().unwrap(); + altered_document.set("displayName", "Samuel".into()); + altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); - let documents_batch_create_serialized_transition = documents_batch_create_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document, + profile, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - let transaction = platform.drive.grove.start_transaction(); + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_create_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + let transaction = platform.drive.grove.start_transaction(); - assert_eq!(processing_result.valid_count(), 1); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.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"); - - let documents_batch_update_transition = - DocumentsBatchTransition::new_document_replacement_transition_from_document( - altered_document, - profile, - &key, - 3, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + assert_eq!(processing_result.valid_count(), 1); - let documents_batch_update_serialized_transition = documents_batch_update_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } - let transaction = platform.drive.grove.start_transaction(); + #[test] + fn test_document_creation_on_restricted_document_type_that_only_allows_contract_owner_to_create( + ) { + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_update_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + let platform_state = platform.state.load(); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); - assert_eq!(processing_result.invalid_paid_count(), 0); + let (another_identity, another_identity_signer, another_identity_key) = + setup_identity(&mut platform, 450, dash_to_credits!(0.1)); - assert_eq!(processing_result.invalid_unpaid_count(), 0); + let card_game_path = "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase-creation-restricted-to-owner.json"; - assert_eq!(processing_result.valid_count(), 1); + let platform_version = platform + .state + .load() + .current_platform_version() + .expect("expected to get current platform version"); - assert_eq!(processing_result.aggregated_fees().processing_fee, 5074230); - } + // let's construct the grovedb structure for the card game data contract + let mut contract = json_document_to_contract(card_game_path, true, platform_version) + .expect("expected to get data contract"); - #[test] - fn test_document_replace_on_document_type_that_is_not_mutable() { - let platform_version = PlatformVersion::latest(); - let mut platform = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_genesis_state(); + contract.set_owner_id(identity.id()); - let mut rng = StdRng::seed_from_u64(437); + platform + .drive + .apply_contract( + &contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); - let platform_state = platform.state.load(); + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); - let (identity, signer, key) = setup_identity(&mut platform, 958); + assert_eq!( + card_document_type.creation_restriction_mode(), + CreationRestrictionMode::OwnerOnly + ); - let (other_identity, ..) = setup_identity(&mut platform, 495); + let mut rng = StdRng::seed_from_u64(433); - let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); - let dashpay_contract = dashpay.clone(); + let entropy = Bytes32::random_with_rng(&mut rng); - let contact_request_document_type = dashpay_contract - .document_type_for_name("contactRequest") - .expect("expected a profile document type"); + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - assert!(!contact_request_document_type.documents_mutable()); + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - let entropy = Bytes32::random_with_rng(&mut rng); + let transaction = platform.drive.grove.start_transaction(); - let mut document = contact_request_document_type - .random_document_with_identifier_and_entropy( - &mut rng, - identity.id(), - entropy, - DocumentFieldFillType::FillIfNotRequired, - DocumentFieldFillSize::AnyDocumentFillSize, - platform_version, - ) - .expect("expected a random document"); - - document.set( - "toUserId", - Value::Identifier(other_identity.id().to_buffer()), - ); - document.set("recipientKeyIndex", Value::U32(1)); - document.set("senderKeyIndex", Value::U32(1)); - document.set("accountReference", Value::U32(0)); - document.set("coreHeightCreatedAt", Value::U32(5)); - - let mut altered_document = document.clone(); - - altered_document.set_revision(Some(1)); - altered_document.set("senderKeyIndex", Value::U32(2)); - - let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( - document, - contact_request_document_type, - entropy.0, - &key, - 2, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - let documents_batch_create_serialized_transition = documents_batch_create_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + // There is no issue because the creator of the contract made the document - let transaction = platform.drive.grove.start_transaction(); + assert_eq!(processing_result.valid_count(), 1); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_create_serialized_transition.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(), 1); + // Now let's try for another identity - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); - - let documents_batch_update_transition = - DocumentsBatchTransition::new_document_replacement_transition_from_document( - altered_document, - contact_request_document_type, - &key, - 3, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + another_identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 8.into()); + document.set("defense", 2.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &another_identity_key, + 2, + 0, + &another_identity_signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - let documents_batch_update_serialized_transition = documents_batch_update_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - let transaction = platform.drive.grove.start_transaction(); + let transaction = platform.drive.grove.start_transaction(); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_update_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.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"); + // There is no issue because the creator of the contract made the document - assert_eq!(processing_result.invalid_paid_count(), 1); + assert_eq!(processing_result.invalid_paid_count(), 1); - assert_eq!(processing_result.invalid_unpaid_count(), 0); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - assert_eq!(processing_result.valid_count(), 0); + let result = processing_result.into_execution_results().remove(0); - assert_eq!(processing_result.aggregated_fees().processing_fee, 102690); + let StateTransitionExecutionResult::PaidConsensusError(consensus_error, _) = result + else { + panic!("expected a paid consensus error"); + }; + assert_eq!(consensus_error.to_string(), "Document Creation on 86LHvdC1Tqx5P97LQUSibGFqf2vnKFpB6VkqQ7oso86e:card is not allowed because of the document type's creation restriction mode Owner Only"); + } } - #[test] - fn test_document_replace_on_document_type_that_is_not_mutable_but_is_transferable() { - let platform_version = PlatformVersion::latest(); - let (mut platform, contract) = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_initial_state_structure() - .with_crypto_card_game(Transferable::Always); + mod replacement_tests { + use super::*; - let mut rng = StdRng::seed_from_u64(435); + #[test] + fn test_document_replace_on_document_type_that_is_mutable() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); - let platform_state = platform.state.load(); + let mut rng = StdRng::seed_from_u64(433); - let (identity, signer, key) = setup_identity(&mut platform, 958); + let platform_state = platform.state.load(); - let (receiver, _, _) = setup_identity(&mut platform, 452); + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); - let card_document_type = contract - .document_type_for_name("card") - .expect("expected a profile document type"); + let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); + let dashpay_contract = dashpay.clone(); - let entropy = Bytes32::random_with_rng(&mut rng); + let profile = dashpay_contract + .document_type_for_name("profile") + .expect("expected a profile document type"); - let mut document = card_document_type - .random_document_with_identifier_and_entropy( - &mut rng, - identity.id(), - entropy, - DocumentFieldFillType::DoNotFillIfNotRequired, - DocumentFieldFillSize::AnyDocumentFillSize, - platform_version, - ) - .expect("expected a random document"); - - document.set("attack", 4.into()); - document.set("defense", 7.into()); - - let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( - document.clone(), - card_document_type, - entropy.0, - &key, - 2, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + assert!(profile.documents_mutable()); - let documents_batch_create_serialized_transition = documents_batch_create_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + let entropy = Bytes32::random_with_rng(&mut rng); - let transaction = platform.drive.grove.start_transaction(); + let mut document = profile + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_create_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + document.set("avatarUrl", "http://test.com/bob.jpg".into()); - assert_eq!(processing_result.valid_count(), 1); + let mut altered_document = document.clone(); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); - - let sender_documents_sql_string = - format!("select * from card where $ownerId == '{}'", identity.id()); - - let query_sender_identity_documents = DriveQuery::from_sql_expr( - sender_documents_sql_string.as_str(), - &contract, - Some(&platform.config.drive), - ) - .expect("expected document query"); - - let receiver_documents_sql_string = - format!("select * from card where $ownerId == '{}'", receiver.id()); - - let query_receiver_identity_documents = DriveQuery::from_sql_expr( - receiver_documents_sql_string.as_str(), - &contract, - Some(&platform.config.drive), - ) - .expect("expected document query"); - - let query_sender_results = platform - .drive - .query_documents( - query_sender_identity_documents.clone(), - None, - false, - None, - None, - ) - .expect("expected query result"); + altered_document.increment_revision().unwrap(); + altered_document.set("displayName", "Samuel".into()); + altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); - let query_receiver_results = platform - .drive - .query_documents( - query_receiver_identity_documents.clone(), - None, - false, - None, - None, - ) - .expect("expected query result"); + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document, + profile, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - // We expect the sender to have 1 document, and the receiver to have none - assert_eq!(query_sender_results.documents().len(), 1); + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - assert_eq!(query_receiver_results.documents().len(), 0); + let transaction = platform.drive.grove.start_transaction(); - document.set_revision(Some(2)); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let documents_batch_update_transition = + DocumentsBatchTransition::new_document_replacement_transition_from_document( + altered_document, + profile, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - document.set("attack", 6.into()); - document.set("defense", 0.into()); + let documents_batch_update_serialized_transition = documents_batch_update_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - let documents_batch_transfer_transition = - DocumentsBatchTransition::new_document_replacement_transition_from_document( - document, - card_document_type, - &key, - 3, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition for transfer"); + let transaction = platform.drive.grove.start_transaction(); - let documents_batch_transfer_serialized_transition = documents_batch_transfer_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_update_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - let transaction = platform.drive.grove.start_transaction(); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_transfer_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + assert_eq!(processing_result.invalid_paid_count(), 0); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); + assert_eq!(processing_result.invalid_unpaid_count(), 0); - assert_eq!(processing_result.invalid_paid_count(), 1); + assert_eq!(processing_result.valid_count(), 1); - assert_eq!(processing_result.invalid_unpaid_count(), 0); + assert_eq!(processing_result.aggregated_fees().processing_fee, 5081030); + } - assert_eq!(processing_result.valid_count(), 0); + #[test] + fn test_document_replace_on_document_type_that_is_not_mutable() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); - assert_eq!(processing_result.aggregated_fees().processing_fee, 1253950); + let mut rng = StdRng::seed_from_u64(437); - let query_sender_results = platform - .drive - .query_documents(query_sender_identity_documents, None, false, None, None) - .expect("expected query result"); + let platform_state = platform.state.load(); - let query_receiver_results = platform - .drive - .query_documents(query_receiver_identity_documents, None, false, None, None) - .expect("expected query result"); + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); - // We expect the sender to still have their document, and the receiver to have none - assert_eq!(query_sender_results.documents().len(), 1); + let (other_identity, ..) = setup_identity(&mut platform, 495, dash_to_credits!(0.1)); - assert_eq!(query_receiver_results.documents().len(), 0); - } + let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); + let dashpay_contract = dashpay.clone(); - #[test] - fn test_document_replace_that_does_not_yet_exist() { - let platform_version = PlatformVersion::latest(); - let mut platform = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_genesis_state(); + let contact_request_document_type = dashpay_contract + .document_type_for_name("contactRequest") + .expect("expected a profile document type"); - let mut rng = StdRng::seed_from_u64(433); + assert!(!contact_request_document_type.documents_mutable()); - let platform_state = platform.state.load(); + let entropy = Bytes32::random_with_rng(&mut rng); - let (identity, signer, key) = setup_identity(&mut platform, 958); + let mut document = contact_request_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set( + "toUserId", + Value::Identifier(other_identity.id().to_buffer()), + ); + document.set("recipientKeyIndex", Value::U32(1)); + document.set("senderKeyIndex", Value::U32(1)); + document.set("accountReference", Value::U32(0)); + document.set("coreHeightCreatedAt", Value::U32(5)); + + let mut altered_document = document.clone(); + + altered_document.set_revision(Some(1)); + altered_document.set("senderKeyIndex", Value::U32(2)); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document, + contact_request_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); - let dashpay_contract = dashpay.clone(); + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - let profile = dashpay_contract - .document_type_for_name("profile") - .expect("expected a profile document type"); + let transaction = platform.drive.grove.start_transaction(); - let entropy = Bytes32::random_with_rng(&mut rng); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let documents_batch_update_transition = + DocumentsBatchTransition::new_document_replacement_transition_from_document( + altered_document, + contact_request_document_type, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - let mut document = profile - .random_document_with_identifier_and_entropy( - &mut rng, - identity.id(), - entropy, - DocumentFieldFillType::FillIfNotRequired, - DocumentFieldFillSize::AnyDocumentFillSize, - platform_version, - ) - .expect("expected a random document"); + let documents_batch_update_serialized_transition = documents_batch_update_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - document.set("avatarUrl", "http://test.com/bob.jpg".into()); + let transaction = platform.drive.grove.start_transaction(); - let mut altered_document = document.clone(); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_update_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - altered_document.increment_revision().unwrap(); - altered_document.set("displayName", "Samuel".into()); - altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - let documents_batch_update_transition = - DocumentsBatchTransition::new_document_replacement_transition_from_document( - altered_document, - profile, - &key, - 3, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + assert_eq!(processing_result.invalid_paid_count(), 1); - let documents_batch_update_serialized_transition = documents_batch_update_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + assert_eq!(processing_result.invalid_unpaid_count(), 0); - let transaction = platform.drive.grove.start_transaction(); + assert_eq!(processing_result.valid_count(), 0); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_update_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + assert_eq!(processing_result.aggregated_fees().processing_fee, 102690); + } - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); + #[test] + fn test_document_replace_on_document_type_that_is_not_mutable_but_is_transferable() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_transfer_only(Transferable::Always); - assert_eq!(processing_result.invalid_paid_count(), 1); + let mut rng = StdRng::seed_from_u64(435); - assert_eq!(processing_result.invalid_unpaid_count(), 0); + let platform_state = platform.state.load(); - assert_eq!(processing_result.valid_count(), 0); + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); - assert_eq!(processing_result.aggregated_fees().processing_fee, 1244470); - } + let (receiver, _, _) = setup_identity(&mut platform, 452, dash_to_credits!(0.1)); - #[test] - fn test_document_delete_on_document_type_that_is_mutable() { - let platform_version = PlatformVersion::latest(); - let mut platform = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_genesis_state(); + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + let entropy = Bytes32::random_with_rng(&mut rng); - let mut rng = StdRng::seed_from_u64(433); + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - let platform_state = platform.state.load(); + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - let (identity, signer, key) = setup_identity(&mut platform, 958); + let transaction = platform.drive.grove.start_transaction(); - let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); - let dashpay_contract = dashpay.clone(); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - let profile = dashpay_contract - .document_type_for_name("profile") - .expect("expected a profile document type"); + assert_eq!(processing_result.valid_count(), 1); - assert!(profile.documents_mutable()); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - let entropy = Bytes32::random_with_rng(&mut rng); + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); - let mut document = profile - .random_document_with_identifier_and_entropy( - &mut rng, - identity.id(), - entropy, - DocumentFieldFillType::FillIfNotRequired, - DocumentFieldFillSize::AnyDocumentFillSize, - platform_version, + let query_sender_identity_documents = DriveQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), ) - .expect("expected a random document"); + .expect("expected document query"); - document.set("avatarUrl", "http://test.com/bob.jpg".into()); + let receiver_documents_sql_string = + format!("select * from card where $ownerId == '{}'", receiver.id()); - let mut altered_document = document.clone(); + let query_receiver_identity_documents = DriveQuery::from_sql_expr( + receiver_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); - altered_document.increment_revision().unwrap(); - altered_document.set("displayName", "Samuel".into()); - altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); + // We expect the sender to have 1 document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); - let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( - document, - profile, - entropy.0, - &key, - 2, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + assert_eq!(query_receiver_results.documents().len(), 0); - let documents_batch_create_serialized_transition = documents_batch_create_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + document.set_revision(Some(2)); - let transaction = platform.drive.grove.start_transaction(); + document.set("attack", 6.into()); + document.set("defense", 0.into()); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_create_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + let documents_batch_transfer_transition = + DocumentsBatchTransition::new_document_replacement_transition_from_document( + document, + card_document_type, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for transfer"); + + let documents_batch_transfer_serialized_transition = + documents_batch_transfer_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![documents_batch_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - assert_eq!(processing_result.valid_count(), 1); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); - - let documents_batch_deletion_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( - altered_document, - profile, - &key, - 3, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + assert_eq!(processing_result.invalid_paid_count(), 1); - let documents_batch_update_serialized_transition = documents_batch_deletion_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + assert_eq!(processing_result.invalid_unpaid_count(), 0); - let transaction = platform.drive.grove.start_transaction(); + assert_eq!(processing_result.valid_count(), 0); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_update_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + assert_eq!(processing_result.aggregated_fees().processing_fee, 1253950); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); + let query_sender_results = platform + .drive + .query_documents(query_sender_identity_documents, None, false, None, None) + .expect("expected query result"); - assert_eq!(processing_result.invalid_paid_count(), 0); + let query_receiver_results = platform + .drive + .query_documents(query_receiver_identity_documents, None, false, None, None) + .expect("expected query result"); - assert_eq!(processing_result.invalid_unpaid_count(), 0); + // We expect the sender to still have their document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); - assert_eq!(processing_result.valid_count(), 1); + assert_eq!(query_receiver_results.documents().len(), 0); + } - assert_eq!(processing_result.aggregated_fees().processing_fee, 5588830); - } + #[test] + fn test_document_replace_that_does_not_yet_exist() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); - #[test] - fn test_document_delete_on_document_type_that_is_not_mutable() { - 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 mut rng = StdRng::seed_from_u64(437); + let platform_state = platform.state.load(); - let platform_state = platform.state.load(); + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); - let (identity, signer, key) = setup_identity(&mut platform, 958); + let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); + let dashpay_contract = dashpay.clone(); - let (other_identity, ..) = setup_identity(&mut platform, 495); + let profile = dashpay_contract + .document_type_for_name("profile") + .expect("expected a profile document type"); - let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); - let dashpay_contract = dashpay.clone(); + let entropy = Bytes32::random_with_rng(&mut rng); - let contact_request_document_type = dashpay_contract - .document_type_for_name("contactRequest") - .expect("expected a profile document type"); + let mut document = profile + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); - assert!(!contact_request_document_type.documents_mutable()); + document.set("avatarUrl", "http://test.com/bob.jpg".into()); - let entropy = Bytes32::random_with_rng(&mut rng); + let mut altered_document = document.clone(); - let mut document = contact_request_document_type - .random_document_with_identifier_and_entropy( - &mut rng, - identity.id(), - entropy, - DocumentFieldFillType::FillIfNotRequired, - DocumentFieldFillSize::AnyDocumentFillSize, - platform_version, - ) - .expect("expected a random document"); - - document.set( - "toUserId", - Value::Identifier(other_identity.id().to_buffer()), - ); - document.set("recipientKeyIndex", Value::U32(1)); - document.set("senderKeyIndex", Value::U32(1)); - document.set("accountReference", Value::U32(0)); - document.set("coreHeightCreatedAt", Value::U32(5)); - - let mut altered_document = document.clone(); - - altered_document.set_revision(Some(1)); - altered_document.set("senderKeyIndex", Value::U32(2)); - - let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( - document, - contact_request_document_type, - entropy.0, - &key, - 2, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + altered_document.increment_revision().unwrap(); + altered_document.set("displayName", "Samuel".into()); + altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); - let documents_batch_create_serialized_transition = documents_batch_create_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + let documents_batch_update_transition = + DocumentsBatchTransition::new_document_replacement_transition_from_document( + altered_document, + profile, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - let transaction = platform.drive.grove.start_transaction(); + let documents_batch_update_serialized_transition = documents_batch_update_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_create_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + let transaction = platform.drive.grove.start_transaction(); - assert_eq!(processing_result.valid_count(), 1); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_update_serialized_transition.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"); - - let documents_batch_deletion_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( - altered_document, - contact_request_document_type, - &key, - 3, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - let documents_batch_deletion_serialized_transition = documents_batch_deletion_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + assert_eq!(processing_result.invalid_paid_count(), 1); - let transaction = platform.drive.grove.start_transaction(); + assert_eq!(processing_result.invalid_unpaid_count(), 0); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_deletion_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + assert_eq!(processing_result.valid_count(), 0); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); + assert_eq!(processing_result.aggregated_fees().processing_fee, 1244470); + } + } - assert_eq!(processing_result.invalid_paid_count(), 1); + mod deletion_tests { + use super::*; - assert_eq!(processing_result.invalid_unpaid_count(), 0); + #[test] + fn test_document_delete_on_document_type_that_is_mutable_and_can_be_deleted() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); - assert_eq!(processing_result.valid_count(), 0); + let mut rng = StdRng::seed_from_u64(433); - assert_eq!(processing_result.aggregated_fees().processing_fee, 1507670); - } + let platform_state = platform.state.load(); - #[test] - fn test_document_delete_that_does_not_yet_exist() { - let platform_version = PlatformVersion::latest(); - let mut platform = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_genesis_state(); + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); - let mut rng = StdRng::seed_from_u64(433); + let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); + let dashpay_contract = dashpay.clone(); - let platform_state = platform.state.load(); + let profile = dashpay_contract + .document_type_for_name("profile") + .expect("expected a profile document type"); - let (identity, signer, key) = setup_identity(&mut platform, 958); + assert!(profile.documents_mutable()); - let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); - let dashpay_contract = dashpay.clone(); + assert!(profile.documents_can_be_deleted()); - let profile = dashpay_contract - .document_type_for_name("profile") - .expect("expected a profile document type"); + let entropy = Bytes32::random_with_rng(&mut rng); - let entropy = Bytes32::random_with_rng(&mut rng); + let mut document = profile + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); - let mut document = profile - .random_document_with_identifier_and_entropy( - &mut rng, - identity.id(), - entropy, - DocumentFieldFillType::FillIfNotRequired, - DocumentFieldFillSize::AnyDocumentFillSize, - platform_version, - ) - .expect("expected a random document"); + document.set("avatarUrl", "http://test.com/bob.jpg".into()); - document.set("avatarUrl", "http://test.com/bob.jpg".into()); + let mut altered_document = document.clone(); - let mut altered_document = document.clone(); + altered_document.increment_revision().unwrap(); + altered_document.set("displayName", "Samuel".into()); + altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); - altered_document.increment_revision().unwrap(); - altered_document.set("displayName", "Samuel".into()); - altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document, + profile, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - let documents_batch_delete_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( - altered_document, - profile, - &key, - 3, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - let documents_batch_delete_serialized_transition = documents_batch_delete_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + let transaction = platform.drive.grove.start_transaction(); - let transaction = platform.drive.grove.start_transaction(); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let documents_batch_deletion_transition = + DocumentsBatchTransition::new_document_deletion_transition_from_document( + altered_document, + profile, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_delete_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + let documents_batch_update_serialized_transition = documents_batch_deletion_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); + let transaction = platform.drive.grove.start_transaction(); - assert_eq!(processing_result.invalid_paid_count(), 1); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_update_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - assert_eq!(processing_result.invalid_unpaid_count(), 0); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - assert_eq!(processing_result.valid_count(), 0); + assert_eq!(processing_result.invalid_paid_count(), 0); - assert_eq!(processing_result.aggregated_fees().processing_fee, 1244470); - } + assert_eq!(processing_result.invalid_unpaid_count(), 0); - #[test] - fn test_document_transfer_on_document_type_that_is_transferable() { - let platform_version = PlatformVersion::latest(); - let (mut platform, contract) = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_initial_state_structure() - .with_crypto_card_game(Transferable::Always); + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 5588830); + } + + #[test] + fn test_document_delete_on_document_type_that_is_mutable_and_can_not_be_deleted() { + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); + + let contract_path = "tests/supporting_files/contract/dashpay/dashpay-contract-contact-request-mutable-and-can-not-be-deleted.json"; + + let platform_version = platform + .state + .load() + .current_platform_version() + .expect("expected to get current platform version"); + + // let's construct the grovedb structure for the card game data contract + let dashpay_contract = json_document_to_contract(contract_path, true, platform_version) + .expect("expected to get data contract"); + platform + .drive + .apply_contract( + &dashpay_contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + let mut rng = StdRng::seed_from_u64(437); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (other_identity, ..) = setup_identity(&mut platform, 495, dash_to_credits!(0.1)); + + let contact_request_document_type = dashpay_contract + .document_type_for_name("contactRequest") + .expect("expected a profile document type"); + + assert!(contact_request_document_type.documents_mutable()); + + assert!(!contact_request_document_type.documents_can_be_deleted()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = contact_request_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set( + "toUserId", + Value::Identifier(other_identity.id().to_buffer()), + ); + document.set("recipientKeyIndex", Value::U32(1)); + document.set("senderKeyIndex", Value::U32(1)); + document.set("accountReference", Value::U32(0)); + document.set("coreHeightCreatedAt", Value::U32(5)); + + let mut altered_document = document.clone(); + + altered_document.set_revision(Some(1)); + altered_document.set("senderKeyIndex", Value::U32(2)); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document, + contact_request_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_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![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let documents_batch_deletion_transition = + DocumentsBatchTransition::new_document_deletion_transition_from_document( + altered_document, + contact_request_document_type, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_deletion_serialized_transition = + documents_batch_deletion_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![documents_batch_deletion_serialized_transition.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.invalid_paid_count(), 1); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 0); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 1253950); + } + + #[test] + fn test_document_delete_on_document_type_that_is_not_mutable_and_can_be_deleted() { + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); + + let contract_path = "tests/supporting_files/contract/dashpay/dashpay-contract-contact-request-not-mutable-and-can-be-deleted.json"; + + let platform_version = platform + .state + .load() + .current_platform_version() + .expect("expected to get current platform version"); + + // let's construct the grovedb structure for the card game data contract + let dashpay_contract = json_document_to_contract(contract_path, true, platform_version) + .expect("expected to get data contract"); + platform + .drive + .apply_contract( + &dashpay_contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + let mut rng = StdRng::seed_from_u64(437); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (other_identity, ..) = setup_identity(&mut platform, 495, dash_to_credits!(0.1)); + + let contact_request_document_type = dashpay_contract + .document_type_for_name("contactRequest") + .expect("expected a profile document type"); + + assert!(!contact_request_document_type.documents_mutable()); + + assert!(contact_request_document_type.documents_can_be_deleted()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = contact_request_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set( + "toUserId", + Value::Identifier(other_identity.id().to_buffer()), + ); + document.set("recipientKeyIndex", Value::U32(1)); + document.set("senderKeyIndex", Value::U32(1)); + document.set("accountReference", Value::U32(0)); + document.set("coreHeightCreatedAt", Value::U32(5)); + + let mut altered_document = document.clone(); + + altered_document.set_revision(Some(1)); + altered_document.set("senderKeyIndex", Value::U32(2)); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document, + contact_request_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_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![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let documents_batch_deletion_transition = + DocumentsBatchTransition::new_document_deletion_transition_from_document( + altered_document, + contact_request_document_type, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_deletion_serialized_transition = + documents_batch_deletion_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![documents_batch_deletion_serialized_transition.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.invalid_paid_count(), 0); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 9951520); + } + + #[test] + fn test_document_delete_on_document_type_that_is_not_mutable_and_can_not_be_deleted() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(437); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (other_identity, ..) = setup_identity(&mut platform, 495, dash_to_credits!(0.1)); + + let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); + let dashpay_contract = dashpay.clone(); + + let contact_request_document_type = dashpay_contract + .document_type_for_name("contactRequest") + .expect("expected a profile document type"); + + assert!(!contact_request_document_type.documents_mutable()); + + assert!(!contact_request_document_type.documents_can_be_deleted()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = contact_request_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set( + "toUserId", + Value::Identifier(other_identity.id().to_buffer()), + ); + document.set("recipientKeyIndex", Value::U32(1)); + document.set("senderKeyIndex", Value::U32(1)); + document.set("accountReference", Value::U32(0)); + document.set("coreHeightCreatedAt", Value::U32(5)); + + let mut altered_document = document.clone(); + + altered_document.set_revision(Some(1)); + altered_document.set("senderKeyIndex", Value::U32(2)); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document, + contact_request_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_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![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let documents_batch_deletion_transition = + DocumentsBatchTransition::new_document_deletion_transition_from_document( + altered_document, + contact_request_document_type, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_deletion_serialized_transition = + documents_batch_deletion_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![documents_batch_deletion_serialized_transition.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.invalid_paid_count(), 1); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 0); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 1507670); + } + + #[test] + fn test_document_delete_that_does_not_yet_exist() { + 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, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); + let dashpay_contract = dashpay.clone(); + + let profile = dashpay_contract + .document_type_for_name("profile") + .expect("expected a profile document type"); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = profile + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("avatarUrl", "http://test.com/bob.jpg".into()); + + let mut altered_document = document.clone(); + + altered_document.increment_revision().unwrap(); + altered_document.set("displayName", "Samuel".into()); + altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); + + let documents_batch_delete_transition = + DocumentsBatchTransition::new_document_deletion_transition_from_document( + altered_document, + profile, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_delete_serialized_transition = documents_batch_delete_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![documents_batch_delete_serialized_transition.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.invalid_paid_count(), 1); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 0); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 1244470); + } + } + + mod transfer_tests { + use super::*; + + #[test] + fn test_document_transfer_on_document_type_that_is_transferable_that_has_no_owner_indices() + { + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); + + let card_game_path = "tests/supporting_files/contract/crypto-card-game/crypto-card-game-all-transferable-no-owner-indexes.json"; + + let platform_version = platform + .state + .load() + .current_platform_version() + .expect("expected to get current platform version"); + + // let's construct the grovedb structure for the card game data contract + let contract = json_document_to_contract(card_game_path, true, platform_version) + .expect("expected to get data contract"); + platform + .drive + .apply_contract( + &contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (receiver, _, _) = setup_identity(&mut platform, 450, dash_to_credits!(0.1)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + assert!(!card_document_type.documents_mutable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_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![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + document.set_revision(Some(2)); + + let documents_batch_transfer_transition = + DocumentsBatchTransition::new_document_transfer_transition_from_document( + document, + card_document_type, + receiver.id(), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for transfer"); + + let documents_batch_transfer_serialized_transition = + documents_batch_transfer_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![documents_batch_transfer_serialized_transition.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.invalid_paid_count(), 0); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().storage_fee, 0); // There is no storage fee, as there are no indexes that will change + + assert_eq!(processing_result.aggregated_fees().processing_fee, 5609930); + } + + #[test] + fn test_document_transfer_on_document_type_that_is_transferable() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_transfer_only(Transferable::Always); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (receiver, _, _) = setup_identity(&mut platform, 450, dash_to_credits!(0.1)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + assert!(!card_document_type.documents_mutable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_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![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); + + let query_sender_identity_documents = DriveQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let receiver_documents_sql_string = + format!("select * from card where $ownerId == '{}'", receiver.id()); + + let query_receiver_identity_documents = DriveQuery::from_sql_expr( + receiver_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to have 1 document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + + document.set_revision(Some(2)); + + let documents_batch_transfer_transition = + DocumentsBatchTransition::new_document_transfer_transition_from_document( + document, + card_document_type, + receiver.id(), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for transfer"); + + let documents_batch_transfer_serialized_transition = + documents_batch_transfer_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![documents_batch_transfer_serialized_transition.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.invalid_paid_count(), 0); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().storage_fee, 37341000); // 1383 bytes added + + // todo: we should expect these numbers to be closer + + assert_eq!( + processing_result + .aggregated_fees() + .fee_refunds + .calculate_refunds_amount_for_identity(identity.id()), + Some(14992395) + ); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 9357180); + + let query_sender_results = platform + .drive + .query_documents(query_sender_identity_documents, None, false, None, None) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents(query_receiver_identity_documents, None, false, None, None) + .expect("expected query result"); + + // We expect the sender to have no documents, and the receiver to have 1 + assert_eq!(query_sender_results.documents().len(), 0); + + assert_eq!(query_receiver_results.documents().len(), 1); + } + + #[test] + fn test_document_transfer_on_document_type_that_is_not_transferable() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_transfer_only(Transferable::Never); + + let mut rng = StdRng::seed_from_u64(435); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (receiver, _, _) = setup_identity(&mut platform, 452, dash_to_credits!(0.1)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_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![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); + + let query_sender_identity_documents = DriveQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let receiver_documents_sql_string = + format!("select * from card where $ownerId == '{}'", receiver.id()); + + let query_receiver_identity_documents = DriveQuery::from_sql_expr( + receiver_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to have 1 document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + + document.set_revision(Some(2)); + + let documents_batch_transfer_transition = + DocumentsBatchTransition::new_document_transfer_transition_from_document( + document, + card_document_type, + receiver.id(), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for transfer"); + + let documents_batch_transfer_serialized_transition = + documents_batch_transfer_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![documents_batch_transfer_serialized_transition.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.invalid_paid_count(), 1); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 0); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 1253950); + + let query_sender_results = platform + .drive + .query_documents(query_sender_identity_documents, None, false, None, None) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents(query_receiver_identity_documents, None, false, None, None) + .expect("expected query result"); + + // We expect the sender to still have their document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + } + + #[test] + fn test_document_transfer_that_does_not_yet_exist() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_transfer_only(Transferable::Never); + + let mut rng = StdRng::seed_from_u64(435); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (receiver, _, _) = setup_identity(&mut platform, 452, dash_to_credits!(0.1)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); + + let query_sender_identity_documents = DriveQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let receiver_documents_sql_string = + format!("select * from card where $ownerId == '{}'", receiver.id()); + + let query_receiver_identity_documents = DriveQuery::from_sql_expr( + receiver_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to have 0 documents, and the receiver to also have none + assert_eq!(query_sender_results.documents().len(), 0); + + assert_eq!(query_receiver_results.documents().len(), 0); + + document.set_revision(Some(2)); + + let documents_batch_transfer_transition = + DocumentsBatchTransition::new_document_transfer_transition_from_document( + document, + card_document_type, + receiver.id(), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for transfer"); + + let documents_batch_transfer_serialized_transition = + documents_batch_transfer_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![documents_batch_transfer_serialized_transition.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.invalid_paid_count(), 1); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 0); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 25090); + + let query_sender_results = platform + .drive + .query_documents(query_sender_identity_documents, None, false, None, None) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents(query_receiver_identity_documents, None, false, None, None) + .expect("expected query result"); + + // We expect the sender to still have no document, and the receiver to have none as well + assert_eq!(query_sender_results.documents().len(), 0); + + assert_eq!(query_receiver_results.documents().len(), 0); + } + + #[test] + fn test_document_delete_after_transfer() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_transfer_only(Transferable::Always); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (receiver, recipient_signer, recipient_key) = + setup_identity(&mut platform, 450, dash_to_credits!(0.1)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + assert!(!card_document_type.documents_mutable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_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![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); + + let query_sender_identity_documents = DriveQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let receiver_documents_sql_string = + format!("select * from card where $ownerId == '{}'", receiver.id()); + + let query_receiver_identity_documents = DriveQuery::from_sql_expr( + receiver_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to have 1 document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + + document.set_revision(Some(2)); + + let documents_batch_transfer_transition = + DocumentsBatchTransition::new_document_transfer_transition_from_document( + document.clone(), + card_document_type, + receiver.id(), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for transfer"); + + let documents_batch_transfer_serialized_transition = + documents_batch_transfer_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![documents_batch_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(50000000), + &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.invalid_paid_count(), 0); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 10283900); + + let query_sender_results = platform + .drive + .query_documents(query_sender_identity_documents, None, false, None, None) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents(query_receiver_identity_documents, None, false, None, None) + .expect("expected query result"); + + // We expect the sender to have no documents, and the receiver to have 1 + assert_eq!(query_sender_results.documents().len(), 0); + + assert_eq!(query_receiver_results.documents().len(), 1); + + // Now let's try to delete the transferred document + + document.set_owner_id(receiver.id()); + + let documents_batch_deletion_transition = + DocumentsBatchTransition::new_document_deletion_transition_from_document( + document, + card_document_type, + &recipient_key, + 2, + 0, + &recipient_signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_deletion_serialized_transition = + documents_batch_deletion_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![documents_batch_deletion_serialized_transition.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.invalid_paid_count(), 1); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 0); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 1107610); + } + } + + mod nft_tests { + use super::*; + #[test] + fn test_document_set_price_on_document_without_ability_to_purchase() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_transfer_only(Transferable::Always); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + assert!(!card_document_type.documents_mutable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_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![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); + + let query_sender_identity_documents = DriveQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to have 1 document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + document.set_revision(Some(2)); + + let documents_batch_update_price_transition = + DocumentsBatchTransition::new_document_update_price_transition_from_document( + document.clone(), + card_document_type, + dash_to_credits!(0.1), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the update price"); + + let documents_batch_transfer_serialized_transition = + documents_batch_update_price_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![documents_batch_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(50000000), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let result = processing_result.into_execution_results().remove(0); + + let StateTransitionExecutionResult::PaidConsensusError(consensus_error, _) = result + else { + panic!("expected a paid consensus error"); + }; + assert_eq!(consensus_error.to_string(), "Document transition action card is in trade mode No Trading that does not support the seller setting the price is not supported"); + } + + #[test] + fn test_document_set_price() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_nft(TradeMode::DirectPurchase); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (receiver, _, _) = setup_identity(&mut platform, 450, dash_to_credits!(0.1)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + assert!(!card_document_type.documents_mutable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_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![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); + + let query_sender_identity_documents = DriveQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let receiver_documents_sql_string = + format!("select * from card where $ownerId == '{}'", receiver.id()); + + let query_receiver_identity_documents = DriveQuery::from_sql_expr( + receiver_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to have 1 document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + + document.set_revision(Some(2)); + + let documents_batch_update_price_transition = + DocumentsBatchTransition::new_document_update_price_transition_from_document( + document.clone(), + card_document_type, + dash_to_credits!(0.1), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the update price"); + + let documents_batch_transfer_serialized_transition = + documents_batch_update_price_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![documents_batch_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(50000000), + &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.invalid_paid_count(), 0); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 6814950); + + let query_sender_results = platform + .drive + .query_documents(query_sender_identity_documents, None, false, None, None) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents(query_receiver_identity_documents, None, false, None, None) + .expect("expected query result"); + + // We expect the sender to still have their document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + + // The sender document should have the desired price + + let document = query_sender_results.documents().first().unwrap(); + + let price: Credits = document + .properties() + .get_integer("$price") + .expect("expected to get back price"); + + assert_eq!(dash_to_credits!(0.1), price); + + assert_eq!(document.revision(), Some(2)); + } + + #[test] + fn test_document_set_price_and_purchase() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_nft(TradeMode::DirectPurchase); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (purchaser, recipient_signer, recipient_key) = + setup_identity(&mut platform, 450, dash_to_credits!(1.0)); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + assert_eq!(seller_balance, dash_to_credits!(0.1)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + assert!(!card_document_type.documents_mutable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_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![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!( + processing_result + .aggregated_fees() + .clone() + .into_balance_change(identity.id()) + .change(), + &BalanceChange::RemoveFromBalance { + required_removed_balance: 123579000, + desired_removed_balance: 128673220, + } + ); + + let original_creation_cost = 128673220; + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + // the seller should have received 0.1 and already had 0.1 minus the processing fee and storage fee + assert_eq!( + seller_balance, + dash_to_credits!(0.1) - original_creation_cost + ); + + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); + + let query_sender_identity_documents = DriveQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let receiver_documents_sql_string = + format!("select * from card where $ownerId == '{}'", purchaser.id()); + + let query_receiver_identity_documents = DriveQuery::from_sql_expr( + receiver_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to have 1 document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + + document.set_revision(Some(2)); + + let documents_batch_update_price_transition = + DocumentsBatchTransition::new_document_update_price_transition_from_document( + document.clone(), + card_document_type, + dash_to_credits!(0.1), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the update price"); + + let documents_batch_transfer_serialized_transition = + documents_batch_update_price_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![documents_batch_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(50000000), + &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.invalid_paid_count(), 0); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().storage_fee, 216000); // we added 8 bytes for the price + + assert_eq!( + processing_result + .aggregated_fees() + .fee_refunds + .calculate_refunds_amount_for_identity(identity.id()), + None + ); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 6814950); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + // the seller should have received 0.1 and already had 0.1 minus the processing fee and storage fee + assert_eq!( + seller_balance, + dash_to_credits!(0.1) - 6814950 - 216000 - original_creation_cost + ); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to still have their document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + + // The sender document should have the desired price + + let mut document = query_sender_results.documents_owned().remove(0); + + let price: Credits = document + .properties() + .get_integer("$price") + .expect("expected to get back price"); + + assert_eq!(dash_to_credits!(0.1), price); + + // At this point we want to have the receiver purchase the document + + document.set_revision(Some(3)); + + let documents_batch_purchase_transition = + DocumentsBatchTransition::new_document_purchase_transition_from_document( + document.clone(), + card_document_type, + purchaser.id(), + dash_to_credits!(0.1), //same price as requested + &recipient_key, + 1, // 1 because he's never done anything + 0, + &recipient_signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the purchase"); + + let documents_batch_purchase_serialized_transition = + documents_batch_purchase_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![documents_batch_purchase_serialized_transition], + &platform_state, + &BlockInfo::default_with_time(50000000), + &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.invalid_paid_count(), 0); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); - let mut rng = StdRng::seed_from_u64(433); + assert_eq!(processing_result.valid_count(), 1); - let platform_state = platform.state.load(); + assert_eq!(processing_result.aggregated_fees().storage_fee, 64611000); - let (identity, signer, key) = setup_identity(&mut platform, 958); + assert_eq!(processing_result.aggregated_fees().processing_fee, 10873700); - let (receiver, _, _) = setup_identity(&mut platform, 450); + assert_eq!( + processing_result + .aggregated_fees() + .fee_refunds + .calculate_refunds_amount_for_identity(identity.id()), + Some(22704503) + ); - let card_document_type = contract - .document_type_for_name("card") - .expect("expected a profile document type"); + let query_sender_results = platform + .drive + .query_documents(query_sender_identity_documents, None, false, None, None) + .expect("expected query result"); - assert!(!card_document_type.documents_mutable()); + let query_receiver_results = platform + .drive + .query_documents(query_receiver_identity_documents, None, false, None, None) + .expect("expected query result"); - let entropy = Bytes32::random_with_rng(&mut rng); + // We expect the sender to have no documents, and the receiver to have 1 + assert_eq!(query_sender_results.documents().len(), 0); - let mut document = card_document_type - .random_document_with_identifier_and_entropy( - &mut rng, - identity.id(), - entropy, - DocumentFieldFillType::DoNotFillIfNotRequired, - DocumentFieldFillSize::AnyDocumentFillSize, - platform_version, - ) - .expect("expected a random document"); - - document.set("attack", 4.into()); - document.set("defense", 7.into()); - - let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( - document.clone(), - card_document_type, - entropy.0, - &key, - 2, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + assert_eq!(query_receiver_results.documents().len(), 1); - let documents_batch_create_serialized_transition = documents_batch_create_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); - let transaction = platform.drive.grove.start_transaction(); + // the seller should have received 0.1 and already had 0.1 minus the processing fee and storage fee + assert_eq!( + seller_balance, + dash_to_credits!(0.2) - 6814950 - 216000 - original_creation_cost + 22704503 + ); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_create_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + let buyers_balance = platform + .drive + .fetch_identity_balance(purchaser.id().to_buffer(), None, platform_version) + .expect("expected to get purchaser balance") + .expect("expected that purchaser exists"); - assert_eq!(processing_result.valid_count(), 1); + // the buyer payed 0.1, but also storage and processing fees + assert_eq!(buyers_balance, dash_to_credits!(0.9) - 10873700 - 64611000); + } - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); - - let sender_documents_sql_string = - format!("select * from card where $ownerId == '{}'", identity.id()); - - let query_sender_identity_documents = DriveQuery::from_sql_expr( - sender_documents_sql_string.as_str(), - &contract, - Some(&platform.config.drive), - ) - .expect("expected document query"); - - let receiver_documents_sql_string = - format!("select * from card where $ownerId == '{}'", receiver.id()); - - let query_receiver_identity_documents = DriveQuery::from_sql_expr( - receiver_documents_sql_string.as_str(), - &contract, - Some(&platform.config.drive), - ) - .expect("expected document query"); - - let query_sender_results = platform - .drive - .query_documents( - query_sender_identity_documents.clone(), - None, - false, - None, - None, - ) - .expect("expected query result"); + #[test] + fn test_document_set_price_and_try_purchase_at_different_amount() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_nft(TradeMode::DirectPurchase); - let query_receiver_results = platform - .drive - .query_documents( - query_receiver_identity_documents.clone(), - None, - false, - None, - None, - ) - .expect("expected query result"); + let mut rng = StdRng::seed_from_u64(433); - // We expect the sender to have 1 document, and the receiver to have none - assert_eq!(query_sender_results.documents().len(), 1); + let platform_state = platform.state.load(); - assert_eq!(query_receiver_results.documents().len(), 0); + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); - document.set_revision(Some(2)); + let (purchaser, recipient_signer, recipient_key) = + setup_identity(&mut platform, 450, dash_to_credits!(1.0)); - let documents_batch_transfer_transition = - DocumentsBatchTransition::new_document_transfer_transition_from_document( - document, - card_document_type, - receiver.id(), - &key, - 3, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition for transfer"); + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); - let documents_batch_transfer_serialized_transition = documents_batch_transfer_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + assert_eq!(seller_balance, dash_to_credits!(0.1)); - let transaction = platform.drive.grove.start_transaction(); + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_transfer_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + assert!(!card_document_type.documents_mutable()); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); + let entropy = Bytes32::random_with_rng(&mut rng); - assert_eq!(processing_result.invalid_paid_count(), 0); + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - assert_eq!(processing_result.invalid_unpaid_count(), 0); + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - assert_eq!(processing_result.valid_count(), 1); + let transaction = platform.drive.grove.start_transaction(); - assert_eq!(processing_result.aggregated_fees().processing_fee, 9350380); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + document.set_revision(Some(2)); + + let documents_batch_update_price_transition = + DocumentsBatchTransition::new_document_update_price_transition_from_document( + document.clone(), + card_document_type, + dash_to_credits!(0.5), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the update price"); + + let documents_batch_transfer_serialized_transition = + documents_batch_update_price_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![documents_batch_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(50000000), + &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(), 1); + + // At this point we want to have the receiver purchase the document + + document.set_revision(Some(3)); + + let documents_batch_purchase_transition = + DocumentsBatchTransition::new_document_purchase_transition_from_document( + document.clone(), + card_document_type, + purchaser.id(), + dash_to_credits!(0.35), //different than requested price + &recipient_key, + 1, // 1 because he's never done anything + 0, + &recipient_signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the purchase"); + + let documents_batch_purchase_serialized_transition = + documents_batch_purchase_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![documents_batch_purchase_serialized_transition], + &platform_state, + &BlockInfo::default_with_time(50000000), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - let query_sender_results = platform - .drive - .query_documents(query_sender_identity_documents, None, false, None, None) - .expect("expected query result"); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - let query_receiver_results = platform - .drive - .query_documents(query_receiver_identity_documents, None, false, None, None) - .expect("expected query result"); + assert_eq!(processing_result.invalid_paid_count(), 1); - // We expect the sender to have no documents, and the receiver to have 1 - assert_eq!(query_sender_results.documents().len(), 0); + let result = processing_result.into_execution_results().remove(0); - assert_eq!(query_receiver_results.documents().len(), 1); - } + let StateTransitionExecutionResult::PaidConsensusError(consensus_error, _) = result + else { + panic!("expected a paid consensus error"); + }; + assert_eq!(consensus_error.to_string(), "5rJccTdtJfg6AxSKyrptWUug3PWjveEitTTLqBn9wHdk document can not be purchased for 35000000000, it's sale price is 50000000000 (in credits)"); + } - #[test] - fn test_document_transfer_on_document_type_that_is_not_transferable() { - let platform_version = PlatformVersion::latest(); - let (mut platform, contract) = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_initial_state_structure() - .with_crypto_card_game(Transferable::Never); + #[test] + fn test_document_set_price_and_purchase_from_ones_self() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_nft(TradeMode::DirectPurchase); - let mut rng = StdRng::seed_from_u64(435); + let mut rng = StdRng::seed_from_u64(433); - let platform_state = platform.state.load(); + let platform_state = platform.state.load(); - let (identity, signer, key) = setup_identity(&mut platform, 958); + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.5)); - let (receiver, _, _) = setup_identity(&mut platform, 452); + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); - let card_document_type = contract - .document_type_for_name("card") - .expect("expected a profile document type"); + assert_eq!(seller_balance, dash_to_credits!(0.5)); - let entropy = Bytes32::random_with_rng(&mut rng); + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); - let mut document = card_document_type - .random_document_with_identifier_and_entropy( - &mut rng, - identity.id(), - entropy, - DocumentFieldFillType::DoNotFillIfNotRequired, - DocumentFieldFillSize::AnyDocumentFillSize, - platform_version, - ) - .expect("expected a random document"); - - document.set("attack", 4.into()); - document.set("defense", 7.into()); - - let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( - document.clone(), - card_document_type, - entropy.0, - &key, - 2, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + assert!(!card_document_type.documents_mutable()); - let documents_batch_create_serialized_transition = documents_batch_create_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + let entropy = Bytes32::random_with_rng(&mut rng); - let transaction = platform.drive.grove.start_transaction(); + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_create_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - assert_eq!(processing_result.valid_count(), 1); + let transaction = platform.drive.grove.start_transaction(); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); - - let sender_documents_sql_string = - format!("select * from card where $ownerId == '{}'", identity.id()); - - let query_sender_identity_documents = DriveQuery::from_sql_expr( - sender_documents_sql_string.as_str(), - &contract, - Some(&platform.config.drive), - ) - .expect("expected document query"); - - let receiver_documents_sql_string = - format!("select * from card where $ownerId == '{}'", receiver.id()); - - let query_receiver_identity_documents = DriveQuery::from_sql_expr( - receiver_documents_sql_string.as_str(), - &contract, - Some(&platform.config.drive), - ) - .expect("expected document query"); - - let query_sender_results = platform - .drive - .query_documents( - query_sender_identity_documents.clone(), - None, - false, - None, - None, - ) - .expect("expected query result"); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + document.set_revision(Some(2)); + + let documents_batch_update_price_transition = + DocumentsBatchTransition::new_document_update_price_transition_from_document( + document.clone(), + card_document_type, + dash_to_credits!(0.1), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the update price"); + + let documents_batch_transfer_serialized_transition = + documents_batch_update_price_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![documents_batch_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(50000000), + &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(), 1); + + // At this point we want to have the receiver purchase the document + + document.set_revision(Some(3)); + + let documents_batch_purchase_transition = + DocumentsBatchTransition::new_document_purchase_transition_from_document( + document.clone(), + card_document_type, + identity.id(), + dash_to_credits!(0.1), //same price as requested + &key, + 1, // 1 because he's never done anything + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the purchase"); + + let documents_batch_purchase_serialized_transition = + documents_batch_purchase_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![documents_batch_purchase_serialized_transition], + &platform_state, + &BlockInfo::default_with_time(50000000), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - let query_receiver_results = platform - .drive - .query_documents( - query_receiver_identity_documents.clone(), - None, - false, - None, - None, - ) - .expect("expected query result"); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - // We expect the sender to have 1 document, and the receiver to have none - assert_eq!(query_sender_results.documents().len(), 1); + assert_eq!(processing_result.invalid_paid_count(), 1); - assert_eq!(query_receiver_results.documents().len(), 0); + let result = processing_result.into_execution_results().remove(0); - document.set_revision(Some(2)); + let StateTransitionExecutionResult::PaidConsensusError(consensus_error, _) = result + else { + panic!("expected a paid consensus error"); + }; + assert_eq!(consensus_error.to_string(), "Document transition action on document type: card identity trying to purchase a document that is already owned by the purchaser is not supported"); + } - let documents_batch_transfer_transition = - DocumentsBatchTransition::new_document_transfer_transition_from_document( - document, - card_document_type, - receiver.id(), - &key, - 3, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition for transfer"); + #[test] + fn test_document_set_price_and_purchase_then_try_buy_back() { + // In this test we try to buy back a document after it has been sold - let documents_batch_transfer_serialized_transition = documents_batch_transfer_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_nft(TradeMode::DirectPurchase); - let transaction = platform.drive.grove.start_transaction(); + let mut rng = StdRng::seed_from_u64(433); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_transfer_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + let platform_state = platform.state.load(); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); - assert_eq!(processing_result.invalid_paid_count(), 1); + let (purchaser, recipient_signer, recipient_key) = + setup_identity(&mut platform, 450, dash_to_credits!(1.0)); - assert_eq!(processing_result.invalid_unpaid_count(), 0); + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); - assert_eq!(processing_result.valid_count(), 0); + assert_eq!(seller_balance, dash_to_credits!(0.1)); - assert_eq!(processing_result.aggregated_fees().processing_fee, 1253950); + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); - let query_sender_results = platform - .drive - .query_documents(query_sender_identity_documents, None, false, None, None) - .expect("expected query result"); + assert!(!card_document_type.documents_mutable()); - let query_receiver_results = platform - .drive - .query_documents(query_receiver_identity_documents, None, false, None, None) - .expect("expected query result"); + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - // We expect the sender to still have their document, and the receiver to have none - assert_eq!(query_sender_results.documents().len(), 1); + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - assert_eq!(query_receiver_results.documents().len(), 0); - } + let transaction = platform.drive.grove.start_transaction(); - #[test] - fn test_document_transfer_that_does_not_yet_exist() { - let platform_version = PlatformVersion::latest(); - let (mut platform, contract) = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_initial_state_structure() - .with_crypto_card_game(Transferable::Never); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + document.set_revision(Some(2)); + + let documents_batch_update_price_transition = + DocumentsBatchTransition::new_document_update_price_transition_from_document( + document.clone(), + card_document_type, + dash_to_credits!(0.1), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the update price"); + + let documents_batch_transfer_serialized_transition = + documents_batch_update_price_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![documents_batch_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(50000000), + &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(), 1); + + // At this point we want to have the receiver purchase the document + + document.set_revision(Some(3)); + + let documents_batch_purchase_transition = + DocumentsBatchTransition::new_document_purchase_transition_from_document( + document.clone(), + card_document_type, + purchaser.id(), + dash_to_credits!(0.1), //same price as requested + &recipient_key, + 1, // 1 because he's never done anything + 0, + &recipient_signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the purchase"); + + let documents_batch_purchase_serialized_transition = + documents_batch_purchase_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![documents_batch_purchase_serialized_transition], + &platform_state, + &BlockInfo::default_with_time(50000000), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - let mut rng = StdRng::seed_from_u64(435); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - let platform_state = platform.state.load(); + assert_eq!(processing_result.valid_count(), 1); - let (identity, signer, key) = setup_identity(&mut platform, 958); + // Let's verify some stuff - let (receiver, _, _) = setup_identity(&mut platform, 452); + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); - let card_document_type = contract - .document_type_for_name("card") - .expect("expected a profile document type"); + let query_sender_identity_documents = DriveQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); - let entropy = Bytes32::random_with_rng(&mut rng); + let receiver_documents_sql_string = + format!("select * from card where $ownerId == '{}'", purchaser.id()); - let mut document = card_document_type - .random_document_with_identifier_and_entropy( - &mut rng, - identity.id(), - entropy, - DocumentFieldFillType::DoNotFillIfNotRequired, - DocumentFieldFillSize::AnyDocumentFillSize, - platform_version, + let query_receiver_identity_documents = DriveQuery::from_sql_expr( + receiver_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), ) - .expect("expected a random document"); + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); - document.set("attack", 4.into()); - document.set("defense", 7.into()); + // We expect the sender to still have their document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 0); - let sender_documents_sql_string = - format!("select * from card where $ownerId == '{}'", identity.id()); + assert_eq!(query_receiver_results.documents().len(), 1); - let query_sender_identity_documents = DriveQuery::from_sql_expr( - sender_documents_sql_string.as_str(), - &contract, - Some(&platform.config.drive), - ) - .expect("expected document query"); + // The sender document should have the desired price - let receiver_documents_sql_string = - format!("select * from card where $ownerId == '{}'", receiver.id()); + let mut document = query_receiver_results.documents_owned().remove(0); - let query_receiver_identity_documents = DriveQuery::from_sql_expr( - receiver_documents_sql_string.as_str(), - &contract, - Some(&platform.config.drive), - ) - .expect("expected document query"); + let price: Option = document + .properties() + .get_optional_integer("$price") + .expect("expected to get back price"); - let query_sender_results = platform - .drive - .query_documents( - query_sender_identity_documents.clone(), - None, - false, - None, - None, - ) - .expect("expected query result"); + assert_eq!(price, None); - let query_receiver_results = platform - .drive - .query_documents( - query_receiver_identity_documents.clone(), - None, - false, - None, - None, - ) - .expect("expected query result"); + assert_eq!(document.owner_id(), purchaser.id()); - // We expect the sender to have 0 documents, and the receiver to also have none - assert_eq!(query_sender_results.documents().len(), 0); + // At this point we want to have the sender to try to buy back the document - assert_eq!(query_receiver_results.documents().len(), 0); + document.set_revision(Some(4)); - document.set_revision(Some(2)); + let documents_batch_purchase_transition = + DocumentsBatchTransition::new_document_purchase_transition_from_document( + document.clone(), + card_document_type, + identity.id(), + dash_to_credits!(0.1), //same price as old requested + &key, + 4, // 1 because he's never done anything + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the purchase"); + + let documents_batch_purchase_serialized_transition = + documents_batch_purchase_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![documents_batch_purchase_serialized_transition], + &platform_state, + &BlockInfo::default_with_time(50000000), + &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.invalid_paid_count(), 1); + + let result = processing_result.into_execution_results().remove(0); + + let StateTransitionExecutionResult::PaidConsensusError(consensus_error, _) = result + else { + panic!("expected a paid consensus error"); + }; + assert_eq!( + consensus_error.to_string(), + "5rJccTdtJfg6AxSKyrptWUug3PWjveEitTTLqBn9wHdk document not for sale" + ); + } - let documents_batch_transfer_transition = - DocumentsBatchTransition::new_document_transfer_transition_from_document( - document, - card_document_type, - receiver.id(), - &key, - 3, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition for transfer"); + #[test] + fn test_document_set_price_and_purchase_with_enough_credits_to_buy_but_not_enough_to_pay_for_processing( + ) { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_nft(TradeMode::DirectPurchase); - let documents_batch_transfer_serialized_transition = documents_batch_transfer_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + let mut rng = StdRng::seed_from_u64(433); - let transaction = platform.drive.grove.start_transaction(); + let platform_state = platform.state.load(); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_transfer_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (receiver, recipient_signer, recipient_key) = + setup_identity(&mut platform, 450, dash_to_credits!(0.1)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + assert!(!card_document_type.documents_mutable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = documents_batch_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![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); + + let query_sender_identity_documents = DriveQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), ) - .expect("expected to process state transition"); + .expect("expected document query"); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); + let receiver_documents_sql_string = + format!("select * from card where $ownerId == '{}'", receiver.id()); - assert_eq!(processing_result.invalid_paid_count(), 1); + let query_receiver_identity_documents = DriveQuery::from_sql_expr( + receiver_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); - assert_eq!(processing_result.invalid_unpaid_count(), 0); + // We expect the sender to have 1 document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); - assert_eq!(processing_result.valid_count(), 0); + assert_eq!(query_receiver_results.documents().len(), 0); - assert_eq!(processing_result.aggregated_fees().processing_fee, 25090); + document.set_revision(Some(2)); - let query_sender_results = platform - .drive - .query_documents(query_sender_identity_documents, None, false, None, None) - .expect("expected query result"); + let documents_batch_update_price_transition = + DocumentsBatchTransition::new_document_update_price_transition_from_document( + document.clone(), + card_document_type, + dash_to_credits!(0.1), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the update price"); + + let documents_batch_transfer_serialized_transition = + documents_batch_update_price_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![documents_batch_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(50000000), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - let query_receiver_results = platform - .drive - .query_documents(query_receiver_identity_documents, None, false, None, None) - .expect("expected query result"); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - // We expect the sender to still have no document, and the receiver to have none as well - assert_eq!(query_sender_results.documents().len(), 0); + assert_eq!(processing_result.invalid_paid_count(), 0); - assert_eq!(query_receiver_results.documents().len(), 0); - } + assert_eq!(processing_result.invalid_unpaid_count(), 0); - #[test] - fn test_document_delete_after_transfer() { - let platform_version = PlatformVersion::latest(); - let (mut platform, contract) = TestPlatformBuilder::new() - .build_with_mock_rpc() - .set_initial_state_structure() - .with_crypto_card_game(Transferable::Always); + assert_eq!(processing_result.valid_count(), 1); - let mut rng = StdRng::seed_from_u64(433); + assert_eq!(processing_result.aggregated_fees().processing_fee, 6814950); - let platform_state = platform.state.load(); + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); - let (identity, signer, key) = setup_identity(&mut platform, 958); + // We expect the sender to still have their document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); - let (receiver, recipient_signer, recipient_key) = setup_identity(&mut platform, 450); + assert_eq!(query_receiver_results.documents().len(), 0); - let card_document_type = contract - .document_type_for_name("card") - .expect("expected a profile document type"); + // The sender document should have the desired price - assert!(!card_document_type.documents_mutable()); + let mut document = query_sender_results.documents_owned().remove(0); - let entropy = Bytes32::random_with_rng(&mut rng); + let price: Credits = document + .properties() + .get_integer("$price") + .expect("expected to get back price"); - let mut document = card_document_type - .random_document_with_identifier_and_entropy( - &mut rng, - identity.id(), - entropy, - DocumentFieldFillType::DoNotFillIfNotRequired, - DocumentFieldFillSize::AnyDocumentFillSize, - platform_version, - ) - .expect("expected a random document"); - - document.set("attack", 4.into()); - document.set("defense", 7.into()); - - let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( - document.clone(), - card_document_type, - entropy.0, - &key, - 2, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + assert_eq!(dash_to_credits!(0.1), price); - let documents_batch_create_serialized_transition = documents_batch_create_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + // At this point we want to have the receiver purchase the document - let transaction = platform.drive.grove.start_transaction(); + document.set_revision(Some(3)); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_create_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + let documents_batch_purchase_transition = + DocumentsBatchTransition::new_document_purchase_transition_from_document( + document.clone(), + card_document_type, + receiver.id(), + dash_to_credits!(0.1), //same price as requested + &recipient_key, + 1, // 1 because he's never done anything + 0, + &recipient_signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the purchase"); + + let documents_batch_purchase_serialized_transition = + documents_batch_purchase_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![documents_batch_purchase_serialized_transition], + &platform_state, + &BlockInfo::default_with_time(50000000), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - assert_eq!(processing_result.valid_count(), 1); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); - - let sender_documents_sql_string = - format!("select * from card where $ownerId == '{}'", identity.id()); - - let query_sender_identity_documents = DriveQuery::from_sql_expr( - sender_documents_sql_string.as_str(), - &contract, - Some(&platform.config.drive), - ) - .expect("expected document query"); - - let receiver_documents_sql_string = - format!("select * from card where $ownerId == '{}'", receiver.id()); - - let query_receiver_identity_documents = DriveQuery::from_sql_expr( - receiver_documents_sql_string.as_str(), - &contract, - Some(&platform.config.drive), - ) - .expect("expected document query"); - - let query_sender_results = platform - .drive - .query_documents( - query_sender_identity_documents.clone(), - None, - false, - None, - None, - ) - .expect("expected query result"); + // nothing can go through because the purchaser doesn't have enough balance - let query_receiver_results = platform - .drive - .query_documents( - query_receiver_identity_documents.clone(), - None, - false, - None, - None, - ) - .expect("expected query result"); + assert_eq!(processing_result.invalid_paid_count(), 0); - // We expect the sender to have 1 document, and the receiver to have none - assert_eq!(query_sender_results.documents().len(), 1); + assert_eq!(processing_result.invalid_unpaid_count(), 1); - assert_eq!(query_receiver_results.documents().len(), 0); + assert_eq!(processing_result.valid_count(), 0); - document.set_revision(Some(2)); + assert_eq!(processing_result.aggregated_fees().processing_fee, 0); + } - let documents_batch_transfer_transition = - DocumentsBatchTransition::new_document_transfer_transition_from_document( - document.clone(), - card_document_type, - receiver.id(), - &key, - 3, - 0, - &signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition for transfer"); + #[test] + fn test_document_set_price_on_not_owned_document() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_nft(TradeMode::DirectPurchase); - let documents_batch_transfer_serialized_transition = documents_batch_transfer_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + let mut rng = StdRng::seed_from_u64(433); - let transaction = platform.drive.grove.start_transaction(); + let platform_state = platform.state.load(); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_transfer_serialized_transition.clone()], - &platform_state, - &BlockInfo::default_with_time(50000000), - &transaction, - platform_version, - ) - .expect("expected to process state transition"); + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); + let (other_identity, other_identity_signer, other_identity_key) = + setup_identity(&mut platform, 450, dash_to_credits!(0.1)); - assert_eq!(processing_result.invalid_paid_count(), 0); + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); - assert_eq!(processing_result.invalid_unpaid_count(), 0); + assert!(!card_document_type.documents_mutable()); - assert_eq!(processing_result.valid_count(), 1); + let entropy = Bytes32::random_with_rng(&mut rng); - assert_eq!(processing_result.aggregated_fees().processing_fee, 10277100); + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); - let query_sender_results = platform - .drive - .query_documents(query_sender_identity_documents, None, false, None, None) - .expect("expected query result"); + let documents_batch_create_serialized_transition = documents_batch_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); - let query_receiver_results = platform - .drive - .query_documents(query_receiver_identity_documents, None, false, None, None) - .expect("expected query result"); + let transaction = platform.drive.grove.start_transaction(); - // We expect the sender to have no documents, and the receiver to have 1 - assert_eq!(query_sender_results.documents().len(), 0); + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + document.set_revision(Some(2)); + + document.set_owner_id(other_identity.id()); // we do this to trick the system + + let documents_batch_update_price_transition = + DocumentsBatchTransition::new_document_update_price_transition_from_document( + document.clone(), + card_document_type, + dash_to_credits!(0.1), + &other_identity_key, + 1, + 0, + &other_identity_signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the update price"); + + let documents_batch_transfer_serialized_transition = + documents_batch_update_price_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![documents_batch_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(50000000), + &transaction, + platform_version, + ) + .expect("expected to process state transition"); - assert_eq!(query_receiver_results.documents().len(), 1); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); - // Now let's try to delete the transferred document + assert_eq!(processing_result.invalid_paid_count(), 1); - document.set_owner_id(receiver.id()); + assert_eq!(processing_result.invalid_unpaid_count(), 0); - let documents_batch_deletion_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( - document, - card_document_type, - &recipient_key, - 2, - 0, - &recipient_signer, - platform_version, - None, - None, - None, - ) - .expect("expect to create documents batch transition"); + assert_eq!(processing_result.valid_count(), 0); - let documents_batch_deletion_serialized_transition = documents_batch_deletion_transition - .serialize_to_bytes() - .expect("expected documents batch serialized state transition"); + assert_eq!(processing_result.aggregated_fees().processing_fee, 25090); - let transaction = platform.drive.grove.start_transaction(); + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![documents_batch_deletion_serialized_transition.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, + let query_sender_identity_documents = DriveQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), ) - .expect("expected to process state transition"); + .expect("expected document query"); - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit transaction"); + let query_sender_results = platform + .drive + .query_documents(query_sender_identity_documents, None, false, None, None) + .expect("expected query result"); - assert_eq!(processing_result.invalid_paid_count(), 1); + // The sender document should not have the desired price - assert_eq!(processing_result.invalid_unpaid_count(), 0); + let document = query_sender_results.documents().first().unwrap(); - assert_eq!(processing_result.valid_count(), 0); - - assert_eq!(processing_result.aggregated_fees().processing_fee, 1107610); + assert_eq!( + document + .properties() + .get_optional_integer::("$price") + .expect("expected None"), + None + ); + } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/mod.rs index d65b0892893..ad7ed837616 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/mod.rs @@ -16,8 +16,10 @@ use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::execution::validation::state_transition::documents_batch::action_validation::document_create_transition_action::DocumentCreateTransitionActionValidation; use crate::execution::validation::state_transition::documents_batch::action_validation::document_delete_transition_action::DocumentDeleteTransitionActionValidation; +use crate::execution::validation::state_transition::documents_batch::action_validation::document_purchase_transition_action::DocumentPurchaseTransitionActionValidation; use crate::execution::validation::state_transition::documents_batch::action_validation::document_replace_transition_action::DocumentReplaceTransitionActionValidation; use crate::execution::validation::state_transition::documents_batch::action_validation::document_transfer_transition_action::DocumentTransferTransitionActionValidation; +use crate::execution::validation::state_transition::documents_batch::action_validation::document_update_price_transition_action::DocumentUpdatePriceTransitionActionValidation; use crate::execution::validation::state_transition::documents_batch::data_triggers::{data_trigger_bindings_list, DataTriggerExecutionContext, DataTriggerExecutor}; use crate::platform_types::platform::{PlatformStateRef}; use crate::execution::validation::state_transition::state_transitions::documents_batch::transformer::v0::DocumentsBatchTransitionTransformerV0; @@ -111,6 +113,25 @@ impl DocumentsBatchStateTransitionStateValidationV0 for DocumentsBatchTransition transaction, platform_version, )?, + DocumentTransitionAction::UpdatePriceAction(update_price_action) => { + update_price_action.validate_state( + platform, + owner_id, + epoch, + execution_context, + transaction, + platform_version, + )? + } + DocumentTransitionAction::PurchaseAction(purchase_action) => purchase_action + .validate_state( + platform, + owner_id, + epoch, + execution_context, + transaction, + platform_version, + )?, DocumentTransitionAction::BumpIdentityDataContractNonce(..) => { return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( "we should never start with a bump identity data contract nonce", diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/v0/mod.rs index 07ae9b5e7e7..96fa641efac 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/v0/mod.rs @@ -15,7 +15,12 @@ use dpp::consensus::state::state_error::StateError; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::block::block_info::BlockInfo; +use dpp::consensus::state::document::document_incorrect_purchase_price_error::DocumentIncorrectPurchasePriceError; +use dpp::consensus::state::document::document_not_for_sale_error::DocumentNotForSaleError; +use dpp::document::property_names::PRICE; use dpp::document::{Document, DocumentV0Getters}; +use dpp::fee::Credits; +use dpp::platform_value::btreemap_extensions::BTreeValueMapHelper; use dpp::prelude::Revision; use dpp::validation::SimpleConsensusValidationResult; use dpp::{consensus::ConsensusError, prelude::Identifier, validation::ConsensusValidationResult}; @@ -24,6 +29,7 @@ use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; use dpp::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; use dpp::state_transition::documents_batch_transition::document_transition::{DocumentTransition, DocumentTransitionV0Methods}; +use dpp::state_transition::documents_batch_transition::document_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; use dpp::state_transition::StateTransitionLike; use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentCreateTransitionAction; use drive::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; @@ -38,8 +44,11 @@ use drive::grovedb::TransactionArg; use dpp::state_transition::documents_batch_transition::document_transition::document_replace_transition::v0::v0_methods::DocumentReplaceTransitionV0Methods; use dpp::state_transition::documents_batch_transition::document_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; +use dpp::state_transition::documents_batch_transition::document_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; use drive::drive::contract::DataContractFetchInfo; +use drive::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionAction; use drive::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::DocumentTransferTransitionAction; +use drive::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionAction; use drive::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; @@ -273,7 +282,10 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition .filter(|transition| { matches!( transition, - DocumentTransition::Replace(_) | DocumentTransition::Transfer(_) + DocumentTransition::Replace(_) + | DocumentTransition::Transfer(_) + | DocumentTransition::Purchase(_) + | DocumentTransition::UpdatePrice(_) ) }) .copied() @@ -345,9 +357,10 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition DocumentTransition::Create(document_create_transition) => { let result = ConsensusValidationResult::::new(); - let document_create_action = DocumentCreateTransitionAction::from_document_borrowed_create_transition_with_contract_lookup(document_create_transition, block_info, |_identifier| { - Ok(data_contract_fetch_info.clone()) - })?; + let document_create_action = DocumentCreateTransitionAction::from_document_borrowed_create_transition_with_contract_lookup( + document_create_transition, block_info, |_identifier| { + Ok(data_contract_fetch_info.clone()) + })?; if result.is_valid() { Ok(DocumentTransitionAction::CreateAction(document_create_action).into()) @@ -502,6 +515,128 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition Ok(result) } } + DocumentTransition::UpdatePrice(document_update_price_transition) => { + let mut result = ConsensusValidationResult::::new(); + + let validation_result = + Self::find_replaced_document_v0(transition, replaced_documents); + + if !validation_result.is_valid_with_data() { + result.merge(validation_result); + return Ok(result); + } + + let original_document = validation_result.into_data()?; + + let validation_result = Self::check_ownership_of_old_replaced_document_v0( + document_update_price_transition.base().id(), + original_document, + &owner_id, + ); + + if !validation_result.is_valid() { + result.merge(validation_result); + return Ok(result); + } + + if validate_against_state { + //there are situations where we don't want to validate this against the state + // for example when we already applied the state transition action + // and we are just validating it happened + let validation_result = Self::check_revision_is_bumped_by_one_during_replace_v0( + document_update_price_transition.revision(), + document_update_price_transition.base().id(), + original_document, + ); + + if !validation_result.is_valid() { + result.merge(validation_result); + return Ok(result); + } + } + + let document_update_price_action = + DocumentUpdatePriceTransitionAction::try_from_borrowed_document_update_price_transition( + document_update_price_transition, + original_document.clone(), //todo: find a way to not have to use cloning + block_info, + |_identifier| Ok(data_contract_fetch_info.clone()), + )?; + + if result.is_valid() { + Ok( + DocumentTransitionAction::UpdatePriceAction(document_update_price_action) + .into(), + ) + } else { + Ok(result) + } + } + DocumentTransition::Purchase(document_purchase_transition) => { + let mut result = ConsensusValidationResult::::new(); + + let validation_result = + Self::find_replaced_document_v0(transition, replaced_documents); + + if !validation_result.is_valid_with_data() { + result.merge(validation_result); + return Ok(result); + } + + let original_document = validation_result.into_data()?; + + let Some(listed_price) = original_document + .properties() + .get_optional_integer::(PRICE)? + else { + result.add_error(StateError::DocumentNotForSaleError( + DocumentNotForSaleError::new(original_document.id()), + )); + return Ok(result); + }; + + if listed_price != document_purchase_transition.price() { + result.add_error(StateError::DocumentIncorrectPurchasePriceError( + DocumentIncorrectPurchasePriceError::new( + original_document.id(), + document_purchase_transition.price(), + listed_price, + ), + )); + return Ok(result); + } + + if validate_against_state { + //there are situations where we don't want to validate this against the state + // for example when we already applied the state transition action + // and we are just validating it happened + let validation_result = Self::check_revision_is_bumped_by_one_during_replace_v0( + document_purchase_transition.revision(), + document_purchase_transition.base().id(), + original_document, + ); + + if !validation_result.is_valid() { + result.merge(validation_result); + return Ok(result); + } + } + + let document_purchase_action = + DocumentPurchaseTransitionAction::try_from_borrowed_document_purchase_transition( + document_purchase_transition, + original_document.clone(), //todo: find a way to not have to use cloning + owner_id, + block_info, + |_identifier| Ok(data_contract_fetch_info.clone()), + )?; + + if result.is_valid() { + Ok(DocumentTransitionAction::PurchaseAction(document_purchase_action).into()) + } else { + Ok(result) + } + } } } diff --git a/packages/rs-drive-abci/src/test/helpers/setup.rs b/packages/rs-drive-abci/src/test/helpers/setup.rs index a3971dc066c..45ab6a0e36b 100644 --- a/packages/rs-drive-abci/src/test/helpers/setup.rs +++ b/packages/rs-drive-abci/src/test/helpers/setup.rs @@ -41,6 +41,7 @@ use crate::test::fixture::abci::static_system_identity_public_keys_v0; use crate::{config::PlatformConfig, rpc::core::DefaultCoreRPC}; use dpp::block::block_info::BlockInfo; use dpp::document::transfer::Transferable; +use dpp::nft::TradeMode; use dpp::prelude::DataContract; use dpp::tests::json_document::json_document_to_contract; use dpp::version::PlatformVersion; @@ -125,7 +126,10 @@ impl TempPlatform { } /// A function which adds the crypto card game to the state and returns it. - pub fn with_crypto_card_game(self, transferable: Transferable) -> (Self, DataContract) { + pub fn with_crypto_card_game_transfer_only( + self, + transferable: Transferable, + ) -> (Self, DataContract) { let card_game_path = match transferable { Transferable::Never => "tests/supporting_files/contract/crypto-card-game/crypto-card-game-not-transferable.json", Transferable::Always => "tests/supporting_files/contract/crypto-card-game/crypto-card-game-all-transferable.json", @@ -155,6 +159,37 @@ impl TempPlatform { (self, card_game_contract) } + /// A function which adds the crypto card game to the state and returns it. + pub fn with_crypto_card_game_nft(self, marketplace: TradeMode) -> (Self, DataContract) { + let card_game_path = match marketplace { + TradeMode::DirectPurchase => "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json", + _ => panic!("not yet supported") + }; + + let platform_version = self + .platform + .state + .load() + .current_platform_version() + .expect("expected to get current platform version"); + + // let's construct the grovedb structure for the card game data contract + let card_game_contract = json_document_to_contract(card_game_path, true, platform_version) + .expect("expected to get data contract"); + self.drive + .apply_contract( + &card_game_contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + (self, card_game_contract) + } + /// Sets Platform to genesis state. pub fn set_genesis_state(self) -> Self { self.platform diff --git a/packages/rs-drive-abci/tests/strategy_tests/main.rs b/packages/rs-drive-abci/tests/strategy_tests/main.rs index 1f0d30beb48..812cf5f846f 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/main.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/main.rs @@ -1088,7 +1088,7 @@ mod tests { .unwrap() .unwrap() ), - "547963a6f85f531173493bc145bdec8796bfd4d61240ef108c3a2644175939eb".to_string() + "3beaf287fb5fb712715e688ef3cf642e3e4042270907ebd022050b06af0cb433".to_string() ) } @@ -1217,6 +1217,7 @@ mod tests { }, keep_history_chance: 1.0, documents_mutable_chance: 1.0, + documents_can_be_deleted_chance: 1.0, }, 30..31, ), @@ -1777,7 +1778,7 @@ mod tests { .unwrap() .unwrap() ), - "2609439c79ea50f6f6a2d4e4f357f710097fa2fab8a196e35c176689b2f2687a".to_string() + "c0c1f59b535f358448a33c20b419b93bcfa12b05b221f77a7347892f48ca2f16".to_string() ) } @@ -1902,7 +1903,7 @@ mod tests { .unwrap() .unwrap() ), - "58b927769fb1782259883aa91a91a60c6d451cc5f95d3e0d905abcd9ff61f434".to_string() + "a7be306dcdf58930dc14befa2b78c839d66699cf9d454942ac9c595161ffe99e".to_string() ) } diff --git a/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs b/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs index 13910492ef1..0a097575679 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs @@ -7,6 +7,7 @@ use dpp::document::{Document, DocumentV0Getters}; use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; use dpp::asset_lock::reduced_asset_lock_value::AssetLockValueGettersV0; +use dpp::document::property_names::PRICE; use dpp::state_transition::StateTransition; use dpp::version::PlatformVersion; use drive::drive::identity::key::fetch::IdentityKeysRequest; @@ -22,8 +23,10 @@ use tenderdash_abci::proto::abci::ExecTxResult; use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentFromCreateTransitionAction; +use drive::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionActionAccessorsV0; use drive::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::DocumentFromReplaceTransitionAction; use drive::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::DocumentTransferTransitionActionAccessorsV0; +use drive::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionActionAccessorsV0; use drive_abci::abci::app::FullAbciApplication; use drive_abci::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use drive_abci::execution::validation::state_transition::ValidationMode; @@ -404,6 +407,44 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( } } } + DocumentTransitionAction::PurchaseAction(purchase_action) => { + if *was_executed { + if let Some(document) = document { + assert_eq!( + document.owner_id(), + purchase_action.document().owner_id() + ); + } + } else { + //there is the possibility that the state transition was not executed and the state is equal to the previous + // state, aka there would have been no change anyways, we can discount that for now + if let Some(document) = document { + assert_ne!( + document.owner_id(), + purchase_action.document().owner_id() + ); + } + } + } + DocumentTransitionAction::UpdatePriceAction(update_price_action) => { + if *was_executed { + if let Some(document) = document { + assert_eq!( + document.get(PRICE), + update_price_action.document().get(PRICE) + ); + } + } else { + //there is the possibility that the state transition was not executed and the state is equal to the previous + // state, aka there would have been no change anyways, we can discount that for now + if let Some(document) = document { + assert_ne!( + document.get(PRICE), + update_price_action.document().get(PRICE) + ); + } + } + } } } } diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-all-transferable-no-owner-indexes.json b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-all-transferable-no-owner-indexes.json new file mode 100644 index 00000000000..aa852c13bbe --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-all-transferable-no-owner-indexes.json @@ -0,0 +1,114 @@ +{ + "$format_version": "0", + "id": "86LHvdC1Tqx5P97LQUSibGFqf2vnKFpB6VkqQ7oso86e", + "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", + "version": 1, + "documentSchemas": { + "card": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": false, + "transferable": 1, + "properties": { + "name": { + "type": "string", + "description": "Name of the card", + "maxLength": 63, + "position": 0 + }, + "description": { + "type": "string", + "description": "Description of the card", + "maxLength": 256, + "position": 1 + }, + "imageUrl": { + "type": "string", + "description": "URL of the image associated with the card", + "maxLength": 2048, + "format": "uri", + "position": 2 + }, + "imageHash": { + "type": "array", + "description": "SHA256 hash of the bytes of the image specified by imageUrl", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 3 + }, + "imageFingerprint": { + "type": "array", + "description": "dHash of the image specified by imageUrl", + "byteArray": true, + "minItems": 8, + "maxItems": 8, + "position": 4 + }, + "attack": { + "type": "integer", + "description": "Attack power of the card", + "minimum": 0, + "position": 5 + }, + "defense": { + "type": "integer", + "description": "Defense level of the card", + "minimum": 0, + "position": 6 + } + }, + "indices": [ + { + "name": "attack", + "properties": [ + { + "attack": "asc" + } + ] + }, + { + "name": "defense", + "properties": [ + { + "defense": "asc" + } + ] + }, + { + "name": "transferredAt", + "properties": [ + { + "$transferredAt": "asc" + } + ] + }, + { + "name": "transferredAtBlockHeight", + "properties": [ + { + "$transferredAtBlockHeight": "asc" + } + ] + }, + { + "name": "transferredAtCoreBlockHeight", + "properties": [ + { + "$transferredAtCoreBlockHeight": "asc" + } + ] + } + ], + "required": [ + "name", + "$transferredAt", + "$transferredAtBlockHeight", + "$transferredAtCoreBlockHeight", + "attack", + "defense" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-all-transferable.json b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-all-transferable.json index b14e8fe5adc..88a6c22aa98 100644 --- a/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-all-transferable.json +++ b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-all-transferable.json @@ -7,6 +7,7 @@ "card": { "type": "object", "documentsMutable": false, + "canBeDeleted": false, "transferable": 1, "properties": { "name": { diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase-creation-restricted-to-owner.json b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase-creation-restricted-to-owner.json new file mode 100644 index 00000000000..3a1c2daeccd --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase-creation-restricted-to-owner.json @@ -0,0 +1,135 @@ +{ + "$format_version": "0", + "id": "86LHvdC1Tqx5P97LQUSibGFqf2vnKFpB6VkqQ7oso86e", + "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", + "version": 1, + "documentSchemas": { + "card": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": true, + "transferable": 1, + "tradeMode": 1, + "creationRestrictionMode": 1, + "properties": { + "name": { + "type": "string", + "description": "Name of the card", + "maxLength": 63, + "position": 0 + }, + "description": { + "type": "string", + "description": "Description of the card", + "maxLength": 256, + "position": 1 + }, + "imageUrl": { + "type": "string", + "description": "URL of the image associated with the card", + "maxLength": 2048, + "format": "uri", + "position": 2 + }, + "imageHash": { + "type": "array", + "description": "SHA256 hash of the bytes of the image specified by imageUrl", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 3 + }, + "imageFingerprint": { + "type": "array", + "description": "dHash of the image specified by imageUrl", + "byteArray": true, + "minItems": 8, + "maxItems": 8, + "position": 4 + }, + "attack": { + "type": "integer", + "description": "Attack power of the card", + "minimum": 0, + "position": 5 + }, + "defense": { + "type": "integer", + "description": "Defense level of the card", + "minimum": 0, + "position": 6 + } + }, + "indices": [ + { + "name": "owner", + "properties": [ + { + "$ownerId": "asc" + } + ] + }, + { + "name": "attack", + "properties": [ + { + "attack": "asc" + } + ] + }, + { + "name": "defense", + "properties": [ + { + "defense": "asc" + } + ] + }, + { + "name": "transferredAt", + "properties": [ + { + "$transferredAt": "asc" + } + ] + }, + { + "name": "ownerTransferredAt", + "properties": [ + { + "$ownerId": "asc" + }, + { + "$transferredAt": "asc" + } + ] + }, + { + "name": "transferredAtBlockHeight", + "properties": [ + { + "$transferredAtBlockHeight": "asc" + } + ] + }, + { + "name": "transferredAtCoreBlockHeight", + "properties": [ + { + "$transferredAtCoreBlockHeight": "asc" + } + ] + } + ], + "required": [ + "name", + "$transferredAt", + "$transferredAtBlockHeight", + "$transferredAtCoreBlockHeight", + "attack", + "defense" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json new file mode 100644 index 00000000000..0dbc7641d5a --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json @@ -0,0 +1,134 @@ +{ + "$format_version": "0", + "id": "86LHvdC1Tqx5P97LQUSibGFqf2vnKFpB6VkqQ7oso86e", + "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", + "version": 1, + "documentSchemas": { + "card": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": true, + "transferable": 1, + "tradeMode": 1, + "properties": { + "name": { + "type": "string", + "description": "Name of the card", + "maxLength": 63, + "position": 0 + }, + "description": { + "type": "string", + "description": "Description of the card", + "maxLength": 256, + "position": 1 + }, + "imageUrl": { + "type": "string", + "description": "URL of the image associated with the card", + "maxLength": 2048, + "format": "uri", + "position": 2 + }, + "imageHash": { + "type": "array", + "description": "SHA256 hash of the bytes of the image specified by imageUrl", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 3 + }, + "imageFingerprint": { + "type": "array", + "description": "dHash of the image specified by imageUrl", + "byteArray": true, + "minItems": 8, + "maxItems": 8, + "position": 4 + }, + "attack": { + "type": "integer", + "description": "Attack power of the card", + "minimum": 0, + "position": 5 + }, + "defense": { + "type": "integer", + "description": "Defense level of the card", + "minimum": 0, + "position": 6 + } + }, + "indices": [ + { + "name": "owner", + "properties": [ + { + "$ownerId": "asc" + } + ] + }, + { + "name": "attack", + "properties": [ + { + "attack": "asc" + } + ] + }, + { + "name": "defense", + "properties": [ + { + "defense": "asc" + } + ] + }, + { + "name": "transferredAt", + "properties": [ + { + "$transferredAt": "asc" + } + ] + }, + { + "name": "ownerTransferredAt", + "properties": [ + { + "$ownerId": "asc" + }, + { + "$transferredAt": "asc" + } + ] + }, + { + "name": "transferredAtBlockHeight", + "properties": [ + { + "$transferredAtBlockHeight": "asc" + } + ] + }, + { + "name": "transferredAtCoreBlockHeight", + "properties": [ + { + "$transferredAtCoreBlockHeight": "asc" + } + ] + } + ], + "required": [ + "name", + "$transferredAt", + "$transferredAtBlockHeight", + "$transferredAtCoreBlockHeight", + "attack", + "defense" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/dashpay/dashpay-contract-contact-request-mutable-and-can-not-be-deleted.json b/packages/rs-drive-abci/tests/supporting_files/contract/dashpay/dashpay-contract-contact-request-mutable-and-can-not-be-deleted.json new file mode 100644 index 00000000000..1011c390f05 --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/dashpay/dashpay-contract-contact-request-mutable-and-can-not-be-deleted.json @@ -0,0 +1,234 @@ +{ + "$format_version": "0", + "id": "8MjTnX7JUbGfYYswyuCtHU7ZqcYU9s1fUaNiqD9s5tEw", + "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", + "version": 1, + "documentSchemas": { + "profile": { + "type": "object", + "indices": [ + { + "name": "ownerId", + "properties": [ + { + "$ownerId": "asc" + } + ], + "unique": true + }, + { + "name": "ownerIdUpdatedAt", + "properties": [ + { + "$ownerId": "asc" + }, + { + "$updatedAt": "asc" + } + ] + } + ], + "properties": { + "avatarUrl": { + "type": "string", + "format": "uri", + "maxLength": 2048, + "position": 0 + }, + "publicMessage": { + "type": "string", + "maxLength": 140, + "position": 1 + }, + "displayName": { + "type": "string", + "maxLength": 25, + "position": 2 + } + }, + "required": [ + "$createdAt", + "$updatedAt" + ], + "additionalProperties": false + }, + "contactInfo": { + "type": "object", + "indices": [ + { + "name": "ownerIdKeyIndexes", + "properties": [ + { + "$ownerId": "asc" + }, + { + "rootEncryptionKeyIndex": "asc" + }, + { + "derivationEncryptionKeyIndex": "asc" + } + ], + "unique": true + }, + { + "name": "owner_updated", + "properties": [ + { + "$ownerId": "asc" + }, + { + "$updatedAt": "asc" + } + ] + } + ], + "properties": { + "encToUserId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 0 + }, + "rootEncryptionKeyIndex": { + "type": "integer", + "position": 1 + }, + "derivationEncryptionKeyIndex": { + "type": "integer", + "position": 2 + }, + "privateData": { + "type": "array", + "byteArray": true, + "minItems": 48, + "maxItems": 2048, + "position": 3, + "description": "This is the encrypted values of aliasName + note + displayHidden encoded as an array in cbor" + } + }, + "required": [ + "$createdAt", + "$updatedAt", + "encToUserId", + "privateData", + "rootEncryptionKeyIndex", + "derivationEncryptionKeyIndex" + ], + "additionalProperties": false + }, + "contactRequest": { + "documentsMutable": true, + "canBeDeleted": false, + "requiresIdentityEncryptionBoundedKey": 2, + "requiresIdentityDecryptionBoundedKey": 2, + "type": "object", + "indices": [ + { + "name": "owner_user_ref", + "properties": [ + { + "$ownerId": "asc" + }, + { + "toUserId": "asc" + }, + { + "accountReference": "asc" + } + ], + "unique": true + }, + { + "name": "ownerId_toUserId", + "properties": [ + { + "$ownerId": "asc" + }, + { + "toUserId": "asc" + } + ] + }, + { + "name": "toUserId_$createdAt", + "properties": [ + { + "toUserId": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "$ownerId_$createdAt", + "properties": [ + { + "$ownerId": "asc" + }, + { + "$createdAt": "asc" + } + ] + } + ], + "properties": { + "toUserId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 0 + }, + "encryptedPublicKey": { + "type": "array", + "byteArray": true, + "minItems": 96, + "maxItems": 96, + "position": 1 + }, + "senderKeyIndex": { + "type": "integer", + "position": 2 + }, + "recipientKeyIndex": { + "type": "integer", + "position": 3 + }, + "accountReference": { + "type": "integer", + "position": 4 + }, + "encryptedAccountLabel": { + "type": "array", + "byteArray": true, + "minItems": 48, + "maxItems": 80, + "position": 5 + }, + "autoAcceptProof": { + "type": "array", + "byteArray": true, + "minItems": 38, + "maxItems": 102, + "position": 6 + }, + "coreHeightCreatedAt": { + "type": "integer", + "minimum": 1, + "position": 7 + } + }, + "required": [ + "$createdAt", + "toUserId", + "encryptedPublicKey", + "senderKeyIndex", + "recipientKeyIndex", + "accountReference" + ], + "additionalProperties": false + } + } +} diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/dashpay/dashpay-contract-contact-request-not-mutable-and-can-be-deleted.json b/packages/rs-drive-abci/tests/supporting_files/contract/dashpay/dashpay-contract-contact-request-not-mutable-and-can-be-deleted.json new file mode 100644 index 00000000000..bda8b4f7293 --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/dashpay/dashpay-contract-contact-request-not-mutable-and-can-be-deleted.json @@ -0,0 +1,234 @@ +{ + "$format_version": "0", + "id": "8MjTnX7JUbGfYYswyuCtHU7ZqcYU9s1fUaNiqD9s5tEw", + "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", + "version": 1, + "documentSchemas": { + "profile": { + "type": "object", + "indices": [ + { + "name": "ownerId", + "properties": [ + { + "$ownerId": "asc" + } + ], + "unique": true + }, + { + "name": "ownerIdUpdatedAt", + "properties": [ + { + "$ownerId": "asc" + }, + { + "$updatedAt": "asc" + } + ] + } + ], + "properties": { + "avatarUrl": { + "type": "string", + "format": "uri", + "maxLength": 2048, + "position": 0 + }, + "publicMessage": { + "type": "string", + "maxLength": 140, + "position": 1 + }, + "displayName": { + "type": "string", + "maxLength": 25, + "position": 2 + } + }, + "required": [ + "$createdAt", + "$updatedAt" + ], + "additionalProperties": false + }, + "contactInfo": { + "type": "object", + "indices": [ + { + "name": "ownerIdKeyIndexes", + "properties": [ + { + "$ownerId": "asc" + }, + { + "rootEncryptionKeyIndex": "asc" + }, + { + "derivationEncryptionKeyIndex": "asc" + } + ], + "unique": true + }, + { + "name": "owner_updated", + "properties": [ + { + "$ownerId": "asc" + }, + { + "$updatedAt": "asc" + } + ] + } + ], + "properties": { + "encToUserId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 0 + }, + "rootEncryptionKeyIndex": { + "type": "integer", + "position": 1 + }, + "derivationEncryptionKeyIndex": { + "type": "integer", + "position": 2 + }, + "privateData": { + "type": "array", + "byteArray": true, + "minItems": 48, + "maxItems": 2048, + "position": 3, + "description": "This is the encrypted values of aliasName + note + displayHidden encoded as an array in cbor" + } + }, + "required": [ + "$createdAt", + "$updatedAt", + "encToUserId", + "privateData", + "rootEncryptionKeyIndex", + "derivationEncryptionKeyIndex" + ], + "additionalProperties": false + }, + "contactRequest": { + "documentsMutable": false, + "canBeDeleted": true, + "requiresIdentityEncryptionBoundedKey": 2, + "requiresIdentityDecryptionBoundedKey": 2, + "type": "object", + "indices": [ + { + "name": "owner_user_ref", + "properties": [ + { + "$ownerId": "asc" + }, + { + "toUserId": "asc" + }, + { + "accountReference": "asc" + } + ], + "unique": true + }, + { + "name": "ownerId_toUserId", + "properties": [ + { + "$ownerId": "asc" + }, + { + "toUserId": "asc" + } + ] + }, + { + "name": "toUserId_$createdAt", + "properties": [ + { + "toUserId": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "$ownerId_$createdAt", + "properties": [ + { + "$ownerId": "asc" + }, + { + "$createdAt": "asc" + } + ] + } + ], + "properties": { + "toUserId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 0 + }, + "encryptedPublicKey": { + "type": "array", + "byteArray": true, + "minItems": 96, + "maxItems": 96, + "position": 1 + }, + "senderKeyIndex": { + "type": "integer", + "position": 2 + }, + "recipientKeyIndex": { + "type": "integer", + "position": 3 + }, + "accountReference": { + "type": "integer", + "position": 4 + }, + "encryptedAccountLabel": { + "type": "array", + "byteArray": true, + "minItems": 48, + "maxItems": 80, + "position": 5 + }, + "autoAcceptProof": { + "type": "array", + "byteArray": true, + "minItems": 38, + "maxItems": 102, + "position": 6 + }, + "coreHeightCreatedAt": { + "type": "integer", + "minimum": 1, + "position": 7 + } + }, + "required": [ + "$createdAt", + "toUserId", + "encryptedPublicKey", + "senderKeyIndex", + "recipientKeyIndex", + "accountReference" + ], + "additionalProperties": false + } + } +} diff --git a/packages/rs-drive-proof-verifier/Cargo.toml b/packages/rs-drive-proof-verifier/Cargo.toml index 28d9a19f72f..b1afb8ade4c 100644 --- a/packages/rs-drive-proof-verifier/Cargo.toml +++ b/packages/rs-drive-proof-verifier/Cargo.toml @@ -13,7 +13,7 @@ json = ["dep:serde_json"] [dependencies] -thiserror = { version = "1.0.58" } +thiserror = { version = "1.0.59" } dapi-grpc = { path = "../dapi-grpc" } drive = { path = "../rs-drive", default-features = false, features = [ "verify", diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index a29d414f177..dedd0375754 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -26,7 +26,7 @@ sqlparser = { version = "0.38.0" } # used for int maps and needed in the verifier nohash-hasher = { version = "0.2.0" } dpp = { path = "../rs-dpp", features = ["state-transitions"], default-features = false, optional = true } -thiserror = { version = "1.0.58" } +thiserror = { version = "1.0.59" } tracing = { version = "0.1.37", default-features = false, features = [] } derive_more = { version = "0.99.17", optional = true} @@ -45,10 +45,10 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "2.0.0", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.11.0", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev = "f5a3382c5537de7417e983cdf2132792aa9fdc9d", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "f5a3382c5537de7417e983cdf2132792aa9fdc9d", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "f5a3382c5537de7417e983cdf2132792aa9fdc9d" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "f5a3382c5537de7417e983cdf2132792aa9fdc9d", optional = true } +grovedb = { git = "https://github.com/dashpay/grovedb", rev = "941dd86d70c86e7a236541919e789dba078abae6", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "941dd86d70c86e7a236541919e789dba078abae6", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "941dd86d70c86e7a236541919e789dba078abae6" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "941dd86d70c86e7a236541919e789dba078abae6", optional = true } [dev-dependencies] criterion = "0.3.5" diff --git a/packages/rs-drive/src/drive/batch/transitions/document/document_purchase_transition.rs b/packages/rs-drive/src/drive/batch/transitions/document/document_purchase_transition.rs new file mode 100644 index 00000000000..97d9cf38164 --- /dev/null +++ b/packages/rs-drive/src/drive/batch/transitions/document/document_purchase_transition.rs @@ -0,0 +1,61 @@ +use crate::drive::batch::transitions::document::DriveHighLevelDocumentOperationConverter; +use crate::drive::batch::DriveOperation::{DocumentOperation, IdentityOperation}; +use crate::drive::batch::{DocumentOperationType, DriveOperation, IdentityOperationType}; +use crate::drive::flags::StorageFlags; +use crate::drive::object_size_info::DocumentInfo::DocumentOwnedInfo; +use crate::drive::object_size_info::OwnedDocumentInfo; +use crate::error::Error; +use dpp::block::epoch::Epoch; + +use dpp::prelude::Identifier; +use std::borrow::Cow; +use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; +use dpp::version::PlatformVersion; + +impl DriveHighLevelDocumentOperationConverter for DocumentPurchaseTransitionAction { + fn into_high_level_document_drive_operations<'b>( + self, + epoch: &Epoch, + owner_id: Identifier, + _platform_version: &PlatformVersion, + ) -> Result>, Error> { + let data_contract_id = self.base().data_contract_id(); + let document_type_name = self.base().document_type_name().clone(); + let identity_contract_nonce = self.base().identity_contract_nonce(); + let original_owner_id = self.original_owner_id(); + let purchase_amount = self.price(); + let document = self.document_owned(); + + // we are purchasing the document so the new storage flags should be on the new owner + + let new_document_owner_id = owner_id; + + let storage_flags = + StorageFlags::new_single_epoch(epoch.index, Some(new_document_owner_id.to_buffer())); + + Ok(vec![ + IdentityOperation(IdentityOperationType::UpdateIdentityContractNonce { + identity_id: owner_id.into_buffer(), + contract_id: data_contract_id.into_buffer(), + nonce: identity_contract_nonce, + }), + DocumentOperation(DocumentOperationType::UpdateDocument { + owned_document_info: OwnedDocumentInfo { + document_info: DocumentOwnedInfo((document, Some(Cow::Owned(storage_flags)))), + owner_id: Some(new_document_owner_id.into_buffer()), + }, + contract_id: data_contract_id, + document_type_name: Cow::Owned(document_type_name), + }), + IdentityOperation(IdentityOperationType::RemoveFromIdentityBalance { + identity_id: owner_id.to_buffer(), + balance_to_remove: purchase_amount, + }), + IdentityOperation(IdentityOperationType::AddToIdentityBalance { + identity_id: original_owner_id.to_buffer(), + added_balance: purchase_amount, + }), + ]) + } +} diff --git a/packages/rs-drive/src/drive/batch/transitions/document/document_transition.rs b/packages/rs-drive/src/drive/batch/transitions/document/document_transition.rs index c141cae6c46..e902db925f2 100644 --- a/packages/rs-drive/src/drive/batch/transitions/document/document_transition.rs +++ b/packages/rs-drive/src/drive/batch/transitions/document/document_transition.rs @@ -43,6 +43,20 @@ impl DriveHighLevelDocumentOperationConverter for DocumentTransitionAction { platform_version, ) } + DocumentTransitionAction::PurchaseAction(document_purchase_transition) => { + document_purchase_transition.into_high_level_document_drive_operations( + epoch, + owner_id, + platform_version, + ) + } + DocumentTransitionAction::UpdatePriceAction(document_update_price_transition) => { + document_update_price_transition.into_high_level_document_drive_operations( + epoch, + owner_id, + platform_version, + ) + } DocumentTransitionAction::BumpIdentityDataContractNonce( bump_identity_contract_nonce_action, ) => bump_identity_contract_nonce_action diff --git a/packages/rs-drive/src/drive/batch/transitions/document/document_update_price_transition.rs b/packages/rs-drive/src/drive/batch/transitions/document/document_update_price_transition.rs new file mode 100644 index 00000000000..835af6aa21f --- /dev/null +++ b/packages/rs-drive/src/drive/batch/transitions/document/document_update_price_transition.rs @@ -0,0 +1,46 @@ +use crate::drive::batch::transitions::document::DriveHighLevelDocumentOperationConverter; +use crate::drive::batch::DriveOperation::{DocumentOperation, IdentityOperation}; +use crate::drive::batch::{DocumentOperationType, DriveOperation, IdentityOperationType}; +use crate::drive::flags::StorageFlags; +use crate::drive::object_size_info::DocumentInfo::DocumentOwnedInfo; +use crate::drive::object_size_info::OwnedDocumentInfo; +use crate::error::Error; +use dpp::block::epoch::Epoch; + +use dpp::prelude::Identifier; +use std::borrow::Cow; +use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; +use dpp::version::PlatformVersion; + +impl DriveHighLevelDocumentOperationConverter for DocumentUpdatePriceTransitionAction { + fn into_high_level_document_drive_operations<'b>( + self, + epoch: &Epoch, + owner_id: Identifier, + _platform_version: &PlatformVersion, + ) -> Result>, Error> { + let data_contract_id = self.base().data_contract_id(); + let document_type_name = self.base().document_type_name().clone(); + let identity_contract_nonce = self.base().identity_contract_nonce(); + let document = self.document_owned(); + + let storage_flags = StorageFlags::new_single_epoch(epoch.index, Some(owner_id.to_buffer())); + + Ok(vec![ + IdentityOperation(IdentityOperationType::UpdateIdentityContractNonce { + identity_id: owner_id.into_buffer(), + contract_id: data_contract_id.into_buffer(), + nonce: identity_contract_nonce, + }), + DocumentOperation(DocumentOperationType::UpdateDocument { + owned_document_info: OwnedDocumentInfo { + document_info: DocumentOwnedInfo((document, Some(Cow::Owned(storage_flags)))), + owner_id: Some(owner_id.into_buffer()), + }, + contract_id: data_contract_id, + document_type_name: Cow::Owned(document_type_name), + }), + ]) + } +} diff --git a/packages/rs-drive/src/drive/batch/transitions/document/mod.rs b/packages/rs-drive/src/drive/batch/transitions/document/mod.rs index b7df757580c..46ec23550ea 100644 --- a/packages/rs-drive/src/drive/batch/transitions/document/mod.rs +++ b/packages/rs-drive/src/drive/batch/transitions/document/mod.rs @@ -6,9 +6,11 @@ use dpp::version::PlatformVersion; mod document_create_transition; mod document_delete_transition; +mod document_purchase_transition; mod document_replace_transition; mod document_transfer_transition; mod document_transition; +mod document_update_price_transition; mod documents_batch_transition; /// A converter that will get High Level Drive Operations from State transitions diff --git a/packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs index 7eb61ca5fb4..1adaab41ae1 100644 --- a/packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs @@ -49,7 +49,7 @@ impl Drive { ) -> Result, Error> { let mut batch_operations: Vec = vec![]; - if !document_type.documents_mutable() { + if !document_type.documents_can_be_deleted() { return Err(Error::Drive(DriveError::UpdatingReadOnlyImmutableDocument( "this document type is not mutable and can not be deleted", ))); diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/mod.rs index ffeeab47df0..e5dac3fa3ea 100644 --- a/packages/rs-drive/src/drive/document/index_uniqueness/mod.rs +++ b/packages/rs-drive/src/drive/document/index_uniqueness/mod.rs @@ -39,5 +39,7 @@ mod validate_document_create_transition_action_uniqueness; mod validate_document_replace_transition_action_uniqueness; +mod validate_document_purchase_transition_action_uniqueness; mod validate_document_transfer_transition_action_uniqueness; mod validate_document_uniqueness; +mod validate_document_update_price_transition_action_uniqueness; diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/mod.rs new file mode 100644 index 00000000000..a4e3bc9d05c --- /dev/null +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/mod.rs @@ -0,0 +1,70 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; + +use dpp::data_contract::document_type::DocumentTypeRef; +use dpp::data_contract::DataContract; + +use dpp::identifier::Identifier; + +use dpp::validation::SimpleConsensusValidationResult; + +use grovedb::TransactionArg; + +use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionAction; +use dpp::version::PlatformVersion; + +impl Drive { + /// Validate that a document purchase transition action would be unique in the state. + /// + /// # Arguments + /// + /// * `contract` - A `DataContract` object representing the contract. + /// * `document_type` - A `DocumentType` object representing the type of the document. + /// * `document_purchase_transition` - A `DocumentPurchaseTransitionAction` object representing the document purchase transition action. + /// * `owner_id` - An `Identifier` object representing the owner's ID. + /// * `transaction` - A `TransactionArg` object representing the transaction. + /// * `drive_version` - A `DriveVersion` object representing the version of the Drive. + /// + /// # Returns + /// + /// * `Result` - If successful, returns a `SimpleConsensusValidationResult` object representing the result of the validation. + /// If an error occurs during the operation, returns an `Error`. + /// + /// # Errors + /// + /// This function will return an error if the version of the Drive is unknown. + pub fn validate_document_purchase_transition_action_uniqueness( + &self, + contract: &DataContract, + document_type: DocumentTypeRef, + document_purchase_transition: &DocumentPurchaseTransitionAction, + owner_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .document + .index_uniqueness + .validate_document_purchase_transition_action_uniqueness + { + 0 => self.validate_document_purchase_transition_action_uniqueness_v0( + contract, + document_type, + document_purchase_transition, + owner_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "validate_document_purchase_transition_action_uniqueness".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/v0/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/v0/mod.rs new file mode 100644 index 00000000000..a9673724cfc --- /dev/null +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/v0/mod.rs @@ -0,0 +1,64 @@ +use dpp::data_contract::DataContract; + +use crate::drive::Drive; + +use crate::drive::document::index_uniqueness::internal::validate_uniqueness_of_data::UniquenessOfDataRequest; +use crate::error::Error; + +use dpp::data_contract::document_type::DocumentTypeRef; + +use dpp::identifier::Identifier; + +use dpp::validation::SimpleConsensusValidationResult; + +use dpp::document::DocumentV0Getters; +use grovedb::TransactionArg; + +use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; +use dpp::version::PlatformVersion; + +impl Drive { + /// Validate that a document purchase transition action would be unique in the state + #[inline(always)] + pub(super) fn validate_document_purchase_transition_action_uniqueness_v0( + &self, + contract: &DataContract, + document_type: DocumentTypeRef, + document_purchase_transition: &DocumentPurchaseTransitionAction, + owner_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let request = UniquenessOfDataRequest { + contract, + document_type, + owner_id, + document_id: document_purchase_transition.base().id(), + allow_original: true, + created_at: document_purchase_transition.document().created_at(), + updated_at: document_purchase_transition.document().updated_at(), + transferred_at: document_purchase_transition.document().transferred_at(), + created_at_block_height: document_purchase_transition + .document() + .created_at_block_height(), + updated_at_block_height: document_purchase_transition + .document() + .updated_at_block_height(), + transferred_at_block_height: document_purchase_transition + .document() + .transferred_at_block_height(), + created_at_core_block_height: document_purchase_transition + .document() + .created_at_core_block_height(), + updated_at_core_block_height: document_purchase_transition + .document() + .updated_at_core_block_height(), + transferred_at_core_block_height: document_purchase_transition + .document() + .transferred_at_core_block_height(), + data: document_purchase_transition.document().properties(), + }; + self.validate_uniqueness_of_data(request, transaction, platform_version) + } +} diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/mod.rs new file mode 100644 index 00000000000..6d412a95ab8 --- /dev/null +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/mod.rs @@ -0,0 +1,70 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; + +use dpp::data_contract::document_type::DocumentTypeRef; +use dpp::data_contract::DataContract; + +use dpp::identifier::Identifier; + +use dpp::validation::SimpleConsensusValidationResult; + +use grovedb::TransactionArg; + +use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionAction; +use dpp::version::PlatformVersion; + +impl Drive { + /// Validate that a document update_price transition action would be unique in the state. + /// + /// # Arguments + /// + /// * `contract` - A `DataContract` object representing the contract. + /// * `document_type` - A `DocumentType` object representing the type of the document. + /// * `document_update_price_transition` - A `DocumentUpdatePriceTransitionAction` object representing the document update_price transition action. + /// * `owner_id` - An `Identifier` object representing the owner's ID. + /// * `transaction` - A `TransactionArg` object representing the transaction. + /// * `drive_version` - A `DriveVersion` object representing the version of the Drive. + /// + /// # Returns + /// + /// * `Result` - If successful, returns a `SimpleConsensusValidationResult` object representing the result of the validation. + /// If an error occurs during the operation, returns an `Error`. + /// + /// # Errors + /// + /// This function will return an error if the version of the Drive is unknown. + pub fn validate_document_update_price_transition_action_uniqueness( + &self, + contract: &DataContract, + document_type: DocumentTypeRef, + document_update_price_transition: &DocumentUpdatePriceTransitionAction, + owner_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .document + .index_uniqueness + .validate_document_update_price_transition_action_uniqueness + { + 0 => self.validate_document_update_price_transition_action_uniqueness_v0( + contract, + document_type, + document_update_price_transition, + owner_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "validate_document_update_price_transition_action_uniqueness".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/v0/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/v0/mod.rs new file mode 100644 index 00000000000..21b3d94564d --- /dev/null +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/v0/mod.rs @@ -0,0 +1,64 @@ +use dpp::data_contract::DataContract; + +use crate::drive::Drive; + +use crate::drive::document::index_uniqueness::internal::validate_uniqueness_of_data::UniquenessOfDataRequest; +use crate::error::Error; + +use dpp::data_contract::document_type::DocumentTypeRef; + +use dpp::identifier::Identifier; + +use dpp::validation::SimpleConsensusValidationResult; + +use dpp::document::DocumentV0Getters; +use grovedb::TransactionArg; + +use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; +use dpp::version::PlatformVersion; + +impl Drive { + /// Validate that a document update_price transition action would be unique in the state + #[inline(always)] + pub(super) fn validate_document_update_price_transition_action_uniqueness_v0( + &self, + contract: &DataContract, + document_type: DocumentTypeRef, + document_update_price_transition: &DocumentUpdatePriceTransitionAction, + owner_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let request = UniquenessOfDataRequest { + contract, + document_type, + owner_id, + document_id: document_update_price_transition.base().id(), + allow_original: true, + created_at: document_update_price_transition.document().created_at(), + updated_at: document_update_price_transition.document().updated_at(), + transferred_at: document_update_price_transition.document().transferred_at(), + created_at_block_height: document_update_price_transition + .document() + .created_at_block_height(), + updated_at_block_height: document_update_price_transition + .document() + .updated_at_block_height(), + transferred_at_block_height: document_update_price_transition + .document() + .transferred_at_block_height(), + created_at_core_block_height: document_update_price_transition + .document() + .created_at_core_block_height(), + updated_at_core_block_height: document_update_price_transition + .document() + .updated_at_core_block_height(), + transferred_at_core_block_height: document_update_price_transition + .document() + .transferred_at_core_block_height(), + data: document_update_price_transition.document().properties(), + }; + self.validate_uniqueness_of_data(request, transaction, platform_version) + } +} diff --git a/packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v0/mod.rs index a39199206f5..a47f7d2a973 100644 --- a/packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v0/mod.rs @@ -28,6 +28,7 @@ use dpp::document::document_methods::DocumentMethodsV0; use dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0; use dpp::document::{Document, DocumentV0Getters}; +use dpp::data_contract::document_type::methods::DocumentTypeV0Methods; use dpp::version::PlatformVersion; use grovedb::batch::key_info::KeyInfo; use grovedb::batch::key_info::KeyInfo::KnownKey; @@ -51,11 +52,8 @@ impl Drive { ) -> Result, Error> { let drive_version = &platform_version.drive; let mut batch_operations: Vec = vec![]; - if !document_and_contract_info.document_type.documents_mutable() - && !document_and_contract_info - .document_type - .documents_transferable() - .is_transferable() + if !document_and_contract_info.document_type.requires_revision() + // if it requires revision then there are reasons for us to be able to update in drive { return Err(Error::Drive(DriveError::UpdatingReadOnlyImmutableDocument( "documents for this contract are not mutable", diff --git a/packages/rs-drive/src/drive/flags.rs b/packages/rs-drive/src/drive/flags.rs index dcae6e3a7ed..d456346943c 100644 --- a/packages/rs-drive/src/drive/flags.rs +++ b/packages/rs-drive/src/drive/flags.rs @@ -97,6 +97,19 @@ pub enum StorageFlags { MultiEpochOwned(BaseEpoch, BTreeMap, OwnerId), } +#[cfg(any(feature = "server", feature = "verify"))] +/// MergingOwnersStrategy decides which owner to keep during a merge +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] +pub enum MergingOwnersStrategy { + #[default] + /// Raise an issue that owners of nodes are different + RaiseIssue, + /// Use the original owner id + UseOurs, + /// Use the new owner id + UseTheirs, +} + #[cfg(feature = "server")] impl StorageFlags { /// Create new single epoch storage flags @@ -107,18 +120,29 @@ impl StorageFlags { } } - fn combine_owner_id<'a>(&'a self, rhs: &'a Self) -> Result, Error> { + fn combine_owner_id<'a>( + &'a self, + rhs: &'a Self, + merging_owners_strategy: MergingOwnersStrategy, + ) -> Result, Error> { if let Some(our_owner_id) = self.owner_id() { if let Some(other_owner_id) = rhs.owner_id() { if our_owner_id != other_owner_id { - return Err(Error::StorageFlags( - StorageFlagsError::MergingStorageFlagsFromDifferentOwners( - "can not merge from different owners", - ), - )); + match merging_owners_strategy { + MergingOwnersStrategy::RaiseIssue => Err(Error::StorageFlags( + StorageFlagsError::MergingStorageFlagsFromDifferentOwners( + "can not merge from different owners", + ), + )), + MergingOwnersStrategy::UseOurs => Ok(Some(our_owner_id)), + MergingOwnersStrategy::UseTheirs => Ok(Some(other_owner_id)), + } + } else { + Ok(Some(our_owner_id)) } + } else { + Ok(Some(our_owner_id)) } - Ok(Some(our_owner_id)) } else if let Some(other_owner_id) = rhs.owner_id() { Ok(Some(other_owner_id)) } else { @@ -152,9 +176,13 @@ impl StorageFlags { } } - fn combine_same_base_epoch(&self, rhs: Self) -> Result { + fn combine_same_base_epoch( + &self, + rhs: Self, + merging_owners_strategy: MergingOwnersStrategy, + ) -> Result { let base_epoch = *self.base_epoch(); - let owner_id = self.combine_owner_id(&rhs)?; + let owner_id = self.combine_owner_id(&rhs, merging_owners_strategy)?; let other_epoch_bytes = self.combine_non_base_epoch_bytes(&rhs); match (owner_id, other_epoch_bytes) { @@ -167,10 +195,15 @@ impl StorageFlags { } } - fn combine_with_higher_base_epoch(&self, rhs: Self, added_bytes: u32) -> Result { + fn combine_with_higher_base_epoch( + &self, + rhs: Self, + added_bytes: u32, + merging_owners_strategy: MergingOwnersStrategy, + ) -> Result { let base_epoch = *self.base_epoch(); let epoch_with_adding_bytes = rhs.base_epoch(); - let owner_id = self.combine_owner_id(&rhs)?; + let owner_id = self.combine_owner_id(&rhs, merging_owners_strategy)?; let mut other_epoch_bytes = self.combine_non_base_epoch_bytes(&rhs).unwrap_or_default(); let original_value = other_epoch_bytes.remove(epoch_with_adding_bytes); match original_value { @@ -190,12 +223,13 @@ impl StorageFlags { self, rhs: Self, removed_bytes: &StorageRemovedBytes, + merging_owners_strategy: MergingOwnersStrategy, ) -> Result { if matches!(&self, &SingleEpoch(_) | &SingleEpochOwned(..)) { return Ok(self); } let base_epoch = *self.base_epoch(); - let owner_id = self.combine_owner_id(&rhs)?; + let owner_id = self.combine_owner_id(&rhs, merging_owners_strategy)?; let mut other_epoch_bytes = self.combine_non_base_epoch_bytes(&rhs).unwrap_or_default(); if let SectionedStorageRemoval(sectioned_bytes_by_identifier) = removed_bytes { if sectioned_bytes_by_identifier.len() > 1 { @@ -246,10 +280,13 @@ impl StorageFlags { ours: Option, theirs: Self, added_bytes: u32, + merging_owners_strategy: MergingOwnersStrategy, ) -> Result { match ours { None => Ok(theirs), - Some(ours) => Ok(ours.combine_added_bytes(theirs, added_bytes)?), + Some(ours) => { + Ok(ours.combine_added_bytes(theirs, added_bytes, merging_owners_strategy)?) + } } } @@ -258,18 +295,28 @@ impl StorageFlags { ours: Option, theirs: Self, removed_bytes: &StorageRemovedBytes, + merging_owners_strategy: MergingOwnersStrategy, ) -> Result { match ours { None => Ok(theirs), - Some(ours) => Ok(ours.combine_removed_bytes(theirs, removed_bytes)?), + Some(ours) => { + Ok(ours.combine_removed_bytes(theirs, removed_bytes, merging_owners_strategy)?) + } } } /// Combine added bytes - pub fn combine_added_bytes(self, rhs: Self, added_bytes: u32) -> Result { + pub fn combine_added_bytes( + self, + rhs: Self, + added_bytes: u32, + merging_owners_strategy: MergingOwnersStrategy, + ) -> Result { match self.base_epoch().cmp(rhs.base_epoch()) { - Ordering::Equal => self.combine_same_base_epoch(rhs), - Ordering::Less => self.combine_with_higher_base_epoch(rhs, added_bytes), + Ordering::Equal => self.combine_same_base_epoch(rhs, merging_owners_strategy), + Ordering::Less => { + self.combine_with_higher_base_epoch(rhs, added_bytes, merging_owners_strategy) + } Ordering::Greater => Err(Error::StorageFlags( StorageFlagsError::MergingStorageFlagsWithDifferentBaseEpoch( "can not merge with new item in older base epoch", @@ -283,10 +330,15 @@ impl StorageFlags { self, rhs: Self, removed_bytes: &StorageRemovedBytes, + merging_owners_strategy: MergingOwnersStrategy, ) -> Result { match self.base_epoch().cmp(rhs.base_epoch()) { - Ordering::Equal => self.combine_same_base_epoch(rhs), - Ordering::Less => self.combine_with_higher_base_epoch_remove_bytes(rhs, removed_bytes), + Ordering::Equal => self.combine_same_base_epoch(rhs, merging_owners_strategy), + Ordering::Less => self.combine_with_higher_base_epoch_remove_bytes( + rhs, + removed_bytes, + merging_owners_strategy, + ), Ordering::Greater => Err(Error::StorageFlags( StorageFlagsError::MergingStorageFlagsWithDifferentBaseEpoch( "can not merge with new item in older base epoch", diff --git a/packages/rs-drive/src/drive/grove_operations/grove_apply_batch_with_add_costs/v0/mod.rs b/packages/rs-drive/src/drive/grove_operations/grove_apply_batch_with_add_costs/v0/mod.rs index 1ada7f8918a..b6d86527ffe 100644 --- a/packages/rs-drive/src/drive/grove_operations/grove_apply_batch_with_add_costs/v0/mod.rs +++ b/packages/rs-drive/src/drive/grove_operations/grove_apply_batch_with_add_costs/v0/mod.rs @@ -1,6 +1,6 @@ use crate::drive::batch::grovedb_op_batch::GroveDbOpBatchV0Methods; use crate::drive::batch::GroveDbOpBatch; -use crate::drive::flags::StorageFlags; +use crate::drive::flags::{MergingOwnersStrategy, StorageFlags}; use crate::drive::grove_operations::push_drive_operation_result; use crate::drive::Drive; use crate::error::drive::DriveError; @@ -76,30 +76,33 @@ impl Drive { // This could be none only because the old element didn't exist // If they were empty we get an error let maybe_old_storage_flags = StorageFlags::map_some_element_flags_ref(&old_flags) - .map_err(|_| { + .map_err(|e| { GroveError::JustInTimeElementFlagsClientError( - "drive did not understand flags of old item being updated", + format!("drive did not understand flags of old item being updated: {}", e) ) })?; let new_storage_flags = StorageFlags::from_element_flags_ref(new_flags) - .map_err(|_| { + .map_err(|e| { GroveError::JustInTimeElementFlagsClientError( - "drive did not understand updated item flag information", + format!("drive did not understand updated item flag information: {}",e) ) })? .ok_or(GroveError::JustInTimeElementFlagsClientError( - "removing flags from an item with flags is not allowed", + "removing flags from an item with flags is not allowed".to_string() ))?; match &cost.transition_type() { OperationStorageTransitionType::OperationUpdateBiggerSize => { + // In the case that the owners do not match up this means that there has been a transfer + // of ownership of the underlying document, the value held is transferred to the new owner let combined_storage_flags = StorageFlags::optional_combine_added_bytes( maybe_old_storage_flags, new_storage_flags, cost.added_bytes, + MergingOwnersStrategy::UseTheirs, ) - .map_err(|_| { + .map_err(|e| { GroveError::JustInTimeElementFlagsClientError( - "drive could not combine storage flags (new flags were bigger)", + format!("drive could not combine storage flags (new flags were bigger): {}",e) ) })?; let combined_flags = combined_storage_flags.to_element_flags(); @@ -113,14 +116,17 @@ impl Drive { } } OperationStorageTransitionType::OperationUpdateSmallerSize => { + // In the case that the owners do not match up this means that there has been a transfer + // of ownership of the underlying document, the value held is transferred to the new owner let combined_storage_flags = StorageFlags::optional_combine_removed_bytes( maybe_old_storage_flags, new_storage_flags, &cost.removed_bytes, + MergingOwnersStrategy::UseTheirs, ) - .map_err(|_| { + .map_err(|e| { GroveError::JustInTimeElementFlagsClientError( - "drive could not combine storage flags (new flags were smaller)", + format!("drive could not combine storage flags (new flags were smaller): {}", e) ) })?; let combined_flags = combined_storage_flags.to_element_flags(); @@ -138,9 +144,9 @@ impl Drive { }, |flags, removed_key_bytes, removed_value_bytes| { let maybe_storage_flags = - StorageFlags::from_element_flags_ref(flags).map_err(|_| { + StorageFlags::from_element_flags_ref(flags).map_err(|e| { GroveError::SplitRemovalBytesClientError( - "drive did not understand flags of item being updated", + format!("drive did not understand flags of item being updated: {}",e) ) })?; // if there were no flags before then the new flags are used diff --git a/packages/rs-drive/src/drive/grove_operations/grove_apply_partial_batch_with_add_costs/v0/mod.rs b/packages/rs-drive/src/drive/grove_operations/grove_apply_partial_batch_with_add_costs/v0/mod.rs index c26e17fe483..55e400c2402 100644 --- a/packages/rs-drive/src/drive/grove_operations/grove_apply_partial_batch_with_add_costs/v0/mod.rs +++ b/packages/rs-drive/src/drive/grove_operations/grove_apply_partial_batch_with_add_costs/v0/mod.rs @@ -1,6 +1,6 @@ use crate::drive::batch::grovedb_op_batch::GroveDbOpBatchV0Methods; use crate::drive::batch::GroveDbOpBatch; -use crate::drive::flags::StorageFlags; +use crate::drive::flags::{MergingOwnersStrategy, StorageFlags}; use crate::drive::grove_operations::push_drive_operation_result; use crate::drive::Drive; use crate::error::drive::DriveError; @@ -59,19 +59,19 @@ impl Drive { // This could be none only because the old element didn't exist // If they were empty we get an error let maybe_old_storage_flags = StorageFlags::map_some_element_flags_ref(&old_flags) - .map_err(|_| { + .map_err(|e| { GroveError::JustInTimeElementFlagsClientError( - "drive did not understand flags of old item being updated", + format!("drive did not understand flags of old item being updated {}",e) ) })?; let new_storage_flags = StorageFlags::from_element_flags_ref(new_flags) - .map_err(|_| { + .map_err(|e| { GroveError::JustInTimeElementFlagsClientError( - "drive did not understand updated item flag information", + format!("drive did not understand updated item flag information {}", e) ) })? .ok_or(GroveError::JustInTimeElementFlagsClientError( - "removing flags from an item with flags is not allowed", + "removing flags from an item with flags is not allowed".to_string() ))?; match &cost.transition_type() { OperationStorageTransitionType::OperationUpdateBiggerSize => { @@ -79,10 +79,11 @@ impl Drive { maybe_old_storage_flags, new_storage_flags, cost.added_bytes, + MergingOwnersStrategy::RaiseIssue, ) - .map_err(|_| { + .map_err(|e| { GroveError::JustInTimeElementFlagsClientError( - "drive could not combine storage flags (new flags were bigger)", + format!("drive could not combine storage flags (new flags were bigger): {}", e) ) })?; let combined_flags = combined_storage_flags.to_element_flags(); @@ -100,10 +101,11 @@ impl Drive { maybe_old_storage_flags, new_storage_flags, &cost.removed_bytes, + MergingOwnersStrategy::RaiseIssue, ) - .map_err(|_| { + .map_err(|e| { GroveError::JustInTimeElementFlagsClientError( - "drive could not combine storage flags (new flags were smaller)", + format!("drive could not combine storage flags (new flags were smaller): {}",e) ) })?; let combined_flags = combined_storage_flags.to_element_flags(); @@ -121,9 +123,9 @@ impl Drive { }, |flags, removed_key_bytes, removed_value_bytes| { let maybe_storage_flags = - StorageFlags::from_element_flags_ref(flags).map_err(|_| { + StorageFlags::from_element_flags_ref(flags).map_err(|e| { GroveError::SplitRemovalBytesClientError( - "drive did not understand flags of item being updated", + format!("drive did not understand flags of item being updated: {}",e) ) })?; // if there were no flags before then the new flags are used diff --git a/packages/rs-drive/src/drive/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs b/packages/rs-drive/src/drive/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs index d4d4e148e49..1a703b6b4b9 100644 --- a/packages/rs-drive/src/drive/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs +++ b/packages/rs-drive/src/drive/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs @@ -6,7 +6,10 @@ use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::data_contract::serialized_version::DataContractInSerializationFormat; use dpp::document::{Document, DocumentV0Getters}; use dpp::document::document_methods::DocumentMethodsV0; +use dpp::document::property_names::PRICE; +use dpp::fee::Credits; use dpp::identity::PartialIdentity; +use dpp::platform_value::btreemap_extensions::BTreeValueMapHelper; use dpp::prelude::{DataContract, Identifier}; use dpp::state_transition::data_contract_create_transition::accessors::DataContractCreateTransitionAccessorsV0; use dpp::state_transition::data_contract_update_transition::accessors::DataContractUpdateTransitionAccessorsV0; @@ -24,7 +27,9 @@ use dpp::state_transition::documents_batch_transition::document_create_transitio use dpp::state_transition::documents_batch_transition::document_delete_transition::v0::v0_methods::DocumentDeleteTransitionV0Methods; use dpp::state_transition::documents_batch_transition::document_replace_transition::DocumentFromReplaceTransition; use dpp::state_transition::documents_batch_transition::document_replace_transition::v0::v0_methods::DocumentReplaceTransitionV0Methods; +use dpp::state_transition::documents_batch_transition::document_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; use dpp::state_transition::documents_batch_transition::document_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; +use dpp::state_transition::documents_batch_transition::document_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; use dpp::state_transition::proof_result::StateTransitionProofResult; use dpp::state_transition::proof_result::StateTransitionProofResult::{VerifiedBalanceTransfer, VerifiedDataContract, VerifiedDocuments, VerifiedIdentity, VerifiedPartialIdentity}; use platform_version::TryIntoPlatformVersioned; @@ -94,6 +99,8 @@ impl Drive { ))); }; + let owner_id = documents_batch_transition.owner_id(); + let data_contract_id = transition.data_contract_id(); let contract = known_contracts_provider_fn(&data_contract_id)?.ok_or( @@ -198,6 +205,29 @@ impl Drive { )])), )) } + DocumentTransition::UpdatePrice(update_price_transition) => { + let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (update price)", update_price_transition.base().id()))))?; + let new_document_price : Credits = document.properties().get_integer(PRICE).map_err(|e| Error::Proof(ProofError::IncorrectProof(format!("proof did not contain a document that contained a price field with id {} expected to exist because of state transition (update price): {}", update_price_transition.base().id(), e))))?; + if new_document_price != update_price_transition.price() { + return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not contain expected document update of price after price update with id {}", update_price_transition.base().id())))); + } + Ok(( + root_hash, + VerifiedDocuments(BTreeMap::from([(document.id(), Some(document))])), + )) + } + DocumentTransition::Purchase(purchase_transition) => { + let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (purchase)", purchase_transition.base().id()))))?; + + if document.owner_id() != owner_id { + return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not have the transfer executed after expected transfer with id {}", purchase_transition.base().id())))); + } + + Ok(( + root_hash, + VerifiedDocuments(BTreeMap::from([(document.id(), Some(document))])), + )) + } } } StateTransition::IdentityCreate(identity_create_transition) => { diff --git a/packages/rs-drive/src/query/test_index.rs b/packages/rs-drive/src/query/test_index.rs index f486f0128f8..d0b4b12cb6b 100644 --- a/packages/rs-drive/src/query/test_index.rs +++ b/packages/rs-drive/src/query/test_index.rs @@ -84,6 +84,7 @@ mod tests { None, false, false, + false, true, &mut vec![], platform_version, diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/action_type.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/action_type.rs index f2dda795254..de03698b223 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/action_type.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/action_type.rs @@ -10,6 +10,10 @@ impl TransitionActionTypeGetter for DocumentTransitionAction { DocumentTransitionAction::DeleteAction(_) => DocumentTransitionActionType::Delete, DocumentTransitionAction::ReplaceAction(_) => DocumentTransitionActionType::Replace, DocumentTransitionAction::TransferAction(_) => DocumentTransitionActionType::Transfer, + DocumentTransitionAction::PurchaseAction(_) => DocumentTransitionActionType::Purchase, + DocumentTransitionAction::UpdatePriceAction(_) => { + DocumentTransitionActionType::UpdatePrice + } DocumentTransitionAction::BumpIdentityDataContractNonce(_) => { DocumentTransitionActionType::IgnoreWhileBumpingRevision } diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/mod.rs new file mode 100644 index 00000000000..53a84fe1a5d --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/mod.rs @@ -0,0 +1,98 @@ +mod v0; + +use derive_more::From; +use dpp::document::Document; +use dpp::fee::Credits; + +use dpp::platform_value::Identifier; +use dpp::ProtocolError; +pub use v0::*; + +use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use dpp::version::PlatformVersion; + +/// transformer +pub mod transformer; + +/// action +#[derive(Debug, Clone, From)] +pub enum DocumentPurchaseTransitionAction { + /// v0 + V0(DocumentPurchaseTransitionActionV0), +} + +impl DocumentPurchaseTransitionActionAccessorsV0 for DocumentPurchaseTransitionAction { + fn base(&self) -> &DocumentBaseTransitionAction { + match self { + DocumentPurchaseTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> DocumentBaseTransitionAction { + match self { + DocumentPurchaseTransitionAction::V0(v0) => v0.base, + } + } + + fn document(&self) -> &Document { + match self { + DocumentPurchaseTransitionAction::V0(v0) => &v0.document, + } + } + + fn document_owned(self) -> Document { + match self { + DocumentPurchaseTransitionAction::V0(v0) => v0.document, + } + } + + fn original_owner_id(&self) -> Identifier { + match self { + DocumentPurchaseTransitionAction::V0(v0) => v0.original_owner_id, + } + } + + fn price(&self) -> Credits { + match self { + DocumentPurchaseTransitionAction::V0(v0) => v0.price, + } + } +} + +/// document from purchase transition +pub trait DocumentFromPurchaseTransitionAction { + /// Attempts to create a new `Document` from the given `DocumentPurchaseTransitionAction` reference and `owner_id`. + /// + /// # Arguments + /// + /// * `value` - A reference to the `DocumentPurchaseTransitionAction` containing information about the document being purchased. + /// * `owner_id` - The `Identifier` of the document's owner. + /// + /// # Returns + /// + /// * `Result` - A new `Document` object if successful, otherwise a `ProtocolError`. + fn try_from_purchase_transition_action( + document_purchase_transition_action: &DocumentPurchaseTransitionAction, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result + where + Self: Sized; + /// Attempts to create a new `Document` from the given `DocumentPurchaseTransitionAction` instance and `owner_id`. + /// + /// # Arguments + /// + /// * `value` - A `DocumentPurchaseTransitionAction` instance containing information about the document being purchased. + /// * `owner_id` - The `Identifier` of the document's owner. + /// + /// # Returns + /// + /// * `Result` - A new `Document` object if successful, otherwise a `ProtocolError`. + fn try_from_owned_purchase_transition_action( + document_purchase_transition_action: DocumentPurchaseTransitionAction, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result + where + Self: Sized; +} diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/transformer.rs new file mode 100644 index 00000000000..894e13b5bdc --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/transformer.rs @@ -0,0 +1,33 @@ +use dpp::block::block_info::BlockInfo; +use dpp::document::Document; +use dpp::platform_value::Identifier; +use std::sync::Arc; + +use dpp::ProtocolError; +use dpp::state_transition::documents_batch_transition::document_transition::DocumentPurchaseTransition; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionV0}; + +impl DocumentPurchaseTransitionAction { + /// try from borrowed + pub fn try_from_borrowed_document_purchase_transition( + document_purchase_transition: &DocumentPurchaseTransition, + original_document: Document, + purchaser_id: Identifier, + block_info: &BlockInfo, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + ) -> Result { + match document_purchase_transition { + DocumentPurchaseTransition::V0(v0) => Ok( + DocumentPurchaseTransitionActionV0::try_from_borrowed_document_purchase_transition( + v0, + original_document, + purchaser_id, + block_info, + get_data_contract, + )? + .into(), + ), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/mod.rs new file mode 100644 index 00000000000..785ccb32b60 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/mod.rs @@ -0,0 +1,37 @@ +pub mod transformer; + +use dpp::document::Document; +use dpp::fee::Credits; +use dpp::identifier::Identifier; + +use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; + +/// document purchase transition action v0 +#[derive(Debug, Clone)] +pub struct DocumentPurchaseTransitionActionV0 { + /// Document Base Transition + pub base: DocumentBaseTransitionAction, + /// The new document to be inserted + pub document: Document, + /// The original owner id + pub original_owner_id: Identifier, + /// Price + pub price: Credits, +} + +/// document purchase transition action accessors v0 +pub trait DocumentPurchaseTransitionActionAccessorsV0 { + /// base + fn base(&self) -> &DocumentBaseTransitionAction; + /// base owned + fn base_owned(self) -> DocumentBaseTransitionAction; + /// the document to be inserted as a ref + fn document(&self) -> &Document; + /// the document to be inserted as owned + fn document_owned(self) -> Document; + + /// The original owner id + fn original_owner_id(&self) -> Identifier; + /// Price + fn price(&self) -> Credits; +} diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/transformer.rs new file mode 100644 index 00000000000..e888f20d33e --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/transformer.rs @@ -0,0 +1,59 @@ +use dpp::block::block_info::BlockInfo; +use dpp::document::property_names::PRICE; +use dpp::document::{property_names, Document, DocumentV0Getters, DocumentV0Setters}; +use dpp::platform_value::Identifier; +use std::sync::Arc; + +use dpp::ProtocolError; +use dpp::state_transition::documents_batch_transition::document_transition::document_purchase_transition::DocumentPurchaseTransitionV0; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::v0::DocumentPurchaseTransitionActionV0; +use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; + +impl DocumentPurchaseTransitionActionV0 { + /// try from borrowed + pub fn try_from_borrowed_document_purchase_transition( + document_purchase_transition: &DocumentPurchaseTransitionV0, + original_document: Document, + purchaser_id: Identifier, + block_info: &BlockInfo, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + ) -> Result { + let DocumentPurchaseTransitionV0 { base, price, .. } = document_purchase_transition; + let base = + DocumentBaseTransitionAction::from_borrowed_base_transition_with_contract_lookup( + base, + get_data_contract, + )?; + + let original_owner_id = original_document.owner_id(); + + let mut modified_document = original_document; + + modified_document.bump_revision(); + + // We must remove the price if there is one + modified_document.properties_mut().remove(PRICE); + + modified_document.set_owner_id(purchaser_id); + + if base.document_type_field_is_required(property_names::TRANSFERRED_AT)? { + modified_document.set_transferred_at(Some(block_info.time_ms)); + } + + if base.document_type_field_is_required(property_names::TRANSFERRED_AT_BLOCK_HEIGHT)? { + modified_document.set_transferred_at_block_height(Some(block_info.height)); + } + + if base.document_type_field_is_required(property_names::TRANSFERRED_AT_CORE_BLOCK_HEIGHT)? { + modified_document.set_transferred_at_core_block_height(Some(block_info.core_height)); + } + + Ok(DocumentPurchaseTransitionActionV0 { + base, + document: modified_document, + original_owner_id, + price: *price, + }) + } +} diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/v0/transformer.rs index aec0832019b..88f6d0776ab 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/v0/transformer.rs @@ -1,5 +1,6 @@ use dpp::block::block_info::BlockInfo; -use dpp::document::{property_names, Document, DocumentV0Setters}; +use dpp::document::property_names::PRICE; +use dpp::document::{property_names, Document, DocumentV0Getters, DocumentV0Setters}; use dpp::platform_value::Identifier; use std::sync::Arc; @@ -32,6 +33,11 @@ impl DocumentTransferTransitionActionV0 { modified_document.set_owner_id(*recipient_owner_id); + // We must remove the price + modified_document.properties_mut().remove(PRICE); + + modified_document.bump_revision(); + if base.document_type_field_is_required(property_names::TRANSFERRED_AT)? { modified_document.set_transferred_at(Some(block_info.time_ms)); } diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/mod.rs new file mode 100644 index 00000000000..c206f21da92 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/mod.rs @@ -0,0 +1,85 @@ +mod v0; + +use derive_more::From; +use dpp::document::Document; + +use dpp::platform_value::Identifier; +use dpp::ProtocolError; +pub use v0::*; + +use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use dpp::version::PlatformVersion; + +/// transformer +pub mod transformer; + +/// action +#[derive(Debug, Clone, From)] +pub enum DocumentUpdatePriceTransitionAction { + /// v0 + V0(DocumentUpdatePriceTransitionActionV0), +} + +impl DocumentUpdatePriceTransitionActionAccessorsV0 for DocumentUpdatePriceTransitionAction { + fn base(&self) -> &DocumentBaseTransitionAction { + match self { + DocumentUpdatePriceTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> DocumentBaseTransitionAction { + match self { + DocumentUpdatePriceTransitionAction::V0(v0) => v0.base, + } + } + + fn document(&self) -> &Document { + match self { + DocumentUpdatePriceTransitionAction::V0(v0) => &v0.document, + } + } + + fn document_owned(self) -> Document { + match self { + DocumentUpdatePriceTransitionAction::V0(v0) => v0.document, + } + } +} + +/// document from update price transition +pub trait DocumentFromUpdatePriceTransitionAction { + /// Attempts to create a new `Document` from the given `DocumentUpdatePriceTransitionAction` reference and `owner_id`. + /// + /// # Arguments + /// + /// * `value` - A reference to the `DocumentUpdatePriceTransitionAction` containing information about the document being update_priced. + /// * `owner_id` - The `Identifier` of the document's owner. + /// + /// # Returns + /// + /// * `Result` - A new `Document` object if successful, otherwise a `ProtocolError`. + fn try_from_update_price_transition_action( + document_update_price_transition_action: &DocumentUpdatePriceTransitionAction, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result + where + Self: Sized; + /// Attempts to create a new `Document` from the given `DocumentUpdatePriceTransitionAction` instance and `owner_id`. + /// + /// # Arguments + /// + /// * `value` - A `DocumentUpdatePriceTransitionAction` instance containing information about the document being update_priced. + /// * `owner_id` - The `Identifier` of the document's owner. + /// + /// # Returns + /// + /// * `Result` - A new `Document` object if successful, otherwise a `ProtocolError`. + fn try_from_owned_update_price_transition_action( + document_update_price_transition_action: DocumentUpdatePriceTransitionAction, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result + where + Self: Sized; +} diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/transformer.rs new file mode 100644 index 00000000000..f52e99d0d61 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/transformer.rs @@ -0,0 +1,31 @@ +use dpp::block::block_info::BlockInfo; +use dpp::document::Document; +use dpp::platform_value::Identifier; +use std::sync::Arc; + +use dpp::ProtocolError; +use dpp::state_transition::documents_batch_transition::document_transition::DocumentUpdatePriceTransition; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionV0}; + +impl DocumentUpdatePriceTransitionAction { + /// try from borrowed + pub fn try_from_borrowed_document_update_price_transition( + document_update_price_transition: &DocumentUpdatePriceTransition, + original_document: Document, + block_info: &BlockInfo, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + ) -> Result { + match document_update_price_transition { + DocumentUpdatePriceTransition::V0(v0) => Ok( + DocumentUpdatePriceTransitionActionV0::try_from_borrowed_document_update_price_transition( + v0, + original_document, + block_info, + get_data_contract, + )? + .into(), + ), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/mod.rs new file mode 100644 index 00000000000..37f3f8100c4 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/mod.rs @@ -0,0 +1,26 @@ +pub mod transformer; + +use dpp::document::Document; + +use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; + +/// document transfer transition action v0 +#[derive(Debug, Clone)] +pub struct DocumentUpdatePriceTransitionActionV0 { + /// Document Base Transition + pub base: DocumentBaseTransitionAction, + /// The new document to be updated + pub document: Document, +} + +/// document transfer transition action accessors v0 +pub trait DocumentUpdatePriceTransitionActionAccessorsV0 { + /// base + fn base(&self) -> &DocumentBaseTransitionAction; + /// base owned + fn base_owned(self) -> DocumentBaseTransitionAction; + /// the document with updated price to be reinserted as a ref + fn document(&self) -> &Document; + /// the document with updated price to be reinserted as owned + fn document_owned(self) -> Document; +} diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/transformer.rs new file mode 100644 index 00000000000..6054d09f9b8 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/transformer.rs @@ -0,0 +1,51 @@ +use dpp::block::block_info::BlockInfo; +use dpp::document::property_names::PRICE; +use dpp::document::{property_names, Document, DocumentV0Setters}; +use dpp::platform_value::Identifier; +use std::sync::Arc; + +use dpp::ProtocolError; +use dpp::state_transition::documents_batch_transition::document_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::v0::DocumentUpdatePriceTransitionActionV0; +use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; + +impl DocumentUpdatePriceTransitionActionV0 { + /// try from borrowed + pub fn try_from_borrowed_document_update_price_transition( + document_update_price_transition: &DocumentUpdatePriceTransitionV0, + original_document: Document, + block_info: &BlockInfo, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + ) -> Result { + let DocumentUpdatePriceTransitionV0 { base, price, .. } = document_update_price_transition; + let base = + DocumentBaseTransitionAction::from_borrowed_base_transition_with_contract_lookup( + base, + get_data_contract, + )?; + + let mut modified_document = original_document; + + modified_document.set_u64(PRICE, *price); + + modified_document.bump_revision(); + + if base.document_type_field_is_required(property_names::UPDATED_AT)? { + modified_document.set_updated_at(Some(block_info.time_ms)); + } + + if base.document_type_field_is_required(property_names::UPDATED_AT_BLOCK_HEIGHT)? { + modified_document.set_updated_at_block_height(Some(block_info.height)); + } + + if base.document_type_field_is_required(property_names::UPDATED_AT_CORE_BLOCK_HEIGHT)? { + modified_document.set_updated_at_core_block_height(Some(block_info.core_height)); + } + + Ok(DocumentUpdatePriceTransitionActionV0 { + base, + document: modified_document, + }) + } +} diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/mod.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/mod.rs index d5df86cb324..51c7f19d2d0 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/mod.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/mod.rs @@ -5,10 +5,14 @@ pub mod document_base_transition_action; pub mod document_create_transition_action; /// document_delete_transition_action pub mod document_delete_transition_action; +/// document_purchase_transition_action +pub mod document_purchase_transition_action; /// document_replace_transition_action pub mod document_replace_transition_action; /// document_transfer_transition_action pub mod document_transfer_transition_action; +/// document_update_price_transition_action +pub mod document_update_price_transition_action; pub use dpp::state_transition::documents_batch_transition::document_transition::action_type::DocumentTransitionActionType; @@ -19,7 +23,9 @@ use crate::state_transition_action::document::documents_batch::document_transiti use crate::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; use crate::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; use crate::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; +use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; use crate::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; +use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; /// version @@ -36,6 +42,10 @@ pub enum DocumentTransitionAction { DeleteAction(DocumentDeleteTransitionAction), /// transfer TransferAction(DocumentTransferTransitionAction), + /// purchase + PurchaseAction(DocumentPurchaseTransitionAction), + /// update price + UpdatePriceAction(DocumentUpdatePriceTransitionAction), /// bump identity data contract nonce BumpIdentityDataContractNonce(BumpIdentityDataContractNonceAction), } @@ -48,6 +58,8 @@ impl DocumentTransitionAction { DocumentTransitionAction::DeleteAction(d) => Some(d.base()), DocumentTransitionAction::ReplaceAction(d) => Some(d.base()), DocumentTransitionAction::TransferAction(d) => Some(d.base()), + DocumentTransitionAction::PurchaseAction(d) => Some(d.base()), + DocumentTransitionAction::UpdatePriceAction(d) => Some(d.base()), DocumentTransitionAction::BumpIdentityDataContractNonce(_) => None, } } @@ -59,6 +71,8 @@ impl DocumentTransitionAction { DocumentTransitionAction::DeleteAction(d) => Some(d.base_owned()), DocumentTransitionAction::ReplaceAction(d) => Some(d.base_owned()), DocumentTransitionAction::TransferAction(d) => Some(d.base_owned()), + DocumentTransitionAction::PurchaseAction(d) => Some(d.base_owned()), + DocumentTransitionAction::UpdatePriceAction(d) => Some(d.base_owned()), DocumentTransitionAction::BumpIdentityDataContractNonce(_) => None, } } diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/mod.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/mod.rs index d6581cd9d1e..fc5de09a359 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/mod.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/mod.rs @@ -3,6 +3,7 @@ use crate::state_transition_action::document::documents_batch::v0::DocumentsBatc use derive_more::From; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; +use dpp::fee::Credits; use dpp::identity::SecurityLevel; use dpp::platform_value::Identifier; use dpp::prelude::UserFeeIncrease; @@ -73,6 +74,13 @@ impl DocumentsBatchTransitionAction { } impl DocumentsBatchTransitionAction { + /// The sum of all purchases amounts for all purchase transitions in the batch + pub fn all_purchases_amount(&self) -> Option { + match self { + DocumentsBatchTransitionAction::V0(v0) => v0.all_purchases_amount(), + } + } + /// Determines the security level requirements for the batch transition action. /// /// This method performs the following steps: diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/v0/mod.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/v0/mod.rs index 6fef9bd8537..4d1ccce401d 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/v0/mod.rs @@ -1,6 +1,8 @@ +use dpp::fee::Credits; use crate::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; use dpp::identifier::Identifier; use dpp::prelude::UserFeeIncrease; +use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionActionAccessorsV0; /// action v0 #[derive(Default, Debug, Clone)] @@ -12,3 +14,22 @@ pub struct DocumentsBatchTransitionActionV0 { /// fee multiplier pub user_fee_increase: UserFeeIncrease, } + +impl DocumentsBatchTransitionActionV0 { + pub(super) fn all_purchases_amount(&self) -> Option { + let (total, any_purchases) = self + .transitions + .iter() + .filter_map(|transition| match transition { + DocumentTransitionAction::PurchaseAction(purchase) => Some(purchase.price()), + _ => None, + }) + .fold((0, false), |(acc, _), price| (acc + price, true)); + + if any_purchases { + Some(total) // Return the sum as Some(Credits) if there were any purchases + } else { + None // Return None if no purchases were found + } + } +} diff --git a/packages/rs-drive/tests/deterministic_root_hash.rs b/packages/rs-drive/tests/deterministic_root_hash.rs index e0385745739..fa6ecc90918 100644 --- a/packages/rs-drive/tests/deterministic_root_hash.rs +++ b/packages/rs-drive/tests/deterministic_root_hash.rs @@ -446,7 +446,7 @@ fn test_root_hash_with_batches(drive: &Drive, db_transaction: &Transaction) { .unwrap() .expect("should return app hash"); - let expected_app_hash = "8880c628746348b09621b00589ccf856f75634388436a105473eb4506bb7e85e"; + let expected_app_hash = "fa23fefadd8b0254b9e4c594f09026c070148f5de9c39ff9ea227a327761e062"; assert_eq!(hex::encode(app_hash), expected_app_hash); } diff --git a/packages/rs-drive/tests/query_tests.rs b/packages/rs-drive/tests/query_tests.rs index a696c6df347..9a0e0333911 100644 --- a/packages/rs-drive/tests/query_tests.rs +++ b/packages/rs-drive/tests/query_tests.rs @@ -993,8 +993,8 @@ fn test_family_basic_queries() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 90, 210, 2, 14, 207, 220, 54, 103, 243, 153, 202, 228, 38, 19, 30, 201, 119, 135, 210, 26, - 216, 14, 17, 94, 98, 181, 133, 247, 36, 139, 235, 67, + 32, 210, 24, 196, 148, 43, 20, 34, 0, 116, 183, 136, 32, 210, 163, 183, 214, 6, 152, 86, + 46, 45, 88, 13, 23, 41, 37, 70, 129, 119, 211, 12, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -2305,8 +2305,8 @@ fn test_family_basic_queries() { assert_eq!( root_hash.as_slice(), vec![ - 60, 109, 98, 63, 192, 76, 21, 51, 95, 13, 145, 173, 155, 30, 5, 194, 221, 33, 152, 195, - 108, 127, 146, 37, 82, 5, 166, 38, 67, 162, 1, 83, + 251, 69, 177, 93, 128, 236, 106, 87, 205, 123, 80, 61, 44, 107, 186, 193, 22, 192, 239, + 7, 107, 110, 97, 197, 59, 245, 26, 12, 63, 91, 248, 231, ], ); } @@ -2452,8 +2452,8 @@ fn test_family_starts_at_queries() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 90, 210, 2, 14, 207, 220, 54, 103, 243, 153, 202, 228, 38, 19, 30, 201, 119, 135, 210, 26, - 216, 14, 17, 94, 98, 181, 133, 247, 36, 139, 235, 67, + 32, 210, 24, 196, 148, 43, 20, 34, 0, 116, 183, 136, 32, 210, 163, 183, 214, 6, 152, 86, + 46, 45, 88, 13, 23, 41, 37, 70, 129, 119, 211, 12, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -2894,8 +2894,8 @@ fn test_family_with_nulls_query() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 124, 137, 76, 15, 82, 78, 62, 179, 206, 204, 2, 84, 187, 107, 28, 121, 186, 221, 98, 66, - 187, 78, 66, 70, 54, 10, 193, 108, 39, 59, 195, 209, + 92, 186, 224, 49, 242, 195, 32, 14, 46, 55, 244, 57, 55, 191, 10, 119, 228, 132, 91, 235, + 170, 114, 36, 41, 126, 136, 180, 51, 132, 17, 26, 182, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -3017,8 +3017,8 @@ fn test_query_with_cached_contract() { // Make sure the state is deterministic let expected_app_hash = vec![ - 90, 210, 2, 14, 207, 220, 54, 103, 243, 153, 202, 228, 38, 19, 30, 201, 119, 135, 210, 26, - 216, 14, 17, 94, 98, 181, 133, 247, 36, 139, 235, 67, + 32, 210, 24, 196, 148, 43, 20, 34, 0, 116, 183, 136, 32, 210, 163, 183, 214, 6, 152, 86, + 46, 45, 88, 13, 23, 41, 37, 70, 129, 119, 211, 12, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -3166,8 +3166,8 @@ fn test_dpns_query() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 175, 37, 171, 184, 32, 136, 247, 111, 230, 81, 39, 88, 130, 203, 38, 44, 228, 121, 233, - 118, 123, 8, 192, 213, 216, 249, 146, 44, 95, 0, 130, 52, + 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, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -3718,8 +3718,8 @@ fn test_dpns_query_start_at() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 175, 37, 171, 184, 32, 136, 247, 111, 230, 81, 39, 88, 130, 203, 38, 44, 228, 121, 233, - 118, 123, 8, 192, 213, 216, 249, 146, 44, 95, 0, 130, 52, + 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, ]; assert_eq!(root_hash.as_slice(), expected_app_hash,); @@ -3812,8 +3812,8 @@ fn test_dpns_query_start_after() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 175, 37, 171, 184, 32, 136, 247, 111, 230, 81, 39, 88, 130, 203, 38, 44, 228, 121, 233, - 118, 123, 8, 192, 213, 216, 249, 146, 44, 95, 0, 130, 52, + 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, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -3906,8 +3906,8 @@ fn test_dpns_query_start_at_desc() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 175, 37, 171, 184, 32, 136, 247, 111, 230, 81, 39, 88, 130, 203, 38, 44, 228, 121, 233, - 118, 123, 8, 192, 213, 216, 249, 146, 44, 95, 0, 130, 52, + 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, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4000,8 +4000,8 @@ fn test_dpns_query_start_after_desc() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 175, 37, 171, 184, 32, 136, 247, 111, 230, 81, 39, 88, 130, 203, 38, 44, 228, 121, 233, - 118, 123, 8, 192, 213, 216, 249, 146, 44, 95, 0, 130, 52, + 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, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4192,8 +4192,8 @@ fn test_dpns_query_start_at_with_null_id() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 1, 56, 101, 133, 212, 109, 114, 252, 181, 180, 21, 151, 38, 31, 9, 88, 2, 61, 230, 165, - 228, 57, 90, 132, 94, 38, 166, 89, 44, 13, 49, 115, + 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, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4393,8 +4393,8 @@ fn test_dpns_query_start_after_with_null_id() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 1, 56, 101, 133, 212, 109, 114, 252, 181, 180, 21, 151, 38, 31, 9, 88, 2, 61, 230, 165, - 228, 57, 90, 132, 94, 38, 166, 89, 44, 13, 49, 115, + 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, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4598,8 +4598,8 @@ fn test_dpns_query_start_after_with_null_id_desc() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 1, 56, 101, 133, 212, 109, 114, 252, 181, 180, 21, 151, 38, 31, 9, 88, 2, 61, 230, 165, - 228, 57, 90, 132, 94, 38, 166, 89, 44, 13, 49, 115, + 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, ]; assert_eq!(root_hash.as_slice(), expected_app_hash,); diff --git a/packages/rs-drive/tests/query_tests_history.rs b/packages/rs-drive/tests/query_tests_history.rs index ef1e5528fee..d89480eb016 100644 --- a/packages/rs-drive/tests/query_tests_history.rs +++ b/packages/rs-drive/tests/query_tests_history.rs @@ -291,8 +291,8 @@ fn test_query_historical() { assert_eq!( root_hash.as_slice(), vec![ - 54, 217, 155, 152, 174, 237, 193, 15, 240, 181, 31, 17, 238, 127, 246, 92, 20, 222, 37, - 39, 104, 146, 240, 98, 159, 130, 29, 227, 5, 94, 69, 207, + 163, 151, 181, 112, 234, 184, 171, 83, 83, 105, 116, 97, 25, 160, 197, 58, 81, 214, + 243, 144, 11, 91, 223, 83, 71, 99, 170, 203, 145, 244, 137, 134, ] ); @@ -1655,8 +1655,8 @@ fn test_query_historical() { assert_eq!( root_hash.as_slice(), vec![ - 117, 239, 44, 103, 118, 107, 30, 109, 225, 15, 234, 90, 59, 0, 22, 79, 32, 4, 94, 225, - 241, 206, 146, 22, 138, 217, 87, 208, 96, 176, 216, 114 + 212, 52, 34, 33, 150, 181, 101, 7, 122, 203, 197, 177, 146, 225, 160, 186, 49, 229, 70, + 206, 170, 180, 253, 90, 90, 188, 107, 108, 162, 216, 195, 81 ] ); } diff --git a/packages/rs-json-schema-compatibility-validator/src/rules/rule_set.rs b/packages/rs-json-schema-compatibility-validator/src/rules/rule_set.rs index f04f513e270..54798669892 100644 --- a/packages/rs-json-schema-compatibility-validator/src/rules/rule_set.rs +++ b/packages/rs-json-schema-compatibility-validator/src/rules/rule_set.rs @@ -1374,5 +1374,356 @@ pub static KEYWORD_COMPATIBILITY_RULES: Lazy { + /// Tries to purchase a document on platform + /// Setting settings to `None` sets default connection behavior + async fn purchase_document( + &self, + price: Credits, + sdk: &Sdk, + document_type: DocumentType, + purchaser_id: Identifier, + identity_public_key: IdentityPublicKey, + signer: &S, + settings: Option, + ) -> Result; + + /// Waits for the response of a state transition after it has been broadcast + async fn wait_for_response( + &self, + sdk: &Sdk, + state_transition: StateTransition, + data_contract: Arc, + ) -> Result; + + /// Tries to purchase a document on platform and waits for the response + async fn purchase_document_and_wait_for_response( + &self, + price: Credits, + sdk: &Sdk, + document_type: DocumentType, + purchaser_id: Identifier, + identity_public_key: IdentityPublicKey, + data_contract: Arc, + signer: &S, + ) -> Result; +} + +#[async_trait::async_trait] +impl PurchaseDocument for Document { + async fn purchase_document( + &self, + price: Credits, + sdk: &Sdk, + document_type: DocumentType, + purchaser_id: Identifier, + identity_public_key: IdentityPublicKey, + signer: &S, + settings: Option, + ) -> Result { + let new_identity_contract_nonce = sdk + .get_identity_contract_nonce( + purchaser_id, + document_type.data_contract_id(), + true, + settings, + ) + .await?; + + let settings = settings.unwrap_or_default(); + + let transition = DocumentsBatchTransition::new_document_purchase_transition_from_document( + self.clone(), + document_type.as_ref(), + purchaser_id, + price, + &identity_public_key, + new_identity_contract_nonce, + settings.user_fee_increase.unwrap_or_default(), + signer, + sdk.version(), + None, + None, + None, + )?; + + let request = transition.broadcast_request_for_state_transition()?; + + request + .clone() + .execute(sdk, settings.request_settings) + .await?; + + // response is empty for a broadcast, result comes from the stream wait for state transition result + + Ok(transition) + } + + async fn wait_for_response( + &self, + sdk: &Sdk, + state_transition: StateTransition, + data_contract: Arc, + ) -> Result { + let request = state_transition.wait_for_state_transition_result_request()?; + + let response = request.execute(sdk, RequestSettings::default()).await?; + + let block_info = block_info_from_metadata(response.metadata()?)?; + + let proof = response.proof_owned()?; + + let (_, result) = Drive::verify_state_transition_was_executed_with_proof( + &state_transition, + &block_info, + proof.grovedb_proof.as_slice(), + &|_| Ok(Some(data_contract.clone())), + sdk.version(), + )?; + + match result { + StateTransitionProofResult::VerifiedDocuments(mut documents) => { + let document = documents + .remove(self.id_ref()) + .ok_or(Error::InvalidProvedResponse( + "did not prove the sent document".to_string(), + ))? + .ok_or(Error::InvalidProvedResponse( + "expected there to actually be a document".to_string(), + ))?; + Ok(document) + } + _ => Err(Error::DapiClientError("proved a non document".to_string())), + } + } + + async fn purchase_document_and_wait_for_response( + &self, + price: Credits, + sdk: &Sdk, + document_type: DocumentType, + purchaser_id: Identifier, + identity_public_key: IdentityPublicKey, + data_contract: Arc, + signer: &S, + ) -> Result { + let state_transition = self + .purchase_document( + price, + sdk, + document_type, + purchaser_id, + identity_public_key, + signer, + None, + ) + .await?; + + let document = >::wait_for_response( + self, + sdk, + state_transition, + data_contract, + ) + .await?; + + Ok(document) + } +} diff --git a/packages/rs-sdk/src/platform/transition/update_price_of_document.rs b/packages/rs-sdk/src/platform/transition/update_price_of_document.rs new file mode 100644 index 00000000000..93da9aaf2b7 --- /dev/null +++ b/packages/rs-sdk/src/platform/transition/update_price_of_document.rs @@ -0,0 +1,168 @@ +use crate::platform::transition::broadcast_request::BroadcastRequestForStateTransition; +use std::sync::Arc; + +use crate::{Error, Sdk}; + +use crate::platform::block_info_from_metadata::block_info_from_metadata; +use crate::platform::transition::put_settings::PutSettings; +use dapi_grpc::platform::VersionedGrpcResponse; +use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; +use dpp::data_contract::document_type::DocumentType; +use dpp::data_contract::DataContract; +use dpp::document::{Document, DocumentV0Getters}; +use dpp::fee::Credits; +use dpp::identity::signer::Signer; +use dpp::identity::IdentityPublicKey; +use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::state_transition::proof_result::StateTransitionProofResult; +use dpp::state_transition::StateTransition; +use drive::drive::Drive; +use rs_dapi_client::{DapiRequest, RequestSettings}; + +#[async_trait::async_trait] +/// A trait for updating the price of a document on Platform +pub trait UpdatePriceOfDocument { + /// Updates the price of a document on platform + /// Setting settings to `None` sets default connection behavior + async fn update_price_of_document( + &self, + price: Credits, + sdk: &Sdk, + document_type: DocumentType, + identity_public_key: IdentityPublicKey, + signer: &S, + settings: Option, + ) -> Result; + + /// Waits for the response of a state transition after it has been broadcast + async fn wait_for_response( + &self, + sdk: &Sdk, + state_transition: StateTransition, + data_contract: Arc, + ) -> Result; + + /// Updates the price of a document on platform and waits for the response + async fn update_price_of_document_and_wait_for_response( + &self, + price: Credits, + sdk: &Sdk, + document_type: DocumentType, + identity_public_key: IdentityPublicKey, + data_contract: Arc, + signer: &S, + ) -> Result; +} + +#[async_trait::async_trait] +impl UpdatePriceOfDocument for Document { + async fn update_price_of_document( + &self, + price: Credits, + sdk: &Sdk, + document_type: DocumentType, + identity_public_key: IdentityPublicKey, + signer: &S, + settings: Option, + ) -> Result { + let new_identity_contract_nonce = sdk + .get_identity_contract_nonce( + self.owner_id(), + document_type.data_contract_id(), + true, + settings, + ) + .await?; + + let settings = settings.unwrap_or_default(); + + let transition = + DocumentsBatchTransition::new_document_update_price_transition_from_document( + self.clone(), + document_type.as_ref(), + price, + &identity_public_key, + new_identity_contract_nonce, + settings.user_fee_increase.unwrap_or_default(), + signer, + sdk.version(), + None, + None, + None, + )?; + + let request = transition.broadcast_request_for_state_transition()?; + + request + .clone() + .execute(sdk, settings.request_settings) + .await?; + + // response is empty for a broadcast, result comes from the stream wait for state transition result + + Ok(transition) + } + + async fn wait_for_response( + &self, + sdk: &Sdk, + state_transition: StateTransition, + data_contract: Arc, + ) -> Result { + let request = state_transition.wait_for_state_transition_result_request()?; + + let response = request.execute(sdk, RequestSettings::default()).await?; + + let block_info = block_info_from_metadata(response.metadata()?)?; + + let proof = response.proof_owned()?; + + let (_, result) = Drive::verify_state_transition_was_executed_with_proof( + &state_transition, + &block_info, + proof.grovedb_proof.as_slice(), + &|_| Ok(Some(data_contract.clone())), + sdk.version(), + )?; + + match result { + StateTransitionProofResult::VerifiedDocuments(mut documents) => { + let document = documents + .remove(self.id_ref()) + .ok_or(Error::InvalidProvedResponse( + "did not prove the sent document".to_string(), + ))? + .ok_or(Error::InvalidProvedResponse( + "expected there to actually be a document".to_string(), + ))?; + Ok(document) + } + _ => Err(Error::DapiClientError("proved a non document".to_string())), + } + } + + async fn update_price_of_document_and_wait_for_response( + &self, + price: Credits, + sdk: &Sdk, + document_type: DocumentType, + identity_public_key: IdentityPublicKey, + data_contract: Arc, + signer: &S, + ) -> Result { + let state_transition = self + .update_price_of_document(price, sdk, document_type, identity_public_key, signer, None) + .await?; + + let document = >::wait_for_response( + self, + sdk, + state_transition, + data_contract, + ) + .await?; + + Ok(document) + } +} diff --git a/packages/rs-sdk/tests/fetch/common.rs b/packages/rs-sdk/tests/fetch/common.rs index 2ad8df272ff..e286593bb61 100644 --- a/packages/rs-sdk/tests/fetch/common.rs +++ b/packages/rs-sdk/tests/fetch/common.rs @@ -29,6 +29,7 @@ pub fn mock_document_type() -> dpp::data_contract::document_type::DocumentType { None, false, false, + false, true, &mut vec![], platform_version, diff --git a/packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-20T17:32:57.729547000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-24T00:37:29.546154000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json similarity index 96% rename from packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-20T17:32:57.729547000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json rename to packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-24T00:37:29.546154000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json index 0528f564cf7..a20af6fd4f9 100644 Binary files a/packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-20T17:32:57.729547000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and b/packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-24T00:37:29.546154000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-20T17:32:57.791831000Z_DocumentQuery_4dd78cc4a7f90bcf8393c36115a093d92d2c84b425f8393ffa9599b06a3a77be.json b/packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-24T00:37:29.598081000Z_DocumentQuery_466b07ebed6757e3497ed2487cd8a6c7c92c604537febea6e2287e0e3f386284.json similarity index 87% rename from packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-20T17:32:57.791831000Z_DocumentQuery_4dd78cc4a7f90bcf8393c36115a093d92d2c84b425f8393ffa9599b06a3a77be.json rename to packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-24T00:37:29.598081000Z_DocumentQuery_466b07ebed6757e3497ed2487cd8a6c7c92c604537febea6e2287e0e3f386284.json index 99bd6629a38..2ba70ef6edf 100644 Binary files a/packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-20T17:32:57.791831000Z_DocumentQuery_4dd78cc4a7f90bcf8393c36115a093d92d2c84b425f8393ffa9599b06a3a77be.json and b/packages/rs-sdk/tests/vectors/document_list_document_query/msg_2024-04-24T00:37:29.598081000Z_DocumentQuery_466b07ebed6757e3497ed2487cd8a6c7c92c604537febea6e2287e0e3f386284.json differ diff --git a/packages/rs-sdk/tests/vectors/document_list_document_query/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/document_list_document_query/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/document_list_document_query/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/document_list_document_query/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/document_list_document_query/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/document_list_document_query/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-20T17:32:57.732862000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-24T00:37:29.544194000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json similarity index 96% rename from packages/rs-sdk/tests/vectors/document_read/msg_2024-04-20T17:32:57.732862000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json rename to packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-24T00:37:29.544194000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json index 0528f564cf7..a20af6fd4f9 100644 Binary files a/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-20T17:32:57.732862000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and b/packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-24T00:37:29.544194000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-20T17:32:57.791314000Z_DocumentQuery_c104c67292061fe0b8e2f959cd2625892e0011f1264c65e1474532f59456ff51.json b/packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-24T00:37:29.598737000Z_DocumentQuery_f7b86e21e5bcf796a7c9d570c64ee4e5ee0324e5f38b49daf9dc9d1f1384bdae.json similarity index 87% rename from packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-20T17:32:57.791314000Z_DocumentQuery_c104c67292061fe0b8e2f959cd2625892e0011f1264c65e1474532f59456ff51.json rename to packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-24T00:37:29.598737000Z_DocumentQuery_f7b86e21e5bcf796a7c9d570c64ee4e5ee0324e5f38b49daf9dc9d1f1384bdae.json index 441ce761234..29d1cf16b88 100644 Binary files a/packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-20T17:32:57.791314000Z_DocumentQuery_c104c67292061fe0b8e2f959cd2625892e0011f1264c65e1474532f59456ff51.json and b/packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-24T00:37:29.598737000Z_DocumentQuery_f7b86e21e5bcf796a7c9d570c64ee4e5ee0324e5f38b49daf9dc9d1f1384bdae.json differ diff --git a/packages/rs-sdk/tests/vectors/document_list_drive_query/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/document_list_drive_query/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/document_list_drive_query/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/document_list_drive_query/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/document_list_drive_query/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/document_list_drive_query/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-20T17:32:57.729722000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-24T00:37:29.546204000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json similarity index 96% rename from packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-20T17:32:57.729722000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json rename to packages/rs-sdk/tests/vectors/document_read/msg_2024-04-24T00:37:29.546204000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json index 0528f564cf7..a20af6fd4f9 100644 Binary files a/packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-20T17:32:57.729722000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and b/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-24T00:37:29.546204000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-20T17:32:57.792844000Z_DocumentQuery_4dd78cc4a7f90bcf8393c36115a093d92d2c84b425f8393ffa9599b06a3a77be.json b/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-24T00:37:29.597728000Z_DocumentQuery_466b07ebed6757e3497ed2487cd8a6c7c92c604537febea6e2287e0e3f386284.json similarity index 87% rename from packages/rs-sdk/tests/vectors/document_read/msg_2024-04-20T17:32:57.792844000Z_DocumentQuery_4dd78cc4a7f90bcf8393c36115a093d92d2c84b425f8393ffa9599b06a3a77be.json rename to packages/rs-sdk/tests/vectors/document_read/msg_2024-04-24T00:37:29.597728000Z_DocumentQuery_466b07ebed6757e3497ed2487cd8a6c7c92c604537febea6e2287e0e3f386284.json index 99bd6629a38..2ba70ef6edf 100644 Binary files a/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-20T17:32:57.792844000Z_DocumentQuery_4dd78cc4a7f90bcf8393c36115a093d92d2c84b425f8393ffa9599b06a3a77be.json and b/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-24T00:37:29.597728000Z_DocumentQuery_466b07ebed6757e3497ed2487cd8a6c7c92c604537febea6e2287e0e3f386284.json differ diff --git a/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-20T17:32:57.805474000Z_DocumentQuery_90af5a08200f1b0e42dbd3ad7a6af38ff6415d9cabab87315b9d9d736194597f.json b/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-24T00:37:29.611459000Z_DocumentQuery_254e866b054c1427a47d649d455dfd789f4e600ee4aa306f63d281b740f2d0e7.json similarity index 87% rename from packages/rs-sdk/tests/vectors/document_read/msg_2024-04-20T17:32:57.805474000Z_DocumentQuery_90af5a08200f1b0e42dbd3ad7a6af38ff6415d9cabab87315b9d9d736194597f.json rename to packages/rs-sdk/tests/vectors/document_read/msg_2024-04-24T00:37:29.611459000Z_DocumentQuery_254e866b054c1427a47d649d455dfd789f4e600ee4aa306f63d281b740f2d0e7.json index 1325a37dbf1..e92d96a3240 100644 Binary files a/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-20T17:32:57.805474000Z_DocumentQuery_90af5a08200f1b0e42dbd3ad7a6af38ff6415d9cabab87315b9d9d736194597f.json and b/packages/rs-sdk/tests/vectors/document_read/msg_2024-04-24T00:37:29.611459000Z_DocumentQuery_254e866b054c1427a47d649d455dfd789f4e600ee4aa306f63d281b740f2d0e7.json differ diff --git a/packages/rs-sdk/tests/vectors/document_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/document_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/document_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/document_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/document_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/document_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/document_read_no_contract/msg_2024-04-20T17:32:57.733023000Z_GetDataContractRequest_e4cf74168e03a40bd159451456b501c1ba166a2dd8f6efb31b0289dc011da983.json b/packages/rs-sdk/tests/vectors/document_read_no_contract/msg_2024-04-24T00:37:29.543524000Z_GetDataContractRequest_e4cf74168e03a40bd159451456b501c1ba166a2dd8f6efb31b0289dc011da983.json similarity index 66% rename from packages/rs-sdk/tests/vectors/document_read_no_contract/msg_2024-04-20T17:32:57.733023000Z_GetDataContractRequest_e4cf74168e03a40bd159451456b501c1ba166a2dd8f6efb31b0289dc011da983.json rename to packages/rs-sdk/tests/vectors/document_read_no_contract/msg_2024-04-24T00:37:29.543524000Z_GetDataContractRequest_e4cf74168e03a40bd159451456b501c1ba166a2dd8f6efb31b0289dc011da983.json index 029dad249d0..c3d5d74ec79 100644 Binary files a/packages/rs-sdk/tests/vectors/document_read_no_contract/msg_2024-04-20T17:32:57.733023000Z_GetDataContractRequest_e4cf74168e03a40bd159451456b501c1ba166a2dd8f6efb31b0289dc011da983.json and b/packages/rs-sdk/tests/vectors/document_read_no_contract/msg_2024-04-24T00:37:29.543524000Z_GetDataContractRequest_e4cf74168e03a40bd159451456b501c1ba166a2dd8f6efb31b0289dc011da983.json differ diff --git a/packages/rs-sdk/tests/vectors/document_read_no_contract/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/document_read_no_contract/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/document_read_no_contract/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/document_read_no_contract/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/document_read_no_contract/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/document_read_no_contract/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-20T17:32:57.734304000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-24T00:37:29.545143000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json similarity index 96% rename from packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-20T17:32:57.734304000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json rename to packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-24T00:37:29.545143000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json index 0528f564cf7..a20af6fd4f9 100644 Binary files a/packages/rs-sdk/tests/vectors/document_list_drive_query/msg_2024-04-20T17:32:57.734304000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and b/packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-24T00:37:29.545143000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-20T17:32:57.792219000Z_DocumentQuery_fb3b25c8fa37750a6c1b18d9085fcf0df7bf150009b1ced887a6f051ab86085b.json b/packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-24T00:37:29.598817000Z_DocumentQuery_d67f67ad2f9ff259ca475971fae971699f696f184c08c2a12a5930a1d6631661.json similarity index 86% rename from packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-20T17:32:57.792219000Z_DocumentQuery_fb3b25c8fa37750a6c1b18d9085fcf0df7bf150009b1ced887a6f051ab86085b.json rename to packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-24T00:37:29.598817000Z_DocumentQuery_d67f67ad2f9ff259ca475971fae971699f696f184c08c2a12a5930a1d6631661.json index 9cc73151769..1fd3f33a522 100644 Binary files a/packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-20T17:32:57.792219000Z_DocumentQuery_fb3b25c8fa37750a6c1b18d9085fcf0df7bf150009b1ced887a6f051ab86085b.json and b/packages/rs-sdk/tests/vectors/document_read_no_document/msg_2024-04-24T00:37:29.598817000Z_DocumentQuery_d67f67ad2f9ff259ca475971fae971699f696f184c08c2a12a5930a1d6631661.json differ diff --git a/packages/rs-sdk/tests/vectors/document_read_no_document/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/document_read_no_document/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/document_read_no_document/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/document_read_no_document/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/document_read_no_document/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/document_read_no_document/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_data_contract_read/msg_2024-04-20T17:32:57.729789000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/test_data_contract_read/msg_2024-04-20T17:32:57.729789000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json deleted file mode 100644 index 0528f564cf7..00000000000 Binary files a/packages/rs-sdk/tests/vectors/test_data_contract_read/msg_2024-04-20T17:32:57.729789000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json and /dev/null differ diff --git a/packages/rs-sdk/tests/vectors/test_data_contract_read/msg_2024-04-24T00:37:29.546319000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json b/packages/rs-sdk/tests/vectors/test_data_contract_read/msg_2024-04-24T00:37:29.546319000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json new file mode 100644 index 00000000000..a20af6fd4f9 Binary files /dev/null and b/packages/rs-sdk/tests/vectors/test_data_contract_read/msg_2024-04-24T00:37:29.546319000Z_GetDataContractRequest_e87a2e6acef76975c30eb7272da71733fb6ad13495beb7ca1b6a6c4ceb30e0f7.json differ diff --git a/packages/rs-sdk/tests/vectors/test_data_contract_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_data_contract_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_data_contract_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_data_contract_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_data_contract_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_data_contract_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/msg_2024-04-20T17:32:57.732964000Z_GetDataContractRequest_1d1e53ab5e04d9ec5dce4ff9ac048c03122daf7ab2e77108f4bf44af1ad15eae.json b/packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/msg_2024-04-24T00:37:29.544535000Z_GetDataContractRequest_1d1e53ab5e04d9ec5dce4ff9ac048c03122daf7ab2e77108f4bf44af1ad15eae.json similarity index 66% rename from packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/msg_2024-04-20T17:32:57.732964000Z_GetDataContractRequest_1d1e53ab5e04d9ec5dce4ff9ac048c03122daf7ab2e77108f4bf44af1ad15eae.json rename to packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/msg_2024-04-24T00:37:29.544535000Z_GetDataContractRequest_1d1e53ab5e04d9ec5dce4ff9ac048c03122daf7ab2e77108f4bf44af1ad15eae.json index 3dee81e184d..3cc40f9459e 100644 Binary files a/packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/msg_2024-04-20T17:32:57.732964000Z_GetDataContractRequest_1d1e53ab5e04d9ec5dce4ff9ac048c03122daf7ab2e77108f4bf44af1ad15eae.json and b/packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/msg_2024-04-24T00:37:29.544535000Z_GetDataContractRequest_1d1e53ab5e04d9ec5dce4ff9ac048c03122daf7ab2e77108f4bf44af1ad15eae.json differ diff --git a/packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_data_contract_read_not_found/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/msg_2024-04-20T17:32:57.730152000Z_GetDataContractsRequest_f229a0e58a5c4fb050f57c087bf067bd9ccc29eca3092a5664a5a9ba3bb7e967.json b/packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/msg_2024-04-24T00:37:29.544223000Z_GetDataContractsRequest_f229a0e58a5c4fb050f57c087bf067bd9ccc29eca3092a5664a5a9ba3bb7e967.json similarity index 96% rename from packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/msg_2024-04-20T17:32:57.730152000Z_GetDataContractsRequest_f229a0e58a5c4fb050f57c087bf067bd9ccc29eca3092a5664a5a9ba3bb7e967.json rename to packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/msg_2024-04-24T00:37:29.544223000Z_GetDataContractsRequest_f229a0e58a5c4fb050f57c087bf067bd9ccc29eca3092a5664a5a9ba3bb7e967.json index e5b544d05db..4fcf0041b93 100644 Binary files a/packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/msg_2024-04-20T17:32:57.730152000Z_GetDataContractsRequest_f229a0e58a5c4fb050f57c087bf067bd9ccc29eca3092a5664a5a9ba3bb7e967.json and b/packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/msg_2024-04-24T00:37:29.544223000Z_GetDataContractsRequest_f229a0e58a5c4fb050f57c087bf067bd9ccc29eca3092a5664a5a9ba3bb7e967.json differ diff --git a/packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_data_contracts_1_ok_1_nx/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/msg_2024-04-20T17:32:57.729112000Z_GetDataContractsRequest_93bdf343bce1bafb96fd873236cabbc4ac6ad7e80f0e55fe98bbcfbebf6c0878.json b/packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/msg_2024-04-24T00:37:29.547687000Z_GetDataContractsRequest_93bdf343bce1bafb96fd873236cabbc4ac6ad7e80f0e55fe98bbcfbebf6c0878.json similarity index 66% rename from packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/msg_2024-04-20T17:32:57.729112000Z_GetDataContractsRequest_93bdf343bce1bafb96fd873236cabbc4ac6ad7e80f0e55fe98bbcfbebf6c0878.json rename to packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/msg_2024-04-24T00:37:29.547687000Z_GetDataContractsRequest_93bdf343bce1bafb96fd873236cabbc4ac6ad7e80f0e55fe98bbcfbebf6c0878.json index fc630dc6888..4123a0044a3 100644 Binary files a/packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/msg_2024-04-20T17:32:57.729112000Z_GetDataContractsRequest_93bdf343bce1bafb96fd873236cabbc4ac6ad7e80f0e55fe98bbcfbebf6c0878.json and b/packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/msg_2024-04-24T00:37:29.547687000Z_GetDataContractsRequest_93bdf343bce1bafb96fd873236cabbc4ac6ad7e80f0e55fe98bbcfbebf6c0878.json differ diff --git a/packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_data_contracts_2_nx/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-20T17:32:57.792457000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-24T00:37:29.599078000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json similarity index 74% rename from packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-20T17:32:57.792457000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json rename to packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-24T00:37:29.599078000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json index 348f1953ea7..883396a628a 100644 Binary files a/packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-20T17:32:57.792457000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json and b/packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-24T00:37:29.599078000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-20T17:32:57.933588000Z_GetEpochsInfoRequest_b2b426ac4a52cb4cb08904c63386caf3663c40a12d3b03827006d66058e439ac.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-24T00:37:29.754758000Z_GetEpochsInfoRequest_b2b426ac4a52cb4cb08904c63386caf3663c40a12d3b03827006d66058e439ac.json similarity index 99% rename from packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-20T17:32:57.933588000Z_GetEpochsInfoRequest_b2b426ac4a52cb4cb08904c63386caf3663c40a12d3b03827006d66058e439ac.json rename to packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-24T00:37:29.754758000Z_GetEpochsInfoRequest_b2b426ac4a52cb4cb08904c63386caf3663c40a12d3b03827006d66058e439ac.json index b0522e468fb..4d1eaa7fe52 100644 Binary files a/packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-20T17:32:57.933588000Z_GetEpochsInfoRequest_b2b426ac4a52cb4cb08904c63386caf3663c40a12d3b03827006d66058e439ac.json and b/packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-24T00:37:29.754758000Z_GetEpochsInfoRequest_b2b426ac4a52cb4cb08904c63386caf3663c40a12d3b03827006d66058e439ac.json differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_epoch_fetch/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_epoch_fetch/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-20T17:32:57.792846000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-24T00:37:29.598966000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json similarity index 74% rename from packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-20T17:32:57.792846000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json rename to packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-24T00:37:29.598966000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json index 348f1953ea7..883396a628a 100644 Binary files a/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-20T17:32:57.792846000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json and b/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-24T00:37:29.598966000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-20T17:32:57.795519000Z_GetEpochsInfoRequest_1b87e649557ccb609adb9e2904c67089535588985622579e77969e0ffd68afc7.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-24T00:37:29.606190000Z_GetEpochsInfoRequest_1b87e649557ccb609adb9e2904c67089535588985622579e77969e0ffd68afc7.json similarity index 86% rename from packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-20T17:32:57.795519000Z_GetEpochsInfoRequest_1b87e649557ccb609adb9e2904c67089535588985622579e77969e0ffd68afc7.json rename to packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-24T00:37:29.606190000Z_GetEpochsInfoRequest_1b87e649557ccb609adb9e2904c67089535588985622579e77969e0ffd68afc7.json index ac77510963d..4e023eea4ea 100644 Binary files a/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-20T17:32:57.795519000Z_GetEpochsInfoRequest_1b87e649557ccb609adb9e2904c67089535588985622579e77969e0ffd68afc7.json and b/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-24T00:37:29.606190000Z_GetEpochsInfoRequest_1b87e649557ccb609adb9e2904c67089535588985622579e77969e0ffd68afc7.json differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-20T17:32:57.792584000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-24T00:37:29.598638000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json similarity index 74% rename from packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-20T17:32:57.792584000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json rename to packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-24T00:37:29.598638000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json index 348f1953ea7..883396a628a 100644 Binary files a/packages/rs-sdk/tests/vectors/test_epoch_fetch/msg_2024-04-20T17:32:57.792584000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json and b/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-24T00:37:29.598638000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-20T17:32:58.239918000Z_GetEpochsInfoRequest_6a828350e795a088dbc835260a1add01a7428085ffdcf1e11cccf19c48c5f7a1.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-24T00:37:30.085258000Z_GetEpochsInfoRequest_6a828350e795a088dbc835260a1add01a7428085ffdcf1e11cccf19c48c5f7a1.json similarity index 99% rename from packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-20T17:32:58.239918000Z_GetEpochsInfoRequest_6a828350e795a088dbc835260a1add01a7428085ffdcf1e11cccf19c48c5f7a1.json rename to packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-24T00:37:30.085258000Z_GetEpochsInfoRequest_6a828350e795a088dbc835260a1add01a7428085ffdcf1e11cccf19c48c5f7a1.json index 47a7cc84c41..374fc7868a5 100644 Binary files a/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-20T17:32:58.239918000Z_GetEpochsInfoRequest_6a828350e795a088dbc835260a1add01a7428085ffdcf1e11cccf19c48c5f7a1.json and b/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/msg_2024-04-24T00:37:30.085258000Z_GetEpochsInfoRequest_6a828350e795a088dbc835260a1add01a7428085ffdcf1e11cccf19c48c5f7a1.json differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_epoch_fetch_future/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-24T00:37:29.599207000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json b/packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-24T00:37:29.599207000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json new file mode 100644 index 00000000000..883396a628a Binary files /dev/null and b/packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-24T00:37:29.599207000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-20T17:32:58.219154000Z_GetEpochsInfoRequest_734f6594c67fe6a9ab170191031d592c8fe7361bed628d9a36747664c9789bf1.json b/packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-24T00:37:30.072218000Z_GetEpochsInfoRequest_734f6594c67fe6a9ab170191031d592c8fe7361bed628d9a36747664c9789bf1.json similarity index 99% rename from packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-20T17:32:58.219154000Z_GetEpochsInfoRequest_734f6594c67fe6a9ab170191031d592c8fe7361bed628d9a36747664c9789bf1.json rename to packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-24T00:37:30.072218000Z_GetEpochsInfoRequest_734f6594c67fe6a9ab170191031d592c8fe7361bed628d9a36747664c9789bf1.json index 8d42780da13..34407691cb2 100644 Binary files a/packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-20T17:32:58.219154000Z_GetEpochsInfoRequest_734f6594c67fe6a9ab170191031d592c8fe7361bed628d9a36747664c9789bf1.json and b/packages/rs-sdk/tests/vectors/test_epoch_list/msg_2024-04-24T00:37:30.072218000Z_GetEpochsInfoRequest_734f6594c67fe6a9ab170191031d592c8fe7361bed628d9a36747664c9789bf1.json differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_list/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_epoch_list/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_epoch_list/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_epoch_list/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_epoch_list/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_epoch_list/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-20T17:32:57.794148000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json b/packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-20T17:32:57.794148000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json deleted file mode 100644 index 348f1953ea7..00000000000 Binary files a/packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-20T17:32:57.794148000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json and /dev/null differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-24T00:37:29.599593000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json b/packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-24T00:37:29.599593000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json new file mode 100644 index 00000000000..883396a628a Binary files /dev/null and b/packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-24T00:37:29.599593000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-20T17:32:58.215202000Z_GetEpochsInfoRequest_ae2b6b4e09e8e68e73f2df9af38b0b93d9d2e841a5e3d60755f8e7be3b93315b.json b/packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-24T00:37:30.072303000Z_GetEpochsInfoRequest_ae2b6b4e09e8e68e73f2df9af38b0b93d9d2e841a5e3d60755f8e7be3b93315b.json similarity index 99% rename from packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-20T17:32:58.215202000Z_GetEpochsInfoRequest_ae2b6b4e09e8e68e73f2df9af38b0b93d9d2e841a5e3d60755f8e7be3b93315b.json rename to packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-24T00:37:30.072303000Z_GetEpochsInfoRequest_ae2b6b4e09e8e68e73f2df9af38b0b93d9d2e841a5e3d60755f8e7be3b93315b.json index e6f8492c798..30a0e8c0d78 100644 Binary files a/packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-20T17:32:58.215202000Z_GetEpochsInfoRequest_ae2b6b4e09e8e68e73f2df9af38b0b93d9d2e841a5e3d60755f8e7be3b93315b.json and b/packages/rs-sdk/tests/vectors/test_epoch_list_limit/msg_2024-04-24T00:37:30.072303000Z_GetEpochsInfoRequest_ae2b6b4e09e8e68e73f2df9af38b0b93d9d2e841a5e3d60755f8e7be3b93315b.json differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_list_limit/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_epoch_list_limit/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_epoch_list_limit/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_epoch_list_limit/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_epoch_list_limit/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_epoch_list_limit/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_balance_read/msg_2024-04-20T17:32:57.805378000Z_GetIdentityBalanceRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json b/packages/rs-sdk/tests/vectors/test_identity_balance_read/msg_2024-04-24T00:37:29.611908000Z_GetIdentityBalanceRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json similarity index 68% rename from packages/rs-sdk/tests/vectors/test_identity_balance_read/msg_2024-04-20T17:32:57.805378000Z_GetIdentityBalanceRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json rename to packages/rs-sdk/tests/vectors/test_identity_balance_read/msg_2024-04-24T00:37:29.611908000Z_GetIdentityBalanceRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json index 16eed9d48e9..ed92121f133 100644 Binary files a/packages/rs-sdk/tests/vectors/test_identity_balance_read/msg_2024-04-20T17:32:57.805378000Z_GetIdentityBalanceRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json and b/packages/rs-sdk/tests/vectors/test_identity_balance_read/msg_2024-04-24T00:37:29.611908000Z_GetIdentityBalanceRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json differ diff --git a/packages/rs-sdk/tests/vectors/test_identity_balance_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_identity_balance_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_identity_balance_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_balance_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_identity_balance_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_identity_balance_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/msg_2024-04-20T17:32:57.807110000Z_GetIdentityBalanceAndRevisionRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json b/packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/msg_2024-04-20T17:32:57.807110000Z_GetIdentityBalanceAndRevisionRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json deleted file mode 100644 index 4f098886a58..00000000000 Binary files a/packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/msg_2024-04-20T17:32:57.807110000Z_GetIdentityBalanceAndRevisionRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json and /dev/null differ diff --git a/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-20T17:32:57.791668000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json b/packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/msg_2024-04-24T00:37:29.615871000Z_GetIdentityBalanceAndRevisionRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json similarity index 75% rename from packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-20T17:32:57.791668000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json rename to packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/msg_2024-04-24T00:37:29.615871000Z_GetIdentityBalanceAndRevisionRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json index 348f1953ea7..c23d877534b 100644 Binary files a/packages/rs-sdk/tests/vectors/test_epoch_fetch_current/msg_2024-04-20T17:32:57.791668000Z_GetIdentityRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json and b/packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/msg_2024-04-24T00:37:29.615871000Z_GetIdentityBalanceAndRevisionRequest_e4060c14ceaca6844d682c7393d7776113debe4287515ae60d0645da450a80a1.json differ diff --git a/packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_identity_balance_revision_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/msg_2024-04-20T17:32:57.825471000Z_GetIdentityContractNonceRequest_b7c02dae0c3c762ece1f70a36f88fa69b4749b19cc1f5ef0abf37fa0c04ab2ef.json b/packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/msg_2024-04-24T00:37:29.632356000Z_GetIdentityContractNonceRequest_b7c02dae0c3c762ece1f70a36f88fa69b4749b19cc1f5ef0abf37fa0c04ab2ef.json similarity index 71% rename from packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/msg_2024-04-20T17:32:57.825471000Z_GetIdentityContractNonceRequest_b7c02dae0c3c762ece1f70a36f88fa69b4749b19cc1f5ef0abf37fa0c04ab2ef.json rename to packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/msg_2024-04-24T00:37:29.632356000Z_GetIdentityContractNonceRequest_b7c02dae0c3c762ece1f70a36f88fa69b4749b19cc1f5ef0abf37fa0c04ab2ef.json index d6c0fefcd87..e0e9171f38f 100644 Binary files a/packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/msg_2024-04-20T17:32:57.825471000Z_GetIdentityContractNonceRequest_b7c02dae0c3c762ece1f70a36f88fa69b4749b19cc1f5ef0abf37fa0c04ab2ef.json and b/packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/msg_2024-04-24T00:37:29.632356000Z_GetIdentityContractNonceRequest_b7c02dae0c3c762ece1f70a36f88fa69b4749b19cc1f5ef0abf37fa0c04ab2ef.json differ diff --git a/packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_identity_contract_no_nonce_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/msg_2024-04-20T17:32:57.805215000Z_GetIdentityKeysRequest_b4ecff7acf52818aef9ed37a98d4a459dc7a67570ea6df3f8858d3fae7820ffe.json b/packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/msg_2024-04-24T00:37:29.611949000Z_GetIdentityKeysRequest_b4ecff7acf52818aef9ed37a98d4a459dc7a67570ea6df3f8858d3fae7820ffe.json similarity index 72% rename from packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/msg_2024-04-20T17:32:57.805215000Z_GetIdentityKeysRequest_b4ecff7acf52818aef9ed37a98d4a459dc7a67570ea6df3f8858d3fae7820ffe.json rename to packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/msg_2024-04-24T00:37:29.611949000Z_GetIdentityKeysRequest_b4ecff7acf52818aef9ed37a98d4a459dc7a67570ea6df3f8858d3fae7820ffe.json index 73d7c1d6c87..a45f6fb1f95 100644 Binary files a/packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/msg_2024-04-20T17:32:57.805215000Z_GetIdentityKeysRequest_b4ecff7acf52818aef9ed37a98d4a459dc7a67570ea6df3f8858d3fae7820ffe.json and b/packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/msg_2024-04-24T00:37:29.611949000Z_GetIdentityKeysRequest_b4ecff7acf52818aef9ed37a98d4a459dc7a67570ea6df3f8858d3fae7820ffe.json differ diff --git a/packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_identity_public_keys_all_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_read/msg_2024-04-20T17:32:57.819765000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json b/packages/rs-sdk/tests/vectors/test_identity_read/msg_2024-04-24T00:37:29.627284000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json similarity index 74% rename from packages/rs-sdk/tests/vectors/test_identity_read/msg_2024-04-20T17:32:57.819765000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json rename to packages/rs-sdk/tests/vectors/test_identity_read/msg_2024-04-24T00:37:29.627284000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json index 26ea2400cf8..2f7f45c7000 100644 Binary files a/packages/rs-sdk/tests/vectors/test_identity_read/msg_2024-04-20T17:32:57.819765000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json and b/packages/rs-sdk/tests/vectors/test_identity_read/msg_2024-04-24T00:37:29.627284000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json differ diff --git a/packages/rs-sdk/tests/vectors/test_identity_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_identity_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_identity_read/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_identity_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_identity_read/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-20T17:32:57.822981000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json b/packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-24T00:37:29.629157000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json similarity index 74% rename from packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-20T17:32:57.822981000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json rename to packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-24T00:37:29.629157000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json index 26ea2400cf8..2f7f45c7000 100644 Binary files a/packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-20T17:32:57.822981000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json and b/packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-24T00:37:29.629157000Z_IdentityRequest_5789e2afa300c2ac039646d8b81c53464633a072722c5a04b15ee01f3a45de99.json differ diff --git a/packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-20T17:32:57.846960000Z_IdentityRequest_3107337faa1f180a1071b78a90dcdc46e3cf0d7d4ce093bba24086e17410ed7d.json b/packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-24T00:37:29.651813000Z_IdentityRequest_abf7b19244827334575a04cf67f428f9b6b120d8fa853e3398e1539b8fc54d9b.json similarity index 77% rename from packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-20T17:32:57.846960000Z_IdentityRequest_3107337faa1f180a1071b78a90dcdc46e3cf0d7d4ce093bba24086e17410ed7d.json rename to packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-24T00:37:29.651813000Z_IdentityRequest_abf7b19244827334575a04cf67f428f9b6b120d8fa853e3398e1539b8fc54d9b.json index 12a843e9bc7..de49a8398d2 100644 Binary files a/packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-20T17:32:57.846960000Z_IdentityRequest_3107337faa1f180a1071b78a90dcdc46e3cf0d7d4ce093bba24086e17410ed7d.json and b/packages/rs-sdk/tests/vectors/test_identity_read_by_key/msg_2024-04-24T00:37:29.651813000Z_IdentityRequest_abf7b19244827334575a04cf67f428f9b6b120d8fa853e3398e1539b8fc54d9b.json differ diff --git a/packages/rs-sdk/tests/vectors/test_identity_read_by_key/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_identity_read_by_key/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_identity_read_by_key/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_identity_read_by_key/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_identity_read_by_key/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_identity_read_by_key/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/msg_2024-04-20T17:32:57.844598000Z_GetProtocolVersionUpgradeStateRequest_bb149e1933b9dc561bbfacfb6d09550f0ea4a6af6f68037e7d50ff4e4de74509.json b/packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/msg_2024-04-24T00:37:29.650095000Z_GetProtocolVersionUpgradeStateRequest_bb149e1933b9dc561bbfacfb6d09550f0ea4a6af6f68037e7d50ff4e4de74509.json similarity index 67% rename from packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/msg_2024-04-20T17:32:57.844598000Z_GetProtocolVersionUpgradeStateRequest_bb149e1933b9dc561bbfacfb6d09550f0ea4a6af6f68037e7d50ff4e4de74509.json rename to packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/msg_2024-04-24T00:37:29.650095000Z_GetProtocolVersionUpgradeStateRequest_bb149e1933b9dc561bbfacfb6d09550f0ea4a6af6f68037e7d50ff4e4de74509.json index 78c519bd079..c81cd274819 100644 Binary files a/packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/msg_2024-04-20T17:32:57.844598000Z_GetProtocolVersionUpgradeStateRequest_bb149e1933b9dc561bbfacfb6d09550f0ea4a6af6f68037e7d50ff4e4de74509.json and b/packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/msg_2024-04-24T00:37:29.650095000Z_GetProtocolVersionUpgradeStateRequest_bb149e1933b9dc561bbfacfb6d09550f0ea4a6af6f68037e7d50ff4e4de74509.json differ diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_protocol_version_vote_count/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/msg_2024-04-20T17:32:57.847045000Z_GetProtocolVersionUpgradeVoteStatusRequest_ec9dca65a964669b3bc8195d5ff106e5eda740be44679cc960ea35f2134af628.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/msg_2024-04-24T00:37:29.650285000Z_GetProtocolVersionUpgradeVoteStatusRequest_ec9dca65a964669b3bc8195d5ff106e5eda740be44679cc960ea35f2134af628.json similarity index 69% rename from packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/msg_2024-04-20T17:32:57.847045000Z_GetProtocolVersionUpgradeVoteStatusRequest_ec9dca65a964669b3bc8195d5ff106e5eda740be44679cc960ea35f2134af628.json rename to packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/msg_2024-04-24T00:37:29.650285000Z_GetProtocolVersionUpgradeVoteStatusRequest_ec9dca65a964669b3bc8195d5ff106e5eda740be44679cc960ea35f2134af628.json index 21c535cabdd..c82ac29784c 100644 Binary files a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/msg_2024-04-20T17:32:57.847045000Z_GetProtocolVersionUpgradeVoteStatusRequest_ec9dca65a964669b3bc8195d5ff106e5eda740be44679cc960ea35f2134af628.json and b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/msg_2024-04-24T00:37:29.650285000Z_GetProtocolVersionUpgradeVoteStatusRequest_ec9dca65a964669b3bc8195d5ff106e5eda740be44679cc960ea35f2134af628.json differ diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_limit_2/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/msg_2024-04-20T17:32:57.846269000Z_GetProtocolVersionUpgradeVoteStatusRequest_983670ac95678b1166deab32209bf1acc3394d29ac72f662d38e81344496631e.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/msg_2024-04-24T00:37:29.653372000Z_GetProtocolVersionUpgradeVoteStatusRequest_983670ac95678b1166deab32209bf1acc3394d29ac72f662d38e81344496631e.json similarity index 68% rename from packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/msg_2024-04-20T17:32:57.846269000Z_GetProtocolVersionUpgradeVoteStatusRequest_983670ac95678b1166deab32209bf1acc3394d29ac72f662d38e81344496631e.json rename to packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/msg_2024-04-24T00:37:29.653372000Z_GetProtocolVersionUpgradeVoteStatusRequest_983670ac95678b1166deab32209bf1acc3394d29ac72f662d38e81344496631e.json index 59b15a0b608..82b4cc8cd36 100644 Binary files a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/msg_2024-04-20T17:32:57.846269000Z_GetProtocolVersionUpgradeVoteStatusRequest_983670ac95678b1166deab32209bf1acc3394d29ac72f662d38e81344496631e.json and b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/msg_2024-04-24T00:37:29.653372000Z_GetProtocolVersionUpgradeVoteStatusRequest_983670ac95678b1166deab32209bf1acc3394d29ac72f662d38e81344496631e.json differ diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_none/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/msg_2024-04-20T17:32:57.853232000Z_GetProtocolVersionUpgradeVoteStatusRequest_8534be7e0b4dd648520dc3a67209b1a05862cb8d40c088b193b59ca3564210bc.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/msg_2024-04-24T00:37:29.656446000Z_GetProtocolVersionUpgradeVoteStatusRequest_8534be7e0b4dd648520dc3a67209b1a05862cb8d40c088b193b59ca3564210bc.json similarity index 71% rename from packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/msg_2024-04-20T17:32:57.853232000Z_GetProtocolVersionUpgradeVoteStatusRequest_8534be7e0b4dd648520dc3a67209b1a05862cb8d40c088b193b59ca3564210bc.json rename to packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/msg_2024-04-24T00:37:29.656446000Z_GetProtocolVersionUpgradeVoteStatusRequest_8534be7e0b4dd648520dc3a67209b1a05862cb8d40c088b193b59ca3564210bc.json index 2c38e442166..2d44ba66353 100644 Binary files a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/msg_2024-04-20T17:32:57.853232000Z_GetProtocolVersionUpgradeVoteStatusRequest_8534be7e0b4dd648520dc3a67209b1a05862cb8d40c088b193b59ca3564210bc.json and b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/msg_2024-04-24T00:37:29.656446000Z_GetProtocolVersionUpgradeVoteStatusRequest_8534be7e0b4dd648520dc3a67209b1a05862cb8d40c088b193b59ca3564210bc.json differ diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_nx/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/msg_2024-04-20T17:32:57.858773000Z_GetProtocolVersionUpgradeVoteStatusRequest_92a45a0fe4f69d355022d2f2f7622dfc69cc7b123be24b7ad993281979b2a3a2.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/msg_2024-04-24T00:37:29.661820000Z_GetProtocolVersionUpgradeVoteStatusRequest_92a45a0fe4f69d355022d2f2f7622dfc69cc7b123be24b7ad993281979b2a3a2.json similarity index 69% rename from packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/msg_2024-04-20T17:32:57.858773000Z_GetProtocolVersionUpgradeVoteStatusRequest_92a45a0fe4f69d355022d2f2f7622dfc69cc7b123be24b7ad993281979b2a3a2.json rename to packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/msg_2024-04-24T00:37:29.661820000Z_GetProtocolVersionUpgradeVoteStatusRequest_92a45a0fe4f69d355022d2f2f7622dfc69cc7b123be24b7ad993281979b2a3a2.json index 392990daf17..3b75d945a3a 100644 Binary files a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/msg_2024-04-20T17:32:57.858773000Z_GetProtocolVersionUpgradeVoteStatusRequest_92a45a0fe4f69d355022d2f2f7622dfc69cc7b123be24b7ad993281979b2a3a2.json and b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/msg_2024-04-24T00:37:29.661820000Z_GetProtocolVersionUpgradeVoteStatusRequest_92a45a0fe4f69d355022d2f2f7622dfc69cc7b123be24b7ad993281979b2a3a2.json differ diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json new file mode 100644 index 00000000000..ca9f21e7523 --- /dev/null +++ b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/quorum_pubkey-106-32f78e1ab8f7beb1edc06a461c486e1afd90c1d4732f93cf8287fa0e9c27e35e.json @@ -0,0 +1 @@ +[183,213,77,25,46,6,139,69,130,159,190,72,193,8,131,191,105,54,247,90,65,206,156,68,41,55,185,93,114,209,189,211,207,236,91,86,76,47,4,205,217,32,122,8,123,104,168,118] \ No newline at end of file diff --git a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json b/packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json deleted file mode 100644 index 7f0850a40db..00000000000 --- a/packages/rs-sdk/tests/vectors/test_protocol_version_votes_zeros/quorum_pubkey-106-74a99f32dc4d12a6d3a3f02dfa34f96cedd665e3629baec62e8777fe169fc6e7.json +++ /dev/null @@ -1 +0,0 @@ -[132,249,59,196,81,157,6,73,112,77,16,80,212,23,49,138,16,164,4,130,169,33,129,84,52,20,174,186,3,132,254,96,166,51,9,209,96,142,242,180,224,179,143,71,37,70,89,13] \ No newline at end of file diff --git a/packages/strategy-tests/src/operations.rs b/packages/strategy-tests/src/operations.rs index 2affeddf50c..2cbf7e8a04a 100644 --- a/packages/strategy-tests/src/operations.rs +++ b/packages/strategy-tests/src/operations.rs @@ -323,6 +323,7 @@ impl PlatformDeserializableWithPotentialValidationFromVersionedStructure for Dat None, true, true, + true, validate, &mut vec![], platform_version, diff --git a/packages/wasm-dpp/Cargo.toml b/packages/wasm-dpp/Cargo.toml index 5bec0550a4f..dd1eff352df 100644 --- a/packages/wasm-dpp/Cargo.toml +++ b/packages/wasm-dpp/Cargo.toml @@ -18,7 +18,7 @@ serde_json = { version = "1.0", features = ["preserve_order"] } wasm-bindgen = { version = "=0.2.86" } js-sys = "0.3.53" web-sys = { version = "0.3.6", features = ["console"] } -thiserror = { version = "1.0.58" } +thiserror = { version = "1.0.59" } serde-wasm-bindgen = { git = "https://github.com/QuantumExplorer/serde-wasm-bindgen", branch = "feat/not_human_readable" } dpp = { path = "../rs-dpp", default-features = false, features = [ "state-transition-serde-conversion", diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index c124b9f0ace..4f39880387c 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -61,10 +61,12 @@ use dpp::consensus::state::data_trigger::DataTriggerError::{ DataTriggerConditionError, DataTriggerExecutionError, DataTriggerInvalidResultError, }; use wasm_bindgen::{JsError, JsValue}; -use dpp::consensus::basic::data_contract::{InvalidDocumentTypeRequiredSecurityLevelError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTransferableTypeError}; -use dpp::consensus::basic::document::{MaxDocumentsTransitionsExceededError, MissingPositionsInDocumentTypePropertiesError}; +use dpp::consensus::basic::data_contract::{InvalidDocumentTypeRequiredSecurityLevelError, UnknownDocumentCreationRestrictionModeError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError}; +use dpp::consensus::basic::document::{DocumentCreationNotAllowedError, MaxDocumentsTransitionsExceededError, MissingPositionsInDocumentTypePropertiesError}; use dpp::consensus::basic::identity::{DataContractBoundsNotPresentError, DisablingKeyIdAlsoBeingAddedInSameTransitionError, InvalidIdentityCreditWithdrawalTransitionAmountError, InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, TooManyMasterPublicKeyError}; use dpp::consensus::state::data_contract::document_type_update_error::DocumentTypeUpdateError; +use dpp::consensus::state::document::document_incorrect_purchase_price_error::DocumentIncorrectPurchasePriceError; +use dpp::consensus::state::document::document_not_for_sale_error::DocumentNotForSaleError; use dpp::consensus::state::identity::identity_public_key_already_exists_for_unique_contract_bounds_error::IdentityPublicKeyAlreadyExistsForUniqueContractBoundsError; use dpp::consensus::state::identity::master_public_key_update_error::MasterPublicKeyUpdateError; @@ -229,6 +231,12 @@ pub fn from_state_error(state_error: &StateError) -> JsValue { StateError::DocumentTypeUpdateError(e) => { generic_consensus_error!(DocumentTypeUpdateError, e).into() } + StateError::DocumentNotForSaleError(e) => { + generic_consensus_error!(DocumentNotForSaleError, e).into() + } + StateError::DocumentIncorrectPurchasePriceError(e) => { + generic_consensus_error!(DocumentIncorrectPurchasePriceError, e).into() + } } } @@ -460,6 +468,15 @@ fn from_basic_error(basic_error: &BasicError) -> JsValue { BasicError::UnknownTransferableTypeError(e) => { generic_consensus_error!(UnknownTransferableTypeError, e).into() } + BasicError::UnknownTradeModeError(e) => { + generic_consensus_error!(UnknownTradeModeError, e).into() + } + BasicError::UnknownDocumentCreationRestrictionModeError(e) => { + generic_consensus_error!(UnknownDocumentCreationRestrictionModeError, e).into() + } + BasicError::DocumentCreationNotAllowedError(e) => { + generic_consensus_error!(DocumentCreationNotAllowedError, e).into() + } } } diff --git a/packages/wasm-dpp/test/unit/dataContract/DataContract.spec.js b/packages/wasm-dpp/test/unit/dataContract/DataContract.spec.js index 649e61bc986..4726cb31cd5 100644 --- a/packages/wasm-dpp/test/unit/dataContract/DataContract.spec.js +++ b/packages/wasm-dpp/test/unit/dataContract/DataContract.spec.js @@ -223,6 +223,7 @@ describe('DataContract', () => { config: { $format_version: '0', canBeDeleted: false, + documentsCanBeDeletedContractDefault: true, documentsKeepHistoryContractDefault: false, documentsMutableContractDefault: true, keepsHistory: false, @@ -252,6 +253,7 @@ describe('DataContract', () => { config: { $format_version: '0', canBeDeleted: false, + documentsCanBeDeletedContractDefault: true, documentsKeepHistoryContractDefault: false, documentsMutableContractDefault: true, keepsHistory: false, @@ -272,7 +274,7 @@ describe('DataContract', () => { it('should return DataContract as a Buffer', () => { const result = dataContract.toBuffer(); expect(result).to.be.instanceOf(Buffer); - expect(result).to.have.lengthOf(235); + expect(result).to.have.lengthOf(236); }); }); diff --git a/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractCreateTransition/DataContractCreateTransition.spec.js b/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractCreateTransition/DataContractCreateTransition.spec.js index 973c2f90e31..dc394aee3c6 100644 --- a/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractCreateTransition/DataContractCreateTransition.spec.js +++ b/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractCreateTransition/DataContractCreateTransition.spec.js @@ -66,7 +66,7 @@ describe('DataContractCreateTransition', () => { it('should return serialized State Transition', () => { const result = stateTransition.toBuffer(); expect(result).to.be.instanceOf(Buffer); - expect(result).to.have.lengthOf(2358); + expect(result).to.have.lengthOf(2359); }); it('should be able to restore contract config from bytes', () => { diff --git a/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractUpdateTransition/DataContractUpdateTransition.spec.js b/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractUpdateTransition/DataContractUpdateTransition.spec.js index dd2cda514c3..444f695113c 100644 --- a/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractUpdateTransition/DataContractUpdateTransition.spec.js +++ b/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractUpdateTransition/DataContractUpdateTransition.spec.js @@ -65,7 +65,7 @@ describe('DataContractUpdateTransition', () => { it('should return serialized State Transition', () => { const result = stateTransition.toBuffer(); expect(result).to.be.instanceOf(Buffer); - expect(result).to.have.lengthOf(2358); + expect(result).to.have.lengthOf(2359); }); it('should be able to restore contract config from bytes', () => { diff --git a/packages/wasm-dpp/test/unit/document/Document.spec.js b/packages/wasm-dpp/test/unit/document/Document.spec.js index 8e7f80d90b5..3caa3750ccf 100644 --- a/packages/wasm-dpp/test/unit/document/Document.spec.js +++ b/packages/wasm-dpp/test/unit/document/Document.spec.js @@ -424,7 +424,7 @@ describe('Document', () => { it('should return serialized Document', () => { const buffer = document.toBuffer(); expect(buffer).to.be.instanceOf(Buffer); - expect(buffer.length).to.equal(648); + expect(buffer.length).to.equal(649); }); // TODO: remove or replace?