From 88f3f058485e5e390ebdf917e9166b0d94b3ae2d Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Sun, 19 Jan 2025 19:29:20 +0700 Subject: [PATCH 01/13] more tests and fixes for group queries --- .../rs-drive/src/drive/group/fetch/queries.rs | 13 +- .../drive/group/prove/prove_group_info/mod.rs | 5 +- .../group/prove/prove_group_info/v0/mod.rs | 154 +++++++++ .../group/prove/prove_group_infos/mod.rs | 2 - .../group/prove/prove_group_infos/v0/mod.rs | 317 ++++++++++++++++++ .../src/drive/tokens/balance/queries.rs | 4 +- .../calculate_total_tokens_balance/mod.rs | 1 - .../rs-drive/src/drive/tokens/info/queries.rs | 3 +- .../mod.rs | 6 +- packages/rs-drive/src/verify/group/mod.rs | 2 + .../src/verify/group/verify_group_info/mod.rs | 69 ++++ .../verify/group/verify_group_info/v0/mod.rs | 57 ++++ .../verify_group_infos_in_contract/mod.rs | 77 +++++ .../verify_group_infos_in_contract/v0/mod.rs | 79 +++++ packages/rs-drive/src/verify/mod.rs | 6 +- .../drive_verify_method_versions/mod.rs | 7 + .../drive_verify_method_versions/v1.rs | 6 +- 17 files changed, 783 insertions(+), 25 deletions(-) create mode 100644 packages/rs-drive/src/verify/group/mod.rs create mode 100644 packages/rs-drive/src/verify/group/verify_group_info/mod.rs create mode 100644 packages/rs-drive/src/verify/group/verify_group_info/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/group/verify_group_infos_in_contract/mod.rs create mode 100644 packages/rs-drive/src/verify/group/verify_group_infos_in_contract/v0/mod.rs diff --git a/packages/rs-drive/src/drive/group/fetch/queries.rs b/packages/rs-drive/src/drive/group/fetch/queries.rs index 7dbd1223c50..dcd532b4c10 100644 --- a/packages/rs-drive/src/drive/group/fetch/queries.rs +++ b/packages/rs-drive/src/drive/group/fetch/queries.rs @@ -1,4 +1,4 @@ -use crate::drive::group::paths::group_contract_path_vec; +use crate::drive::group::paths::{group_contract_path_vec, group_path_vec, GROUP_INFO_KEY}; use crate::drive::Drive; use crate::query::{Query, QueryItem}; use dpp::data_contract::GroupContractPosition; @@ -11,11 +11,10 @@ impl Drive { contract_id: [u8; 32], group_contract_position: GroupContractPosition, ) -> PathQuery { - let group_contract_path = group_contract_path_vec(&contract_id); - PathQuery::new_single_key( - group_contract_path, - group_contract_position.to_be_bytes().to_vec(), - ) + let group_path = group_path_vec(&contract_id, group_contract_position); + let mut path_query = PathQuery::new_single_key(group_path, GROUP_INFO_KEY.to_vec()); + path_query.query.limit = Some(1); + path_query } /// The query for the group infos inside a contract. @@ -35,6 +34,8 @@ impl Drive { } else { query.insert_item(QueryItem::RangeFull(RangeFull)) } + + query.set_subquery_key(GROUP_INFO_KEY.to_vec()); PathQuery { path: group_contract_path, query: SizedQuery { diff --git a/packages/rs-drive/src/drive/group/prove/prove_group_info/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_group_info/mod.rs index 5fd307c25ee..a985301f6d5 100644 --- a/packages/rs-drive/src/drive/group/prove/prove_group_info/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/prove_group_info/mod.rs @@ -2,13 +2,10 @@ use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; -use dpp::data_contract::group::Group; use dpp::data_contract::GroupContractPosition; use dpp::identifier::Identifier; -use grovedb::batch::KeyInfoPath; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::TransactionArg; use platform_version::version::PlatformVersion; -use std::collections::HashMap; mod v0; diff --git a/packages/rs-drive/src/drive/group/prove/prove_group_info/v0/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_group_info/v0/mod.rs index 0dd20e36e01..189cc63a2a0 100644 --- a/packages/rs-drive/src/drive/group/prove/prove_group_info/v0/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/prove_group_info/v0/mod.rs @@ -43,3 +43,157 @@ impl Drive { ) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::block::block_info::BlockInfo; + use dpp::data_contract::accessors::v0::DataContractV0Getters; + use dpp::data_contract::config::v0::DataContractConfigV0; + use dpp::data_contract::config::DataContractConfig; + use dpp::data_contract::group::v0::GroupV0; + use dpp::data_contract::group::Group; + use dpp::data_contract::v1::DataContractV1; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + use dpp::prelude::DataContract; + use dpp::version::PlatformVersion; + use std::collections::BTreeMap; + + #[test] + fn should_prove_group_info_for_existing_group() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + // Create identities for group members + let identity_1 = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + let identity_2 = Identity::random_identity(3, Some(506), platform_version) + .expect("expected a platform identity"); + + let identity_1_id = identity_1.id(); + let identity_2_id = identity_2.id(); + + // Create a data contract with a single group + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: BTreeMap::from([( + 0, + Group::V0(GroupV0 { + members: [(identity_1_id, 1), (identity_2_id, 2)].into(), + required_power: 3, + }), + )]), + tokens: Default::default(), + }); + + let contract_id = contract.id(); + + // Insert the contract into Drive + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Prove group info for group at position 0 + let proof = drive + .prove_group_info_v0(contract_id, 0, None, platform_version) + .expect("should not error when proving group info"); + + // Verify the proof + let (root_hash, group) = + Drive::verify_group_info(proof.as_slice(), contract_id, 0, false, platform_version) + .expect("expected proof verification to succeed"); + + // Assert root hash is valid + assert!(!root_hash.is_empty(), "root hash should not be empty"); + + // Assert group matches the expected value + assert_eq!( + group, + Some(Group::V0(GroupV0 { + members: [(identity_1_id, 1), (identity_2_id, 2)].into(), + required_power: 3, + })), + "unexpected group info" + ); + } + + #[test] + fn should_prove_no_group_info_for_non_existent_group() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + // Create a data contract without groups + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: Default::default(), + }); + + let contract_id = contract.id(); + + // Insert the contract into Drive + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Prove group info for a non-existent group at position 0 + let proof = drive + .prove_group_info_v0(contract_id, 0, None, platform_version) + .expect("should not error when proving group info for a non-existent group"); + + // Verify the proof + let (root_hash, group) = + Drive::verify_group_info(proof.as_slice(), contract_id, 0, false, platform_version) + .expect("expected proof verification to succeed"); + + // Assert root hash is valid + assert!(!root_hash.is_empty(), "root hash should not be empty"); + + // Assert group is None + assert!(group.is_none(), "expected no group info, but got some"); + } +} diff --git a/packages/rs-drive/src/drive/group/prove/prove_group_infos/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_group_infos/mod.rs index 27b153c2b19..3b882557dea 100644 --- a/packages/rs-drive/src/drive/group/prove/prove_group_infos/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/prove_group_infos/mod.rs @@ -2,13 +2,11 @@ use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; -use dpp::data_contract::group::Group; use dpp::data_contract::GroupContractPosition; use dpp::identifier::Identifier; use dpp::prelude::StartAtIncluded; use grovedb::TransactionArg; use platform_version::version::PlatformVersion; -use std::collections::BTreeMap; mod v0; impl Drive { diff --git a/packages/rs-drive/src/drive/group/prove/prove_group_infos/v0/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_group_infos/v0/mod.rs index d1260102bd8..cf65df54006 100644 --- a/packages/rs-drive/src/drive/group/prove/prove_group_infos/v0/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/prove_group_infos/v0/mod.rs @@ -48,3 +48,320 @@ impl Drive { ) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::block::block_info::BlockInfo; + use dpp::data_contract::accessors::v0::DataContractV0Getters; + use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + use dpp::data_contract::config::v0::DataContractConfigV0; + use dpp::data_contract::config::DataContractConfig; + use dpp::data_contract::group::v0::GroupV0; + use dpp::data_contract::group::Group; + use dpp::data_contract::v1::DataContractV1; + use dpp::data_contract::GroupContractPosition; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + use dpp::prelude::DataContract; + use dpp::version::PlatformVersion; + use std::collections::BTreeMap; + + #[test] + fn should_prove_group_infos_with_multiple_groups() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity_1 = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_1_id = identity_1.id(); + + let identity_2 = Identity::random_identity(3, Some(506), platform_version) + .expect("expected a platform identity"); + + let identity_2_id = identity_2.id(); + + let identity_3 = Identity::random_identity(3, Some(9), platform_version) + .expect("expected a platform identity"); + + let identity_3_id = identity_3.id(); + + // Create a data contract with groups + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: BTreeMap::from([ + ( + 0, + Group::V0(GroupV0 { + members: [(identity_1_id, 1), (identity_2_id, 1)].into(), + required_power: 2, + }), + ), + ( + 1, + Group::V0(GroupV0 { + members: [(identity_1_id, 2), (identity_2_id, 1), (identity_3_id, 1)] + .into(), + required_power: 2, + }), + ), + ]), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + + let contract_id = contract.id(); + + // Insert contract into Drive + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Prove group infos + let proof = drive + .prove_group_infos_v0( + contract_id, + None, // No start position + Some(10), // Limit + None, + platform_version, + ) + .expect("should not error when proving group infos"); + + println!("{}", hex::encode(&proof)); + + // Verify proof + let proved_group_infos: BTreeMap = + Drive::verify_group_infos_in_contract( + proof.as_slice(), + contract_id, + None, + Some(10), + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert group infos match expected values + assert_eq!( + proved_group_infos, + BTreeMap::from([ + ( + 0, + Group::V0(GroupV0 { + members: [(identity_1_id, 1), (identity_2_id, 1)].into(), + required_power: 2, + }), + ), + ( + 1, + Group::V0(GroupV0 { + members: [(identity_1_id, 2), (identity_2_id, 1), (identity_3_id, 1)] + .into(), + required_power: 2, + }), + ), + ]), + "unexpected group infos" + ); + } + + #[test] + fn should_prove_group_infos_with_start_position_and_limit() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity_1 = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_1_id = identity_1.id(); + + let identity_2 = Identity::random_identity(3, Some(506), platform_version) + .expect("expected a platform identity"); + + let identity_2_id = identity_2.id(); + + let identity_3 = Identity::random_identity(3, Some(9), platform_version) + .expect("expected a platform identity"); + + let identity_3_id = identity_3.id(); + + // Create a data contract with groups + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: BTreeMap::from([ + ( + 0, + Group::V0(GroupV0 { + members: [(identity_1_id, 1), (identity_2_id, 1)].into(), + required_power: 2, + }), + ), + ( + 1, + Group::V0(GroupV0 { + members: [(identity_1_id, 2), (identity_2_id, 1), (identity_3_id, 1)] + .into(), + required_power: 2, + }), + ), + ( + 2, + Group::V0(GroupV0 { + members: [(identity_2_id, 1), (identity_3_id, 2)].into(), + required_power: 3, + }), + ), + ( + 3, + Group::V0(GroupV0 { + members: [(identity_1_id, 1), (identity_3_id, 1)].into(), + required_power: 2, + }), + ), + ]), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + + let contract_id = contract.id(); + + // Insert contract into Drive + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Prove group infos starting from position 1 with a limit of 2 + let proof = drive + .prove_group_infos_v0( + contract_id, + Some((1, true)), + Some(2), + None, + platform_version, + ) + .expect("should not error when proving group infos"); + + // Verify proof + let proved_group_infos: BTreeMap = + Drive::verify_group_infos_in_contract( + proof.as_slice(), + contract_id, + Some((1, true)), + Some(2), + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert group infos match expected values + assert_eq!( + proved_group_infos, + BTreeMap::from([ + ( + 1, + Group::V0(GroupV0 { + members: [(identity_1_id, 2), (identity_2_id, 1), (identity_3_id, 1)] + .into(), + required_power: 2, + }) + ), + ( + 2, + Group::V0(GroupV0 { + members: [(identity_2_id, 1), (identity_3_id, 2)].into(), + required_power: 3, + }), + ), + ]), + "unexpected group infos" + ); + } + + #[test] + fn should_prove_no_group_infos_for_empty_contract() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let contract_id = Identifier::random(); + + // Prove group infos for an empty contract + let proof = drive + .prove_group_infos_v0(contract_id, None, Some(10), None, platform_version) + .expect("should not error when proving group infos for an empty contract"); + + // Verify proof + let proved_group_infos: BTreeMap = + Drive::verify_group_infos_in_contract( + proof.as_slice(), + contract_id, + None, + Some(10), + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert no group infos exist for the empty contract + assert!( + proved_group_infos.is_empty(), + "expected no group infos, but got: {:?}", + proved_group_infos + ); + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/queries.rs b/packages/rs-drive/src/drive/tokens/balance/queries.rs index a02a3216db4..1804724e2ac 100644 --- a/packages/rs-drive/src/drive/tokens/balance/queries.rs +++ b/packages/rs-drive/src/drive/tokens/balance/queries.rs @@ -1,7 +1,5 @@ use crate::drive::balances::total_tokens_root_supply_path_vec; -use crate::drive::tokens::paths::{ - token_balances_path_vec, token_balances_root_path_vec, tokens_root_path_vec, TOKEN_BALANCES_KEY, -}; +use crate::drive::tokens::paths::{token_balances_path_vec, token_balances_root_path_vec}; use crate::drive::Drive; use crate::error::Error; use crate::query::{Query, QueryItem}; diff --git a/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs b/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs index 60b85c9dbb6..8472cfb8aa2 100644 --- a/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs +++ b/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs @@ -4,7 +4,6 @@ use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; use dpp::balances::total_tokens_balance::TotalTokensBalance; -use dpp::version::drive_versions::DriveVersion; use grovedb::TransactionArg; use platform_version::version::PlatformVersion; diff --git a/packages/rs-drive/src/drive/tokens/info/queries.rs b/packages/rs-drive/src/drive/tokens/info/queries.rs index c4e80a5af11..8f5a4443806 100644 --- a/packages/rs-drive/src/drive/tokens/info/queries.rs +++ b/packages/rs-drive/src/drive/tokens/info/queries.rs @@ -1,6 +1,5 @@ use crate::drive::tokens::paths::{ - token_identity_infos_path_vec, token_identity_infos_root_path_vec, - token_statuses_root_path_vec, tokens_root_path_vec, TOKEN_STATUS_INFO_KEY, + token_identity_infos_path_vec, token_identity_infos_root_path_vec, token_statuses_root_path_vec, }; use crate::drive::Drive; use crate::query::{Query, QueryItem}; diff --git a/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/mod.rs b/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/mod.rs index 26f2ad535fc..bf442bd2a80 100644 --- a/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/mod.rs +++ b/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/mod.rs @@ -3,12 +3,8 @@ mod v0; use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; -use crate::fees::op::LowLevelDriveOperation; -use dpp::balances::credits::TokenAmount; use dpp::version::PlatformVersion; -use grovedb::batch::KeyInfoPath; -use grovedb::{EstimatedLayerInformation, TransactionArg}; -use std::collections::HashMap; +use grovedb::TransactionArg; impl Drive { /// Proves token's total supply and aggregated identity balances diff --git a/packages/rs-drive/src/verify/group/mod.rs b/packages/rs-drive/src/verify/group/mod.rs new file mode 100644 index 00000000000..23b83652ca4 --- /dev/null +++ b/packages/rs-drive/src/verify/group/mod.rs @@ -0,0 +1,2 @@ +mod verify_group_info; +mod verify_group_infos_in_contract; diff --git a/packages/rs-drive/src/verify/group/verify_group_info/mod.rs b/packages/rs-drive/src/verify/group/verify_group_info/mod.rs new file mode 100644 index 00000000000..ded3f812feb --- /dev/null +++ b/packages/rs-drive/src/verify/group/verify_group_info/mod.rs @@ -0,0 +1,69 @@ +mod v0; + +use crate::drive::Drive; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; + +use crate::error::drive::DriveError; + +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies the proof of a single group's information within a contract. + /// + /// This method validates and extracts a specific group's information stored in a contract based on the provided proof. + /// It ensures the integrity and authenticity of the data associated with the specified group position in the contract. + /// The method supports multiple versions for backward compatibility and forwards the verification logic + /// to the appropriate versioned implementation. + /// + /// # Arguments + /// - `proof`: A byte slice containing the cryptographic proof for the group information. + /// - `contract_id`: The identifier of the contract containing the group information. + /// - `group_contract_position`: The position of the group within the contract to verify. + /// - `verify_subset_of_proof`: A boolean flag indicating whether to verify only a subset of the proof (useful for optimizations). + /// - `platform_version`: A reference to the platform version, used to determine the appropriate versioned implementation. + /// + /// # Returns + /// - `Ok((RootHash, Option))`: On success, returns a tuple containing: + /// - `RootHash`: The root hash of the Merkle tree, confirming the proof's validity. + /// - `Option`: The verified group information if it exists, or `None` if the group is absent. + /// - `Err(Error)`: If verification fails, returns an [`Error`] indicating the cause of failure. + /// + /// # Errors + /// - [`Error::Proof`]: If the proof is invalid, corrupted, or contains unexpected data structures. + /// - [`Error::Drive(DriveError::UnknownVersionMismatch)`]: If the method is called with an unsupported platform version. + /// - [`Error::GroveDB`]: If the data deserialization or conversion fails during proof verification. + pub fn verify_group_info( + proof: &[u8], + contract_id: Identifier, + group_contract_position: GroupContractPosition, + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, Option), Error> { + match platform_version + .drive + .methods + .verify + .group + .verify_group_info + { + 0 => Self::verify_group_info_v0( + proof, + contract_id, + group_contract_position, + verify_subset_of_proof, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_group_info".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/group/verify_group_info/v0/mod.rs b/packages/rs-drive/src/verify/group/verify_group_info/v0/mod.rs new file mode 100644 index 00000000000..0b2ae2397c3 --- /dev/null +++ b/packages/rs-drive/src/verify/group/verify_group_info/v0/mod.rs @@ -0,0 +1,57 @@ +use crate::drive::Drive; + +use crate::error::proof::ProofError; +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::serialization::PlatformDeserializable; +use grovedb::GroveDb; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_group_info_v0( + proof: &[u8], + contract_id: Identifier, + group_contract_position: GroupContractPosition, + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, Option), Error> { + let path_query = Self::group_info_for_contract_id_and_group_contract_position_query( + contract_id.to_buffer(), + group_contract_position, + ); + let (root_hash, mut proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + } else { + GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + }; + + if proved_key_values.len() != 1 { + return Err(Error::Proof(ProofError::CorruptedProof( + "we should always get back one element".to_string(), + ))); + } + + let element = proved_key_values.remove(0).2; + + let group = element + .map(|element| element.into_item_bytes().map_err(Error::GroveDB)) + .transpose()? + .map(|bytes| Group::deserialize_from_bytes(&bytes)) + .transpose()?; + + Ok((root_hash, group)) + } +} diff --git a/packages/rs-drive/src/verify/group/verify_group_infos_in_contract/mod.rs b/packages/rs-drive/src/verify/group/verify_group_infos_in_contract/mod.rs new file mode 100644 index 00000000000..0d20771bc67 --- /dev/null +++ b/packages/rs-drive/src/verify/group/verify_group_infos_in_contract/mod.rs @@ -0,0 +1,77 @@ +mod v0; + +use crate::drive::Drive; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; + +use crate::error::drive::DriveError; + +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies the proof of group information within a contract. + /// + /// This method validates and extracts group information stored in a contract based on the provided proof. + /// It uses the proof to confirm the integrity and authenticity of the group data. The method supports + /// different versions for backward compatibility and forwards the verification logic to the appropriate versioned implementation. + /// + /// # Type Parameters + /// - `T`: The output container type that implements `FromIterator`. This is used to collect the verified group information + /// as pairs of [`GroupContractPosition`] and [`Group`]. + /// + /// # Arguments + /// - `proof`: A byte slice containing the cryptographic proof for the group information. + /// - `contract_id`: The identifier of the contract whose group information is being verified. + /// - `start_group_contract_position`: An optional starting position for the group query, combined with a [`StartAtIncluded`] flag + /// to indicate whether the start position is inclusive. + /// - `limit`: An optional limit on the number of groups to verify. + /// - `verify_subset_of_proof`: A boolean flag indicating whether to verify only a subset of the proof (useful for optimizations). + /// - `platform_version`: A reference to the platform version, used to determine the appropriate versioned implementation. + /// + /// # Returns + /// - `Ok((RootHash, T))`: On success, returns a tuple containing: + /// - `RootHash`: The root hash of the Merkle tree, confirming the proof's validity. + /// - `T`: A collection of verified group information as pairs of [`GroupContractPosition`] and [`Group`]. + /// - `Err(Error)`: If verification fails, returns an [`Error`] indicating the cause of failure. + /// + /// # Errors + /// - [`Error::Proof`]: If the proof is invalid, corrupted, or contains unexpected data structures. + /// - [`Error::Drive(DriveError::UnknownVersionMismatch)`]: If the method is called with an unsupported platform version. + /// - Any other errors propagated from the versioned implementation. + pub fn verify_group_infos_in_contract>( + proof: &[u8], + contract_id: Identifier, + start_group_contract_position: Option<(GroupContractPosition, StartAtIncluded)>, + limit: Option, + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + match platform_version + .drive + .methods + .verify + .group + .verify_group_infos_in_contract + { + 0 => Self::verify_group_infos_in_contract_v0( + proof, + contract_id, + start_group_contract_position, + limit, + verify_subset_of_proof, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_group_infos_in_contract".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/group/verify_group_infos_in_contract/v0/mod.rs b/packages/rs-drive/src/verify/group/verify_group_infos_in_contract/v0/mod.rs new file mode 100644 index 00000000000..e594605f95b --- /dev/null +++ b/packages/rs-drive/src/verify/group/verify_group_infos_in_contract/v0/mod.rs @@ -0,0 +1,79 @@ +use crate::drive::Drive; +use grovedb::Element::Item; + +use crate::error::proof::ProofError; +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; +use dpp::serialization::PlatformDeserializable; +use grovedb::GroveDb; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_group_infos_in_contract_v0< + T: FromIterator<(GroupContractPosition, Group)>, + >( + proof: &[u8], + contract_id: Identifier, + start_group_contract_position: Option<(GroupContractPosition, StartAtIncluded)>, + limit: Option, + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + let path_query = Self::group_infos_for_contract_id_query( + contract_id.to_buffer(), + start_group_contract_position, + limit, + ); + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query(proof, &path_query, &platform_version.drive.grove_version)? + } else { + GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)? + }; + let values = proved_key_values + .into_iter() + .filter_map(|(path, _, element)| { + let key_bytes = match path.last() { + Some(contract_position_bytes) => contract_position_bytes, + None => { + return Some(Err(Error::Proof(ProofError::CorruptedProof( + "path can't be empty in proof".to_string(), + )))) + } + }; + let key_bytes: [u8; 2] = match key_bytes.clone().try_into().map_err(|_| { + Error::Proof(ProofError::IncorrectValueSize( + "group contract position incorrect size", + )) + }) { + Ok(bytes) => bytes, + + Err(e) => return Some(Err(e)), + }; + let group_contract_position: GroupContractPosition = + GroupContractPosition::from_be_bytes(key_bytes); + match element { + Some(Item(value, ..)) => { + let group = match Group::deserialize_from_bytes(&value) { + Ok(group) => group, + + Err(e) => return Some(Err(e.into())), + }; + Some(Ok((group_contract_position, group))) + } + None => None, + Some(element) => Some(Err(Error::Proof(ProofError::IncorrectProof(format!( + "group should be in an item, however a {} was returned", + element.type_str() + ))))), + } + }) + .collect::>()?; + Ok((root_hash, values)) + } +} diff --git a/packages/rs-drive/src/verify/mod.rs b/packages/rs-drive/src/verify/mod.rs index 18474b4bbb7..98d19c7bb06 100644 --- a/packages/rs-drive/src/verify/mod.rs +++ b/packages/rs-drive/src/verify/mod.rs @@ -10,9 +10,13 @@ pub mod single_document; /// System components (Epoch info etc...) verification methods on proofs pub mod system; +/// Group proof verification module +pub mod group; /// Verifies that a state transition contents exist in the proof pub mod state_transition; -mod tokens; +/// Token proof verification module +pub mod tokens; +/// Voting proof verification module pub mod voting; /// Represents the root hash of the grovedb tree diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs index 5b2309458d4..087e593424f 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs @@ -7,6 +7,7 @@ pub struct DriveVerifyMethodVersions { pub contract: DriveVerifyContractMethodVersions, pub document: DriveVerifyDocumentMethodVersions, pub identity: DriveVerifyIdentityMethodVersions, + pub group: DriveVerifyGroupMethodVersions, pub token: DriveVerifyTokenMethodVersions, pub single_document: DriveVerifySingleDocumentMethodVersions, pub system: DriveVerifySystemMethodVersions, @@ -43,6 +44,12 @@ pub struct DriveVerifyIdentityMethodVersions { pub verify_identity_revision_for_identity_id: FeatureVersion, } +#[derive(Clone, Debug, Default)] +pub struct DriveVerifyGroupMethodVersions { + pub verify_group_info: FeatureVersion, + pub verify_group_infos_in_contract: FeatureVersion, +} + #[derive(Clone, Debug, Default)] pub struct DriveVerifyTokenMethodVersions { pub verify_token_balances_for_identity_ids: FeatureVersion, diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs index 0daa0cdd0b6..e4a315835de 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs @@ -1,6 +1,6 @@ use crate::version::drive_versions::drive_verify_method_versions::{ DriveVerifyContractMethodVersions, DriveVerifyDocumentMethodVersions, - DriveVerifyIdentityMethodVersions, DriveVerifyMethodVersions, + DriveVerifyGroupMethodVersions, DriveVerifyIdentityMethodVersions, DriveVerifyMethodVersions, DriveVerifySingleDocumentMethodVersions, DriveVerifyStateTransitionMethodVersions, DriveVerifySystemMethodVersions, DriveVerifyTokenMethodVersions, DriveVerifyVoteMethodVersions, }; @@ -29,6 +29,10 @@ pub const DRIVE_VERIFY_METHOD_VERSIONS_V1: DriveVerifyMethodVersions = DriveVeri verify_identities_contract_keys: 0, verify_identity_revision_for_identity_id: 0, }, + group: DriveVerifyGroupMethodVersions { + verify_group_info: 0, + verify_group_infos_in_contract: 0, + }, token: DriveVerifyTokenMethodVersions { verify_token_balances_for_identity_ids: 0, verify_token_balances_for_identity_id: 0, From 606f2823d2613015d8d9b3c6d90f2dd2865c30df Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Mon, 20 Jan 2025 10:19:58 +0700 Subject: [PATCH 02/13] active group actions query --- .../protos/platform/v0/platform.proto | 73 ++- .../group_queries/active_group_actions/mod.rs | 62 +++ .../active_group_actions/v0/mod.rs | 226 ++++++++ .../query/group_queries/group_info/v0/mod.rs | 2 +- .../query/group_queries/group_infos/v0/mod.rs | 2 +- .../src/query/group_queries/mod.rs | 1 + packages/rs-drive-abci/src/query/service.rs | 22 +- .../mod.rs | 16 +- .../v0/mod.rs | 4 +- .../fetch/fetch_active_action_infos/mod.rs | 121 ++++ .../fetch/fetch_active_action_infos/v0/mod.rs | 81 +++ .../rs-drive/src/drive/group/fetch/mod.rs | 3 +- .../rs-drive/src/drive/group/fetch/queries.rs | 66 ++- .../rs-drive/src/drive/group/prove/mod.rs | 1 + .../prove/prove_active_action_infos/mod.rs | 125 +++++ .../prove/prove_active_action_infos/v0/mod.rs | 523 ++++++++++++++++++ packages/rs-drive/src/verify/group/mod.rs | 1 + .../group/verify_active_action_infos/mod.rs | 79 +++ .../verify_active_action_infos/v0/mod.rs | 73 +++ .../tokens/verify_token_statuses/mod.rs | 1 - .../mod.rs | 7 +- .../drive_abci_query_versions/mod.rs | 1 + .../drive_abci_query_versions/v1.rs | 5 + .../drive_group_method_versions/mod.rs | 4 +- .../drive_group_method_versions/v1.rs | 4 +- .../drive_verify_method_versions/mod.rs | 1 + .../drive_verify_method_versions/v1.rs | 1 + .../src/version/mocks/v2_test.rs | 5 + 28 files changed, 1464 insertions(+), 46 deletions(-) create mode 100644 packages/rs-drive-abci/src/query/group_queries/active_group_actions/mod.rs create mode 100644 packages/rs-drive-abci/src/query/group_queries/active_group_actions/v0/mod.rs rename packages/rs-drive/src/drive/group/fetch/{fetch_action_id_info => fetch_active_action_info}/mod.rs (91%) rename packages/rs-drive/src/drive/group/fetch/{fetch_action_id_info => fetch_active_action_info}/v0/mod.rs (96%) create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/prove/prove_active_action_infos/mod.rs create mode 100644 packages/rs-drive/src/drive/group/prove/prove_active_action_infos/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs create mode 100644 packages/rs-drive/src/verify/group/verify_active_action_infos/v0/mod.rs diff --git a/packages/dapi-grpc/protos/platform/v0/platform.proto b/packages/dapi-grpc/protos/platform/v0/platform.proto index 76b2cce1054..8a632d22911 100644 --- a/packages/dapi-grpc/protos/platform/v0/platform.proto +++ b/packages/dapi-grpc/protos/platform/v0/platform.proto @@ -63,7 +63,7 @@ service Platform { rpc getTokenTotalSupply(GetTokenTotalSupplyRequest) returns (GetTokenTotalSupplyResponse); rpc getGroupInfo(GetGroupInfoRequest) returns (GetGroupInfoResponse); rpc getGroupInfos(GetGroupInfosRequest) returns (GetGroupInfosResponse); -// rpc getActiveGroupActions(GetActiveGroupActionsRequest) returns (GetActiveGroupActionsResponse); + rpc getActiveGroupActions(GetActiveGroupActionsRequest) returns (GetActiveGroupActionsResponse); // rpc getClosedGroupActions(GetClosedGroupActionsRequest) returns (GetClosedGroupActionsResponse); } @@ -1513,10 +1513,17 @@ message GetGroupInfosResponse { } message GetActiveGroupActionsRequest { + message StartAtActionId { + bytes start_action_id = 1; + bool start_action_id_included = 2; + } + message GetActiveGroupActionsRequestV0 { bytes contract_id = 1; uint32 group_contract_position = 2; - bool prove = 3; + optional StartAtActionId start_at_action_id = 3; + optional uint32 count = 4; + bool prove = 5; } oneof version { GetActiveGroupActionsRequestV0 v0 = 1; @@ -1529,53 +1536,95 @@ message GetActiveGroupActionsResponse { message MintEvent { uint64 amount = 1; // Amount to mint bytes recipient_id = 2; // Recipient identifier - string public_note = 3; // Public note + optional string public_note = 3; // Public note } // Burn event message BurnEvent { uint64 amount = 1; // Amount to burn - string public_note = 2; // Public note + optional string public_note = 2; // Public note } // Freeze event message FreezeEvent { bytes frozen_id = 1; // Identifier of the frozen entity - string public_note = 2; // Public note + optional string public_note = 2; // Public note } // Unfreeze event message UnfreezeEvent { bytes frozen_id = 1; // Identifier of the unfrozen entity - string public_note = 2; // Public note + optional string public_note = 2; // Public note } // Destroy frozen funds event message DestroyFrozenFundsEvent { bytes frozen_id = 1; // Identifier of the frozen entity uint64 amount = 2; // Amount to destroy - string public_note = 3; // Public note + optional string public_note = 3; // Public note + } + + // Shared encrypted note + message SharedEncryptedNote { + uint32 sender_key_index = 1; // Sender key index + uint32 recipient_key_index = 2; // Recipient key index + bytes encrypted_data = 3; // Encrypted data + } + + // Personal encrypted note + message PersonalEncryptedNote { + uint32 root_encryption_key_index = 1; // Root encryption key index + uint32 derivation_encryption_key_index = 2; // Derivation encryption key index + bytes encrypted_data = 3; // Encrypted data } // Transfer event message TransferEvent { bytes recipient_id = 1; // Recipient identifier - string public_note = 2; // Public note - bytes shared_encrypted_note = 3; // Shared encrypted note - bytes personal_encrypted_note = 4; // Personal encrypted note + optional string public_note = 2; // Public note + optional SharedEncryptedNote shared_encrypted_note = 3; // Shared encrypted note + optional PersonalEncryptedNote personal_encrypted_note = 4; // Personal encrypted note uint64 amount = 5; // Amount transferred } // Emergency action event message EmergencyActionEvent { - string action_type = 1; // Emergency action type - string public_note = 2; // Public note + // Enum for emergency action types + enum ActionType { + PAUSE = 0; // Pause action + RESUME = 1; // Resume action + } + + ActionType action_type = 1; // Emergency action type + optional string public_note = 2; // Public note } // Event associated with this action message GroupActionEvent { oneof event_type { TokenEvent token_event = 1; // Token event details + DocumentEvent document_event = 2; + ContractEvent contract_event = 3; + } + } + + message DocumentEvent { + oneof type { + DocumentCreateEvent create = 1; // Create event details + } + } + + message DocumentCreateEvent { + bytes created_document = 1; + } + + message ContractUpdateEvent { + bytes updated_contract = 1; + } + + message ContractEvent { + oneof type { + ContractUpdateEvent update = 1; // Contract update event } } diff --git a/packages/rs-drive-abci/src/query/group_queries/active_group_actions/mod.rs b/packages/rs-drive-abci/src/query/group_queries/active_group_actions/mod.rs new file mode 100644 index 00000000000..b63b1c82c88 --- /dev/null +++ b/packages/rs-drive-abci/src/query/group_queries/active_group_actions/mod.rs @@ -0,0 +1,62 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_active_group_actions_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_active_group_actions_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetActiveGroupActionsRequest, GetActiveGroupActionsResponse}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of active group actions + pub fn query_active_group_actions( + &self, + GetActiveGroupActionsRequest { version }: GetActiveGroupActionsRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode active group actions query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .group_queries + .active_group_actions; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "active_group_actions".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_active_group_actions_v0( + request_v0, + platform_state, + platform_version, + )?; + Ok(result.map(|response_v0| GetActiveGroupActionsResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/group_queries/active_group_actions/v0/mod.rs b/packages/rs-drive-abci/src/query/group_queries/active_group_actions/v0/mod.rs new file mode 100644 index 00000000000..97124d51bb4 --- /dev/null +++ b/packages/rs-drive-abci/src/query/group_queries/active_group_actions/v0/mod.rs @@ -0,0 +1,226 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_active_group_actions_request::GetActiveGroupActionsRequestV0; +use dapi_grpc::platform::v0::get_active_group_actions_response::{ + get_active_group_actions_response_v0, GetActiveGroupActionsResponseV0, +}; +use dapi_grpc::platform::v0::get_active_group_actions_response::get_active_group_actions_response_v0::{BurnEvent, DestroyFrozenFundsEvent, emergency_action_event, EmergencyActionEvent, FreezeEvent, group_action_event, GroupActionEntry, GroupActionEvent, GroupActions, MintEvent, PersonalEncryptedNote, SharedEncryptedNote, token_event, TransferEvent, UnfreezeEvent, TokenEvent as TokenEventResponse}; +use dpp::check_validation_result_with_data; +use dpp::data_contract::GroupContractPosition; +use dpp::group::action_event; +use dpp::group::group_action::GroupAction; +use dpp::identifier::Identifier; +use dpp::tokens::emergency_action::TokenEmergencyAction; +use dpp::tokens::token_event::TokenEvent; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; +use drive::error::query::QuerySyntaxError; + +impl Platform { + pub(super) fn query_active_group_actions_v0( + &self, + GetActiveGroupActionsRequestV0 { + contract_id, + group_contract_position, + start_at_action_id, + count, + prove, + }: GetActiveGroupActionsRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let config = &self.config.drive; + let contract_id: Identifier = + check_validation_result_with_data!(contract_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "contract id must be a valid identifier (32 bytes long)".to_string(), + ) + })); + + if group_contract_position > u16::MAX as u32 { + return Ok(QueryValidationResult::new_with_error(QueryError::Query( + QuerySyntaxError::InvalidParameter(format!( + "group contract position {} can not be over u16::MAX", + group_contract_position + )), + ))); + } + + let limit = count + .map_or(Some(config.default_query_limit), |limit_value| { + if limit_value == 0 + || limit_value > u16::MAX as u32 + || limit_value as u16 > config.default_query_limit + { + None + } else { + Some(limit_value as u16) + } + }) + .ok_or(drive::error::Error::Query(QuerySyntaxError::InvalidLimit( + format!("limit greater than max limit {}", config.max_query_limit), + )))?; + + let maybe_start_at_action_id = match start_at_action_id { + None => None, + Some(start_at_action_id) => { + let start_at_action_id_identifier: Identifier = + check_validation_result_with_data!(start_at_action_id + .start_action_id + .try_into() + .map_err(|_| { + QueryError::InvalidArgument( + "start at action id must be a valid identifier (32 bytes long)" + .to_string(), + ) + })); + Some(( + start_at_action_id_identifier, + start_at_action_id.start_action_id_included, + )) + } + }; + + let response = if prove { + let proof = check_validation_result_with_data!(self.drive.prove_active_action_infos( + contract_id, + group_contract_position as GroupContractPosition, + maybe_start_at_action_id, + Some(limit), + None, + platform_version, + )); + + GetActiveGroupActionsResponseV0 { + result: Some(get_active_group_actions_response_v0::Result::Proof( + self.response_proof_v0(platform_state, proof), + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + } else { + let group_actions = self + .drive + .fetch_active_action_infos( + contract_id, + group_contract_position as GroupContractPosition, + maybe_start_at_action_id, + Some(limit), + None, + platform_version, + )? + .into_iter() + .map(|(action_id, group_action)| { + // Convert the fetched GroupAction into a GroupActionEntry + GroupActionEntry { + action_id: action_id.to_vec(), + event: Some(GroupActionEvent { + event_type: Some(match group_action { + GroupAction::V0(group_action_v0) => match group_action_v0.event { + action_event::GroupActionEvent::TokenEvent(token_event) => match token_event { + TokenEvent::Mint(amount, recipient_id, public_note) => { + group_action_event::EventType::TokenEvent(TokenEventResponse { + r#type: Some(token_event::Type::Mint(MintEvent { + amount: amount as u64, + recipient_id: recipient_id.to_vec(), + public_note, + })), + }) + } + TokenEvent::Burn(amount, public_note) => { + group_action_event::EventType::TokenEvent(TokenEventResponse { + r#type: Some(token_event::Type::Burn(BurnEvent { + amount: amount as u64, + public_note, + })), + }) + } + TokenEvent::Freeze(frozen_id, public_note) => { + group_action_event::EventType::TokenEvent(TokenEventResponse { + r#type: Some(token_event::Type::Freeze(FreezeEvent { + frozen_id: frozen_id.to_vec(), + public_note, + })), + }) + } + TokenEvent::Unfreeze(frozen_id, public_note) => { + group_action_event::EventType::TokenEvent(TokenEventResponse { + r#type: Some(token_event::Type::Unfreeze(UnfreezeEvent { + frozen_id: frozen_id.to_vec(), + public_note, + })), + }) + } + TokenEvent::DestroyFrozenFunds(frozen_id, amount, public_note) => { + group_action_event::EventType::TokenEvent(TokenEventResponse { + r#type: Some(token_event::Type::DestroyFrozenFunds( + DestroyFrozenFundsEvent { + frozen_id: frozen_id.to_vec(), + amount, + public_note, + }, + )), + }) + } + TokenEvent::Transfer( + recipient_id, + public_note, + shared_encrypted_note, + personal_encrypted_note, + amount, + ) => { + group_action_event::EventType::TokenEvent(TokenEventResponse { + r#type: Some(token_event::Type::Transfer(TransferEvent { + recipient_id: recipient_id.to_vec(), + public_note, + shared_encrypted_note: shared_encrypted_note + .map(|(sender_key_index, recipient_key_index, note)| { + SharedEncryptedNote { + sender_key_index, + recipient_key_index, + encrypted_data: note, + } + }), + personal_encrypted_note: personal_encrypted_note + .map(|(root_encryption_key_index, derivation_encryption_key_index, note)| { + PersonalEncryptedNote { + root_encryption_key_index, + derivation_encryption_key_index, + encrypted_data: note, + } + }), + amount: amount as u64, + })), + }) + }, + TokenEvent::EmergencyAction(action, public_note) => { + group_action_event::EventType::TokenEvent(TokenEventResponse { + r#type: Some(token_event::Type::EmergencyAction(EmergencyActionEvent { + action_type: match action { + TokenEmergencyAction::Pause => emergency_action_event::ActionType::Pause.into(), + TokenEmergencyAction::Resume => emergency_action_event::ActionType::Resume.into(), + }, + public_note, + })), + }) + } + }, + }, + }), + }), + } + }) + .collect(); + GetActiveGroupActionsResponseV0 { + result: Some(get_active_group_actions_response_v0::Result::GroupActions( + GroupActions { group_actions }, + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/group_queries/group_info/v0/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_info/v0/mod.rs index a5175ac3cff..84c55bfc609 100644 --- a/packages/rs-drive-abci/src/query/group_queries/group_info/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/group_queries/group_info/v0/mod.rs @@ -31,7 +31,7 @@ impl Platform { let contract_id: Identifier = check_validation_result_with_data!(contract_id.try_into().map_err(|_| { QueryError::InvalidArgument( - "token_id must be a valid identifier (32 bytes long)".to_string(), + "contract id must be a valid identifier (32 bytes long)".to_string(), ) })); diff --git a/packages/rs-drive-abci/src/query/group_queries/group_infos/v0/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_infos/v0/mod.rs index 88787fef920..e9dc27aab46 100644 --- a/packages/rs-drive-abci/src/query/group_queries/group_infos/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/group_queries/group_infos/v0/mod.rs @@ -33,7 +33,7 @@ impl Platform { let contract_id: Identifier = check_validation_result_with_data!(contract_id.try_into().map_err(|_| { QueryError::InvalidArgument( - "token_id must be a valid identifier (32 bytes long)".to_string(), + "contract id must be a valid identifier (32 bytes long)".to_string(), ) })); diff --git a/packages/rs-drive-abci/src/query/group_queries/mod.rs b/packages/rs-drive-abci/src/query/group_queries/mod.rs index b9ae74339a8..cb939e021bb 100644 --- a/packages/rs-drive-abci/src/query/group_queries/mod.rs +++ b/packages/rs-drive-abci/src/query/group_queries/mod.rs @@ -1,2 +1,3 @@ +mod active_group_actions; mod group_info; mod group_infos; diff --git a/packages/rs-drive-abci/src/query/service.rs b/packages/rs-drive-abci/src/query/service.rs index 7ac860eac19..510b661dee3 100644 --- a/packages/rs-drive-abci/src/query/service.rs +++ b/packages/rs-drive-abci/src/query/service.rs @@ -712,17 +712,17 @@ impl PlatformService for QueryService { .await } - // async fn get_active_group_actions( - // &self, - // request: Request, - // ) -> Result, Status> { - // self.handle_blocking_query( - // request, - // Platform::::query_active_group_actions, - // "get_active_group_actions", - // ) - // .await - // } + async fn get_active_group_actions( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_active_group_actions, + "get_active_group_actions", + ) + .await + } } fn query_error_into_status(error: QueryError) -> Status { diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_active_action_info/mod.rs similarity index 91% rename from packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/mod.rs rename to packages/rs-drive/src/drive/group/fetch/fetch_active_action_info/mod.rs index 99c38f711eb..7f99fad7f5a 100644 --- a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/fetch_active_action_info/mod.rs @@ -32,7 +32,7 @@ impl Drive { /// /// # Errors /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. - pub fn fetch_action_id_info( + pub fn fetch_active_action_info( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, @@ -45,9 +45,9 @@ impl Drive { .methods .group .fetch - .fetch_action_id_info + .fetch_active_action_info { - 0 => self.fetch_action_id_info_v0( + 0 => self.fetch_active_action_info_v0( contract_id, group_contract_position, action_id, @@ -55,7 +55,7 @@ impl Drive { platform_version, ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { - method: "fetch_action_id_info".to_string(), + method: "fetch_active_action_info".to_string(), known_versions: vec![0], received: version, })), @@ -83,7 +83,7 @@ impl Drive { /// /// # Errors /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. - pub(crate) fn fetch_action_id_info_and_add_operations( + pub(crate) fn fetch_active_action_info_and_add_operations( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, @@ -100,9 +100,9 @@ impl Drive { .methods .group .fetch - .fetch_action_id_info + .fetch_active_action_info { - 0 => self.fetch_action_id_info_and_add_operations_v0( + 0 => self.fetch_active_action_info_and_add_operations_v0( contract_id, group_contract_position, action_id, @@ -112,7 +112,7 @@ impl Drive { platform_version, ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { - method: "fetch_action_id_signers_and_add_operations".to_string(), + method: "fetch_active_action_info_and_add_operations".to_string(), known_versions: vec![0], received: version, })), diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/v0/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_active_action_info/v0/mod.rs similarity index 96% rename from packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/v0/mod.rs rename to packages/rs-drive/src/drive/group/fetch/fetch_active_action_info/v0/mod.rs index 723e7312cd4..1e807d289e4 100644 --- a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/v0/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/fetch_active_action_info/v0/mod.rs @@ -15,7 +15,7 @@ use grovedb::batch::KeyInfoPath; use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; impl Drive { - pub(super) fn fetch_action_id_info_v0( + pub(super) fn fetch_active_action_info_v0( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, @@ -45,7 +45,7 @@ impl Drive { Ok(group_action) } - pub(super) fn fetch_action_id_info_and_add_operations_v0( + pub(super) fn fetch_active_action_info_and_add_operations_v0( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/mod.rs new file mode 100644 index 00000000000..5070435eb7b --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/mod.rs @@ -0,0 +1,121 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action::GroupAction; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; +use std::collections::BTreeMap; + +mod v0; + +impl Drive { + /// Fetches the `GroupAction` for the given action ID and group contract position. + /// + /// This function queries the GroveDB to fetch the `GroupAction` associated with a specific + /// group contract position and action ID. The method selects the appropriate version of + /// `fetch_action_id_info` based on the `platform_version` provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `action_id`: The identifier of the action whose `GroupAction` is being fetched. + /// - `transaction`: The transaction argument used for the query. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(GroupAction)`: The `GroupAction` for the specified action ID and contract position. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub fn fetch_active_action_infos( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + start_action_id: Option<(Identifier, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .fetch + .fetch_active_action_infos + { + 0 => self.fetch_active_action_infos_v0( + contract_id, + group_contract_position, + start_action_id, + limit, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_active_action_infos".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the `GroupAction` and adds corresponding operations to the drive for the given action ID and group contract position. + /// + /// This function is similar to `fetch_action_id_info` but also adds operations to the drive for state changes or queries. + /// Additionally, it supports cost estimation by interacting with the layer information if provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `action_id`: The identifier of the action whose `GroupAction` is being fetched. + /// - `estimated_costs_only_with_layer_info`: A mutable reference to an optional `HashMap` containing + /// layer information used for cost estimation. + /// - `transaction`: The transaction argument used for the query. + /// - `drive_operations`: A mutable reference to a vector that stores low-level drive operations. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(GroupAction)`: The `GroupAction` for the specified action ID and contract position, along with any added operations. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub(crate) fn fetch_active_action_infos_and_add_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + start_action_id: Option<(Identifier, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .fetch + .fetch_active_action_infos + { + 0 => self.fetch_active_action_infos_and_add_operations_v0( + contract_id, + group_contract_position, + start_action_id, + limit, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_active_action_infos_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/v0/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/v0/mod.rs new file mode 100644 index 00000000000..d52a672070c --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/v0/mod.rs @@ -0,0 +1,81 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action::GroupAction; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; +use dpp::serialization::PlatformDeserializable; +use dpp::version::PlatformVersion; +use grovedb::query_result_type::QueryResultType; +use grovedb::Element::Item; +use grovedb::TransactionArg; +use std::collections::BTreeMap; + +impl Drive { + pub(super) fn fetch_active_action_infos_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + start_action_id: Option<(Identifier, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.fetch_active_action_infos_and_add_operations_v0( + contract_id, + group_contract_position, + start_action_id, + limit, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn fetch_active_action_infos_and_add_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + start_action_id: Option<(Identifier, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path_query = Drive::group_active_action_infos_query( + contract_id.to_buffer(), + group_contract_position, + start_action_id.map(|(s, i)| (s.to_buffer(), i)), + limit, + ); + + self.grove_get_raw_path_query( + &path_query, + transaction, + QueryResultType::QueryPathKeyElementTrioResultType, + drive_operations, + &platform_version.drive, + )? + .0 + .to_path_key_elements() + .into_iter() + .map(|(path, _, element)| { + let Some(last_path_component) = path.last() else { + return Err(Error::Drive(DriveError::CorruptedDriveState( + "we should always have a path not be empty".to_string(), + ))); + }; + let action_id = Identifier::from_bytes(last_path_component)?; + + match element { + Item(value, ..) => Ok((action_id, GroupAction::deserialize_from_bytes(&value)?)), + _ => Err(Error::Drive(DriveError::CorruptedDriveState( + "element should be an item representing the group action".to_string(), + ))), + } + }) + .collect() + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/mod.rs b/packages/rs-drive/src/drive/group/fetch/mod.rs index 8df377a7a90..d7456d8a992 100644 --- a/packages/rs-drive/src/drive/group/fetch/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/mod.rs @@ -1,7 +1,8 @@ mod fetch_action_id_has_signer; -mod fetch_action_id_info; mod fetch_action_id_info_keep_serialized; mod fetch_action_id_signers_power; +mod fetch_active_action_info; +mod fetch_active_action_infos; mod fetch_group_info; mod fetch_group_infos; mod queries; diff --git a/packages/rs-drive/src/drive/group/fetch/queries.rs b/packages/rs-drive/src/drive/group/fetch/queries.rs index dcd532b4c10..5d6ea366b3c 100644 --- a/packages/rs-drive/src/drive/group/fetch/queries.rs +++ b/packages/rs-drive/src/drive/group/fetch/queries.rs @@ -1,4 +1,7 @@ -use crate::drive::group::paths::{group_contract_path_vec, group_path_vec, GROUP_INFO_KEY}; +use crate::drive::group::paths::{ + group_action_root_path_vec, group_closed_action_root_path_vec, group_contract_path_vec, + group_path_vec, ACTION_INFO_KEY, GROUP_INFO_KEY, +}; use crate::drive::Drive; use crate::query::{Query, QueryItem}; use dpp::data_contract::GroupContractPosition; @@ -45,4 +48,65 @@ impl Drive { }, } } + + /// Gets the active group actions + pub fn group_active_action_infos_query( + contract_id: [u8; 32], + group_contract_position: GroupContractPosition, + start_at: Option<([u8; 32], bool)>, + limit: Option, + ) -> PathQuery { + let group_actions_path = group_action_root_path_vec(&contract_id, group_contract_position); + let mut query = Query::new_with_direction(true); + if let Some((start_at, start_at_included)) = start_at { + if start_at_included { + query.insert_item(QueryItem::RangeFrom(start_at.to_vec()..)) + } else { + query.insert_item(QueryItem::RangeAfter(start_at.to_vec()..)) + } + } else { + query.insert_item(QueryItem::RangeFull(RangeFull)) + } + + query.set_subquery_key(ACTION_INFO_KEY.to_vec()); + + PathQuery { + path: group_actions_path, + query: SizedQuery { + query, + limit, + offset: None, + }, + } + } + + /// Gets the active group actions + pub fn group_closed_action_infos_query( + contract_id: [u8; 32], + group_contract_position: GroupContractPosition, + start_at: Option<([u8; 32], bool)>, + limit: Option, + ) -> PathQuery { + let group_actions_path = + group_closed_action_root_path_vec(&contract_id, group_contract_position); + let mut query = Query::new_with_direction(true); + if let Some((start_at, start_at_included)) = start_at { + if start_at_included { + query.insert_item(QueryItem::RangeFrom(start_at.to_vec()..)) + } else { + query.insert_item(QueryItem::RangeAfter(start_at.to_vec()..)) + } + } else { + query.insert_item(QueryItem::RangeFull(RangeFull)) + } + + PathQuery { + path: group_actions_path, + query: SizedQuery { + query, + limit, + offset: None, + }, + } + } } diff --git a/packages/rs-drive/src/drive/group/prove/mod.rs b/packages/rs-drive/src/drive/group/prove/mod.rs index c6fa82c789e..ff2a36d87b4 100644 --- a/packages/rs-drive/src/drive/group/prove/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/mod.rs @@ -1,2 +1,3 @@ +mod prove_active_action_infos; mod prove_group_info; mod prove_group_infos; diff --git a/packages/rs-drive/src/drive/group/prove/prove_active_action_infos/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_active_action_infos/mod.rs new file mode 100644 index 00000000000..bf1ab468ea6 --- /dev/null +++ b/packages/rs-drive/src/drive/group/prove/prove_active_action_infos/mod.rs @@ -0,0 +1,125 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; + +mod v0; +impl Drive { + /// Generates a proof of active action information within a specific group of a contract. + /// + /// This method produces a cryptographic proof that validates and retrieves active action information + /// associated with a specific group in the given contract. The proof can be limited to a subset of actions + /// based on the `start_action_id` and `limit` parameters. It supports multiple versions for backward + /// compatibility and forwards the request to the appropriate versioned implementation. + /// + /// # Arguments + /// - `contract_id`: The identifier of the contract containing the group. + /// - `group_contract_position`: The position of the group within the contract whose actions are to be proven. + /// - `start_action_id`: An optional starting action ID, combined with a [`StartAtIncluded`] flag to specify whether + /// the start position is inclusive. + /// - `limit`: An optional limit on the number of actions to include in the proof. + /// - `transaction`: The transaction context for the operation. + /// - `platform_version`: A reference to the platform version, used to determine the appropriate versioned implementation. + /// + /// # Returns + /// - `Ok(Vec)`: On success, returns a serialized proof as a vector of bytes. + /// - `Err(Error)`: If the operation fails, returns an [`Error`] indicating the cause of failure. + /// + /// # Errors + /// - [`Error::Drive(DriveError::UnknownVersionMismatch)`]: If the method is called with an unsupported platform version. + /// - Any other errors propagated from the versioned implementation. + pub fn prove_active_action_infos( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + start_action_id: Option<(Identifier, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .prove + .prove_active_action_infos + { + 0 => self.prove_active_action_infos_v0( + contract_id, + group_contract_position, + start_action_id, + limit, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_active_action_infos".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Generates a proof of active action information within a specific group of a contract and adds operations. + /// + /// This method extends the functionality of `prove_active_action_infos` by additionally allowing + /// operations to be added to a provided `drive_operations` list. It produces a cryptographic proof + /// of active action information associated with a specific group in the given contract and supports + /// different versions for backward compatibility. + /// + /// # Arguments + /// - `contract_id`: The identifier of the contract containing the group. + /// - `group_contract_position`: The position of the group within the contract whose actions are to be proven. + /// - `start_action_id`: An optional starting action ID, combined with a [`StartAtIncluded`] flag to specify whether + /// the start position is inclusive. + /// - `limit`: An optional limit on the number of actions to include in the proof. + /// - `transaction`: The transaction context for the operation. + /// - `drive_operations`: A mutable reference to a vector where additional low-level operations can be appended. + /// - `platform_version`: A reference to the platform version, used to determine the appropriate versioned implementation. + /// + /// # Returns + /// - `Ok(Vec)`: On success, returns a serialized proof as a vector of bytes. + /// - `Err(Error)`: If the operation fails, returns an [`Error`] indicating the cause of failure. + /// + /// # Errors + /// - [`Error::Drive(DriveError::UnknownVersionMismatch)`]: If the method is called with an unsupported platform version. + /// - Any other errors propagated from the versioned implementation. + pub(crate) fn prove_active_action_infos_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + start_action_id: Option<(Identifier, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .prove + .prove_active_action_infos + { + 0 => self.prove_active_action_infos_operations_v0( + contract_id, + group_contract_position, + start_action_id, + limit, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_active_action_infos_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/prove/prove_active_action_infos/v0/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_active_action_infos/v0/mod.rs new file mode 100644 index 00000000000..7c13b859c34 --- /dev/null +++ b/packages/rs-drive/src/drive/group/prove/prove_active_action_infos/v0/mod.rs @@ -0,0 +1,523 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + pub(super) fn prove_active_action_infos_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + start_action_id: Option<(Identifier, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_active_action_infos_operations_v0( + contract_id, + group_contract_position, + start_action_id, + limit, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_active_action_infos_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + start_action_id: Option<(Identifier, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path_query = Drive::group_active_action_infos_query( + contract_id.to_buffer(), + group_contract_position, + start_action_id.map(|(s, i)| (s.to_buffer(), i)), + limit, + ); + self.grove_get_proved_path_query( + &path_query, + transaction, + drive_operations, + &platform_version.drive, + ) + } +} +#[cfg(test)] +mod tests { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::block::block_info::BlockInfo; + use dpp::data_contract::accessors::v0::DataContractV0Getters; + use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + use dpp::data_contract::config::v0::DataContractConfigV0; + use dpp::data_contract::config::DataContractConfig; + use dpp::data_contract::group::v0::GroupV0; + use dpp::data_contract::group::Group; + use dpp::data_contract::v1::DataContractV1; + use dpp::data_contract::DataContract; + use dpp::group::action_event::GroupActionEvent; + use dpp::group::group_action::v0::GroupActionV0; + use dpp::group::group_action::GroupAction; + use dpp::identifier::Identifier; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + use dpp::tokens::token_event::TokenEvent; + use dpp::version::PlatformVersion; + use std::collections::BTreeMap; + + #[test] + fn should_prove_active_action_infos_with_multiple_actions() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity_1 = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_1_id = identity_1.id(); + + let identity_2 = Identity::random_identity(3, Some(506), platform_version) + .expect("expected a platform identity"); + + let identity_2_id = identity_2.id(); + + let identity_3 = Identity::random_identity(3, Some(9), platform_version) + .expect("expected a platform identity"); + + let identity_3_id = identity_3.id(); + + // Create a data contract with multiple tokens + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: BTreeMap::from([ + ( + 0, + Group::V0(GroupV0 { + members: [(identity_1_id, 1), (identity_2_id, 1)].into(), + required_power: 2, + }), + ), + ( + 1, + Group::V0(GroupV0 { + members: [(identity_1_id, 2), (identity_2_id, 1), (identity_3_id, 1)] + .into(), + required_power: 2, + }), + ), + ]), + tokens: BTreeMap::from([ + ( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ( + 1, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ]), + }); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Contract and group details + let contract_id = contract.id(); + let group_contract_position = 0; + + // Create actions + let action_id_1 = Identifier::random(); + let action_id_2 = Identifier::random(); + + let action_1 = GroupAction::V0(GroupActionV0 { + event: GroupActionEvent::TokenEvent(TokenEvent::Mint(100, identity_1_id, None)), + }); + + let action_2 = GroupAction::V0(GroupActionV0 { + event: GroupActionEvent::TokenEvent(TokenEvent::Burn(50, None)), + }); + + // Add actions using `add_group_action` + drive + .add_group_action( + contract_id, + group_contract_position, + Some(action_1.clone()), + action_id_1, + identity_1_id, + 1, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add action 1"); + + drive + .add_group_action( + contract_id, + group_contract_position, + Some(action_2.clone()), + action_id_2, + identity_2_id, + 1, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add action 2"); + + // Fetch actions directly + let fetched_actions = drive + .fetch_active_action_infos( + contract_id, + group_contract_position, + None, + Some(10), + None, + platform_version, + ) + .expect("expected to fetch active actions"); + + assert_eq!( + fetched_actions, + BTreeMap::from([ + (action_id_1, action_1.clone()), + (action_id_2, action_2.clone()) + ]), + "unexpected fetched actions" + ); + + // Prove actions + let proof = drive + .prove_active_action_infos_v0( + contract_id, + group_contract_position, + None, + Some(10), + None, + platform_version, + ) + .expect("should not error when proving active actions"); + + // Verify proof + let proved_actions: BTreeMap = + Drive::verify_active_action_infos_in_contract( + proof.as_slice(), + contract_id, + group_contract_position, + None, + Some(10), + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert proved actions match fetched actions + assert_eq!(proved_actions, fetched_actions, "unexpected proved actions"); + } + + #[test] + fn should_prove_no_active_action_infos_for_non_existent_contract() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let non_existent_contract_id = Identifier::random(); + let group_contract_position = 0; + + // Prove actions for non-existent contract + let proof = drive + .prove_active_action_infos_v0( + non_existent_contract_id, + group_contract_position, + None, + Some(10), + None, + platform_version, + ) + .expect("should not error when proving active actions for non-existent contract"); + + // Verify proof + let proved_actions: BTreeMap = + Drive::verify_active_action_infos_in_contract( + proof.as_slice(), + non_existent_contract_id, + group_contract_position, + None, + Some(10), + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert no actions exist + assert_eq!( + proved_actions, + BTreeMap::new(), + "expected no proved actions" + ); + } + + #[test] + fn should_fetch_and_prove_active_action_infos_with_start_action_id() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity_1 = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + let identity_1_id = identity_1.id(); + + let identity_2 = Identity::random_identity(3, Some(506), platform_version) + .expect("expected a platform identity"); + let identity_2_id = identity_2.id(); + + let identity_3 = Identity::random_identity(3, Some(9), platform_version) + .expect("expected a platform identity"); + + let identity_3_id = identity_3.id(); + + // Create a data contract with multiple tokens + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: BTreeMap::from([ + ( + 0, + Group::V0(GroupV0 { + members: [(identity_1_id, 1), (identity_2_id, 1)].into(), + required_power: 2, + }), + ), + ( + 1, + Group::V0(GroupV0 { + members: [(identity_1_id, 2), (identity_2_id, 1), (identity_3_id, 1)] + .into(), + required_power: 2, + }), + ), + ]), + tokens: BTreeMap::from([ + ( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ( + 1, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ]), + }); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Contract and group details + let contract_id = contract.id(); + let group_contract_position = 0; + + // Create actions + let action_id_1 = Identifier::new([1; 32]); + let action_id_2 = Identifier::new([2; 32]); + let action_id_3 = Identifier::new([3; 32]); + let action_id_4 = Identifier::new([4; 32]); + + let action_1 = GroupAction::V0(GroupActionV0 { + event: GroupActionEvent::TokenEvent(TokenEvent::Mint(200, identity_1_id, None)), + }); + + let action_2 = GroupAction::V0(GroupActionV0 { + event: GroupActionEvent::TokenEvent(TokenEvent::Burn(50, None)), + }); + + let action_3 = GroupAction::V0(GroupActionV0 { + event: GroupActionEvent::TokenEvent(TokenEvent::Transfer( + identity_2_id, + None, + None, + None, + 150, + )), + }); + + let action_4 = GroupAction::V0(GroupActionV0 { + event: GroupActionEvent::TokenEvent(TokenEvent::Transfer( + identity_3_id, + None, + None, + None, + 150, + )), + }); + + // Add actions using `add_group_action` + drive + .add_group_action( + contract_id, + group_contract_position, + Some(action_1.clone()), + action_id_1, + identity_1_id, + 1, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add action 1"); + + drive + .add_group_action( + contract_id, + group_contract_position, + Some(action_2.clone()), + action_id_2, + identity_1_id, + 1, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add action 2"); + + drive + .add_group_action( + contract_id, + group_contract_position, + Some(action_3.clone()), + action_id_3, + identity_2_id, + 1, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add action 3"); + + drive + .add_group_action( + contract_id, + group_contract_position, + Some(action_4.clone()), + action_id_4, + identity_3_id, + 1, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add action 3"); + + // Fetch actions starting from action_id_2 + let fetched_actions = drive + .fetch_active_action_infos( + contract_id, + group_contract_position, + Some((action_id_2, true)), + Some(2), + None, + platform_version, + ) + .expect("expected to fetch active actions"); + + assert_eq!( + fetched_actions, + BTreeMap::from([ + (action_id_2, action_2.clone()), + (action_id_3, action_3.clone()) + ]), + "unexpected fetched actions" + ); + + // Prove actions starting from action_id_2 + let proof = drive + .prove_active_action_infos_v0( + contract_id, + group_contract_position, + Some((action_id_2, true)), + Some(2), + None, + platform_version, + ) + .expect("should not error when proving active actions"); + + // Verify proof + let proved_actions: BTreeMap = + Drive::verify_active_action_infos_in_contract( + proof.as_slice(), + contract_id, + group_contract_position, + Some((action_id_2, true)), + Some(2), + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert proved actions match fetched actions + assert_eq!(proved_actions, fetched_actions, "unexpected proved actions"); + } +} diff --git a/packages/rs-drive/src/verify/group/mod.rs b/packages/rs-drive/src/verify/group/mod.rs index 23b83652ca4..7b3745c9b25 100644 --- a/packages/rs-drive/src/verify/group/mod.rs +++ b/packages/rs-drive/src/verify/group/mod.rs @@ -1,2 +1,3 @@ +mod verify_active_action_infos; mod verify_group_info; mod verify_group_infos_in_contract; diff --git a/packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs b/packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs new file mode 100644 index 00000000000..c81e4f4653f --- /dev/null +++ b/packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs @@ -0,0 +1,79 @@ +mod v0; + +use crate::drive::Drive; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action::GroupAction; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; + +use crate::error::drive::DriveError; + +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies the proof of active_action information within a contract. + /// + /// This method validates and extracts active_action information stored in a contract based on the provided proof. + /// It uses the proof to confirm the integrity and authenticity of the active_action data. The method supports + /// different versions for backward compatibility and forwards the verification logic to the appropriate versioned implementation. + /// + /// # Type Parameters + /// - `T`: The output container type that implements `FromIterator`. This is used to collect the verified active_action information + /// as pairs of [`GroupContractPosition`] and [`Group`]. + /// + /// # Arguments + /// - `proof`: A byte slice containing the cryptographic proof for the active_action information. + /// - `contract_id`: The identifier of the contract whose active_action information is being verified. + /// - `start_active_action_contract_position`: An optional starting position for the active_action query, combined with a [`StartAtIncluded`] flag + /// to indicate whether the start position is inclusive. + /// - `limit`: An optional limit on the number of active_actions to verify. + /// - `verify_subset_of_proof`: A boolean flag indicating whether to verify only a subset of the proof (useful for optimizations). + /// - `platform_version`: A reference to the platform version, used to determine the appropriate versioned implementation. + /// + /// # Returns + /// - `Ok((RootHash, T))`: On success, returns a tuple containing: + /// - `RootHash`: The root hash of the Merkle tree, confirming the proof's validity. + /// - `T`: A collection of verified active_action information as pairs of [`GroupContractPosition`] and [`Group`]. + /// - `Err(Error)`: If verification fails, returns an [`Error`] indicating the cause of failure. + /// + /// # Errors + /// - [`Error::Proof`]: If the proof is invalid, corrupted, or contains unexpected data structures. + /// - [`Error::Drive(DriveError::UnknownVersionMismatch)`]: If the method is called with an unsupported platform version. + /// - Any other errors propagated from the versioned implementation. + pub fn verify_active_action_infos_in_contract>( + proof: &[u8], + contract_id: Identifier, + group_contract_position: GroupContractPosition, + start_action_id: Option<(Identifier, StartAtIncluded)>, + limit: Option, + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + match platform_version + .drive + .methods + .verify + .group + .verify_active_action_infos + { + 0 => Self::verify_active_action_infos_in_contract_v0( + proof, + contract_id, + group_contract_position, + start_action_id, + limit, + verify_subset_of_proof, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_active_action_infos_in_contract".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/group/verify_active_action_infos/v0/mod.rs b/packages/rs-drive/src/verify/group/verify_active_action_infos/v0/mod.rs new file mode 100644 index 00000000000..7eb5927484d --- /dev/null +++ b/packages/rs-drive/src/verify/group/verify_active_action_infos/v0/mod.rs @@ -0,0 +1,73 @@ +use crate::drive::Drive; +use grovedb::Element::Item; + +use crate::error::proof::ProofError; +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action::GroupAction; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; +use dpp::serialization::PlatformDeserializable; +use grovedb::GroveDb; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_active_action_infos_in_contract_v0< + T: FromIterator<(Identifier, GroupAction)>, + >( + proof: &[u8], + contract_id: Identifier, + group_contract_position: GroupContractPosition, + start_action_id: Option<(Identifier, StartAtIncluded)>, + limit: Option, + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + let path_query = Drive::group_active_action_infos_query( + contract_id.to_buffer(), + group_contract_position, + start_action_id.map(|(s, i)| (s.to_buffer(), i)), + limit, + ); + + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query(proof, &path_query, &platform_version.drive.grove_version)? + } else { + GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)? + }; + let values = proved_key_values + .into_iter() + .filter_map(|(path, _, element)| { + let Some(last_path_component) = path.last() else { + return Some(Err(Error::Proof(ProofError::IncorrectProof( + "last path component is empty".to_string(), + )))); + }; + let action_id = match Identifier::from_bytes(last_path_component) { + Ok(action_id) => action_id, + Err(e) => return Some(Err(e.into())), + }; + + match element { + Some(Item(value, ..)) => { + let active_action = match GroupAction::deserialize_from_bytes(&value) { + Ok(active_action) => active_action, + + Err(e) => return Some(Err(e.into())), + }; + Some(Ok((action_id, active_action))) + } + None => None, + Some(element) => Some(Err(Error::Proof(ProofError::IncorrectProof(format!( + "active_action should be in an item, however a {} was returned", + element.type_str() + ))))), + } + }) + .collect::>()?; + Ok((root_hash, values)) + } +} diff --git a/packages/rs-drive/src/verify/tokens/verify_token_statuses/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_statuses/mod.rs index 7b7e9b82878..8cb213ff901 100644 --- a/packages/rs-drive/src/verify/tokens/verify_token_statuses/mod.rs +++ b/packages/rs-drive/src/verify/tokens/verify_token_statuses/mod.rs @@ -2,7 +2,6 @@ mod v0; use crate::drive::Drive; use crate::error::drive::DriveError; -use dpp::tokens::info::IdentityTokenInfo; use dpp::tokens::status::TokenStatus; use crate::error::Error; diff --git a/packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/mod.rs index 1c2b950104d..4515948dfd6 100644 --- a/packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/mod.rs +++ b/packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/mod.rs @@ -2,14 +2,9 @@ mod v0; use crate::drive::Drive; use crate::error::drive::DriveError; -use dpp::balances::credits::TokenAmount; -use dpp::balances::total_single_token_balance::TotalSingleTokenBalance; -use dpp::balances::total_tokens_balance::TotalTokensBalance; - use crate::error::Error; - use crate::verify::RootHash; - +use dpp::balances::total_single_token_balance::TotalSingleTokenBalance; use dpp::version::PlatformVersion; impl Drive { diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs index bb2e8559b74..beb24a9546c 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs @@ -37,6 +37,7 @@ pub struct DriveAbciQueryTokenVersions { pub struct DriveAbciQueryGroupVersions { pub group_info: FeatureVersionBounds, pub group_infos: FeatureVersionBounds, + pub active_group_actions: FeatureVersionBounds, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs index 2db3bde39c3..af50e0f4657 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs @@ -209,5 +209,10 @@ pub const DRIVE_ABCI_QUERY_VERSIONS_V1: DriveAbciQueryVersions = DriveAbciQueryV max_version: 0, default_current_version: 0, }, + active_group_actions: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, }, }; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs index 20ebc594662..f8749202f32 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs @@ -13,17 +13,19 @@ pub struct DriveGroupMethodVersions { #[derive(Clone, Debug, Default)] pub struct DriveGroupFetchMethodVersions { pub fetch_action_id_signers_power: FeatureVersion, - pub fetch_action_id_info: FeatureVersion, + pub fetch_active_action_info: FeatureVersion, pub fetch_action_id_info_keep_serialized: FeatureVersion, pub fetch_action_id_has_signer: FeatureVersion, pub fetch_group_info: FeatureVersion, pub fetch_group_infos: FeatureVersion, + pub fetch_active_action_infos: FeatureVersion, } #[derive(Clone, Debug, Default)] pub struct DriveGroupProveMethodVersions { pub prove_group_info: FeatureVersion, pub prove_group_infos: FeatureVersion, + pub prove_active_action_infos: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs index 365678957b7..7a3f007ef6a 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs @@ -6,15 +6,17 @@ use crate::version::drive_versions::drive_group_method_versions::{ pub const DRIVE_GROUP_METHOD_VERSIONS_V1: DriveGroupMethodVersions = DriveGroupMethodVersions { fetch: DriveGroupFetchMethodVersions { fetch_action_id_signers_power: 0, - fetch_action_id_info: 0, + fetch_active_action_info: 0, fetch_action_id_info_keep_serialized: 0, fetch_action_id_has_signer: 0, fetch_group_info: 0, fetch_group_infos: 0, + fetch_active_action_infos: 0, }, prove: DriveGroupProveMethodVersions { prove_group_info: 0, prove_group_infos: 0, + prove_active_action_infos: 0, }, insert: DriveGroupInsertMethodVersions { add_new_groups: 0, diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs index 087e593424f..fceaac77075 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs @@ -48,6 +48,7 @@ pub struct DriveVerifyIdentityMethodVersions { pub struct DriveVerifyGroupMethodVersions { pub verify_group_info: FeatureVersion, pub verify_group_infos_in_contract: FeatureVersion, + pub verify_active_action_infos: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs index e4a315835de..3e83c894dca 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs @@ -32,6 +32,7 @@ pub const DRIVE_VERIFY_METHOD_VERSIONS_V1: DriveVerifyMethodVersions = DriveVeri group: DriveVerifyGroupMethodVersions { verify_group_info: 0, verify_group_infos_in_contract: 0, + verify_active_action_infos: 0, }, token: DriveVerifyTokenMethodVersions { verify_token_balances_for_identity_ids: 0, diff --git a/packages/rs-platform-version/src/version/mocks/v2_test.rs b/packages/rs-platform-version/src/version/mocks/v2_test.rs index 9dc5f2d253c..c2dda44c16d 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -347,6 +347,11 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { max_version: 0, default_current_version: 0, }, + active_group_actions: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, }, }, }, From 11fb03b2b37b7c0bd12e2d944822f11477f919e7 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Mon, 20 Jan 2025 11:32:33 +0700 Subject: [PATCH 03/13] much more work on group actions --- .../protos/platform/v0/platform.proto | 27 ++++++----- .../token_configuration/v0/mod.rs | 6 +++ .../rs-dpp/src/group/group_action_status.rs | 29 +++++++++++ packages/rs-dpp/src/group/mod.rs | 2 + .../mod.rs | 25 +++++----- .../v0/mod.rs | 44 +++++++++++------ .../src/query/group_queries/mod.rs | 2 +- packages/rs-drive-abci/src/query/service.rs | 19 ++++---- .../for_add_group_action/v0/mod.rs | 6 +-- .../mod.rs | 21 ++++---- .../v0/mod.rs | 13 +++-- .../rs-drive/src/drive/group/fetch/mod.rs | 2 +- .../rs-drive/src/drive/group/fetch/queries.rs | 48 ++++++------------- .../group/insert/add_group_action/v0/mod.rs | 6 +-- packages/rs-drive/src/drive/group/paths.rs | 4 +- .../rs-drive/src/drive/group/prove/mod.rs | 2 +- .../mod.rs | 23 +++++---- .../v0/mod.rs | 43 +++++++++++------ .../v0/mod.rs | 4 +- .../group/verify_active_action_infos/mod.rs | 11 +++-- .../verify_active_action_infos/v0/mod.rs | 11 +++-- .../drive_abci_query_versions/mod.rs | 2 +- .../drive_abci_query_versions/v1.rs | 2 +- .../drive_group_method_versions/mod.rs | 4 +- .../drive_group_method_versions/v1.rs | 4 +- .../drive_verify_method_versions/mod.rs | 2 +- .../drive_verify_method_versions/v1.rs | 2 +- .../src/version/mocks/v2_test.rs | 2 +- 28 files changed, 217 insertions(+), 149 deletions(-) create mode 100644 packages/rs-dpp/src/group/group_action_status.rs rename packages/rs-drive-abci/src/query/group_queries/{active_group_actions => group_actions}/mod.rs (64%) rename packages/rs-drive-abci/src/query/group_queries/{active_group_actions => group_actions}/v0/mod.rs (88%) rename packages/rs-drive/src/drive/group/fetch/{fetch_active_action_infos => fetch_action_infos}/mod.rs (89%) rename packages/rs-drive/src/drive/group/fetch/{fetch_active_action_infos => fetch_action_infos}/v0/mod.rs (86%) rename packages/rs-drive/src/drive/group/prove/{prove_active_action_infos => prove_action_infos}/mod.rs (88%) rename packages/rs-drive/src/drive/group/prove/{prove_active_action_infos => prove_action_infos}/v0/mod.rs (92%) diff --git a/packages/dapi-grpc/protos/platform/v0/platform.proto b/packages/dapi-grpc/protos/platform/v0/platform.proto index 8a632d22911..6fbd175c63c 100644 --- a/packages/dapi-grpc/protos/platform/v0/platform.proto +++ b/packages/dapi-grpc/protos/platform/v0/platform.proto @@ -63,8 +63,7 @@ service Platform { rpc getTokenTotalSupply(GetTokenTotalSupplyRequest) returns (GetTokenTotalSupplyResponse); rpc getGroupInfo(GetGroupInfoRequest) returns (GetGroupInfoResponse); rpc getGroupInfos(GetGroupInfosRequest) returns (GetGroupInfosResponse); - rpc getActiveGroupActions(GetActiveGroupActionsRequest) returns (GetActiveGroupActionsResponse); -// rpc getClosedGroupActions(GetClosedGroupActionsRequest) returns (GetClosedGroupActionsResponse); + rpc getGroupActions(GetGroupActionsRequest) returns (GetGroupActionsResponse); } // Proof message includes cryptographic proofs for validating responses @@ -1512,26 +1511,32 @@ message GetGroupInfosResponse { } } -message GetActiveGroupActionsRequest { +message GetGroupActionsRequest { + enum ActionStatus { + ACTIVE = 0; // Request the active actions + CLOSED = 1; // Request the closed actions + } + message StartAtActionId { bytes start_action_id = 1; bool start_action_id_included = 2; } - message GetActiveGroupActionsRequestV0 { + message GetGroupActionsRequestV0 { bytes contract_id = 1; uint32 group_contract_position = 2; - optional StartAtActionId start_at_action_id = 3; - optional uint32 count = 4; - bool prove = 5; + ActionStatus status = 3; + optional StartAtActionId start_at_action_id = 4; + optional uint32 count = 5; + bool prove = 6; } oneof version { - GetActiveGroupActionsRequestV0 v0 = 1; + GetGroupActionsRequestV0 v0 = 1; } } -message GetActiveGroupActionsResponse { - message GetActiveGroupActionsResponseV0 { +message GetGroupActionsResponse { + message GetGroupActionsResponseV0 { // Mint event message MintEvent { uint64 amount = 1; // Amount to mint @@ -1657,6 +1662,6 @@ message GetActiveGroupActionsResponse { ResponseMetadata metadata = 3; } oneof version { - GetActiveGroupActionsResponseV0 v0 = 1; + GetGroupActionsResponseV0 v0 = 1; } } \ No newline at end of file diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs index 4aed4bdc11f..093b8ac8806 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs @@ -1,5 +1,6 @@ mod accessors; +use crate::balances::credits::TokenAmount; use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; use crate::data_contract::change_control_rules::v0::ChangeControlRulesV0; use crate::data_contract::change_control_rules::ChangeControlRules; @@ -217,4 +218,9 @@ impl TokenConfigurationV0 { main_control_group_can_be_modified: AuthorizedActionTakers::NoOne, } } + + pub fn with_base_supply(mut self, base_supply: TokenAmount) -> Self { + self.base_supply = base_supply; + self + } } diff --git a/packages/rs-dpp/src/group/group_action_status.rs b/packages/rs-dpp/src/group/group_action_status.rs new file mode 100644 index 00000000000..95a7e54dc11 --- /dev/null +++ b/packages/rs-dpp/src/group/group_action_status.rs @@ -0,0 +1,29 @@ +use anyhow::bail; + +#[derive(Debug, PartialEq, PartialOrd, Clone, Eq)] +pub enum GroupActionStatus { + ActionActive, + ActionClosed, +} + +impl TryFrom for GroupActionStatus { + type Error = anyhow::Error; + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::ActionActive), + 1 => Ok(Self::ActionClosed), + value => bail!("unrecognized action status: {}", value), + } + } +} + +impl TryFrom for GroupActionStatus { + type Error = anyhow::Error; + fn try_from(value: i32) -> Result { + match value { + 0 => Ok(Self::ActionActive), + 1 => Ok(Self::ActionClosed), + value => bail!("unrecognized action status: {}", value), + } + } +} diff --git a/packages/rs-dpp/src/group/mod.rs b/packages/rs-dpp/src/group/mod.rs index 1915d41c212..aba7606668e 100644 --- a/packages/rs-dpp/src/group/mod.rs +++ b/packages/rs-dpp/src/group/mod.rs @@ -8,6 +8,8 @@ use serde::{Deserialize, Serialize}; pub mod action_event; pub mod group_action; +pub mod group_action_status; + #[derive(Debug, Clone, Copy, Encode, Decode, PartialEq)] pub enum GroupStateTransitionInfoStatus { GroupStateTransitionInfoProposer(GroupContractPosition), diff --git a/packages/rs-drive-abci/src/query/group_queries/active_group_actions/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_actions/mod.rs similarity index 64% rename from packages/rs-drive-abci/src/query/group_queries/active_group_actions/mod.rs rename to packages/rs-drive-abci/src/query/group_queries/group_actions/mod.rs index b63b1c82c88..51425507b78 100644 --- a/packages/rs-drive-abci/src/query/group_queries/active_group_actions/mod.rs +++ b/packages/rs-drive-abci/src/query/group_queries/group_actions/mod.rs @@ -3,20 +3,20 @@ use crate::error::Error; use crate::platform_types::platform::Platform; use crate::platform_types::platform_state::PlatformState; use crate::query::QueryValidationResult; -use dapi_grpc::platform::v0::get_active_group_actions_request::Version as RequestVersion; -use dapi_grpc::platform::v0::get_active_group_actions_response::Version as ResponseVersion; -use dapi_grpc::platform::v0::{GetActiveGroupActionsRequest, GetActiveGroupActionsResponse}; +use dapi_grpc::platform::v0::get_group_actions_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_group_actions_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetGroupActionsRequest, GetGroupActionsResponse}; use dpp::version::PlatformVersion; mod v0; impl Platform { /// Querying of active group actions - pub fn query_active_group_actions( + pub fn query_group_actions( &self, - GetActiveGroupActionsRequest { version }: GetActiveGroupActionsRequest, + GetGroupActionsRequest { version }: GetGroupActionsRequest, platform_state: &PlatformState, platform_version: &PlatformVersion, - ) -> Result, Error> { + ) -> Result, Error> { let Some(version) = version else { return Ok(QueryValidationResult::new_with_error( QueryError::DecodingError( @@ -29,7 +29,7 @@ impl Platform { .drive_abci .query .group_queries - .active_group_actions; + .group_actions; let feature_version = match &version { RequestVersion::V0(_) => 0, @@ -37,7 +37,7 @@ impl Platform { if !feature_version_bounds.check_version(feature_version) { return Ok(QueryValidationResult::new_with_error( QueryError::UnsupportedQueryVersion( - "active_group_actions".to_string(), + "group_actions".to_string(), feature_version_bounds.min_version, feature_version_bounds.max_version, platform_version.protocol_version, @@ -48,12 +48,9 @@ impl Platform { match version { RequestVersion::V0(request_v0) => { - let result = self.query_active_group_actions_v0( - request_v0, - platform_state, - platform_version, - )?; - Ok(result.map(|response_v0| GetActiveGroupActionsResponse { + let result = + self.query_group_actions_v0(request_v0, platform_state, platform_version)?; + Ok(result.map(|response_v0| GetGroupActionsResponse { version: Some(ResponseVersion::V0(response_v0)), })) } diff --git a/packages/rs-drive-abci/src/query/group_queries/active_group_actions/v0/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_actions/v0/mod.rs similarity index 88% rename from packages/rs-drive-abci/src/query/group_queries/active_group_actions/v0/mod.rs rename to packages/rs-drive-abci/src/query/group_queries/group_actions/v0/mod.rs index 97124d51bb4..ef664f87f6d 100644 --- a/packages/rs-drive-abci/src/query/group_queries/active_group_actions/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/group_queries/group_actions/v0/mod.rs @@ -3,15 +3,21 @@ use crate::error::Error; use crate::platform_types::platform::Platform; use crate::platform_types::platform_state::PlatformState; use crate::query::QueryValidationResult; -use dapi_grpc::platform::v0::get_active_group_actions_request::GetActiveGroupActionsRequestV0; -use dapi_grpc::platform::v0::get_active_group_actions_response::{ - get_active_group_actions_response_v0, GetActiveGroupActionsResponseV0, +use dapi_grpc::platform::v0::get_group_actions_request::GetGroupActionsRequestV0; +use dapi_grpc::platform::v0::get_group_actions_response::get_group_actions_response_v0::{ + emergency_action_event, group_action_event, token_event, BurnEvent, DestroyFrozenFundsEvent, + EmergencyActionEvent, FreezeEvent, GroupActionEntry, GroupActionEvent, GroupActions, MintEvent, + PersonalEncryptedNote, SharedEncryptedNote, TokenEvent as TokenEventResponse, TransferEvent, + UnfreezeEvent, +}; +use dapi_grpc::platform::v0::get_group_actions_response::{ + get_group_actions_response_v0, GetGroupActionsResponseV0, }; -use dapi_grpc::platform::v0::get_active_group_actions_response::get_active_group_actions_response_v0::{BurnEvent, DestroyFrozenFundsEvent, emergency_action_event, EmergencyActionEvent, FreezeEvent, group_action_event, GroupActionEntry, GroupActionEvent, GroupActions, MintEvent, PersonalEncryptedNote, SharedEncryptedNote, token_event, TransferEvent, UnfreezeEvent, TokenEvent as TokenEventResponse}; use dpp::check_validation_result_with_data; use dpp::data_contract::GroupContractPosition; use dpp::group::action_event; use dpp::group::group_action::GroupAction; +use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; use dpp::tokens::emergency_action::TokenEmergencyAction; use dpp::tokens::token_event::TokenEvent; @@ -20,18 +26,19 @@ use dpp::version::PlatformVersion; use drive::error::query::QuerySyntaxError; impl Platform { - pub(super) fn query_active_group_actions_v0( + pub(super) fn query_group_actions_v0( &self, - GetActiveGroupActionsRequestV0 { + GetGroupActionsRequestV0 { contract_id, group_contract_position, + status, start_at_action_id, count, prove, - }: GetActiveGroupActionsRequestV0, + }: GetGroupActionsRequestV0, platform_state: &PlatformState, platform_version: &PlatformVersion, - ) -> Result, Error> { + ) -> Result, Error> { let config = &self.config.drive; let contract_id: Identifier = check_validation_result_with_data!(contract_id.try_into().map_err(|_| { @@ -84,18 +91,26 @@ impl Platform { } }; + let group_status: GroupActionStatus = + check_validation_result_with_data!(status.try_into().map_err(|_| { + QueryError::InvalidArgument( + "group action status must be Active or Closed".to_string(), + ) + })); + let response = if prove { - let proof = check_validation_result_with_data!(self.drive.prove_active_action_infos( + let proof = check_validation_result_with_data!(self.drive.prove_action_infos( contract_id, group_contract_position as GroupContractPosition, + group_status, maybe_start_at_action_id, Some(limit), None, platform_version, )); - GetActiveGroupActionsResponseV0 { - result: Some(get_active_group_actions_response_v0::Result::Proof( + GetGroupActionsResponseV0 { + result: Some(get_group_actions_response_v0::Result::Proof( self.response_proof_v0(platform_state, proof), )), metadata: Some(self.response_metadata_v0(platform_state)), @@ -103,9 +118,10 @@ impl Platform { } else { let group_actions = self .drive - .fetch_active_action_infos( + .fetch_action_infos( contract_id, group_contract_position as GroupContractPosition, + group_status, maybe_start_at_action_id, Some(limit), None, @@ -213,8 +229,8 @@ impl Platform { } }) .collect(); - GetActiveGroupActionsResponseV0 { - result: Some(get_active_group_actions_response_v0::Result::GroupActions( + GetGroupActionsResponseV0 { + result: Some(get_group_actions_response_v0::Result::GroupActions( GroupActions { group_actions }, )), metadata: Some(self.response_metadata_v0(platform_state)), diff --git a/packages/rs-drive-abci/src/query/group_queries/mod.rs b/packages/rs-drive-abci/src/query/group_queries/mod.rs index cb939e021bb..290a651e227 100644 --- a/packages/rs-drive-abci/src/query/group_queries/mod.rs +++ b/packages/rs-drive-abci/src/query/group_queries/mod.rs @@ -1,3 +1,3 @@ -mod active_group_actions; +mod group_actions; mod group_info; mod group_infos; diff --git a/packages/rs-drive-abci/src/query/service.rs b/packages/rs-drive-abci/src/query/service.rs index 510b661dee3..cac40054411 100644 --- a/packages/rs-drive-abci/src/query/service.rs +++ b/packages/rs-drive-abci/src/query/service.rs @@ -10,8 +10,7 @@ use crate::utils::spawn_blocking_task_with_name_if_supported; use async_trait::async_trait; use dapi_grpc::platform::v0::platform_server::Platform as PlatformService; use dapi_grpc::platform::v0::{ - BroadcastStateTransitionRequest, BroadcastStateTransitionResponse, - GetActiveGroupActionsRequest, GetActiveGroupActionsResponse, GetConsensusParamsRequest, + BroadcastStateTransitionRequest, BroadcastStateTransitionResponse, GetConsensusParamsRequest, GetConsensusParamsResponse, GetContestedResourceIdentityVotesRequest, GetContestedResourceIdentityVotesResponse, GetContestedResourceVoteStateRequest, GetContestedResourceVoteStateResponse, GetContestedResourceVotersForIdentityRequest, @@ -21,9 +20,9 @@ use dapi_grpc::platform::v0::{ GetDataContractResponse, GetDataContractsRequest, GetDataContractsResponse, GetDocumentsRequest, GetDocumentsResponse, GetEpochsInfoRequest, GetEpochsInfoResponse, GetEvonodesProposedEpochBlocksByIdsRequest, GetEvonodesProposedEpochBlocksByRangeRequest, - GetEvonodesProposedEpochBlocksResponse, GetGroupInfoRequest, GetGroupInfoResponse, - GetGroupInfosRequest, GetGroupInfosResponse, GetIdentitiesBalancesRequest, - GetIdentitiesBalancesResponse, GetIdentitiesContractKeysRequest, + GetEvonodesProposedEpochBlocksResponse, GetGroupActionsRequest, GetGroupActionsResponse, + GetGroupInfoRequest, GetGroupInfoResponse, GetGroupInfosRequest, GetGroupInfosResponse, + GetIdentitiesBalancesRequest, GetIdentitiesBalancesResponse, GetIdentitiesContractKeysRequest, GetIdentitiesContractKeysResponse, GetIdentitiesTokenBalancesRequest, GetIdentitiesTokenBalancesResponse, GetIdentitiesTokenInfosRequest, GetIdentitiesTokenInfosResponse, GetIdentityBalanceAndRevisionRequest, @@ -712,14 +711,14 @@ impl PlatformService for QueryService { .await } - async fn get_active_group_actions( + async fn get_group_actions( &self, - request: Request, - ) -> Result, Status> { + request: Request, + ) -> Result, Status> { self.handle_blocking_query( request, - Platform::::query_active_group_actions, - "get_active_group_actions", + Platform::::query_group_actions, + "get_group_actions", ) .await } diff --git a/packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/v0/mod.rs b/packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/v0/mod.rs index 5923c6a14df..6a9a63b68e3 100644 --- a/packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/v0/mod.rs +++ b/packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/v0/mod.rs @@ -1,8 +1,8 @@ use crate::drive::Drive; use crate::drive::group::paths::{ - group_action_path, group_action_root_path, group_action_signers_path, group_contract_path, - group_path, group_root_path, + group_action_path, group_action_signers_path, group_active_action_root_path, + group_contract_path, group_path, group_root_path, }; use crate::util::type_constants::DEFAULT_HASH_SIZE_U8; use dpp::data_contract::GroupContractPosition; @@ -127,7 +127,7 @@ impl Drive { ); estimated_costs_only_with_layer_info.insert( - KeyInfoPath::from_known_path(group_action_root_path( + KeyInfoPath::from_known_path(group_active_action_root_path( contract_id.as_slice(), &group_contract_position.to_be_bytes(), )), diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs similarity index 89% rename from packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/mod.rs rename to packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs index 5070435eb7b..0fe3f1f6360 100644 --- a/packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs @@ -4,6 +4,7 @@ use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; use dpp::data_contract::GroupContractPosition; use dpp::group::group_action::GroupAction; +use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; use dpp::prelude::StartAtIncluded; use grovedb::TransactionArg; @@ -32,10 +33,11 @@ impl Drive { /// /// # Errors /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. - pub fn fetch_active_action_infos( + pub fn fetch_action_infos( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, start_action_id: Option<(Identifier, StartAtIncluded)>, limit: Option, transaction: TransactionArg, @@ -46,18 +48,19 @@ impl Drive { .methods .group .fetch - .fetch_active_action_infos + .fetch_action_infos { - 0 => self.fetch_active_action_infos_v0( + 0 => self.fetch_action_infos_v0( contract_id, group_contract_position, + action_status, start_action_id, limit, transaction, platform_version, ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { - method: "fetch_active_action_infos".to_string(), + method: "fetch_action_infos".to_string(), known_versions: vec![0], received: version, })), @@ -85,10 +88,11 @@ impl Drive { /// /// # Errors /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. - pub(crate) fn fetch_active_action_infos_and_add_operations( + pub(crate) fn fetch_action_infos_and_add_operations( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, start_action_id: Option<(Identifier, StartAtIncluded)>, limit: Option, transaction: TransactionArg, @@ -100,11 +104,12 @@ impl Drive { .methods .group .fetch - .fetch_active_action_infos + .fetch_action_infos { - 0 => self.fetch_active_action_infos_and_add_operations_v0( + 0 => self.fetch_action_infos_and_add_operations_v0( contract_id, group_contract_position, + action_status, start_action_id, limit, transaction, @@ -112,7 +117,7 @@ impl Drive { platform_version, ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { - method: "fetch_active_action_infos_and_add_operations".to_string(), + method: "fetch_action_infos_and_add_operations".to_string(), known_versions: vec![0], received: version, })), diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/v0/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/v0/mod.rs similarity index 86% rename from packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/v0/mod.rs rename to packages/rs-drive/src/drive/group/fetch/fetch_action_infos/v0/mod.rs index d52a672070c..d8086476af9 100644 --- a/packages/rs-drive/src/drive/group/fetch/fetch_active_action_infos/v0/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/v0/mod.rs @@ -4,6 +4,7 @@ use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; use dpp::data_contract::GroupContractPosition; use dpp::group::group_action::GroupAction; +use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; use dpp::prelude::StartAtIncluded; use dpp::serialization::PlatformDeserializable; @@ -14,18 +15,20 @@ use grovedb::TransactionArg; use std::collections::BTreeMap; impl Drive { - pub(super) fn fetch_active_action_infos_v0( + pub(super) fn fetch_action_infos_v0( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, start_action_id: Option<(Identifier, StartAtIncluded)>, limit: Option, transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result, Error> { - self.fetch_active_action_infos_and_add_operations_v0( + self.fetch_action_infos_and_add_operations_v0( contract_id, group_contract_position, + action_status, start_action_id, limit, transaction, @@ -34,19 +37,21 @@ impl Drive { ) } - pub(super) fn fetch_active_action_infos_and_add_operations_v0( + pub(super) fn fetch_action_infos_and_add_operations_v0( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, start_action_id: Option<(Identifier, StartAtIncluded)>, limit: Option, transaction: TransactionArg, drive_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result, Error> { - let path_query = Drive::group_active_action_infos_query( + let path_query = Drive::group_action_infos_query( contract_id.to_buffer(), group_contract_position, + action_status, start_action_id.map(|(s, i)| (s.to_buffer(), i)), limit, ); diff --git a/packages/rs-drive/src/drive/group/fetch/mod.rs b/packages/rs-drive/src/drive/group/fetch/mod.rs index d7456d8a992..a451139c2b4 100644 --- a/packages/rs-drive/src/drive/group/fetch/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/mod.rs @@ -1,8 +1,8 @@ mod fetch_action_id_has_signer; mod fetch_action_id_info_keep_serialized; mod fetch_action_id_signers_power; +mod fetch_action_infos; mod fetch_active_action_info; -mod fetch_active_action_infos; mod fetch_group_info; mod fetch_group_infos; mod queries; diff --git a/packages/rs-drive/src/drive/group/fetch/queries.rs b/packages/rs-drive/src/drive/group/fetch/queries.rs index 5d6ea366b3c..ddcb407e099 100644 --- a/packages/rs-drive/src/drive/group/fetch/queries.rs +++ b/packages/rs-drive/src/drive/group/fetch/queries.rs @@ -1,10 +1,11 @@ use crate::drive::group::paths::{ - group_action_root_path_vec, group_closed_action_root_path_vec, group_contract_path_vec, - group_path_vec, ACTION_INFO_KEY, GROUP_INFO_KEY, + group_contract_path_vec, group_path_vec, ACTION_INFO_KEY, GROUP_ACTIVE_ACTIONS_KEY, + GROUP_CLOSED_ACTIONS_KEY, GROUP_INFO_KEY, }; use crate::drive::Drive; use crate::query::{Query, QueryItem}; use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action_status::GroupActionStatus; use grovedb::{PathQuery, SizedQuery}; use std::ops::RangeFull; @@ -50,45 +51,22 @@ impl Drive { } /// Gets the active group actions - pub fn group_active_action_infos_query( + pub fn group_action_infos_query( contract_id: [u8; 32], group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, start_at: Option<([u8; 32], bool)>, limit: Option, ) -> PathQuery { - let group_actions_path = group_action_root_path_vec(&contract_id, group_contract_position); - let mut query = Query::new_with_direction(true); - if let Some((start_at, start_at_included)) = start_at { - if start_at_included { - query.insert_item(QueryItem::RangeFrom(start_at.to_vec()..)) - } else { - query.insert_item(QueryItem::RangeAfter(start_at.to_vec()..)) + let mut group_actions_path = group_path_vec(&contract_id, group_contract_position); + match action_status { + GroupActionStatus::ActionActive => { + group_actions_path.push(GROUP_ACTIVE_ACTIONS_KEY.to_vec()) + } + GroupActionStatus::ActionClosed => { + group_actions_path.push(GROUP_CLOSED_ACTIONS_KEY.to_vec()) } - } else { - query.insert_item(QueryItem::RangeFull(RangeFull)) - } - - query.set_subquery_key(ACTION_INFO_KEY.to_vec()); - - PathQuery { - path: group_actions_path, - query: SizedQuery { - query, - limit, - offset: None, - }, } - } - - /// Gets the active group actions - pub fn group_closed_action_infos_query( - contract_id: [u8; 32], - group_contract_position: GroupContractPosition, - start_at: Option<([u8; 32], bool)>, - limit: Option, - ) -> PathQuery { - let group_actions_path = - group_closed_action_root_path_vec(&contract_id, group_contract_position); let mut query = Query::new_with_direction(true); if let Some((start_at, start_at_included)) = start_at { if start_at_included { @@ -100,6 +78,8 @@ impl Drive { query.insert_item(QueryItem::RangeFull(RangeFull)) } + query.set_subquery_key(ACTION_INFO_KEY.to_vec()); + PathQuery { path: group_actions_path, query: SizedQuery { diff --git a/packages/rs-drive/src/drive/group/insert/add_group_action/v0/mod.rs b/packages/rs-drive/src/drive/group/insert/add_group_action/v0/mod.rs index f45e9ec03c7..f7d1dea6d4e 100644 --- a/packages/rs-drive/src/drive/group/insert/add_group_action/v0/mod.rs +++ b/packages/rs-drive/src/drive/group/insert/add_group_action/v0/mod.rs @@ -1,6 +1,6 @@ use crate::drive::group::paths::{ - group_action_path, group_action_root_path, group_action_signers_path_vec, ACTION_INFO_KEY, - ACTION_SIGNERS_KEY, + group_action_path, group_action_signers_path_vec, group_active_action_root_path, + ACTION_INFO_KEY, ACTION_SIGNERS_KEY, }; use crate::drive::Drive; use crate::error::Error; @@ -133,7 +133,7 @@ impl Drive { } let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); - let group_action_root_path = group_action_root_path( + let group_action_root_path = group_active_action_root_path( contract_id.as_slice(), group_contract_position_bytes.as_slice(), ); diff --git a/packages/rs-drive/src/drive/group/paths.rs b/packages/rs-drive/src/drive/group/paths.rs index 07449e982fc..b4cbe648714 100644 --- a/packages/rs-drive/src/drive/group/paths.rs +++ b/packages/rs-drive/src/drive/group/paths.rs @@ -69,7 +69,7 @@ pub fn group_path_vec( /// Group action path -pub fn group_action_root_path<'a>( +pub fn group_active_action_root_path<'a>( contract_id: &'a [u8], group_contract_position_bytes: &'a [u8], ) -> [&'a [u8]; 4] { @@ -83,7 +83,7 @@ pub fn group_action_root_path<'a>( /// Group action path vector -pub fn group_action_root_path_vec( +pub fn group_active_action_root_path_vec( contract_id: &[u8], group_contract_position: GroupContractPosition, ) -> Vec> { diff --git a/packages/rs-drive/src/drive/group/prove/mod.rs b/packages/rs-drive/src/drive/group/prove/mod.rs index ff2a36d87b4..f19d21bc342 100644 --- a/packages/rs-drive/src/drive/group/prove/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/mod.rs @@ -1,3 +1,3 @@ -mod prove_active_action_infos; +mod prove_action_infos; mod prove_group_info; mod prove_group_infos; diff --git a/packages/rs-drive/src/drive/group/prove/prove_active_action_infos/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs similarity index 88% rename from packages/rs-drive/src/drive/group/prove/prove_active_action_infos/mod.rs rename to packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs index bf1ab468ea6..5e7d936a698 100644 --- a/packages/rs-drive/src/drive/group/prove/prove_active_action_infos/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs @@ -3,6 +3,7 @@ use crate::error::drive::DriveError; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; use dpp::prelude::StartAtIncluded; use grovedb::TransactionArg; @@ -33,10 +34,11 @@ impl Drive { /// # Errors /// - [`Error::Drive(DriveError::UnknownVersionMismatch)`]: If the method is called with an unsupported platform version. /// - Any other errors propagated from the versioned implementation. - pub fn prove_active_action_infos( + pub fn prove_action_infos( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, start_action_id: Option<(Identifier, StartAtIncluded)>, limit: Option, transaction: TransactionArg, @@ -47,18 +49,19 @@ impl Drive { .methods .group .prove - .prove_active_action_infos + .prove_action_infos { - 0 => self.prove_active_action_infos_v0( + 0 => self.prove_action_infos_v0( contract_id, group_contract_position, + action_status, start_action_id, limit, transaction, platform_version, ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { - method: "prove_active_action_infos".to_string(), + method: "prove_action_infos".to_string(), known_versions: vec![0], received: version, })), @@ -67,7 +70,7 @@ impl Drive { /// Generates a proof of active action information within a specific group of a contract and adds operations. /// - /// This method extends the functionality of `prove_active_action_infos` by additionally allowing + /// This method extends the functionality of `prove_action_infos` by additionally allowing /// operations to be added to a provided `drive_operations` list. It produces a cryptographic proof /// of active action information associated with a specific group in the given contract and supports /// different versions for backward compatibility. @@ -89,10 +92,11 @@ impl Drive { /// # Errors /// - [`Error::Drive(DriveError::UnknownVersionMismatch)`]: If the method is called with an unsupported platform version. /// - Any other errors propagated from the versioned implementation. - pub(crate) fn prove_active_action_infos_operations( + pub(crate) fn prove_action_infos_operations( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, start_action_id: Option<(Identifier, StartAtIncluded)>, limit: Option, transaction: TransactionArg, @@ -104,11 +108,12 @@ impl Drive { .methods .group .prove - .prove_active_action_infos + .prove_action_infos { - 0 => self.prove_active_action_infos_operations_v0( + 0 => self.prove_action_infos_operations_v0( contract_id, group_contract_position, + action_status, start_action_id, limit, transaction, @@ -116,7 +121,7 @@ impl Drive { platform_version, ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { - method: "prove_active_action_infos_and_add_operations".to_string(), + method: "prove_action_infos_and_add_operations".to_string(), known_versions: vec![0], received: version, })), diff --git a/packages/rs-drive/src/drive/group/prove/prove_active_action_infos/v0/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_action_infos/v0/mod.rs similarity index 92% rename from packages/rs-drive/src/drive/group/prove/prove_active_action_infos/v0/mod.rs rename to packages/rs-drive/src/drive/group/prove/prove_action_infos/v0/mod.rs index 7c13b859c34..1deadafda50 100644 --- a/packages/rs-drive/src/drive/group/prove/prove_active_action_infos/v0/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/prove_action_infos/v0/mod.rs @@ -2,24 +2,27 @@ use crate::drive::Drive; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; use dpp::prelude::StartAtIncluded; use dpp::version::PlatformVersion; use grovedb::TransactionArg; impl Drive { - pub(super) fn prove_active_action_infos_v0( + pub(super) fn prove_action_infos_v0( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, start_action_id: Option<(Identifier, StartAtIncluded)>, limit: Option, transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result, Error> { - self.prove_active_action_infos_operations_v0( + self.prove_action_infos_operations_v0( contract_id, group_contract_position, + action_status, start_action_id, limit, transaction, @@ -28,19 +31,21 @@ impl Drive { ) } - pub(super) fn prove_active_action_infos_operations_v0( + pub(super) fn prove_action_infos_operations_v0( &self, contract_id: Identifier, group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, start_action_id: Option<(Identifier, StartAtIncluded)>, limit: Option, transaction: TransactionArg, drive_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result, Error> { - let path_query = Drive::group_active_action_infos_query( + let path_query = Drive::group_action_infos_query( contract_id.to_buffer(), group_contract_position, + action_status, start_action_id.map(|(s, i)| (s.to_buffer(), i)), limit, ); @@ -77,7 +82,7 @@ mod tests { use std::collections::BTreeMap; #[test] - fn should_prove_active_action_infos_with_multiple_actions() { + fn should_prove_action_infos_with_multiple_actions() { let drive = setup_drive_with_initial_state_structure(None); let platform_version = PlatformVersion::latest(); @@ -203,9 +208,10 @@ mod tests { // Fetch actions directly let fetched_actions = drive - .fetch_active_action_infos( + .fetch_action_infos( contract_id, group_contract_position, + GroupActionStatus::ActionActive, None, Some(10), None, @@ -224,9 +230,10 @@ mod tests { // Prove actions let proof = drive - .prove_active_action_infos_v0( + .prove_action_infos_v0( contract_id, group_contract_position, + GroupActionStatus::ActionActive, None, Some(10), None, @@ -236,10 +243,11 @@ mod tests { // Verify proof let proved_actions: BTreeMap = - Drive::verify_active_action_infos_in_contract( + Drive::verify_action_infos_in_contract( proof.as_slice(), contract_id, group_contract_position, + GroupActionStatus::ActionActive, None, Some(10), false, @@ -253,7 +261,7 @@ mod tests { } #[test] - fn should_prove_no_active_action_infos_for_non_existent_contract() { + fn should_prove_no_action_infos_for_non_existent_contract() { let drive = setup_drive_with_initial_state_structure(None); let platform_version = PlatformVersion::latest(); @@ -263,9 +271,10 @@ mod tests { // Prove actions for non-existent contract let proof = drive - .prove_active_action_infos_v0( + .prove_action_infos_v0( non_existent_contract_id, group_contract_position, + GroupActionStatus::ActionActive, None, Some(10), None, @@ -275,10 +284,11 @@ mod tests { // Verify proof let proved_actions: BTreeMap = - Drive::verify_active_action_infos_in_contract( + Drive::verify_action_infos_in_contract( proof.as_slice(), non_existent_contract_id, group_contract_position, + GroupActionStatus::ActionActive, None, Some(10), false, @@ -296,7 +306,7 @@ mod tests { } #[test] - fn should_fetch_and_prove_active_action_infos_with_start_action_id() { + fn should_fetch_and_prove_action_infos_with_start_action_id() { let drive = setup_drive_with_initial_state_structure(None); let platform_version = PlatformVersion::latest(); @@ -472,9 +482,10 @@ mod tests { // Fetch actions starting from action_id_2 let fetched_actions = drive - .fetch_active_action_infos( + .fetch_action_infos( contract_id, group_contract_position, + GroupActionStatus::ActionActive, Some((action_id_2, true)), Some(2), None, @@ -493,9 +504,10 @@ mod tests { // Prove actions starting from action_id_2 let proof = drive - .prove_active_action_infos_v0( + .prove_action_infos_v0( contract_id, group_contract_position, + GroupActionStatus::ActionActive, Some((action_id_2, true)), Some(2), None, @@ -505,10 +517,11 @@ mod tests { // Verify proof let proved_actions: BTreeMap = - Drive::verify_active_action_infos_in_contract( + Drive::verify_action_infos_in_contract( proof.as_slice(), contract_id, group_contract_position, + GroupActionStatus::ActionActive, Some((action_id_2, true)), Some(2), false, diff --git a/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/v0/mod.rs b/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/v0/mod.rs index 7dde90d7ef3..64ee4a9dd36 100644 --- a/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/v0/mod.rs +++ b/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/v0/mod.rs @@ -197,7 +197,9 @@ mod tests { groups: Default::default(), tokens: BTreeMap::from([( 0, - TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + TokenConfiguration::V0( + TokenConfigurationV0::default_most_restrictive().with_base_supply(0), + ), )]), }); diff --git a/packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs b/packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs index c81e4f4653f..86de716f79f 100644 --- a/packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs +++ b/packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs @@ -3,6 +3,7 @@ mod v0; use crate::drive::Drive; use dpp::data_contract::GroupContractPosition; use dpp::group::group_action::GroupAction; +use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; use dpp::prelude::StartAtIncluded; @@ -44,10 +45,11 @@ impl Drive { /// - [`Error::Proof`]: If the proof is invalid, corrupted, or contains unexpected data structures. /// - [`Error::Drive(DriveError::UnknownVersionMismatch)`]: If the method is called with an unsupported platform version. /// - Any other errors propagated from the versioned implementation. - pub fn verify_active_action_infos_in_contract>( + pub fn verify_action_infos_in_contract>( proof: &[u8], contract_id: Identifier, group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, start_action_id: Option<(Identifier, StartAtIncluded)>, limit: Option, verify_subset_of_proof: bool, @@ -58,19 +60,20 @@ impl Drive { .methods .verify .group - .verify_active_action_infos + .verify_action_infos { - 0 => Self::verify_active_action_infos_in_contract_v0( + 0 => Self::verify_action_infos_in_contract_v0( proof, contract_id, group_contract_position, + action_status, start_action_id, limit, verify_subset_of_proof, platform_version, ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { - method: "verify_active_action_infos_in_contract".to_string(), + method: "verify_action_infos_in_contract".to_string(), known_versions: vec![0], received: version, })), diff --git a/packages/rs-drive/src/verify/group/verify_active_action_infos/v0/mod.rs b/packages/rs-drive/src/verify/group/verify_active_action_infos/v0/mod.rs index 7eb5927484d..972ddc10827 100644 --- a/packages/rs-drive/src/verify/group/verify_active_action_infos/v0/mod.rs +++ b/packages/rs-drive/src/verify/group/verify_active_action_infos/v0/mod.rs @@ -8,6 +8,7 @@ use crate::verify::RootHash; use dpp::data_contract::GroupContractPosition; use dpp::group::group_action::GroupAction; +use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; use dpp::prelude::StartAtIncluded; use dpp::serialization::PlatformDeserializable; @@ -15,20 +16,20 @@ use grovedb::GroveDb; use platform_version::version::PlatformVersion; impl Drive { - pub(super) fn verify_active_action_infos_in_contract_v0< - T: FromIterator<(Identifier, GroupAction)>, - >( + pub(super) fn verify_action_infos_in_contract_v0>( proof: &[u8], contract_id: Identifier, group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, start_action_id: Option<(Identifier, StartAtIncluded)>, limit: Option, verify_subset_of_proof: bool, platform_version: &PlatformVersion, ) -> Result<(RootHash, T), Error> { - let path_query = Drive::group_active_action_infos_query( + let path_query = Drive::group_action_infos_query( contract_id.to_buffer(), group_contract_position, + action_status, start_action_id.map(|(s, i)| (s.to_buffer(), i)), limit, ); @@ -62,7 +63,7 @@ impl Drive { } None => None, Some(element) => Some(Err(Error::Proof(ProofError::IncorrectProof(format!( - "active_action should be in an item, however a {} was returned", + "group action should be in an item, however a {} was returned", element.type_str() ))))), } diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs index beb24a9546c..fd7d5e8b422 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs @@ -37,7 +37,7 @@ pub struct DriveAbciQueryTokenVersions { pub struct DriveAbciQueryGroupVersions { pub group_info: FeatureVersionBounds, pub group_infos: FeatureVersionBounds, - pub active_group_actions: FeatureVersionBounds, + pub group_actions: FeatureVersionBounds, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs index af50e0f4657..1bc8964c392 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs @@ -209,7 +209,7 @@ pub const DRIVE_ABCI_QUERY_VERSIONS_V1: DriveAbciQueryVersions = DriveAbciQueryV max_version: 0, default_current_version: 0, }, - active_group_actions: FeatureVersionBounds { + group_actions: FeatureVersionBounds { min_version: 0, max_version: 0, default_current_version: 0, diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs index f8749202f32..3aa8b448123 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs @@ -18,14 +18,14 @@ pub struct DriveGroupFetchMethodVersions { pub fetch_action_id_has_signer: FeatureVersion, pub fetch_group_info: FeatureVersion, pub fetch_group_infos: FeatureVersion, - pub fetch_active_action_infos: FeatureVersion, + pub fetch_action_infos: FeatureVersion, } #[derive(Clone, Debug, Default)] pub struct DriveGroupProveMethodVersions { pub prove_group_info: FeatureVersion, pub prove_group_infos: FeatureVersion, - pub prove_active_action_infos: FeatureVersion, + pub prove_action_infos: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs index 7a3f007ef6a..9bff96b6c8d 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs @@ -11,12 +11,12 @@ pub const DRIVE_GROUP_METHOD_VERSIONS_V1: DriveGroupMethodVersions = DriveGroupM fetch_action_id_has_signer: 0, fetch_group_info: 0, fetch_group_infos: 0, - fetch_active_action_infos: 0, + fetch_action_infos: 0, }, prove: DriveGroupProveMethodVersions { prove_group_info: 0, prove_group_infos: 0, - prove_active_action_infos: 0, + prove_action_infos: 0, }, insert: DriveGroupInsertMethodVersions { add_new_groups: 0, diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs index fceaac77075..e7b9919c935 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs @@ -48,7 +48,7 @@ pub struct DriveVerifyIdentityMethodVersions { pub struct DriveVerifyGroupMethodVersions { pub verify_group_info: FeatureVersion, pub verify_group_infos_in_contract: FeatureVersion, - pub verify_active_action_infos: FeatureVersion, + pub verify_action_infos: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs index 3e83c894dca..4872470b08e 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs @@ -32,7 +32,7 @@ pub const DRIVE_VERIFY_METHOD_VERSIONS_V1: DriveVerifyMethodVersions = DriveVeri group: DriveVerifyGroupMethodVersions { verify_group_info: 0, verify_group_infos_in_contract: 0, - verify_active_action_infos: 0, + verify_action_infos: 0, }, token: DriveVerifyTokenMethodVersions { verify_token_balances_for_identity_ids: 0, diff --git a/packages/rs-platform-version/src/version/mocks/v2_test.rs b/packages/rs-platform-version/src/version/mocks/v2_test.rs index c2dda44c16d..a5482b60602 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -347,7 +347,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { max_version: 0, default_current_version: 0, }, - active_group_actions: FeatureVersionBounds { + group_actions: FeatureVersionBounds { min_version: 0, max_version: 0, default_current_version: 0, From decb2f717c2b07ac9b72c58c92068f950f12dea0 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Mon, 20 Jan 2025 22:50:05 +0700 Subject: [PATCH 04/13] more work on group queries --- .../protos/platform/v0/platform.proto | 42 ++ .../v0/mod.rs | 1 - .../group_queries/group_action_signers/mod.rs | 59 +++ .../group_action_signers/v0/mod.rs | 105 ++++ .../src/query/group_queries/mod.rs | 1 + packages/rs-drive-abci/src/query/service.rs | 42 +- .../group/fetch/fetch_action_signers/mod.rs | 121 +++++ .../fetch/fetch_action_signers/v0/mod.rs | 76 +++ .../rs-drive/src/drive/group/fetch/mod.rs | 2 + .../rs-drive/src/drive/group/fetch/queries.rs | 35 +- .../rs-drive/src/drive/group/prove/mod.rs | 1 + .../group/prove/prove_action_signers/mod.rs | 124 +++++ .../prove/prove_action_signers/v0/mod.rs | 483 ++++++++++++++++++ packages/rs-drive/src/verify/group/mod.rs | 1 + .../verify/group/verify_action_signers/mod.rs | 79 +++ .../group/verify_action_signers/v0/mod.rs | 63 +++ .../drive_abci_query_versions/mod.rs | 1 + .../drive_abci_query_versions/v1.rs | 5 + .../drive_group_method_versions/mod.rs | 2 + .../drive_group_method_versions/v1.rs | 2 + .../src/version/mocks/v2_test.rs | 5 + 21 files changed, 1213 insertions(+), 37 deletions(-) create mode 100644 packages/rs-drive-abci/src/query/group_queries/group_action_signers/mod.rs create mode 100644 packages/rs-drive-abci/src/query/group_queries/group_action_signers/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_action_signers/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_action_signers/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/prove/prove_action_signers/mod.rs create mode 100644 packages/rs-drive/src/drive/group/prove/prove_action_signers/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/group/verify_action_signers/mod.rs create mode 100644 packages/rs-drive/src/verify/group/verify_action_signers/v0/mod.rs diff --git a/packages/dapi-grpc/protos/platform/v0/platform.proto b/packages/dapi-grpc/protos/platform/v0/platform.proto index 6fbd175c63c..5a0d8842a61 100644 --- a/packages/dapi-grpc/protos/platform/v0/platform.proto +++ b/packages/dapi-grpc/protos/platform/v0/platform.proto @@ -64,6 +64,7 @@ service Platform { rpc getGroupInfo(GetGroupInfoRequest) returns (GetGroupInfoResponse); rpc getGroupInfos(GetGroupInfosRequest) returns (GetGroupInfosResponse); rpc getGroupActions(GetGroupActionsRequest) returns (GetGroupActionsResponse); + rpc getGroupActionSigners(GetGroupActionSignersRequest) returns (GetGroupActionSignersResponse); } // Proof message includes cryptographic proofs for validating responses @@ -1664,4 +1665,45 @@ message GetGroupActionsResponse { oneof version { GetGroupActionsResponseV0 v0 = 1; } +} + + +message GetGroupActionSignersRequest { + enum ActionStatus { + ACTIVE = 0; // Request the active actions + CLOSED = 1; // Request the closed actions + } + + message GetGroupActionSignersRequestV0 { + bytes contract_id = 1; + uint32 group_contract_position = 2; + ActionStatus status = 3; + bytes action_id = 4; + bool prove = 5; + } + oneof version { + GetGroupActionSignersRequestV0 v0 = 1; + } +} + +message GetGroupActionSignersResponse { + message GetGroupActionSignersResponseV0 { + message GroupActionSigner { + bytes signer_id = 1; + uint32 power = 2; + } + message GroupActionSigners { + repeated GroupActionSigner signers = 1; + } + + oneof result { + GroupActionSigners group_action_signers = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + + oneof version { + GetGroupActionSignersResponseV0 v0 = 1; + } } \ No newline at end of file diff --git a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs index 4f65b489782..43a4729a8f9 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs @@ -22,7 +22,6 @@ use drive::drive::identity::withdrawals::paths::{ WITHDRAWAL_TRANSACTIONS_SUM_AMOUNT_TREE_KEY, }; use drive::drive::prefunded_specialized_balances::{ - prefunded_specialized_balances_for_voting_path, prefunded_specialized_balances_for_voting_path_vec, }; use drive::drive::system::misc_path; diff --git a/packages/rs-drive-abci/src/query/group_queries/group_action_signers/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_action_signers/mod.rs new file mode 100644 index 00000000000..910d5f984b4 --- /dev/null +++ b/packages/rs-drive-abci/src/query/group_queries/group_action_signers/mod.rs @@ -0,0 +1,59 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_group_action_signers_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_group_action_signers_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetGroupActionSignersRequest, GetGroupActionSignersResponse}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of group action signers + pub fn query_group_action_signers( + &self, + GetGroupActionSignersRequest { version }: GetGroupActionSignersRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode active group action signers query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .group_queries + .group_action_signers; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "group_action_signers".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = + self.query_group_action_signers_v0(request_v0, platform_state, platform_version)?; + Ok(result.map(|response_v0| GetGroupActionSignersResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/group_queries/group_action_signers/v0/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_action_signers/v0/mod.rs new file mode 100644 index 00000000000..fad0db6d539 --- /dev/null +++ b/packages/rs-drive-abci/src/query/group_queries/group_action_signers/v0/mod.rs @@ -0,0 +1,105 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_group_action_signers_request::GetGroupActionSignersRequestV0; +use dapi_grpc::platform::v0::get_group_action_signers_response::{ + get_group_action_signers_response_v0, GetGroupActionSignersResponseV0, +}; +use dapi_grpc::platform::v0::get_group_action_signers_response::get_group_action_signers_response_v0::{GroupActionSigner, GroupActionSigners}; +use dpp::check_validation_result_with_data; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action_status::GroupActionStatus; +use dpp::identifier::Identifier; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; +use drive::error::query::QuerySyntaxError; + +impl Platform { + pub(super) fn query_group_action_signers_v0( + &self, + GetGroupActionSignersRequestV0 { + contract_id, + group_contract_position, + status, + action_id, + prove, + }: GetGroupActionSignersRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let config = &self.config.drive; + let contract_id: Identifier = + check_validation_result_with_data!(contract_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "contract id must be a valid identifier (32 bytes long)".to_string(), + ) + })); + + let action_id: Identifier = + check_validation_result_with_data!(action_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "action id must be a valid identifier (32 bytes long)".to_string(), + ) + })); + + if group_contract_position > u16::MAX as u32 { + return Ok(QueryValidationResult::new_with_error(QueryError::Query( + QuerySyntaxError::InvalidParameter(format!( + "group contract position {} can not be over u16::MAX", + group_contract_position + )), + ))); + } + + let group_status: GroupActionStatus = + check_validation_result_with_data!(status.try_into().map_err(|_| { + QueryError::InvalidArgument( + "group action status must be Active or Closed".to_string(), + ) + })); + + let response = if prove { + let proof = check_validation_result_with_data!(self.drive.prove_action_signers( + contract_id, + group_contract_position as GroupContractPosition, + group_status, + action_id, + None, + platform_version, + )); + + GetGroupActionSignersResponseV0 { + result: Some(get_group_action_signers_response_v0::Result::Proof( + self.response_proof_v0(platform_state, proof), + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + } else { + let group_action_signers = self + .drive + .fetch_action_signers( + contract_id, + group_contract_position as GroupContractPosition, + group_status, + action_id, + None, + platform_version, + )?.into_iter().map(|(signer_id, power)| { + GroupActionSigner { + signer_id: signer_id.to_vec(), + power, + } + }).collect(); + GetGroupActionSignersResponseV0 { + result: Some(get_group_action_signers_response_v0::Result::GroupActionSigners( + GroupActionSigners { signers: group_action_signers }, + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/group_queries/mod.rs b/packages/rs-drive-abci/src/query/group_queries/mod.rs index 290a651e227..9f8909462fd 100644 --- a/packages/rs-drive-abci/src/query/group_queries/mod.rs +++ b/packages/rs-drive-abci/src/query/group_queries/mod.rs @@ -1,3 +1,4 @@ mod group_actions; mod group_info; mod group_infos; +mod group_action_signers; diff --git a/packages/rs-drive-abci/src/query/service.rs b/packages/rs-drive-abci/src/query/service.rs index cac40054411..6b879393bd5 100644 --- a/packages/rs-drive-abci/src/query/service.rs +++ b/packages/rs-drive-abci/src/query/service.rs @@ -9,38 +9,7 @@ use crate::rpc::core::DefaultCoreRPC; use crate::utils::spawn_blocking_task_with_name_if_supported; use async_trait::async_trait; use dapi_grpc::platform::v0::platform_server::Platform as PlatformService; -use dapi_grpc::platform::v0::{ - BroadcastStateTransitionRequest, BroadcastStateTransitionResponse, GetConsensusParamsRequest, - GetConsensusParamsResponse, GetContestedResourceIdentityVotesRequest, - GetContestedResourceIdentityVotesResponse, GetContestedResourceVoteStateRequest, - GetContestedResourceVoteStateResponse, GetContestedResourceVotersForIdentityRequest, - GetContestedResourceVotersForIdentityResponse, GetContestedResourcesRequest, - GetContestedResourcesResponse, GetCurrentQuorumsInfoRequest, GetCurrentQuorumsInfoResponse, - GetDataContractHistoryRequest, GetDataContractHistoryResponse, GetDataContractRequest, - GetDataContractResponse, GetDataContractsRequest, GetDataContractsResponse, - GetDocumentsRequest, GetDocumentsResponse, GetEpochsInfoRequest, GetEpochsInfoResponse, - GetEvonodesProposedEpochBlocksByIdsRequest, GetEvonodesProposedEpochBlocksByRangeRequest, - GetEvonodesProposedEpochBlocksResponse, GetGroupActionsRequest, GetGroupActionsResponse, - GetGroupInfoRequest, GetGroupInfoResponse, GetGroupInfosRequest, GetGroupInfosResponse, - GetIdentitiesBalancesRequest, GetIdentitiesBalancesResponse, GetIdentitiesContractKeysRequest, - GetIdentitiesContractKeysResponse, GetIdentitiesTokenBalancesRequest, - GetIdentitiesTokenBalancesResponse, GetIdentitiesTokenInfosRequest, - GetIdentitiesTokenInfosResponse, GetIdentityBalanceAndRevisionRequest, - GetIdentityBalanceAndRevisionResponse, GetIdentityBalanceRequest, GetIdentityBalanceResponse, - GetIdentityByPublicKeyHashRequest, GetIdentityByPublicKeyHashResponse, - GetIdentityContractNonceRequest, GetIdentityContractNonceResponse, GetIdentityKeysRequest, - GetIdentityKeysResponse, GetIdentityNonceRequest, GetIdentityNonceResponse, GetIdentityRequest, - GetIdentityResponse, GetIdentityTokenBalancesRequest, GetIdentityTokenBalancesResponse, - GetIdentityTokenInfosRequest, GetIdentityTokenInfosResponse, GetPathElementsRequest, - GetPathElementsResponse, GetPrefundedSpecializedBalanceRequest, - GetPrefundedSpecializedBalanceResponse, GetProofsRequest, GetProofsResponse, - GetProtocolVersionUpgradeStateRequest, GetProtocolVersionUpgradeStateResponse, - GetProtocolVersionUpgradeVoteStatusRequest, GetProtocolVersionUpgradeVoteStatusResponse, - GetStatusRequest, GetStatusResponse, GetTokenStatusesRequest, GetTokenStatusesResponse, - GetTokenTotalSupplyRequest, GetTokenTotalSupplyResponse, GetTotalCreditsInPlatformRequest, - GetTotalCreditsInPlatformResponse, GetVotePollsByEndDateRequest, GetVotePollsByEndDateResponse, - WaitForStateTransitionResultRequest, WaitForStateTransitionResultResponse, -}; +use dapi_grpc::platform::v0::{BroadcastStateTransitionRequest, BroadcastStateTransitionResponse, GetConsensusParamsRequest, GetConsensusParamsResponse, GetContestedResourceIdentityVotesRequest, GetContestedResourceIdentityVotesResponse, GetContestedResourceVoteStateRequest, GetContestedResourceVoteStateResponse, GetContestedResourceVotersForIdentityRequest, GetContestedResourceVotersForIdentityResponse, GetContestedResourcesRequest, GetContestedResourcesResponse, GetCurrentQuorumsInfoRequest, GetCurrentQuorumsInfoResponse, GetDataContractHistoryRequest, GetDataContractHistoryResponse, GetDataContractRequest, GetDataContractResponse, GetDataContractsRequest, GetDataContractsResponse, GetDocumentsRequest, GetDocumentsResponse, GetEpochsInfoRequest, GetEpochsInfoResponse, GetEvonodesProposedEpochBlocksByIdsRequest, GetEvonodesProposedEpochBlocksByRangeRequest, GetEvonodesProposedEpochBlocksResponse, GetGroupActionsRequest, GetGroupActionsResponse, GetGroupInfoRequest, GetGroupInfoResponse, GetGroupInfosRequest, GetGroupInfosResponse, GetIdentitiesBalancesRequest, GetIdentitiesBalancesResponse, GetIdentitiesContractKeysRequest, GetIdentitiesContractKeysResponse, GetIdentitiesTokenBalancesRequest, GetIdentitiesTokenBalancesResponse, GetIdentitiesTokenInfosRequest, GetIdentitiesTokenInfosResponse, GetIdentityBalanceAndRevisionRequest, GetIdentityBalanceAndRevisionResponse, GetIdentityBalanceRequest, GetIdentityBalanceResponse, GetIdentityByPublicKeyHashRequest, GetIdentityByPublicKeyHashResponse, GetIdentityContractNonceRequest, GetIdentityContractNonceResponse, GetIdentityKeysRequest, GetIdentityKeysResponse, GetIdentityNonceRequest, GetIdentityNonceResponse, GetIdentityRequest, GetIdentityResponse, GetIdentityTokenBalancesRequest, GetIdentityTokenBalancesResponse, GetIdentityTokenInfosRequest, GetIdentityTokenInfosResponse, GetPathElementsRequest, GetPathElementsResponse, GetPrefundedSpecializedBalanceRequest, GetPrefundedSpecializedBalanceResponse, GetProofsRequest, GetProofsResponse, GetProtocolVersionUpgradeStateRequest, GetProtocolVersionUpgradeStateResponse, GetProtocolVersionUpgradeVoteStatusRequest, GetProtocolVersionUpgradeVoteStatusResponse, GetStatusRequest, GetStatusResponse, GetTokenStatusesRequest, GetTokenStatusesResponse, GetTokenTotalSupplyRequest, GetTokenTotalSupplyResponse, GetTotalCreditsInPlatformRequest, GetTotalCreditsInPlatformResponse, GetVotePollsByEndDateRequest, GetVotePollsByEndDateResponse, WaitForStateTransitionResultRequest, WaitForStateTransitionResultResponse, GetGroupActionSignersRequest, GetGroupActionSignersResponse}; use dapi_grpc::tonic::{Code, Request, Response, Status}; use dpp::version::PlatformVersion; use std::fmt::Debug; @@ -722,6 +691,15 @@ impl PlatformService for QueryService { ) .await } + + async fn get_group_action_signers(&self, request: Request) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_group_action_signers, + "get_group_action_signers", + ) + .await + } } fn query_error_into_status(error: QueryError) -> Status { diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/mod.rs new file mode 100644 index 00000000000..a5d38a9a86e --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/mod.rs @@ -0,0 +1,121 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action_status::GroupActionStatus; +use dpp::identifier::Identifier; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; +use std::collections::BTreeMap; +use dpp::data_contract::group::GroupMemberPower; + +mod v0; + +impl Drive { + /// Fetches the `GroupAction` for the given action ID and group contract position. + /// + /// This function queries the GroveDB to fetch the `GroupAction` associated with a specific + /// group contract position and action ID. The method selects the appropriate version of + /// `fetch_action_id_info` based on the `platform_version` provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `action_id`: The identifier of the action whose `GroupAction` is being fetched. + /// - `transaction`: The transaction argument used for the query. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(GroupAction)`: The `GroupAction` for the specified action ID and contract position. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub fn fetch_action_signers( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, + action_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .fetch + .fetch_action_signers + { + 0 => self.fetch_action_signers_v0( + contract_id, + group_contract_position, + action_status, + action_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_action_signers".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the `GroupAction` and adds corresponding operations to the drive for the given action ID and group contract position. + /// + /// This function is similar to `fetch_action_id_info` but also adds operations to the drive for state changes or queries. + /// Additionally, it supports cost estimation by interacting with the layer information if provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `action_id`: The identifier of the action whose `GroupAction` is being fetched. + /// - `estimated_costs_only_with_layer_info`: A mutable reference to an optional `HashMap` containing + /// layer information used for cost estimation. + /// - `transaction`: The transaction argument used for the query. + /// - `drive_operations`: A mutable reference to a vector that stores low-level drive operations. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(GroupAction)`: The `GroupAction` for the specified action ID and contract position, along with any added operations. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub(crate) fn fetch_action_signers_and_add_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, + action_id: Identifier, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .fetch + .fetch_action_signers + { + 0 => self.fetch_action_signers_and_add_operations_v0( + contract_id, + group_contract_position, + action_status, + action_id, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_action_signers_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/v0/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/v0/mod.rs new file mode 100644 index 00000000000..ab4f1ec9394 --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/v0/mod.rs @@ -0,0 +1,76 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action_status::GroupActionStatus; +use dpp::identifier::Identifier; +use dpp::version::PlatformVersion; +use grovedb::query_result_type::QueryResultType; +use grovedb::TransactionArg; +use std::collections::BTreeMap; +use grovedb::Element::SumItem; +use dpp::data_contract::group::GroupMemberPower; +use crate::error::drive::DriveError; + +impl Drive { + pub(super) fn fetch_action_signers_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, + action_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.fetch_action_signers_and_add_operations_v0( + contract_id, + group_contract_position, + action_status, + action_id, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn fetch_action_signers_and_add_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, + action_id: Identifier, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path_query = Drive::group_action_signers_query( + contract_id.to_buffer(), + group_contract_position, + action_status, + action_id.to_buffer(), + ); + + self.grove_get_raw_path_query( + &path_query, + transaction, + QueryResultType::QueryKeyElementPairResultType, + drive_operations, + &platform_version.drive, + )? + .0 + .to_key_elements_btree_map() + .into_iter() + .map(|(key, element)| { + + match element { + SumItem(value, ..) => { + Ok((key.try_into()?, value.try_into().map_err(|e| Error::Drive(DriveError::CorruptedDriveState("signed power should be encodable on a u32 integer".to_string())))?)) + }, + _ => Err(Error::Drive(DriveError::CorruptedDriveState( + "element should be a sum item representing member signed power".to_string(), + ))), + } + }) + .collect() + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/mod.rs b/packages/rs-drive/src/drive/group/fetch/mod.rs index a451139c2b4..310f8f35e0f 100644 --- a/packages/rs-drive/src/drive/group/fetch/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/mod.rs @@ -2,7 +2,9 @@ mod fetch_action_id_has_signer; mod fetch_action_id_info_keep_serialized; mod fetch_action_id_signers_power; mod fetch_action_infos; +mod fetch_action_signers; mod fetch_active_action_info; mod fetch_group_info; mod fetch_group_infos; mod queries; + diff --git a/packages/rs-drive/src/drive/group/fetch/queries.rs b/packages/rs-drive/src/drive/group/fetch/queries.rs index ddcb407e099..9f054431366 100644 --- a/packages/rs-drive/src/drive/group/fetch/queries.rs +++ b/packages/rs-drive/src/drive/group/fetch/queries.rs @@ -1,7 +1,4 @@ -use crate::drive::group::paths::{ - group_contract_path_vec, group_path_vec, ACTION_INFO_KEY, GROUP_ACTIVE_ACTIONS_KEY, - GROUP_CLOSED_ACTIONS_KEY, GROUP_INFO_KEY, -}; +use crate::drive::group::paths::{group_contract_path_vec, group_path_vec, ACTION_INFO_KEY, GROUP_ACTIVE_ACTIONS_KEY, GROUP_CLOSED_ACTIONS_KEY, GROUP_INFO_KEY, ACTION_SIGNERS_KEY}; use crate::drive::Drive; use crate::query::{Query, QueryItem}; use dpp::data_contract::GroupContractPosition; @@ -89,4 +86,34 @@ impl Drive { }, } } + + /// Gets the active group actions + pub fn group_action_signers_query( + contract_id: [u8; 32], + group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, + action_id: [u8; 32], + ) -> PathQuery { + let mut group_actions_path = group_path_vec(&contract_id, group_contract_position); + match action_status { + GroupActionStatus::ActionActive => { + group_actions_path.push(GROUP_ACTIVE_ACTIONS_KEY.to_vec()) + } + GroupActionStatus::ActionClosed => { + group_actions_path.push(GROUP_CLOSED_ACTIONS_KEY.to_vec()) + } + } + group_actions_path.push(action_id.to_vec()); + group_actions_path.push(ACTION_SIGNERS_KEY.to_vec()); + let query = Query::new_range_full(); + + PathQuery { + path: group_actions_path, + query: SizedQuery { + query, + limit: None, + offset: None, + }, + } + } } diff --git a/packages/rs-drive/src/drive/group/prove/mod.rs b/packages/rs-drive/src/drive/group/prove/mod.rs index f19d21bc342..afff4d391b2 100644 --- a/packages/rs-drive/src/drive/group/prove/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/mod.rs @@ -1,3 +1,4 @@ mod prove_action_infos; mod prove_group_info; mod prove_group_infos; +mod prove_action_signers; diff --git a/packages/rs-drive/src/drive/group/prove/prove_action_signers/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_action_signers/mod.rs new file mode 100644 index 00000000000..b0e2ca08121 --- /dev/null +++ b/packages/rs-drive/src/drive/group/prove/prove_action_signers/mod.rs @@ -0,0 +1,124 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action_status::GroupActionStatus; +use dpp::identifier::Identifier; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; + +mod v0; +impl Drive { + /// Generates a cryptographic proof of the signers for a specified action in a group within a contract. + /// + /// # Arguments + /// + /// * `contract_id` - The unique identifier of the contract containing the group. + /// * `group_contract_position` - The position of the group within the contract. + /// * `action_status` - The status of the action (e.g., active or closed). + /// * `action_id` - The unique identifier of the action for which to prove signers. + /// * `transaction` - The transaction context for this operation. + /// * `platform_version` - The platform version to use for determining method compatibility. + /// + /// # Returns + /// + /// Returns a `Result` containing: + /// * `Vec` - The serialized cryptographic proof of the signers. + /// * `Error` - An error if the operation fails or if the platform version is unsupported. + /// + /// # Errors + /// + /// Returns an `Error` if: + /// * The specified platform version is not supported. + /// * Internal database or transaction errors occur. + pub fn prove_action_signers( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, + action_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .prove + .prove_action_signers + { + 0 => self.prove_action_signers_v0( + contract_id, + group_contract_position, + action_status, + action_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_action_signers".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Generates a cryptographic proof of the signers for a specified action in a group within a contract + /// and appends the required operations for this proof to the provided list of drive operations. + /// + /// # Arguments + /// + /// * `contract_id` - The unique identifier of the contract containing the group. + /// * `group_contract_position` - The position of the group within the contract. + /// * `action_status` - The status of the action (e.g., active or closed). + /// * `action_id` - The unique identifier of the action for which to prove signers. + /// * `transaction` - The transaction context for this operation. + /// * `drive_operations` - A mutable reference to a list of low-level drive operations to which this operation will be appended. + /// * `platform_version` - The platform version to use for determining method compatibility. + /// + /// # Returns + /// + /// Returns a `Result` containing: + /// * `Vec` - The serialized cryptographic proof of the signers. + /// * `Error` - An error if the operation fails or if the platform version is unsupported. + /// + /// # Errors + /// + /// Returns an `Error` if: + /// * The specified platform version is not supported. + /// * Internal database or transaction errors occur. + pub(crate) fn prove_action_signers_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, + action_id: Identifier, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .prove + .prove_action_signers + { + 0 => self.prove_action_signers_operations_v0( + contract_id, + group_contract_position, + action_status, + action_id, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_action_signers_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/prove/prove_action_signers/v0/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_action_signers/v0/mod.rs new file mode 100644 index 00000000000..88c4dfae85b --- /dev/null +++ b/packages/rs-drive/src/drive/group/prove/prove_action_signers/v0/mod.rs @@ -0,0 +1,483 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action_status::GroupActionStatus; +use dpp::identifier::Identifier; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + pub(super) fn prove_action_signers_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, + action_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_action_signers_operations_v0( + contract_id, + group_contract_position, + action_status, + action_id, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_action_signers_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, + action_id: Identifier, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path_query = Drive::group_action_signers_query( + contract_id.to_buffer(), + group_contract_position, + action_status, + action_id.to_buffer(), + ); + self.grove_get_proved_path_query( + &path_query, + transaction, + drive_operations, + &platform_version.drive, + ) + } +} +#[cfg(test)] +mod tests { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::block::block_info::BlockInfo; + use dpp::data_contract::accessors::v0::DataContractV0Getters; + use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + use dpp::data_contract::config::v0::DataContractConfigV0; + use dpp::data_contract::config::DataContractConfig; + use dpp::data_contract::group::v0::GroupV0; + use dpp::data_contract::group::{Group, GroupMemberPower}; + use dpp::data_contract::v1::DataContractV1; + use dpp::data_contract::DataContract; + use dpp::group::action_event::GroupActionEvent; + use dpp::group::group_action::v0::GroupActionV0; + use dpp::group::group_action::GroupAction; + use dpp::identifier::Identifier; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + use dpp::tokens::token_event::TokenEvent; + use dpp::version::PlatformVersion; + use std::collections::BTreeMap; + + #[test] + fn should_prove_action_signers_with_multiple_actions() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity_1 = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_1_id = identity_1.id(); + + let identity_2 = Identity::random_identity(3, Some(506), platform_version) + .expect("expected a platform identity"); + + let identity_2_id = identity_2.id(); + + let identity_3 = Identity::random_identity(3, Some(9), platform_version) + .expect("expected a platform identity"); + + let identity_3_id = identity_3.id(); + + // Create a data contract with multiple tokens + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: BTreeMap::from([ + ( + 0, + Group::V0(GroupV0 { + members: [(identity_1_id, 1), (identity_2_id, 1)].into(), + required_power: 2, + }), + ), + ( + 1, + Group::V0(GroupV0 { + members: [(identity_1_id, 2), (identity_2_id, 1), (identity_3_id, 1)] + .into(), + required_power: 2, + }), + ), + ]), + tokens: BTreeMap::from([ + ( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ( + 1, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ]), + }); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Contract and group details + let contract_id = contract.id(); + let group_contract_position = 0; + + // Create actions + let action_id_1 = Identifier::random(); + let action_id_2 = Identifier::random(); + + let action_1 = GroupAction::V0(GroupActionV0 { + event: GroupActionEvent::TokenEvent(TokenEvent::Mint(100, identity_1_id, None)), + }); + + let action_2 = GroupAction::V0(GroupActionV0 { + event: GroupActionEvent::TokenEvent(TokenEvent::Burn(50, None)), + }); + + // Add actions using `add_group_action` + drive + .add_group_action( + contract_id, + group_contract_position, + Some(action_1.clone()), + action_id_1, + identity_1_id, + 1, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add action 1"); + + drive + .add_group_action( + contract_id, + group_contract_position, + Some(action_1.clone()), + action_id_1, + identity_2_id, + 1, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add action 1"); + + drive + .add_group_action( + contract_id, + group_contract_position, + Some(action_2.clone()), + action_id_2, + identity_2_id, + 1, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add action 2"); + + // Fetch actions directly + let fetched_actions = drive + .fetch_action_signers( + contract_id, + group_contract_position, + GroupActionStatus::ActionActive, + action_id_1, + None, + platform_version, + ) + .expect("expected to fetch active actions"); + + assert_eq!( + fetched_actions, + BTreeMap::from([ + (identity_1_id, 1), + (identity_2_id, 1) + ]), + "unexpected fetched powers" + ); + + // Prove actions + let proof = drive + .prove_action_signers_v0( + contract_id, + group_contract_position, + GroupActionStatus::ActionActive, + action_id_1, + None, + platform_version, + ) + .expect("should not error when proving active actions"); + + // Verify proof + let proved_actions: BTreeMap = + Drive::verify_action_signers( + proof.as_slice(), + contract_id, + group_contract_position, + GroupActionStatus::ActionActive, + action_id_1, + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert proved actions match fetched actions + assert_eq!(proved_actions, fetched_actions, "unexpected proved actions"); + } + + #[test] + fn should_prove_no_action_signers_for_non_existent_action() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity_1 = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_1_id = identity_1.id(); + + let identity_2 = Identity::random_identity(3, Some(506), platform_version) + .expect("expected a platform identity"); + + let identity_2_id = identity_2.id(); + + // Create a data contract with groups + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: BTreeMap::from([( + 0, + Group::V0(GroupV0 { + members: [(identity_1_id, 1), (identity_2_id, 1)].into(), + required_power: 2, + }), + )]), + tokens: BTreeMap::new(), + }); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Contract and group details + let contract_id = contract.id(); + let group_contract_position = 0; + let non_existent_action_id = Identifier::random(); + + // Prove action signers for a non-existent action + let proof = drive + .prove_action_signers_v0( + contract_id, + group_contract_position, + GroupActionStatus::ActionActive, + non_existent_action_id, + None, + platform_version, + ) + .expect("should not error when proving action signers for non-existent action"); + + // Verify proof + let proved_signers: BTreeMap = Drive::verify_action_signers( + proof.as_slice(), + contract_id, + group_contract_position, + GroupActionStatus::ActionActive, + non_existent_action_id, + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert no signers exist + assert!(proved_signers.is_empty(), "expected no signers"); + } + + #[test] + fn should_prove_action_signers_for_closed_action_if_still_active() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity_1 = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_1_id = identity_1.id(); + + let identity_2 = Identity::random_identity(3, Some(506), platform_version) + .expect("expected a platform identity"); + + let identity_2_id = identity_2.id(); + + // Create a data contract with groups + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: BTreeMap::from([( + 0, + Group::V0(GroupV0 { + members: [(identity_1_id, 1), (identity_2_id, 1)].into(), + required_power: 2, + }), + )]), + tokens: BTreeMap::new(), + }); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Contract and group details + let contract_id = contract.id(); + let group_contract_position = 0; + + // Create a closed action + let action_id = Identifier::random(); + let action = GroupAction::V0(GroupActionV0 { + event: GroupActionEvent::TokenEvent(TokenEvent::Burn(50, None)), + }); + + drive + .add_group_action( + contract_id, + group_contract_position, + Some(action.clone()), + action_id, + identity_2_id, + 1, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add action"); + + // Fetch closed action signers + let fetched_signers = drive + .fetch_action_signers( + contract_id, + group_contract_position, + GroupActionStatus::ActionClosed, + action_id, + None, + platform_version, + ) + .expect("expected to fetch closed action signers"); + + assert_eq!( + fetched_signers, + BTreeMap::new(), + "unexpected fetched powers" + ); + + // Prove closed action signers + let proof = drive + .prove_action_signers_v0( + contract_id, + group_contract_position, + GroupActionStatus::ActionClosed, + action_id, + None, + platform_version, + ) + .expect("should not error when proving closed action signers"); + + // Verify proof + let proved_signers: BTreeMap = Drive::verify_action_signers( + proof.as_slice(), + contract_id, + group_contract_position, + GroupActionStatus::ActionClosed, + action_id, + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert proved signers match fetched signers + assert_eq!(proved_signers, fetched_signers, "unexpected proved signers"); + } +} diff --git a/packages/rs-drive/src/verify/group/mod.rs b/packages/rs-drive/src/verify/group/mod.rs index 7b3745c9b25..a03b4197f14 100644 --- a/packages/rs-drive/src/verify/group/mod.rs +++ b/packages/rs-drive/src/verify/group/mod.rs @@ -1,3 +1,4 @@ mod verify_active_action_infos; mod verify_group_info; mod verify_group_infos_in_contract; +mod verify_action_signers; diff --git a/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs b/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs new file mode 100644 index 00000000000..01f2980a4d8 --- /dev/null +++ b/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs @@ -0,0 +1,79 @@ +mod v0; + +use dpp::data_contract::group::GroupMemberPower; +use crate::drive::Drive; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action_status::GroupActionStatus; +use dpp::identifier::Identifier; + +use crate::error::drive::DriveError; + +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies the proof of active_action information within a contract. + /// + /// This method validates and extracts active_action information stored in a contract based on the provided proof. + /// It uses the proof to confirm the integrity and authenticity of the active_action data. The method supports + /// different versions for backward compatibility and forwards the verification logic to the appropriate versioned implementation. + /// + /// # Type Parameters + /// - `T`: The output container type that implements `FromIterator`. This is used to collect the verified active_action information + /// as pairs of [`GroupContractPosition`] and [`Group`]. + /// + /// # Arguments + /// - `proof`: A byte slice containing the cryptographic proof for the active_action information. + /// - `contract_id`: The identifier of the contract whose active_action information is being verified. + /// - `start_active_action_contract_position`: An optional starting position for the active_action query, combined with a [`StartAtIncluded`] flag + /// to indicate whether the start position is inclusive. + /// - `limit`: An optional limit on the number of active_actions to verify. + /// - `verify_subset_of_proof`: A boolean flag indicating whether to verify only a subset of the proof (useful for optimizations). + /// - `platform_version`: A reference to the platform version, used to determine the appropriate versioned implementation. + /// + /// # Returns + /// - `Ok((RootHash, T))`: On success, returns a tuple containing: + /// - `RootHash`: The root hash of the Merkle tree, confirming the proof's validity. + /// - `T`: A collection of verified active_action information as pairs of [`GroupContractPosition`] and [`Group`]. + /// - `Err(Error)`: If verification fails, returns an [`Error`] indicating the cause of failure. + /// + /// # Errors + /// - [`Error::Proof`]: If the proof is invalid, corrupted, or contains unexpected data structures. + /// - [`Error::Drive(DriveError::UnknownVersionMismatch)`]: If the method is called with an unsupported platform version. + /// - Any other errors propagated from the versioned implementation. + pub fn verify_action_signers>( + proof: &[u8], + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, + action_id: Identifier, + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + match platform_version + .drive + .methods + .verify + .group + .verify_action_infos + { + 0 => Self::verify_action_signers_v0( + proof, + contract_id, + group_contract_position, + action_status, + action_id, + verify_subset_of_proof, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_action_signers".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/group/verify_action_signers/v0/mod.rs b/packages/rs-drive/src/verify/group/verify_action_signers/v0/mod.rs new file mode 100644 index 00000000000..eb51d1861b8 --- /dev/null +++ b/packages/rs-drive/src/verify/group/verify_action_signers/v0/mod.rs @@ -0,0 +1,63 @@ +use crate::drive::Drive; +use grovedb::Element::SumItem; + +use crate::error::proof::ProofError; +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action_status::GroupActionStatus; +use dpp::identifier::Identifier; +use grovedb::GroveDb; +use dpp::data_contract::group::GroupMemberPower; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_action_signers_v0>( + proof: &[u8], + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_status: GroupActionStatus, + action_id: Identifier, + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + let path_query = Drive::group_action_signers_query( + contract_id.to_buffer(), + group_contract_position, + action_status, + action_id.to_buffer(), + ); + + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query(proof, &path_query, &platform_version.drive.grove_version)? + } else { + GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)? + }; + let values = proved_key_values + .into_iter() + .filter_map(|(_, key, element)| { + let id : Identifier = match key.try_into() { + Ok(id) => id, + Err(_) => return Some(Err(Error::Proof(ProofError::IncorrectProof("identifier was not 32 bytes long".to_string())))), + }; + match element { + Some(SumItem(value, ..)) => { + let signing_power : GroupMemberPower = match value.try_into() { + Ok(signing_power) => signing_power, + Err(_) => return Some(Err(Error::Proof(ProofError::IncorrectProof("signed power should be encodable on a u32 integer".to_string())))), + }; + + Some(Ok((id, signing_power))) + }, + None => None, + _ => Some(Err(Error::Proof(ProofError::IncorrectProof( + "element should be a sum item representing member signed power".to_string(), + )).into())), + } + }) + .collect::>()?; + Ok((root_hash, values)) + } +} diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs index fd7d5e8b422..aea9f871338 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs @@ -38,6 +38,7 @@ pub struct DriveAbciQueryGroupVersions { pub group_info: FeatureVersionBounds, pub group_infos: FeatureVersionBounds, pub group_actions: FeatureVersionBounds, + pub group_action_signers: FeatureVersionBounds, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs index 1bc8964c392..ff92cdfcc61 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs @@ -214,5 +214,10 @@ pub const DRIVE_ABCI_QUERY_VERSIONS_V1: DriveAbciQueryVersions = DriveAbciQueryV max_version: 0, default_current_version: 0, }, + group_action_signers: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, }, }; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs index 3aa8b448123..5d4e390d7e3 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs @@ -19,6 +19,7 @@ pub struct DriveGroupFetchMethodVersions { pub fetch_group_info: FeatureVersion, pub fetch_group_infos: FeatureVersion, pub fetch_action_infos: FeatureVersion, + pub fetch_action_signers: FeatureVersion, } #[derive(Clone, Debug, Default)] @@ -26,6 +27,7 @@ pub struct DriveGroupProveMethodVersions { pub prove_group_info: FeatureVersion, pub prove_group_infos: FeatureVersion, pub prove_action_infos: FeatureVersion, + pub prove_action_signers: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs index 9bff96b6c8d..259a9029f6e 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs @@ -12,11 +12,13 @@ pub const DRIVE_GROUP_METHOD_VERSIONS_V1: DriveGroupMethodVersions = DriveGroupM fetch_group_info: 0, fetch_group_infos: 0, fetch_action_infos: 0, + fetch_action_signers: 0, }, prove: DriveGroupProveMethodVersions { prove_group_info: 0, prove_group_infos: 0, prove_action_infos: 0, + prove_action_signers: 0, }, insert: DriveGroupInsertMethodVersions { add_new_groups: 0, diff --git a/packages/rs-platform-version/src/version/mocks/v2_test.rs b/packages/rs-platform-version/src/version/mocks/v2_test.rs index a5482b60602..9a4de6099fd 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -352,6 +352,11 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { max_version: 0, default_current_version: 0, }, + group_action_signers: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, }, }, }, From 3876269037b2fcc73bdceed312ff0e62f76006c6 Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Mon, 20 Jan 2025 23:18:05 +0700 Subject: [PATCH 05/13] Update packages/rs-drive/src/verify/group/verify_action_signers/mod.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../src/verify/group/verify_action_signers/mod.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs b/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs index 01f2980a4d8..b797e940e00 100644 --- a/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs +++ b/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs @@ -15,15 +15,15 @@ use crate::verify::RootHash; use dpp::version::PlatformVersion; impl Drive { - /// Verifies the proof of active_action information within a contract. + /// Verifies the proof of action signer information within a contract. /// - /// This method validates and extracts active_action information stored in a contract based on the provided proof. - /// It uses the proof to confirm the integrity and authenticity of the active_action data. The method supports + /// This method validates and extracts action signer information stored in a contract based on the provided proof. + /// It uses the proof to confirm the integrity and authenticity of the action signer data. The method supports /// different versions for backward compatibility and forwards the verification logic to the appropriate versioned implementation. /// /// # Type Parameters - /// - `T`: The output container type that implements `FromIterator`. This is used to collect the verified active_action information - /// as pairs of [`GroupContractPosition`] and [`Group`]. + /// - `T`: The output container type that implements `FromIterator`. This is used to collect the verified action signer information + /// as pairs of [`Identifier`] and [`GroupMemberPower`]. /// /// # Arguments /// - `proof`: A byte slice containing the cryptographic proof for the active_action information. @@ -38,7 +38,6 @@ impl Drive { /// - `Ok((RootHash, T))`: On success, returns a tuple containing: /// - `RootHash`: The root hash of the Merkle tree, confirming the proof's validity. /// - `T`: A collection of verified active_action information as pairs of [`GroupContractPosition`] and [`Group`]. - /// - `Err(Error)`: If verification fails, returns an [`Error`] indicating the cause of failure. /// /// # Errors /// - [`Error::Proof`]: If the proof is invalid, corrupted, or contains unexpected data structures. From 4ebce13cce7f7522ae19911bfb0cda8d058d25be Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Mon, 20 Jan 2025 23:18:18 +0700 Subject: [PATCH 06/13] Update packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../src/drive/group/fetch/fetch_action_infos/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs index 0fe3f1f6360..f9957bde47e 100644 --- a/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs @@ -69,15 +69,15 @@ impl Drive { /// Fetches the `GroupAction` and adds corresponding operations to the drive for the given action ID and group contract position. /// - /// This function is similar to `fetch_action_id_info` but also adds operations to the drive for state changes or queries. - /// Additionally, it supports cost estimation by interacting with the layer information if provided. + /// This function is similar to `fetch_action_infos` but also adds operations to the drive for state changes or queries. + /// It fetches `GroupAction`s based on the specified `action_status`. Additionally, it supports cost estimation by interacting with the layer information if provided. /// /// # Parameters /// - `contract_id`: The identifier of the contract that the action belongs to. /// - `group_contract_position`: The position of the group contract in the data structure. - /// - `action_id`: The identifier of the action whose `GroupAction` is being fetched. - /// - `estimated_costs_only_with_layer_info`: A mutable reference to an optional `HashMap` containing - /// layer information used for cost estimation. + /// - `action_status`: The status of the group actions to fetch. + /// - `start_action_id`: An optional starting action ID and inclusion flag. + /// - `limit`: An optional limit on the number of group actions to fetch. /// - `transaction`: The transaction argument used for the query. /// - `drive_operations`: A mutable reference to a vector that stores low-level drive operations. /// - `platform_version`: The version of the platform that determines the correct method version. From b3aa1eed575ac99dfb7d0ea506f60d8f2703d39b Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Mon, 20 Jan 2025 23:20:16 +0700 Subject: [PATCH 07/13] Update packages/rs-drive/src/verify/group/verify_action_signers/mod.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- packages/rs-drive/src/verify/group/verify_action_signers/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs b/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs index b797e940e00..7b7a384ae34 100644 --- a/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs +++ b/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs @@ -57,7 +57,7 @@ impl Drive { .methods .verify .group - .verify_action_infos + .verify_action_signers { 0 => Self::verify_action_signers_v0( proof, From 6df5f96a41878595fc1883aeccabe82a270becbc Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Mon, 20 Jan 2025 23:20:28 +0700 Subject: [PATCH 08/13] Update packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../rs-drive/src/drive/group/prove/prove_action_infos/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs index 5e7d936a698..c1b22af8a71 100644 --- a/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs @@ -121,7 +121,7 @@ impl Drive { platform_version, ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { - method: "prove_action_infos_and_add_operations".to_string(), + method: "prove_action_infos_operations".to_string(), known_versions: vec![0], received: version, })), From b6263e55a5f4e92b94f43ab9280ca414b8d5be0b Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Mon, 20 Jan 2025 23:20:54 +0700 Subject: [PATCH 09/13] Update packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../verify/group/verify_active_action_infos/mod.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs b/packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs index 86de716f79f..d0d81ecd694 100644 --- a/packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs +++ b/packages/rs-drive/src/verify/group/verify_active_action_infos/mod.rs @@ -16,15 +16,15 @@ use crate::verify::RootHash; use dpp::version::PlatformVersion; impl Drive { - /// Verifies the proof of active_action information within a contract. + /// Verifies the proof of action information within a contract. /// - /// This method validates and extracts active_action information stored in a contract based on the provided proof. - /// It uses the proof to confirm the integrity and authenticity of the active_action data. The method supports + /// This method validates and extracts action information stored in a contract based on the provided proof. + /// It uses the proof to confirm the integrity and authenticity of the action data. The method supports /// different versions for backward compatibility and forwards the verification logic to the appropriate versioned implementation. /// /// # Type Parameters - /// - `T`: The output container type that implements `FromIterator`. This is used to collect the verified active_action information - /// as pairs of [`GroupContractPosition`] and [`Group`]. + /// - `T`: The output container type that implements `FromIterator`. This is used to collect the verified action information + /// as pairs of [`Identifier`] and [`GroupAction`]. /// /// # Arguments /// - `proof`: A byte slice containing the cryptographic proof for the active_action information. @@ -39,7 +39,6 @@ impl Drive { /// - `Ok((RootHash, T))`: On success, returns a tuple containing: /// - `RootHash`: The root hash of the Merkle tree, confirming the proof's validity. /// - `T`: A collection of verified active_action information as pairs of [`GroupContractPosition`] and [`Group`]. - /// - `Err(Error)`: If verification fails, returns an [`Error`] indicating the cause of failure. /// /// # Errors /// - [`Error::Proof`]: If the proof is invalid, corrupted, or contains unexpected data structures. From edc923864f08cf9d31159d88c89aeb914c18e987 Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Mon, 20 Jan 2025 23:24:10 +0700 Subject: [PATCH 10/13] Update packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../src/drive/group/fetch/fetch_action_infos/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs index f9957bde47e..6b02d74e94a 100644 --- a/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_infos/mod.rs @@ -16,14 +16,16 @@ mod v0; impl Drive { /// Fetches the `GroupAction` for the given action ID and group contract position. /// - /// This function queries the GroveDB to fetch the `GroupAction` associated with a specific - /// group contract position and action ID. The method selects the appropriate version of - /// `fetch_action_id_info` based on the `platform_version` provided. + /// This function queries the GroveDB to fetch `GroupAction`s associated with a specific + /// group contract position and `action_status`. The method selects the appropriate version of + /// `fetch_action_infos` based on the `platform_version` provided. /// /// # Parameters /// - `contract_id`: The identifier of the contract that the action belongs to. /// - `group_contract_position`: The position of the group contract in the data structure. - /// - `action_id`: The identifier of the action whose `GroupAction` is being fetched. + /// - `action_status`: The status of the group actions to fetch. + /// - `start_action_id`: An optional starting action ID and inclusion flag. + /// - `limit`: An optional limit on the number of group actions to fetch. /// - `transaction`: The transaction argument used for the query. /// - `platform_version`: The version of the platform that determines the correct method version. /// From 05ec2d9f17cc9e3acba098ffaecbb0ebfb212c70 Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Mon, 20 Jan 2025 23:24:30 +0700 Subject: [PATCH 11/13] Update packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../rs-drive/src/drive/group/prove/prove_action_infos/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs index c1b22af8a71..225170ce99a 100644 --- a/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs @@ -14,13 +14,14 @@ impl Drive { /// Generates a proof of active action information within a specific group of a contract. /// /// This method produces a cryptographic proof that validates and retrieves active action information - /// associated with a specific group in the given contract. The proof can be limited to a subset of actions + /// associated with a specific group in the given contract based on the `action_status`. The proof can be limited to a subset of actions /// based on the `start_action_id` and `limit` parameters. It supports multiple versions for backward /// compatibility and forwards the request to the appropriate versioned implementation. /// /// # Arguments /// - `contract_id`: The identifier of the contract containing the group. /// - `group_contract_position`: The position of the group within the contract whose actions are to be proven. + /// - `action_status`: The status of the group actions to prove. /// - `start_action_id`: An optional starting action ID, combined with a [`StartAtIncluded`] flag to specify whether /// the start position is inclusive. /// - `limit`: An optional limit on the number of actions to include in the proof. From 0755fcdf949b245a65d871b80dbb13c7a8e0f5b6 Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Mon, 20 Jan 2025 23:24:48 +0700 Subject: [PATCH 12/13] Update packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../rs-drive/src/drive/group/prove/prove_action_infos/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs index 225170ce99a..f5b6cec806a 100644 --- a/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/prove_action_infos/mod.rs @@ -73,12 +73,13 @@ impl Drive { /// /// This method extends the functionality of `prove_action_infos` by additionally allowing /// operations to be added to a provided `drive_operations` list. It produces a cryptographic proof - /// of active action information associated with a specific group in the given contract and supports + /// of active action information associated with a specific group in the given contract based on the `action_status`, and supports /// different versions for backward compatibility. /// /// # Arguments /// - `contract_id`: The identifier of the contract containing the group. /// - `group_contract_position`: The position of the group within the contract whose actions are to be proven. + /// - `action_status`: The status of the group actions to prove. /// - `start_action_id`: An optional starting action ID, combined with a [`StartAtIncluded`] flag to specify whether /// the start position is inclusive. /// - `limit`: An optional limit on the number of actions to include in the proof. From 6d98f64752a9703ff83eec4c61b8f2f6879cecd9 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Mon, 20 Jan 2025 23:26:08 +0700 Subject: [PATCH 13/13] small improvements --- .../token_configuration/accessors/v0/mod.rs | 9 +-- .../token_configuration/v0/accessors.rs | 9 +-- .../token_configuration/v0/mod.rs | 4 +- .../v0/mod.rs | 4 +- .../group_queries/group_action_signers/mod.rs | 7 +- .../group_action_signers/v0/mod.rs | 19 +++-- .../src/query/group_queries/mod.rs | 2 +- packages/rs-drive-abci/src/query/service.rs | 41 ++++++++++- .../group/fetch/fetch_action_signers/mod.rs | 70 +++++++++++-------- .../fetch/fetch_action_signers/v0/mod.rs | 28 ++++---- .../rs-drive/src/drive/group/fetch/mod.rs | 1 - .../rs-drive/src/drive/group/fetch/queries.rs | 7 +- .../rs-drive/src/drive/group/prove/mod.rs | 2 +- .../group/prove/prove_action_signers/mod.rs | 2 +- .../prove/prove_action_signers/v0/mod.rs | 36 +++++----- packages/rs-drive/src/verify/group/mod.rs | 2 +- .../verify/group/verify_action_signers/mod.rs | 2 +- .../group/verify_action_signers/v0/mod.rs | 23 ++++-- 18 files changed, 166 insertions(+), 102 deletions(-) diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs index 83fde97a8e3..cc1de8cb817 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs @@ -1,3 +1,4 @@ +use crate::balances::credits::TokenAmount; use crate::data_contract::associated_token::token_configuration::v0::TokenConfigurationConventionV0; use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; use crate::data_contract::change_control_rules::ChangeControlRules; @@ -13,13 +14,13 @@ pub trait TokenConfigurationV0Getters { fn conventions_mut(&mut self) -> &mut TokenConfigurationConventionV0; /// Returns the base supply. - fn base_supply(&self) -> u64; + fn base_supply(&self) -> TokenAmount; /// Returns the base supply. fn keeps_history(&self) -> bool; fn start_as_paused(&self) -> bool; /// Returns the maximum supply. - fn max_supply(&self) -> Option; + fn max_supply(&self) -> Option; /// Returns the max supply change rules. fn max_supply_change_rules(&self) -> &ChangeControlRules; @@ -63,10 +64,10 @@ pub trait TokenConfigurationV0Setters { fn set_conventions(&mut self, conventions: TokenConfigurationConventionV0); /// Sets the base supply. - fn set_base_supply(&mut self, base_supply: u64); + fn set_base_supply(&mut self, base_supply: TokenAmount); /// Sets the maximum supply. - fn set_max_supply(&mut self, max_supply: Option); + fn set_max_supply(&mut self, max_supply: Option); /// Sets the max supply change rules. fn set_max_supply_change_rules(&mut self, rules: ChangeControlRules); diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs index d0115ead551..60312bd445a 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs @@ -1,3 +1,4 @@ +use crate::balances::credits::TokenAmount; use crate::data_contract::associated_token::token_configuration::accessors::v0::{ TokenConfigurationV0Getters, TokenConfigurationV0Setters, }; @@ -22,7 +23,7 @@ impl TokenConfigurationV0Getters for TokenConfigurationV0 { } /// Returns the base supply. - fn base_supply(&self) -> u64 { + fn base_supply(&self) -> TokenAmount { self.base_supply } @@ -37,7 +38,7 @@ impl TokenConfigurationV0Getters for TokenConfigurationV0 { } /// Returns the maximum supply. - fn max_supply(&self) -> Option { + fn max_supply(&self) -> Option { self.max_supply } @@ -115,12 +116,12 @@ impl TokenConfigurationV0Setters for TokenConfigurationV0 { } /// Sets the base supply. - fn set_base_supply(&mut self, base_supply: u64) { + fn set_base_supply(&mut self, base_supply: TokenAmount) { self.base_supply = base_supply; } /// Sets the maximum supply. - fn set_max_supply(&mut self, max_supply: Option) { + fn set_max_supply(&mut self, max_supply: Option) { self.max_supply = max_supply; } diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs index 093b8ac8806..a192c4ab431 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs @@ -38,10 +38,10 @@ fn default_decimals() -> u16 { pub struct TokenConfigurationV0 { pub conventions: TokenConfigurationConventionV0, /// The supply at the creation of the token - pub base_supply: u64, + pub base_supply: TokenAmount, /// The maximum supply the token can ever have #[serde(default)] - pub max_supply: Option, + pub max_supply: Option, /// Do we keep history, default is true. #[serde(default = "default_keeps_history")] pub keeps_history: bool, diff --git a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs index 43a4729a8f9..a0537bbd1bd 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs @@ -21,9 +21,7 @@ use drive::drive::identity::withdrawals::paths::{ get_withdrawal_root_path, WITHDRAWAL_TRANSACTIONS_BROADCASTED_KEY, WITHDRAWAL_TRANSACTIONS_SUM_AMOUNT_TREE_KEY, }; -use drive::drive::prefunded_specialized_balances::{ - prefunded_specialized_balances_for_voting_path_vec, -}; +use drive::drive::prefunded_specialized_balances::prefunded_specialized_balances_for_voting_path_vec; use drive::drive::system::misc_path; use drive::drive::tokens::paths::{ tokens_root_path, TOKEN_BALANCES_KEY, TOKEN_IDENTITY_INFO_KEY, TOKEN_STATUS_INFO_KEY, diff --git a/packages/rs-drive-abci/src/query/group_queries/group_action_signers/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_action_signers/mod.rs index 910d5f984b4..00d22106981 100644 --- a/packages/rs-drive-abci/src/query/group_queries/group_action_signers/mod.rs +++ b/packages/rs-drive-abci/src/query/group_queries/group_action_signers/mod.rs @@ -48,8 +48,11 @@ impl Platform { match version { RequestVersion::V0(request_v0) => { - let result = - self.query_group_action_signers_v0(request_v0, platform_state, platform_version)?; + let result = self.query_group_action_signers_v0( + request_v0, + platform_state, + platform_version, + )?; Ok(result.map(|response_v0| GetGroupActionSignersResponse { version: Some(ResponseVersion::V0(response_v0)), })) diff --git a/packages/rs-drive-abci/src/query/group_queries/group_action_signers/v0/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_action_signers/v0/mod.rs index fad0db6d539..ed1ca8c424b 100644 --- a/packages/rs-drive-abci/src/query/group_queries/group_action_signers/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/group_queries/group_action_signers/v0/mod.rs @@ -86,16 +86,21 @@ impl Platform { action_id, None, platform_version, - )?.into_iter().map(|(signer_id, power)| { - GroupActionSigner { + )? + .into_iter() + .map(|(signer_id, power)| GroupActionSigner { signer_id: signer_id.to_vec(), power, - } - }).collect(); + }) + .collect(); GetGroupActionSignersResponseV0 { - result: Some(get_group_action_signers_response_v0::Result::GroupActionSigners( - GroupActionSigners { signers: group_action_signers }, - )), + result: Some( + get_group_action_signers_response_v0::Result::GroupActionSigners( + GroupActionSigners { + signers: group_action_signers, + }, + ), + ), metadata: Some(self.response_metadata_v0(platform_state)), } }; diff --git a/packages/rs-drive-abci/src/query/group_queries/mod.rs b/packages/rs-drive-abci/src/query/group_queries/mod.rs index 9f8909462fd..d720872115a 100644 --- a/packages/rs-drive-abci/src/query/group_queries/mod.rs +++ b/packages/rs-drive-abci/src/query/group_queries/mod.rs @@ -1,4 +1,4 @@ +mod group_action_signers; mod group_actions; mod group_info; mod group_infos; -mod group_action_signers; diff --git a/packages/rs-drive-abci/src/query/service.rs b/packages/rs-drive-abci/src/query/service.rs index 6b879393bd5..24f14039a58 100644 --- a/packages/rs-drive-abci/src/query/service.rs +++ b/packages/rs-drive-abci/src/query/service.rs @@ -9,7 +9,39 @@ use crate::rpc::core::DefaultCoreRPC; use crate::utils::spawn_blocking_task_with_name_if_supported; use async_trait::async_trait; use dapi_grpc::platform::v0::platform_server::Platform as PlatformService; -use dapi_grpc::platform::v0::{BroadcastStateTransitionRequest, BroadcastStateTransitionResponse, GetConsensusParamsRequest, GetConsensusParamsResponse, GetContestedResourceIdentityVotesRequest, GetContestedResourceIdentityVotesResponse, GetContestedResourceVoteStateRequest, GetContestedResourceVoteStateResponse, GetContestedResourceVotersForIdentityRequest, GetContestedResourceVotersForIdentityResponse, GetContestedResourcesRequest, GetContestedResourcesResponse, GetCurrentQuorumsInfoRequest, GetCurrentQuorumsInfoResponse, GetDataContractHistoryRequest, GetDataContractHistoryResponse, GetDataContractRequest, GetDataContractResponse, GetDataContractsRequest, GetDataContractsResponse, GetDocumentsRequest, GetDocumentsResponse, GetEpochsInfoRequest, GetEpochsInfoResponse, GetEvonodesProposedEpochBlocksByIdsRequest, GetEvonodesProposedEpochBlocksByRangeRequest, GetEvonodesProposedEpochBlocksResponse, GetGroupActionsRequest, GetGroupActionsResponse, GetGroupInfoRequest, GetGroupInfoResponse, GetGroupInfosRequest, GetGroupInfosResponse, GetIdentitiesBalancesRequest, GetIdentitiesBalancesResponse, GetIdentitiesContractKeysRequest, GetIdentitiesContractKeysResponse, GetIdentitiesTokenBalancesRequest, GetIdentitiesTokenBalancesResponse, GetIdentitiesTokenInfosRequest, GetIdentitiesTokenInfosResponse, GetIdentityBalanceAndRevisionRequest, GetIdentityBalanceAndRevisionResponse, GetIdentityBalanceRequest, GetIdentityBalanceResponse, GetIdentityByPublicKeyHashRequest, GetIdentityByPublicKeyHashResponse, GetIdentityContractNonceRequest, GetIdentityContractNonceResponse, GetIdentityKeysRequest, GetIdentityKeysResponse, GetIdentityNonceRequest, GetIdentityNonceResponse, GetIdentityRequest, GetIdentityResponse, GetIdentityTokenBalancesRequest, GetIdentityTokenBalancesResponse, GetIdentityTokenInfosRequest, GetIdentityTokenInfosResponse, GetPathElementsRequest, GetPathElementsResponse, GetPrefundedSpecializedBalanceRequest, GetPrefundedSpecializedBalanceResponse, GetProofsRequest, GetProofsResponse, GetProtocolVersionUpgradeStateRequest, GetProtocolVersionUpgradeStateResponse, GetProtocolVersionUpgradeVoteStatusRequest, GetProtocolVersionUpgradeVoteStatusResponse, GetStatusRequest, GetStatusResponse, GetTokenStatusesRequest, GetTokenStatusesResponse, GetTokenTotalSupplyRequest, GetTokenTotalSupplyResponse, GetTotalCreditsInPlatformRequest, GetTotalCreditsInPlatformResponse, GetVotePollsByEndDateRequest, GetVotePollsByEndDateResponse, WaitForStateTransitionResultRequest, WaitForStateTransitionResultResponse, GetGroupActionSignersRequest, GetGroupActionSignersResponse}; +use dapi_grpc::platform::v0::{ + BroadcastStateTransitionRequest, BroadcastStateTransitionResponse, GetConsensusParamsRequest, + GetConsensusParamsResponse, GetContestedResourceIdentityVotesRequest, + GetContestedResourceIdentityVotesResponse, GetContestedResourceVoteStateRequest, + GetContestedResourceVoteStateResponse, GetContestedResourceVotersForIdentityRequest, + GetContestedResourceVotersForIdentityResponse, GetContestedResourcesRequest, + GetContestedResourcesResponse, GetCurrentQuorumsInfoRequest, GetCurrentQuorumsInfoResponse, + GetDataContractHistoryRequest, GetDataContractHistoryResponse, GetDataContractRequest, + GetDataContractResponse, GetDataContractsRequest, GetDataContractsResponse, + GetDocumentsRequest, GetDocumentsResponse, GetEpochsInfoRequest, GetEpochsInfoResponse, + GetEvonodesProposedEpochBlocksByIdsRequest, GetEvonodesProposedEpochBlocksByRangeRequest, + GetEvonodesProposedEpochBlocksResponse, GetGroupActionSignersRequest, + GetGroupActionSignersResponse, GetGroupActionsRequest, GetGroupActionsResponse, + GetGroupInfoRequest, GetGroupInfoResponse, GetGroupInfosRequest, GetGroupInfosResponse, + GetIdentitiesBalancesRequest, GetIdentitiesBalancesResponse, GetIdentitiesContractKeysRequest, + GetIdentitiesContractKeysResponse, GetIdentitiesTokenBalancesRequest, + GetIdentitiesTokenBalancesResponse, GetIdentitiesTokenInfosRequest, + GetIdentitiesTokenInfosResponse, GetIdentityBalanceAndRevisionRequest, + GetIdentityBalanceAndRevisionResponse, GetIdentityBalanceRequest, GetIdentityBalanceResponse, + GetIdentityByPublicKeyHashRequest, GetIdentityByPublicKeyHashResponse, + GetIdentityContractNonceRequest, GetIdentityContractNonceResponse, GetIdentityKeysRequest, + GetIdentityKeysResponse, GetIdentityNonceRequest, GetIdentityNonceResponse, GetIdentityRequest, + GetIdentityResponse, GetIdentityTokenBalancesRequest, GetIdentityTokenBalancesResponse, + GetIdentityTokenInfosRequest, GetIdentityTokenInfosResponse, GetPathElementsRequest, + GetPathElementsResponse, GetPrefundedSpecializedBalanceRequest, + GetPrefundedSpecializedBalanceResponse, GetProofsRequest, GetProofsResponse, + GetProtocolVersionUpgradeStateRequest, GetProtocolVersionUpgradeStateResponse, + GetProtocolVersionUpgradeVoteStatusRequest, GetProtocolVersionUpgradeVoteStatusResponse, + GetStatusRequest, GetStatusResponse, GetTokenStatusesRequest, GetTokenStatusesResponse, + GetTokenTotalSupplyRequest, GetTokenTotalSupplyResponse, GetTotalCreditsInPlatformRequest, + GetTotalCreditsInPlatformResponse, GetVotePollsByEndDateRequest, GetVotePollsByEndDateResponse, + WaitForStateTransitionResultRequest, WaitForStateTransitionResultResponse, +}; use dapi_grpc::tonic::{Code, Request, Response, Status}; use dpp::version::PlatformVersion; use std::fmt::Debug; @@ -692,13 +724,16 @@ impl PlatformService for QueryService { .await } - async fn get_group_action_signers(&self, request: Request) -> Result, Status> { + async fn get_group_action_signers( + &self, + request: Request, + ) -> Result, Status> { self.handle_blocking_query( request, Platform::::query_group_action_signers, "get_group_action_signers", ) - .await + .await } } diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/mod.rs index a5d38a9a86e..0556350c6e3 100644 --- a/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/mod.rs @@ -2,36 +2,42 @@ use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::group::GroupMemberPower; use dpp::data_contract::GroupContractPosition; use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; use grovedb::TransactionArg; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; -use dpp::data_contract::group::GroupMemberPower; mod v0; impl Drive { - /// Fetches the `GroupAction` for the given action ID and group contract position. + /// Fetches the signers and their respective powers for a specific action in a group. /// - /// This function queries the GroveDB to fetch the `GroupAction` associated with a specific - /// group contract position and action ID. The method selects the appropriate version of - /// `fetch_action_id_info` based on the `platform_version` provided. + /// This method retrieves the list of signers for an action associated with a given contract, + /// group, and action status. It selects the appropriate version of the method based on the + /// provided platform version. /// - /// # Parameters - /// - `contract_id`: The identifier of the contract that the action belongs to. - /// - `group_contract_position`: The position of the group contract in the data structure. - /// - `action_id`: The identifier of the action whose `GroupAction` is being fetched. - /// - `transaction`: The transaction argument used for the query. - /// - `platform_version`: The version of the platform that determines the correct method version. + /// # Arguments + /// + /// * `contract_id` - The identifier of the contract associated with the action. + /// * `group_contract_position` - The position of the group within the contract. + /// * `action_status` - The status of the action (e.g., active or closed). + /// * `action_id` - The identifier of the action for which to fetch signers. + /// * `transaction` - An optional transaction argument for database operations. + /// * `platform_version` - The platform version to determine which method version to call. /// /// # Returns - /// - `Ok(GroupAction)`: The `GroupAction` for the specified action ID and contract position. - /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// A `Result` containing a `BTreeMap` where the keys are the signer identifiers and the values + /// are their respective powers, or an `Error` if the operation fails. /// /// # Errors - /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + /// + /// This method returns an `Error` if: + /// * The platform version is unknown. + /// * An internal issue occurs during the fetching process. pub fn fetch_action_signers( &self, contract_id: Identifier, @@ -64,27 +70,33 @@ impl Drive { } } - /// Fetches the `GroupAction` and adds corresponding operations to the drive for the given action ID and group contract position. + /// Fetches the signers and their respective powers for a specific action and adds the + /// associated operations for database queries. + /// + /// This method extends the functionality of `fetch_action_signers` by including additional + /// database operations that can be executed as part of a larger transaction. The appropriate + /// version of the method is selected based on the provided platform version. /// - /// This function is similar to `fetch_action_id_info` but also adds operations to the drive for state changes or queries. - /// Additionally, it supports cost estimation by interacting with the layer information if provided. + /// # Arguments /// - /// # Parameters - /// - `contract_id`: The identifier of the contract that the action belongs to. - /// - `group_contract_position`: The position of the group contract in the data structure. - /// - `action_id`: The identifier of the action whose `GroupAction` is being fetched. - /// - `estimated_costs_only_with_layer_info`: A mutable reference to an optional `HashMap` containing - /// layer information used for cost estimation. - /// - `transaction`: The transaction argument used for the query. - /// - `drive_operations`: A mutable reference to a vector that stores low-level drive operations. - /// - `platform_version`: The version of the platform that determines the correct method version. + /// * `contract_id` - The identifier of the contract associated with the action. + /// * `group_contract_position` - The position of the group within the contract. + /// * `action_status` - The status of the action (e.g., active or closed). + /// * `action_id` - The identifier of the action for which to fetch signers. + /// * `transaction` - An optional transaction argument for database operations. + /// * `drive_operations` - A mutable vector to which low-level database operations will be added. + /// * `platform_version` - The platform version to determine which method version to call. /// /// # Returns - /// - `Ok(GroupAction)`: The `GroupAction` for the specified action ID and contract position, along with any added operations. - /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// A `Result` containing a `BTreeMap` where the keys are the signer identifiers and the values + /// are their respective powers, or an `Error` if the operation fails. /// /// # Errors - /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + /// + /// This method returns an `Error` if: + /// * The platform version is unknown. + /// * An internal issue occurs during the fetching process. pub(crate) fn fetch_action_signers_and_add_operations( &self, contract_id: Identifier, diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/v0/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/v0/mod.rs index ab4f1ec9394..c0a64a9b632 100644 --- a/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/v0/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_signers/v0/mod.rs @@ -1,16 +1,16 @@ use crate::drive::Drive; +use crate::error::drive::DriveError; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::group::GroupMemberPower; use dpp::data_contract::GroupContractPosition; use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; use dpp::version::PlatformVersion; use grovedb::query_result_type::QueryResultType; +use grovedb::Element::SumItem; use grovedb::TransactionArg; use std::collections::BTreeMap; -use grovedb::Element::SumItem; -use dpp::data_contract::group::GroupMemberPower; -use crate::error::drive::DriveError; impl Drive { pub(super) fn fetch_action_signers_v0( @@ -60,16 +60,18 @@ impl Drive { .0 .to_key_elements_btree_map() .into_iter() - .map(|(key, element)| { - - match element { - SumItem(value, ..) => { - Ok((key.try_into()?, value.try_into().map_err(|e| Error::Drive(DriveError::CorruptedDriveState("signed power should be encodable on a u32 integer".to_string())))?)) - }, - _ => Err(Error::Drive(DriveError::CorruptedDriveState( - "element should be a sum item representing member signed power".to_string(), - ))), - } + .map(|(key, element)| match element { + SumItem(value, ..) => Ok(( + key.try_into()?, + value.try_into().map_err(|e| { + Error::Drive(DriveError::CorruptedDriveState( + "signed power should be encodable on a u32 integer".to_string(), + )) + })?, + )), + _ => Err(Error::Drive(DriveError::CorruptedDriveState( + "element should be a sum item representing member signed power".to_string(), + ))), }) .collect() } diff --git a/packages/rs-drive/src/drive/group/fetch/mod.rs b/packages/rs-drive/src/drive/group/fetch/mod.rs index 310f8f35e0f..32186f8a6e2 100644 --- a/packages/rs-drive/src/drive/group/fetch/mod.rs +++ b/packages/rs-drive/src/drive/group/fetch/mod.rs @@ -7,4 +7,3 @@ mod fetch_active_action_info; mod fetch_group_info; mod fetch_group_infos; mod queries; - diff --git a/packages/rs-drive/src/drive/group/fetch/queries.rs b/packages/rs-drive/src/drive/group/fetch/queries.rs index 9f054431366..e78e6cca882 100644 --- a/packages/rs-drive/src/drive/group/fetch/queries.rs +++ b/packages/rs-drive/src/drive/group/fetch/queries.rs @@ -1,4 +1,7 @@ -use crate::drive::group::paths::{group_contract_path_vec, group_path_vec, ACTION_INFO_KEY, GROUP_ACTIVE_ACTIONS_KEY, GROUP_CLOSED_ACTIONS_KEY, GROUP_INFO_KEY, ACTION_SIGNERS_KEY}; +use crate::drive::group::paths::{ + group_contract_path_vec, group_path_vec, ACTION_INFO_KEY, ACTION_SIGNERS_KEY, + GROUP_ACTIVE_ACTIONS_KEY, GROUP_CLOSED_ACTIONS_KEY, GROUP_INFO_KEY, +}; use crate::drive::Drive; use crate::query::{Query, QueryItem}; use dpp::data_contract::GroupContractPosition; @@ -87,7 +90,7 @@ impl Drive { } } - /// Gets the active group actions + /// Gets the action signers query pub fn group_action_signers_query( contract_id: [u8; 32], group_contract_position: GroupContractPosition, diff --git a/packages/rs-drive/src/drive/group/prove/mod.rs b/packages/rs-drive/src/drive/group/prove/mod.rs index afff4d391b2..dc5360bb8c2 100644 --- a/packages/rs-drive/src/drive/group/prove/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/mod.rs @@ -1,4 +1,4 @@ mod prove_action_infos; +mod prove_action_signers; mod prove_group_info; mod prove_group_infos; -mod prove_action_signers; diff --git a/packages/rs-drive/src/drive/group/prove/prove_action_signers/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_action_signers/mod.rs index b0e2ca08121..cd6ee8d520e 100644 --- a/packages/rs-drive/src/drive/group/prove/prove_action_signers/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/prove_action_signers/mod.rs @@ -115,7 +115,7 @@ impl Drive { platform_version, ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { - method: "prove_action_signers_and_add_operations".to_string(), + method: "prove_action_signers_operations".to_string(), known_versions: vec![0], received: version, })), diff --git a/packages/rs-drive/src/drive/group/prove/prove_action_signers/v0/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_action_signers/v0/mod.rs index 88c4dfae85b..509b3749319 100644 --- a/packages/rs-drive/src/drive/group/prove/prove_action_signers/v0/mod.rs +++ b/packages/rs-drive/src/drive/group/prove/prove_action_signers/v0/mod.rs @@ -230,10 +230,7 @@ mod tests { assert_eq!( fetched_actions, - BTreeMap::from([ - (identity_1_id, 1), - (identity_2_id, 1) - ]), + BTreeMap::from([(identity_1_id, 1), (identity_2_id, 1)]), "unexpected fetched powers" ); @@ -250,18 +247,17 @@ mod tests { .expect("should not error when proving active actions"); // Verify proof - let proved_actions: BTreeMap = - Drive::verify_action_signers( - proof.as_slice(), - contract_id, - group_contract_position, - GroupActionStatus::ActionActive, - action_id_1, - false, - platform_version, - ) - .expect("expected proof verification to succeed") - .1; + let proved_actions: BTreeMap = Drive::verify_action_signers( + proof.as_slice(), + contract_id, + group_contract_position, + GroupActionStatus::ActionActive, + action_id_1, + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; // Assert proved actions match fetched actions assert_eq!(proved_actions, fetched_actions, "unexpected proved actions"); @@ -348,8 +344,8 @@ mod tests { false, platform_version, ) - .expect("expected proof verification to succeed") - .1; + .expect("expected proof verification to succeed") + .1; // Assert no signers exist assert!(proved_signers.is_empty(), "expected no signers"); @@ -474,8 +470,8 @@ mod tests { false, platform_version, ) - .expect("expected proof verification to succeed") - .1; + .expect("expected proof verification to succeed") + .1; // Assert proved signers match fetched signers assert_eq!(proved_signers, fetched_signers, "unexpected proved signers"); diff --git a/packages/rs-drive/src/verify/group/mod.rs b/packages/rs-drive/src/verify/group/mod.rs index a03b4197f14..d77cec3ea0f 100644 --- a/packages/rs-drive/src/verify/group/mod.rs +++ b/packages/rs-drive/src/verify/group/mod.rs @@ -1,4 +1,4 @@ +mod verify_action_signers; mod verify_active_action_infos; mod verify_group_info; mod verify_group_infos_in_contract; -mod verify_action_signers; diff --git a/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs b/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs index 01f2980a4d8..45a94e67079 100644 --- a/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs +++ b/packages/rs-drive/src/verify/group/verify_action_signers/mod.rs @@ -1,7 +1,7 @@ mod v0; -use dpp::data_contract::group::GroupMemberPower; use crate::drive::Drive; +use dpp::data_contract::group::GroupMemberPower; use dpp::data_contract::GroupContractPosition; use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; diff --git a/packages/rs-drive/src/verify/group/verify_action_signers/v0/mod.rs b/packages/rs-drive/src/verify/group/verify_action_signers/v0/mod.rs index eb51d1861b8..2cffb68635f 100644 --- a/packages/rs-drive/src/verify/group/verify_action_signers/v0/mod.rs +++ b/packages/rs-drive/src/verify/group/verify_action_signers/v0/mod.rs @@ -6,11 +6,11 @@ use crate::error::Error; use crate::verify::RootHash; +use dpp::data_contract::group::GroupMemberPower; use dpp::data_contract::GroupContractPosition; use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; use grovedb::GroveDb; -use dpp::data_contract::group::GroupMemberPower; use platform_version::version::PlatformVersion; impl Drive { @@ -38,23 +38,32 @@ impl Drive { let values = proved_key_values .into_iter() .filter_map(|(_, key, element)| { - let id : Identifier = match key.try_into() { + let id: Identifier = match key.try_into() { Ok(id) => id, - Err(_) => return Some(Err(Error::Proof(ProofError::IncorrectProof("identifier was not 32 bytes long".to_string())))), + Err(_) => { + return Some(Err(Error::Proof(ProofError::IncorrectProof( + "identifier was not 32 bytes long".to_string(), + )))) + } }; match element { Some(SumItem(value, ..)) => { - let signing_power : GroupMemberPower = match value.try_into() { + let signing_power: GroupMemberPower = match value.try_into() { Ok(signing_power) => signing_power, - Err(_) => return Some(Err(Error::Proof(ProofError::IncorrectProof("signed power should be encodable on a u32 integer".to_string())))), + Err(_) => { + return Some(Err(Error::Proof(ProofError::IncorrectProof( + "signed power should be encodable on a u32 integer".to_string(), + )))) + } }; Some(Ok((id, signing_power))) - }, + } None => None, _ => Some(Err(Error::Proof(ProofError::IncorrectProof( "element should be a sum item representing member signed power".to_string(), - )).into())), + )) + .into())), } }) .collect::>()?;