diff --git a/Cargo.lock b/Cargo.lock index 610d978918b..4bd4298815b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2192,7 +2192,8 @@ dependencies = [ [[package]] name = "grovedb" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8#221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "611077565b279965fa34897787ae52f79471f0476db785116cceb92077f237ad" dependencies = [ "axum 0.7.5", "bincode", @@ -2224,7 +2225,8 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8#221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab159c3f82b0387f6a27a54930b18aa594b507013de947c8e909cf61abb75fe" dependencies = [ "integer-encoding", "intmap", @@ -2234,7 +2236,8 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8#221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dce2f34c6bfddb3a26696b42e6169f986330513e0e9f4c5d7ba290d09867a5e" dependencies = [ "grovedb-costs", "hex", @@ -2246,7 +2249,8 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8#221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4580e54da0031d2f36e50312f3361005099bceeb8adb0f6ccbf87a0880cd1b08" dependencies = [ "bincode", "bincode_derive", @@ -2270,7 +2274,8 @@ dependencies = [ [[package]] name = "grovedb-path" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8#221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d61e09bb3055358974ceb65b91752064979450092014d91a6bc4a52d77887ea" dependencies = [ "hex", ] @@ -2278,7 +2283,8 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8#221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33ff6be8e4e4a1e19383cd4af19df28b94b271c3138743570af9e1f0c8ec149" dependencies = [ "blake3", "grovedb-costs", @@ -2297,7 +2303,8 @@ dependencies = [ [[package]] name = "grovedb-version" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8#221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d61d27c76d49758b365a9e4a9da7f995f976b9525626bf645aef258024defd2" dependencies = [ "thiserror 2.0.12", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2306,7 +2313,8 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8#221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaebfe3c1e5f263f14fd25ab060543b31eb4b9d6bdc44fe220e88df6be7ddf59" dependencies = [ "hex", "itertools 0.14.0", @@ -2315,7 +2323,8 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8#221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34fe9eecb0ccf73934672d0b9cad7ebe0bb31f9a38a0bc98dd7ce602ac84fc53" dependencies = [ "serde", "serde_with 3.9.0", diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs index 5f9efe73b85..2f415c0be4b 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/distribution_function/evaluate_interval.rs @@ -1,11 +1,15 @@ use std::ops::{Div, RangeInclusive}; +#[cfg(feature = "token-reward-explanations")] use platform_version::version::PlatformVersion; use crate::balances::credits::TokenAmount; use crate::block::epoch::EpochIndex; -use crate::data_contract::associated_token::token_perpetual_distribution::distribution_function::{DistributionFunction, MAX_DISTRIBUTION_CYCLES_PARAM}; +use crate::data_contract::associated_token::token_perpetual_distribution::distribution_function::DistributionFunction; +#[cfg(feature = "token-reward-explanations")] +use crate::data_contract::associated_token::token_perpetual_distribution::distribution_function::MAX_DISTRIBUTION_CYCLES_PARAM; use crate::data_contract::associated_token::token_perpetual_distribution::distribution_function::reward_ratio::RewardRatio; use crate::data_contract::associated_token::token_perpetual_distribution::reward_distribution_moment::RewardDistributionMoment; use crate::ProtocolError; +#[cfg(feature = "token-reward-explanations")] use chrono::{Utc, TimeZone}; #[cfg(feature = "token-reward-explanations")] use chrono_tz::Tz; 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 59941e0accc..456da8d451f 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -66,8 +66,9 @@ use crate::consensus::basic::identity::{ InvalidIdentityPublicKeyDataError, InvalidIdentityPublicKeySecurityLevelError, InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, InvalidInstantAssetLockProofError, InvalidInstantAssetLockProofSignatureError, - MissingMasterPublicKeyError, NotImplementedIdentityCreditWithdrawalTransitionPoolingError, - TooManyMasterPublicKeyError, WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError, + InvalidKeyPurposeForContractBoundsError, MissingMasterPublicKeyError, + NotImplementedIdentityCreditWithdrawalTransitionPoolingError, TooManyMasterPublicKeyError, + WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError, }; use crate::consensus::basic::invalid_identifier_error::InvalidIdentifierError; use crate::consensus::basic::state_transition::{ @@ -587,6 +588,9 @@ pub enum BasicError { #[error(transparent)] GroupHasTooFewMembersError(GroupHasTooFewMembersError), + + #[error(transparent)] + InvalidKeyPurposeForContractBoundsError(InvalidKeyPurposeForContractBoundsError), } impl From for ConsensusError { diff --git a/packages/rs-dpp/src/errors/consensus/basic/identity/invalid_key_purpose_for_contract_bounds_error.rs b/packages/rs-dpp/src/errors/consensus/basic/identity/invalid_key_purpose_for_contract_bounds_error.rs new file mode 100644 index 00000000000..6014425b53c --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/identity/invalid_key_purpose_for_contract_bounds_error.rs @@ -0,0 +1,47 @@ +use crate::consensus::basic::BasicError; +use crate::errors::ProtocolError; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +use crate::consensus::ConsensusError; + +use crate::identity::Purpose; +use bincode::{Decode, Encode}; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Key purpose {given_key_purpose} is not allowed for contract bounds. Allowed purposes: {allowed_key_purposes:?}")] +#[platform_serialize(unversioned)] +pub struct InvalidKeyPurposeForContractBoundsError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + given_key_purpose: Purpose, + allowed_key_purposes: Vec, +} + +impl InvalidKeyPurposeForContractBoundsError { + pub fn new(given_key_purpose: Purpose, allowed_key_purposes: Vec) -> Self { + Self { + given_key_purpose, + allowed_key_purposes, + } + } + + pub fn given_key_purpose(&self) -> Purpose { + self.given_key_purpose + } + + pub fn allowed_key_purposes(&self) -> &Vec { + &self.allowed_key_purposes + } +} + +impl From for ConsensusError { + fn from(err: InvalidKeyPurposeForContractBoundsError) -> Self { + Self::BasicError(BasicError::InvalidKeyPurposeForContractBoundsError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs index 3b411457faa..953a31a65e9 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/identity/mod.rs @@ -26,6 +26,7 @@ pub use invalid_identity_update_transition_disable_keys_error::*; pub use invalid_identity_update_transition_empty_error::*; pub use invalid_instant_asset_lock_proof_error::*; pub use invalid_instant_asset_lock_proof_signature_error::*; +pub use invalid_key_purpose_for_contract_bounds_error::*; pub use missing_master_public_key_error::*; pub use not_implemented_identity_credit_withdrawal_transition_pooling_error::*; pub use too_many_master_public_key_error::*; @@ -60,6 +61,7 @@ mod invalid_identity_update_transition_disable_keys_error; mod invalid_identity_update_transition_empty_error; mod invalid_instant_asset_lock_proof_error; mod invalid_instant_asset_lock_proof_signature_error; +mod invalid_key_purpose_for_contract_bounds_error; mod missing_master_public_key_error; mod not_implemented_identity_credit_withdrawal_transition_pooling_error; mod too_many_master_public_key_error; diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index 7720794b403..2ee8d8f7918 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -201,6 +201,7 @@ impl ErrorWithCode for BasicError { Self::IdentityAssetLockTransactionOutPointNotEnoughBalanceError(_) => 10530, Self::IdentityAssetLockStateTransitionReplayError(_) => 10531, Self::WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError(_) => 10532, + Self::InvalidKeyPurposeForContractBoundsError(_) => 10533, // State Transition Errors: 10600-10699 Self::InvalidStateTransitionTypeError { .. } => 10600, 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 287058514e3..d4eb16cf4ac 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 @@ -3528,7 +3528,7 @@ mod tests { .build_with_mock_rpc() .set_genesis_state(); - let (identity, signer, key) = + let (identity, signer, _, key) = setup_identity_return_master_key(&mut platform, 958, dash_to_credits!(0.1)); let mut rng = StdRng::seed_from_u64(1); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_identity_public_key_contract_bounds/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_identity_public_key_contract_bounds/v0/mod.rs index 48753f8193a..e20bbdf3c02 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_identity_public_key_contract_bounds/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_identity_public_key_contract_bounds/v0/mod.rs @@ -3,7 +3,7 @@ use crate::execution::types::state_transition_execution_context::StateTransition use dpp::consensus::basic::document::{ DataContractNotPresentError, InvalidDocumentTypeError, }; -use dpp::consensus::basic::identity::DataContractBoundsNotPresentError; +use dpp::consensus::basic::identity::{DataContractBoundsNotPresentError, InvalidKeyPurposeForContractBoundsError}; use dpp::consensus::basic::BasicError; use dpp::consensus::ConsensusError; use dpp::consensus::state::identity::identity_public_key_already_exists_for_unique_contract_bounds_error::IdentityPublicKeyAlreadyExistsForUniqueContractBoundsError; @@ -164,10 +164,13 @@ fn validate_identity_public_key_contract_bounds_v0( } } } - _ => Ok(SimpleConsensusValidationResult::new_with_error( + purpose => Ok(SimpleConsensusValidationResult::new_with_error( ConsensusError::BasicError( - BasicError::DataContractNotPresentError( - DataContractNotPresentError::new(*contract_id), + BasicError::InvalidKeyPurposeForContractBoundsError( + InvalidKeyPurposeForContractBoundsError::new( + purpose, + vec![ENCRYPTION, DECRYPTION], + ), ), ), )), @@ -279,8 +282,11 @@ fn validate_identity_public_key_contract_bounds_v0( } _ => Ok(SimpleConsensusValidationResult::new_with_error( ConsensusError::BasicError( - BasicError::DataContractNotPresentError( - DataContractNotPresentError::new(*contract_id), + BasicError::InvalidKeyPurposeForContractBoundsError( + InvalidKeyPurposeForContractBoundsError::new( + purpose, + vec![ENCRYPTION, DECRYPTION], + ), ), ), )), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/direct_selling/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/direct_selling/mod.rs index 5691b6414c1..16643c3ca14 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/direct_selling/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/token/direct_selling/mod.rs @@ -7,7 +7,6 @@ mod token_selling_tests { use super::*; - use crate::error::Error; use dpp::{ dashcore::secp256k1::hashes::hex::{Case, DisplayHex}, prelude::{DataContract, Identity, IdentityPublicKey}, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs index b580af61702..b76b38ab53d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs @@ -320,7 +320,6 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { )? .1 else { - println!("contract id not found {}", data_contract_id); return Ok(ConsensusValidationResult::new_with_error( BasicError::DataContractNotPresentError(DataContractNotPresentError::new( *data_contract_id, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs index a133712b696..f5662ee5728 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs @@ -163,7 +163,7 @@ mod tests { .build_with_mock_rpc() .set_genesis_state(); - let (identity, signer, key) = + let (identity, signer, _, key) = setup_identity_return_master_key(&mut platform, 958, dash_to_credits!(0.1)); let platform_state = platform.state.load(); @@ -236,7 +236,7 @@ mod tests { .build_with_mock_rpc() .set_genesis_state(); - let (identity, signer, key) = + let (identity, signer, _, key) = setup_identity_return_master_key(&mut platform, 958, dash_to_credits!(0.1)); let platform_state = platform.state.load(); @@ -385,7 +385,7 @@ mod tests { .build_with_mock_rpc() .set_genesis_state(); - let (mut identity, mut signer, master_key) = + let (mut identity, mut signer, _, master_key) = setup_identity_return_master_key(&mut platform, 958, dash_to_credits!(0.1)); let dashpay = platform.drive.cache.system_data_contracts.load_dashpay(); @@ -510,7 +510,7 @@ mod tests { .build_with_mock_rpc() .set_genesis_state(); - let (identity, signer, key) = + let (identity, signer, _, key) = setup_identity_return_master_key(&mut platform, 958, dash_to_credits!(0.1)); let platform_state = platform.state.load(); @@ -597,4 +597,666 @@ mod tests { assert_eq!(issues.len(), 0); } + + #[test] + fn test_identity_update_adding_contract_bound_key() { + use crate::execution::validation::state_transition::tests::{ + register_contract_from_bytes, IdentityTestInfo, + }; + + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform_version = PlatformVersion::latest(); + + let mut platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc() + .set_genesis_state(); + + // { + // "$format_version": "1", + // "id": "5pkMhyeaFjJfVMkFhLtJdDp2ofx6iqt7i9k6ckkHBwbs", + // "config": { + // "$format_version": "1", + // "canBeDeleted": false, + // "readonly": false, + // "keepsHistory": false, + // "documentsKeepHistoryContractDefault": false, + // "documentsMutableContractDefault": true, + // "documentsCanBeDeletedContractDefault": true, + // "requiresIdentityEncryptionBoundedKey": 0, + // "requiresIdentityDecryptionBoundedKey": 0, + // "sizedIntegerTypes": true + // }, + // "version": 1, + // "ownerId": "DicUmimv71VqxNBzZHXb887RgssSEjjx7DyLfxrt8q1X", + // "schemaDefs": null, + // "documentSchemas": { + // "preorder": { + // "documentsMutable": false, + // "canBeDeleted": true, + // "type": "object", + // "indices": [ + // { + // "name": "saltedHash", + // "properties": [ + // { + // "saltedDomainHash": "asc" + // } + // ], + // "unique": true + // } + // ], + // "properties": { + // "saltedDomainHash": { + // "type": "array", + // "byteArray": true, + // "minItems": 32, + // "maxItems": 32, + // "position": 0, + // "description": "Double sha-256 of the concatenation of a 32 byte random salt and a normalized domain name" + // } + // }, + // "required": [ + // "saltedDomainHash" + // ], + // "additionalProperties": false, + // "$comment": "Preorder documents are immutable: modification and deletion are restricted" + // } + // }, + // "createdAt": 1749816974718, + // "updatedAt": null, + // "createdAtBlockHeight": 159130, + // "updatedAtBlockHeight": null, + // "createdAtEpoch": 7906, + // "updatedAtEpoch": null, + // "groups": {}, + // "tokens": {}, + // "keywords": [], + // "description": null + // } + let contract_bytes = hex::decode("0147aa11d517710d509edaf84bb54902394dcb8f6cc68775138d1cdd8334600d2e01000000000101010001000101bcf52c1c5d57d2e21530c5d03ef4c6e7b39a91da7c444fdb17e0a7746b6285860001087072656f7264657216081210646f63756d656e74734d757461626c651300120c63616e426544656c65746564130012047479706512066f626a6563741207696e64696365731501160312046e616d65120a73616c74656448617368120a70726f7065727469657315011601121073616c746564446f6d61696e4861736812036173631206756e697175651301120a70726f706572746965731601121073616c746564446f6d61696e486173681606120474797065120561727261791209627974654172726179130112086d696e4974656d73022012086d61784974656d7302201208706f736974696f6e0200120b6465736372697074696f6e1259446f75626c65207368612d323536206f662074686520636f6e636174656e6174696f6e206f66206120333220627974652072616e646f6d2073616c7420616e642061206e6f726d616c697a656420646f6d61696e206e616d65120872657175697265641501121073616c746564446f6d61696e4861736812146164646974696f6e616c50726f706572746965731300120824636f6d6d656e74124a5072656f7264657220646f63756d656e74732061726520696d6d757461626c653a206d6f64696669636174696f6e20616e642064656c6574696f6e20617265207265737472696374656401fd0000019769381d7e0001fc00026d9a0001fb1ee20000000000").expect("expected to decode contract bytes"); + + let (identity, signer, critical_key, master_key) = + setup_identity_return_master_key(&mut platform, 958, dash_to_credits!(5.0)); + + let platform_state = platform.state.load(); + + // Register the contract + let data_contract = register_contract_from_bytes( + &mut platform, + &platform_state, + contract_bytes, + IdentityTestInfo::Given { + identity: &identity, + signer: &signer, + public_key: &critical_key, + identity_nonce: 1, + }, + platform_version, + ); + + let secp = Secp256k1::new(); + + let mut rng = StdRng::seed_from_u64(1292); + + let new_key_pair = Keypair::new(&secp, &mut rng); + + let mut new_key = IdentityPublicKeyInCreationV0 { + id: 2, + purpose: Purpose::ENCRYPTION, + security_level: SecurityLevel::MEDIUM, + key_type: ECDSA_SECP256K1, + read_only: false, + data: new_key_pair.public_key().serialize().to_vec().into(), + signature: Default::default(), + contract_bounds: Some(ContractBounds::SingleContract { + id: data_contract.id(), + }), + }; + + let update_transition: IdentityUpdateTransition = IdentityUpdateTransitionV0 { + identity_id: identity.id(), + revision: 1, + nonce: 2, // Use nonce 2 since we used 1 for contract creation + add_public_keys: vec![IdentityPublicKeyInCreation::V0(new_key.clone())], + disable_public_keys: vec![], + user_fee_increase: 0, + signature_public_key_id: master_key.id(), + signature: Default::default(), + } + .into(); + + let update_transition: StateTransition = update_transition.into(); + + let signable_bytes = update_transition + .signable_bytes() + .expect("expected signable bytes"); + + // Sign the new key with its own private key + let secret = new_key_pair.secret_key(); + let signature = + signer::sign(&signable_bytes, &secret.secret_bytes()).expect("expected to sign"); + + new_key.signature = signature.to_vec().into(); + + // Create the transition again with the signed key + let update_transition: IdentityUpdateTransition = IdentityUpdateTransitionV0 { + identity_id: identity.id(), + revision: 1, + nonce: 2, + add_public_keys: vec![IdentityPublicKeyInCreation::V0(new_key)], + disable_public_keys: vec![], + user_fee_increase: 0, + signature_public_key_id: master_key.id(), + signature: Default::default(), + } + .into(); + + let mut update_transition: StateTransition = update_transition.into(); + + // Sign the transition with the master key + update_transition.set_signature( + signer + .sign(&master_key, signable_bytes.as_slice()) + .expect("expected to sign"), + ); + + let update_transition_bytes = update_transition + .serialize_to_bytes() + .expect("expected to serialize"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![update_transition_bytes.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + true, + None, + ) + .expect("expected to process state transition"); + + // We expect success - contract bound keys are allowed + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + // Verify the key was added + use drive::drive::identity::key::fetch::{IdentityKeysRequest, KeyRequestType}; + + let identity_keys_request = IdentityKeysRequest { + identity_id: identity.id().to_buffer(), + request_type: KeyRequestType::AllKeys, + limit: None, + offset: None, + }; + + let updated_partial_identity = platform + .drive + .fetch_identity_keys_as_partial_identity(identity_keys_request, None, platform_version) + .expect("expected to fetch identity") + .expect("expected identity to exist"); + + assert_eq!(updated_partial_identity.loaded_public_keys.len(), 3); // Original 2 + new contract bound key + + let contract_bound_key = updated_partial_identity + .loaded_public_keys + .get(&2) + .expect("expected to find key with id 2"); + + assert_eq!( + contract_bound_key.contract_bounds(), + Some(&ContractBounds::SingleContract { + id: data_contract.id() + }) + ); + } + + #[test] + fn test_identity_update_adding_contract_bound_key_on_document_level() { + use crate::execution::validation::state_transition::tests::{ + register_contract_from_bytes, IdentityTestInfo, + }; + + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform_version = PlatformVersion::latest(); + + let mut platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc() + .set_genesis_state(); + + // { + // "$format_version": "1", + // "id": "8m7H1EScryPTeJzck2qbSckTbEjCg2vu7PRth2LCwsHo", + // "config": { + // "$format_version": "1", + // "canBeDeleted": false, + // "readonly": false, + // "keepsHistory": false, + // "documentsKeepHistoryContractDefault": false, + // "documentsMutableContractDefault": true, + // "documentsCanBeDeletedContractDefault": true, + // "requiresIdentityEncryptionBoundedKey": null, + // "requiresIdentityDecryptionBoundedKey": null, + // "sizedIntegerTypes": true + // }, + // "version": 1, + // "ownerId": "Eh5SUY1wHovQn5xoW9gEpA3ABfHSmq2bg9pcSiybkBWW", + // "schemaDefs": null, + // "documentSchemas": { + // "liquidityPool": { + // "type": "object", + // "requiresIdentityEncryptionBoundedKey": 0, + // "requiresIdentityDecryptionBoundedKey": 0, + // "properties": { + // "tokenA": { + // "position": 0, + // "type": "string", + // "description": "The symbol of the first token in the pool.", + // "maxLength": 10 + // }, + // "tokenB": { + // "position": 1, + // "type": "string", + // "description": "The symbol of the second token in the pool.", + // "maxLength": 10 + // }, + // "reserveA": { + // "position": 2, + // "type": "number", + // "description": "The amount of token A in the pool.", + // "minimum": 0 + // }, + // "reserveB": { + // "position": 3, + // "type": "number", + // "description": "The amount of token B in the pool.", + // "minimum": 0 + // }, + // "liquidityTokens": { + // "position": 4, + // "type": "number", + // "description": "The total liquidity tokens issued for this pool.", + // "minimum": 0 + // } + // }, + // "indices": [ + // { + // "name": "tokenPair", + // "properties": [ + // { + // "tokenA": "asc" + // }, + // { + // "tokenB": "asc" + // } + // ] + // } + // ], + // "required": [ + // "tokenA", + // "tokenB", + // "reserveA", + // "reserveB", + // "liquidityTokens" + // ], + // "additionalProperties": false, + // "description": "Represents a liquidity pool for token trading." + // }, + // "swapTransaction": { + // "type": "object", + // "properties": { + // "fromToken": { + // "position": 0, + // "type": "string", + // "description": "The symbol of the token being swapped from.", + // "maxLength": 10 + // }, + // "toToken": { + // "position": 1, + // "type": "string", + // "description": "The symbol of the token being swapped to.", + // "maxLength": 10 + // }, + // "amountIn": { + // "position": 2, + // "type": "number", + // "description": "The amount of the fromToken being swapped.", + // "minimum": 0 + // }, + // "amountOut": { + // "position": 3, + // "type": "number", + // "description": "The amount of the toToken received.", + // "minimum": 0 + // }, + // "timestamp": { + // "position": 4, + // "type": "integer", + // "description": "The timestamp of the transaction.", + // "minimum": 0 + // } + // }, + // "indices": [ + // { + // "name": "fromToken", + // "properties": [ + // { + // "fromToken": "asc" + // } + // ] + // }, + // { + // "name": "toToken", + // "properties": [ + // { + // "toToken": "asc" + // } + // ] + // }, + // { + // "name": "timestamp", + // "properties": [ + // { + // "timestamp": "asc" + // } + // ] + // } + // ], + // "required": [ + // "fromToken", + // "toToken", + // "amountIn", + // "amountOut", + // "timestamp" + // ], + // "additionalProperties": false, + // "description": "Represents a swap transaction between two tokens." + // }, + // "token": { + // "type": "object", + // "properties": { + // "symbol": { + // "position": 0, + // "type": "string", + // "description": "The symbol of the token, e.g., 'DASH'.", + // "maxLength": 10 + // }, + // "name": { + // "position": 1, + // "type": "string", + // "description": "The full name of the token.", + // "maxLength": 63 + // }, + // "decimals": { + // "position": 2, + // "type": "integer", + // "description": "The number of decimal places the token uses.", + // "minimum": 0, + // "maximum": 18 + // }, + // "totalSupply": { + // "position": 3, + // "type": "number", + // "description": "The total supply of the token.", + // "minimum": 0 + // } + // }, + // "indices": [ + // { + // "name": "symbol", + // "properties": [ + // { + // "symbol": "asc" + // } + // ] + // } + // ], + // "required": [ + // "symbol", + // "name", + // "decimals", + // "totalSupply" + // ], + // "additionalProperties": false, + // "description": "Represents a token available for trading on the platform." + // }, + // "userProfile": { + // "type": "object", + // "properties": { + // "username": { + // "position": 0, + // "type": "string", + // "description": "The unique username of the user.", + // "maxLength": 63 + // }, + // "walletAddress": { + // "position": 1, + // "type": "string", + // "description": "The Dash wallet address of the user.", + // "maxLength": 63 + // }, + // "createdAt": { + // "position": 2, + // "type": "integer", + // "description": "The timestamp when the user profile was created.", + // "minimum": 0 + // } + // }, + // "indices": [ + // { + // "name": "username", + // "properties": [ + // { + // "username": "asc" + // } + // ] + // }, + // { + // "name": "walletAddress", + // "properties": [ + // { + // "walletAddress": "asc" + // } + // ] + // } + // ], + // "required": [ + // "username", + // "walletAddress", + // "createdAt" + // ], + // "additionalProperties": false, + // "description": "Represents a user profile within the application." + // } + // }, + // "createdAt": 1750216267336, + // "updatedAt": null, + // "createdAtBlockHeight": 161570, + // "updatedAtBlockHeight": null, + // "createdAtEpoch": 8017, + // "updatedAtEpoch": null, + // "groups": {}, + // "tokens": {}, + // "keywords": [], + // "description": null + // } + let contract_bytes = hex::decode("01734e75d6522ecc1161b1594bc8706c2fe32450c26a6680612c51e1f4806d39160100000000010100000101cb6c2e8d89ad3ec7bbfcef8b02eb85b8f27ef7ac847c3d461c898d6929fb6daf00040d6c6971756964697479506f6f6c160812047479706512066f626a656374122472657175697265734964656e74697479456e6372797074696f6e426f756e6465644b65790200122472657175697265734964656e7469747944656372797074696f6e426f756e6465644b65790200120a70726f7065727469657316051206746f6b656e4116041208706f736974696f6e02001204747970651206737472696e67120b6465736372697074696f6e122a5468652073796d626f6c206f662074686520666972737420746f6b656e20696e2074686520706f6f6c2e12096d61784c656e677468020a1206746f6b656e4216041208706f736974696f6e02011204747970651206737472696e67120b6465736372697074696f6e122b5468652073796d626f6c206f6620746865207365636f6e6420746f6b656e20696e2074686520706f6f6c2e12096d61784c656e677468020a1208726573657276654116041208706f736974696f6e020212047479706512066e756d626572120b6465736372697074696f6e122254686520616d6f756e74206f6620746f6b656e204120696e2074686520706f6f6c2e12076d696e696d756d02001208726573657276654216041208706f736974696f6e020312047479706512066e756d626572120b6465736372697074696f6e122254686520616d6f756e74206f6620746f6b656e204220696e2074686520706f6f6c2e12076d696e696d756d0200120f6c6971756964697479546f6b656e7316041208706f736974696f6e020412047479706512066e756d626572120b6465736372697074696f6e123054686520746f74616c206c697175696469747920746f6b656e732069737375656420666f72207468697320706f6f6c2e12076d696e696d756d02001207696e64696365731501160212046e616d651209746f6b656e50616972120a70726f70657274696573150216011206746f6b656e41120361736316011206746f6b656e4212036173631208726571756972656415051206746f6b656e411206746f6b656e421208726573657276654112087265736572766542120f6c6971756964697479546f6b656e7312146164646974696f6e616c50726f706572746965731300120b6465736372697074696f6e122e526570726573656e74732061206c697175696469747920706f6f6c20666f7220746f6b656e2074726164696e672e0f737761705472616e73616374696f6e160612047479706512066f626a656374120a70726f706572746965731605120966726f6d546f6b656e16041208706f736974696f6e02001204747970651206737472696e67120b6465736372697074696f6e122b5468652073796d626f6c206f662074686520746f6b656e206265696e6720737761707065642066726f6d2e12096d61784c656e677468020a1207746f546f6b656e16041208706f736974696f6e02011204747970651206737472696e67120b6465736372697074696f6e12295468652073796d626f6c206f662074686520746f6b656e206265696e67207377617070656420746f2e12096d61784c656e677468020a1208616d6f756e74496e16041208706f736974696f6e020212047479706512066e756d626572120b6465736372697074696f6e122a54686520616d6f756e74206f66207468652066726f6d546f6b656e206265696e6720737761707065642e12076d696e696d756d02001209616d6f756e744f757416041208706f736974696f6e020312047479706512066e756d626572120b6465736372697074696f6e122354686520616d6f756e74206f662074686520746f546f6b656e2072656365697665642e12076d696e696d756d0200120974696d657374616d7016041208706f736974696f6e02041204747970651207696e7465676572120b6465736372697074696f6e12215468652074696d657374616d70206f6620746865207472616e73616374696f6e2e12076d696e696d756d02001207696e64696365731503160212046e616d65120966726f6d546f6b656e120a70726f7065727469657315011601120966726f6d546f6b656e1203617363160212046e616d651207746f546f6b656e120a70726f70657274696573150116011207746f546f6b656e1203617363160212046e616d65120974696d657374616d70120a70726f7065727469657315011601120974696d657374616d701203617363120872657175697265641505120966726f6d546f6b656e1207746f546f6b656e1208616d6f756e74496e1209616d6f756e744f7574120974696d657374616d7012146164646974696f6e616c50726f706572746965731300120b6465736372697074696f6e1231526570726573656e747320612073776170207472616e73616374696f6e206265747765656e2074776f20746f6b656e732e05746f6b656e160612047479706512066f626a656374120a70726f706572746965731604120673796d626f6c16041208706f736974696f6e02001204747970651206737472696e67120b6465736372697074696f6e12265468652073796d626f6c206f662074686520746f6b656e2c20652e672e2c202744415348272e12096d61784c656e677468020a12046e616d6516041208706f736974696f6e02011204747970651206737472696e67120b6465736372697074696f6e121b5468652066756c6c206e616d65206f662074686520746f6b656e2e12096d61784c656e677468023f1208646563696d616c7316051208706f736974696f6e02021204747970651207696e7465676572120b6465736372697074696f6e122c546865206e756d626572206f6620646563696d616c20706c616365732074686520746f6b656e20757365732e12076d696e696d756d020012076d6178696d756d0212120b746f74616c537570706c7916041208706f736974696f6e020312047479706512066e756d626572120b6465736372697074696f6e121e54686520746f74616c20737570706c79206f662074686520746f6b656e2e12076d696e696d756d02001207696e64696365731501160212046e616d65120673796d626f6c120a70726f7065727469657315011601120673796d626f6c1203617363120872657175697265641504120673796d626f6c12046e616d651208646563696d616c73120b746f74616c537570706c7912146164646974696f6e616c50726f706572746965731300120b6465736372697074696f6e1239526570726573656e7473206120746f6b656e20617661696c61626c6520666f722074726164696e67206f6e2074686520706c6174666f726d2e0b7573657250726f66696c65160612047479706512066f626a656374120a70726f7065727469657316031208757365726e616d6516041208706f736974696f6e02001204747970651206737472696e67120b6465736372697074696f6e122054686520756e6971756520757365726e616d65206f662074686520757365722e12096d61784c656e677468023f120d77616c6c65744164647265737316041208706f736974696f6e02011204747970651206737472696e67120b6465736372697074696f6e122454686520446173682077616c6c65742061646472657373206f662074686520757365722e12096d61784c656e677468023f120963726561746564417416041208706f736974696f6e02021204747970651207696e7465676572120b6465736372697074696f6e12305468652074696d657374616d70207768656e2074686520757365722070726f66696c652077617320637265617465642e12076d696e696d756d02001207696e64696365731502160212046e616d651208757365726e616d65120a70726f70657274696573150116011208757365726e616d651203617363160212046e616d65120d77616c6c657441646472657373120a70726f7065727469657315011601120d77616c6c65744164647265737312036173631208726571756972656415031208757365726e616d65120d77616c6c657441646472657373120963726561746564417412146164646974696f6e616c50726f706572746965731300120b6465736372697074696f6e1231526570726573656e7473206120757365722070726f66696c652077697468696e20746865206170706c69636174696f6e2e01fd000001978104d6480001fc000277220001fb1f510000000000").expect("expected to decode contract bytes"); + + let (identity, signer, critical_key, master_key) = + setup_identity_return_master_key(&mut platform, 959, dash_to_credits!(5.0)); + + let platform_state = platform.state.load(); + + // Register the contract + let data_contract = register_contract_from_bytes( + &mut platform, + &platform_state, + contract_bytes, + IdentityTestInfo::Given { + identity: &identity, + signer: &signer, + public_key: &critical_key, + identity_nonce: 1, + }, + platform_version, + ); + + let secp = Secp256k1::new(); + + let mut rng = StdRng::seed_from_u64(1292); + + let new_key_pair = Keypair::new(&secp, &mut rng); + + let mut new_key = IdentityPublicKeyInCreationV0 { + id: 2, + purpose: Purpose::ENCRYPTION, + security_level: SecurityLevel::MEDIUM, + key_type: ECDSA_SECP256K1, + read_only: false, + data: new_key_pair.public_key().serialize().to_vec().into(), + signature: Default::default(), + contract_bounds: Some(ContractBounds::SingleContractDocumentType { + id: data_contract.id(), + document_type_name: "liquidityPool".to_string(), + }), + }; + + let update_transition: IdentityUpdateTransition = IdentityUpdateTransitionV0 { + identity_id: identity.id(), + revision: 1, + nonce: 2, // Use nonce 2 since we used 1 for contract creation + add_public_keys: vec![IdentityPublicKeyInCreation::V0(new_key.clone())], + disable_public_keys: vec![], + user_fee_increase: 0, + signature_public_key_id: master_key.id(), + signature: Default::default(), + } + .into(); + + let update_transition: StateTransition = update_transition.into(); + + let signable_bytes = update_transition + .signable_bytes() + .expect("expected signable bytes"); + + // Sign the new key with its own private key + let secret = new_key_pair.secret_key(); + let signature = + signer::sign(&signable_bytes, &secret.secret_bytes()).expect("expected to sign"); + + new_key.signature = signature.to_vec().into(); + + // Create the transition again with the signed key + let update_transition: IdentityUpdateTransition = IdentityUpdateTransitionV0 { + identity_id: identity.id(), + revision: 1, + nonce: 2, + add_public_keys: vec![IdentityPublicKeyInCreation::V0(new_key)], + disable_public_keys: vec![], + user_fee_increase: 0, + signature_public_key_id: master_key.id(), + signature: Default::default(), + } + .into(); + + let mut update_transition: StateTransition = update_transition.into(); + + // Sign the transition with the master key + update_transition.set_signature( + signer + .sign(&master_key, signable_bytes.as_slice()) + .expect("expected to sign"), + ); + + let update_transition_bytes = update_transition + .serialize_to_bytes() + .expect("expected to serialize"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![update_transition_bytes.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + true, + None, + ) + .expect("expected to process state transition"); + + // We expect success - contract bound keys are allowed + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + // Verify the key was added + use drive::drive::identity::key::fetch::{IdentityKeysRequest, KeyRequestType}; + + let identity_keys_request = IdentityKeysRequest { + identity_id: identity.id().to_buffer(), + request_type: KeyRequestType::AllKeys, + limit: None, + offset: None, + }; + + let updated_partial_identity = platform + .drive + .fetch_identity_keys_as_partial_identity(identity_keys_request, None, platform_version) + .expect("expected to fetch identity") + .expect("expected identity to exist"); + + assert_eq!(updated_partial_identity.loaded_public_keys.len(), 3); // Original 2 + new contract bound key + + let contract_bound_key = updated_partial_identity + .loaded_public_keys + .get(&2) + .expect("expected to find key with id 2"); + + assert_eq!( + contract_bound_key.contract_bounds(), + Some(&ContractBounds::SingleContractDocumentType { + id: data_contract.id(), + document_type_name: "liquidityPool".to_string(), + }) + ); + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs index 9d402e22339..2d31528d239 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs @@ -70,6 +70,7 @@ pub(in crate::execution) mod tests { use rand::prelude::StdRng; use rand::{Rng, SeedableRng}; use simple_signer::signer::SimpleSigner; + use std::borrow::Cow; use std::collections::BTreeMap; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::ops::Deref; @@ -86,7 +87,7 @@ pub(in crate::execution) mod tests { use dpp::dash_to_credits; use dpp::dashcore::{ProTxHash, Txid}; use dpp::dashcore::hashes::Hash; - use dpp::data_contract::accessors::v0::DataContractV0Getters; + use dpp::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; use dpp::data_contract::accessors::v1::{DataContractV1Getters, DataContractV1Setters}; use dpp::data_contract::{DataContract, GroupContractPosition, TokenContractPosition}; use dpp::data_contract::document_type::accessors::{DocumentTypeV0Getters, DocumentTypeV1Setters}; @@ -139,6 +140,7 @@ pub(in crate::execution) mod tests { use dpp::tokens::gas_fees_paid_by::GasFeesPaidBy; use dpp::tokens::token_amount_on_contract_token::{DocumentActionTokenCost, DocumentActionTokenEffect}; use dpp::data_contract::document_type::accessors::DocumentTypeV0MutGetters; + use dpp::serialization::PlatformDeserializableWithPotentialValidationFromVersionedStructure; /// We add an identity, but we also add the same amount to system credits pub(in crate::execution) fn setup_identity_with_system_credits( @@ -259,7 +261,7 @@ pub(in crate::execution) mod tests { platform: &mut TempPlatform, seed: u64, credits: Credits, - ) -> (Identity, SimpleSigner, IdentityPublicKey) { + ) -> (Identity, SimpleSigner, IdentityPublicKey, IdentityPublicKey) { let platform_version = PlatformVersion::latest(); let mut signer = SimpleSigner::default(); @@ -310,7 +312,7 @@ pub(in crate::execution) mod tests { ) .expect("expected to add a new identity"); - (identity, signer, master_key) + (identity, signer, critical_public_key, master_key) } #[allow(clippy::too_many_arguments)] @@ -772,6 +774,102 @@ pub(in crate::execution) mod tests { platform.state.store(Arc::new(platform_state)); } + pub(in crate::execution) enum IdentityTestInfo<'a> { + Given { + identity: &'a Identity, + signer: &'a SimpleSigner, + public_key: &'a IdentityPublicKey, + identity_nonce: IdentityNonce, + }, + UseSeed(u64), + UseRng(&'a mut StdRng), + } + + pub(in crate::execution) fn register_contract_from_bytes( + platform: &mut TempPlatform, + platform_state: &PlatformState, + contract_bytes: Vec, + identity_info: IdentityTestInfo, + platform_version: &PlatformVersion, + ) -> DataContract { + // Deserialize the data contract from bytes + let mut data_contract = + DataContract::versioned_deserialize(&contract_bytes, false, platform_version) + .expect("expected to deserialize data contract"); + + // Get identity info based on the enum variant + let (identity_cow, signer_cow, key_cow, nonce) = match identity_info { + IdentityTestInfo::Given { + identity, + signer, + public_key, + identity_nonce, + } => ( + Cow::Borrowed(identity), + Cow::Borrowed(signer), + Cow::Borrowed(public_key), + identity_nonce, + ), + IdentityTestInfo::UseSeed(seed) => { + let (identity, signer, key) = setup_identity(platform, seed, dash_to_credits!(1)); + (Cow::Owned(identity), Cow::Owned(signer), Cow::Owned(key), 1) + } + IdentityTestInfo::UseRng(rng) => { + let seed = rng.gen(); + let (identity, signer, key) = setup_identity(platform, seed, dash_to_credits!(1)); + (Cow::Owned(identity), Cow::Owned(signer), Cow::Owned(key), 1) + } + }; + + let contract_id = DataContract::generate_data_contract_id_v0(identity_cow.id(), nonce); + + data_contract.set_id(contract_id); + + // Create and sign the data contract create transition + let state_transition = DataContractCreateTransition::new_from_data_contract( + data_contract.clone(), + nonce, + &identity_cow.as_ref().clone().into_partial_identity_info(), + key_cow.id(), + signer_cow.as_ref(), + platform_version, + None, + ) + .expect("expected to create and sign data contract create transition"); + + // Serialize the state transition + let state_transition_bytes = state_transition + .serialize_to_bytes() + .expect("expected to serialize state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &[state_transition_bytes], + platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let execution_result = processing_result.into_execution_results().remove(0); + assert_matches!(execution_result, SuccessfulExecution(..)); + + data_contract + } + pub(in crate::execution) fn create_dpns_name_contest_give_key_info( platform: &mut TempPlatform, platform_state: &PlatformState, diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index ddd7f945f89..bf683913de4 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,12 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev = "221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" } +grovedb = { version = "3.0.0", optional = true, default-features = false } +grovedb-costs = { version = "3.0.0", optional = true } +grovedb-path = { version = "3.0.0" } +grovedb-storage = { version = "3.0.0", optional = true } +grovedb-version = { version = "3.0.0" } +grovedb-epoch-based-storage-flags = { version = "3.0.0" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-drive/src/drive/identity/key/fetch/mod.rs b/packages/rs-drive/src/drive/identity/key/fetch/mod.rs index d7230b0c64b..042132faff8 100644 --- a/packages/rs-drive/src/drive/identity/key/fetch/mod.rs +++ b/packages/rs-drive/src/drive/identity/key/fetch/mod.rs @@ -195,6 +195,15 @@ fn element_to_identity_public_key_id_and_object_pair( Ok((public_key.id(), public_key)) } +#[cfg(feature = "server")] +fn element_to_identity_public_key_id_and_some_object_pair( + element: Element, +) -> Result<(KeyID, Option), Error> { + let public_key = element_to_identity_public_key(element)?; + + Ok((public_key.id(), Some(public_key))) +} + #[cfg(feature = "server")] fn key_and_optional_element_to_identity_public_key_id_and_object_pair( (_path, key, maybe_element): (Path, Key, Option), @@ -266,6 +275,19 @@ fn supported_query_result_element_to_identity_public_key_id_and_object_pair( } } +#[cfg(feature = "server")] +fn supported_query_result_element_to_identity_public_key_id_and_some_object_pair( + query_result_element: QueryResultElement, +) -> Result<(KeyID, Option), Error> { + match query_result_element { + QueryResultElement::ElementResultItem(element) + | QueryResultElement::KeyElementPairResultItem((_, element)) + | QueryResultElement::PathKeyElementTrioResultItem((_, _, element)) => { + element_to_identity_public_key_id_and_some_object_pair(element) + } + } +} + #[cfg(feature = "server")] impl IdentityPublicKeyResult for SingleIdentityPublicKeyOutcome { fn try_from_path_key_optional( @@ -591,12 +613,14 @@ impl IdentityPublicKeyResult for KeyIDOptionalIdentityPublicKeyPairBTreeMap { } fn try_from_query_results( - _value: QueryResultElements, + value: QueryResultElements, _platform_version: &PlatformVersion, ) -> Result { - Err(Error::Drive(DriveError::NotSupported( - "KeyIDOptionalIdentityPublicKeyPairBTreeMap try from QueryResultElements in IdentityPublicKeyResult", - ))) + value + .elements + .into_iter() + .map(supported_query_result_element_to_identity_public_key_id_and_some_object_pair) + .collect() } } diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_path_query_with_optional/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_path_query_with_optional/v0/mod.rs index 4ee57d66e8d..e415fcd6f5e 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_path_query_with_optional/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_path_query_with_optional/v0/mod.rs @@ -21,7 +21,7 @@ impl Drive { path_query, true, true, - true, + false, transaction, &drive_version.grove_version, ); diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index ed31ee8e336..b04d071b0ee 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "2.0.12" } bincode = { version = "=2.0.0-rc.3" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "221ca6ec6b8d2b192d334192bd5a7b2cab5b0aa8" } +grovedb-version = { version = "3.0.0" } once_cell = "1.19.0" [features] diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index 2cb9c990a0c..89aea52a276 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -64,7 +64,7 @@ use wasm_bindgen::{JsError, JsValue}; use dpp::consensus::basic::data_contract::{ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, DataContractTokenConfigurationUpdateError, DecimalsOverLimitError, DuplicateKeywordsError, GroupExceedsMaxMembersError, GroupHasTooFewMembersError, GroupMemberHasPowerOfZeroError, GroupMemberHasPowerOverLimitError, GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError, GroupPositionDoesNotExistError, GroupRequiredPowerIsInvalidError, GroupTotalPowerLessThanRequiredError, InvalidDescriptionLengthError, InvalidDocumentTypeRequiredSecurityLevelError, InvalidKeywordCharacterError, InvalidKeywordLengthError, InvalidTokenBaseSupplyError, InvalidTokenDistributionFunctionDivideByZeroError, InvalidTokenDistributionFunctionIncoherenceError, InvalidTokenDistributionFunctionInvalidParameterError, InvalidTokenDistributionFunctionInvalidParameterTupleError, InvalidTokenLanguageCodeError, InvalidTokenNameCharacterError, InvalidTokenNameLengthError, MainGroupIsNotDefinedError, NewTokensDestinationIdentityOptionRequiredError, NonContiguousContractGroupPositionsError, NonContiguousContractTokenPositionsError, RedundantDocumentPaidForByTokenWithContractId, TokenPaymentByBurningOnlyAllowedOnInternalTokenError, TooManyKeywordsError, UnknownDocumentActionTokenEffectError, UnknownDocumentCreationRestrictionModeError, UnknownGasFeesPaidByError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError}; use dpp::consensus::basic::document::{ContestedDocumentsTemporarilyNotAllowedError, DocumentCreationNotAllowedError, DocumentFieldMaxSizeExceededError, MaxDocumentsTransitionsExceededError, MissingPositionsInDocumentTypePropertiesError}; use dpp::consensus::basic::group::GroupActionNotAllowedOnTransitionError; -use dpp::consensus::basic::identity::{DataContractBoundsNotPresentError, DisablingKeyIdAlsoBeingAddedInSameTransitionError, InvalidIdentityCreditWithdrawalTransitionAmountError, InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, TooManyMasterPublicKeyError, WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError}; +use dpp::consensus::basic::identity::{DataContractBoundsNotPresentError, DisablingKeyIdAlsoBeingAddedInSameTransitionError, InvalidIdentityCreditWithdrawalTransitionAmountError, InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, InvalidKeyPurposeForContractBoundsError, TooManyMasterPublicKeyError, WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError}; use dpp::consensus::basic::overflow_error::OverflowError; use dpp::consensus::basic::token::{ChoosingTokenMintRecipientNotAllowedError, ContractHasNoTokensError, DestinationIdentityForTokenMintingNotSetError, InvalidActionIdError, InvalidTokenAmountError, InvalidTokenConfigUpdateNoChangeError, InvalidTokenIdError, InvalidTokenNoteTooBigError, InvalidTokenPositionError, MissingDefaultLocalizationError, TokenNoteOnlyAllowedWhenProposerError, TokenTransferToOurselfError, InvalidTokenDistributionTimeIntervalNotMinuteAlignedError, InvalidTokenDistributionTimeIntervalTooShortError, InvalidTokenDistributionBlockIntervalTooShortError}; use dpp::consensus::state::data_contract::data_contract_not_found_error::DataContractNotFoundError; @@ -847,6 +847,9 @@ fn from_basic_error(basic_error: &BasicError) -> JsValue { BasicError::GroupHasTooFewMembersError(e) => { generic_consensus_error!(GroupHasTooFewMembersError, e).into() } + BasicError::InvalidKeyPurposeForContractBoundsError(e) => { + generic_consensus_error!(InvalidKeyPurposeForContractBoundsError, e).into() + } } }