Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(platform): get identities for non unique public key hash #2324

Draft
wants to merge 1 commit into
base: v1.7-dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions packages/dapi-grpc/protos/platform/v0/platform.proto
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ service Platform {
rpc getDocuments(GetDocumentsRequest) returns (GetDocumentsResponse);
rpc getIdentityByPublicKeyHash(GetIdentityByPublicKeyHashRequest)
returns (GetIdentityByPublicKeyHashResponse);
rpc getIdentitiesForNonUniquePublicKeyHash(GetIdentitiesForNonUniquePublicKeyHashRequest)
returns (GetIdentitiesForNonUniquePublicKeyHashResponse);
rpc waitForStateTransitionResult(WaitForStateTransitionResultRequest)
returns (WaitForStateTransitionResultResponse);
rpc getConsensusParams(GetConsensusParamsRequest)
Expand Down Expand Up @@ -592,6 +594,31 @@ message GetIdentityByPublicKeyHashResponse {
oneof version { GetIdentityByPublicKeyHashResponseV0 v0 = 1; }
}

message GetIdentitiesForNonUniquePublicKeyHashRequest {
message GetIdentitiesForNonUniquePublicKeyHashRequestV0 {
bytes public_key_hash = 1; // The non-unique public key hash for which identities are requested
bool prove = 2; // Flag to request proof for the response
}
oneof version { GetIdentitiesForNonUniquePublicKeyHashRequestV0 v0 = 1; }
}

message GetIdentitiesForNonUniquePublicKeyHashResponse {
message GetIdentitiesForNonUniquePublicKeyHashResponseV0 {
message Identities {
repeated bytes identities = 1;
}

oneof result {
Identities identities = 1; // The list of identity data corresponding to the requested public key hash
Proof proof = 2; // Cryptographic proof for the identities data, if requested
}

ResponseMetadata metadata = 3; // Metadata about the blockchain state
}
oneof version { GetIdentitiesForNonUniquePublicKeyHashResponseV0 v0 = 1; }
}


message WaitForStateTransitionResultRequest {
message WaitForStateTransitionResultRequestV0 {
bytes state_transition_hash = 1; // The hash of the state transition to wait for
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
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_identities_for_non_unique_public_key_hash_request::Version as RequestVersion;
use dapi_grpc::platform::v0::get_identities_for_non_unique_public_key_hash_response::Version as ResponseVersion;
use dapi_grpc::platform::v0::{
GetIdentitiesForNonUniquePublicKeyHashRequest, GetIdentitiesForNonUniquePublicKeyHashResponse,
GetIdentityByPublicKeyHashResponse,

Check warning on line 10 in packages/rs-drive-abci/src/query/identity_based_queries/identities_for_non_unique_public_key_hash/mod.rs

View workflow job for this annotation

GitHub Actions / Rust packages (drive-abci) / Linting

unused import: `GetIdentityByPublicKeyHashResponse`

warning: unused import: `GetIdentityByPublicKeyHashResponse` --> packages/rs-drive-abci/src/query/identity_based_queries/identities_for_non_unique_public_key_hash/mod.rs:10:5 | 10 | GetIdentityByPublicKeyHashResponse, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default
};
use dpp::version::PlatformVersion;

mod v0;

impl<C> Platform<C> {
/// Querying of identities for a non-unique public key hash
pub fn query_identities_for_non_unique_public_key_hash(
&self,
GetIdentitiesForNonUniquePublicKeyHashRequest { version }: GetIdentitiesForNonUniquePublicKeyHashRequest,
platform_state: &PlatformState,
platform_version: &PlatformVersion,
) -> Result<QueryValidationResult<GetIdentitiesForNonUniquePublicKeyHashResponse>, Error> {
let Some(version) = version else {
return Ok(QueryValidationResult::new_with_error(
QueryError::DecodingError(
"could not decode identities for non unique public key hash query".to_string(),
),
));
};

let feature_version_bounds = &platform_version
.drive_abci
.query
.identity_based_queries
.identities_for_non_unique_public_key_hash;

let feature_version = match &version {
RequestVersion::V0(_) => 0,
};

if !feature_version_bounds.check_version(feature_version) {
return Ok(QueryValidationResult::new_with_error(
QueryError::UnsupportedQueryVersion(
"identities_for_non_unique_public_key_hash".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 request = self.query_identities_for_non_unique_public_key_hash_v0(
request_v0,
platform_state,
platform_version,
)?;

Ok(request.map(
|response_v0| GetIdentitiesForNonUniquePublicKeyHashResponse {
version: Some(ResponseVersion::V0(response_v0)),
},
))
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
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_identities_for_non_unique_public_key_hash_request::GetIdentitiesForNonUniquePublicKeyHashRequestV0;
use dapi_grpc::platform::v0::get_identities_for_non_unique_public_key_hash_response::{
get_identities_for_non_unique_public_key_hash_response_v0,
GetIdentitiesForNonUniquePublicKeyHashResponseV0,
};
use dpp::check_validation_result_with_data;
use dpp::platform_value::Bytes20;
use dpp::serialization::PlatformSerializable;
use dpp::validation::ValidationResult;
use dpp::version::PlatformVersion;

impl<C> Platform<C> {
pub(super) fn query_identities_for_non_unique_public_key_hash_v0(
&self,
GetIdentitiesForNonUniquePublicKeyHashRequestV0 {
public_key_hash,
prove,
}: GetIdentitiesForNonUniquePublicKeyHashRequestV0,
platform_state: &PlatformState,
platform_version: &PlatformVersion,
) -> Result<QueryValidationResult<GetIdentitiesForNonUniquePublicKeyHashResponseV0>, Error>
{
let public_key_hash =
check_validation_result_with_data!(Bytes20::from_vec(public_key_hash)
.map(|bytes| bytes.0)
.map_err(|_| QueryError::InvalidArgument(
"public key hash must be 20 bytes long".to_string()
)));

let response = if prove {
let proof = self
.drive
.prove_full_identities_for_non_unique_public_key_hash(
public_key_hash,
None,
None,
platform_version,
)?;

GetIdentitiesForNonUniquePublicKeyHashResponseV0 {
result: Some(
get_identities_for_non_unique_public_key_hash_response_v0::Result::Proof(
self.response_proof_v0(platform_state, proof),
),
),
metadata: Some(self.response_metadata_v0(platform_state)),
}
} else {
let identities = self
.drive
.fetch_full_identities_for_non_unique_public_key_hash(
public_key_hash,
None,
None,
platform_version,
)?
.into_iter()
.map(|identity| {
identity
.serialize_consume_to_bytes()
.map_err(Error::Protocol)
})
.collect::<Result<Vec<_>, Error>>()?;

GetIdentitiesForNonUniquePublicKeyHashResponseV0 {
metadata: Some(self.response_metadata_v0(platform_state)),
result: Some(
get_identities_for_non_unique_public_key_hash_response_v0::Result::Identities(
get_identities_for_non_unique_public_key_hash_response_v0::Identities {
identities,
},
),
),
}
};

Ok(QueryValidationResult::new_with_data(response))
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::query::tests::setup_platform;
use dpp::dashcore::Network;

#[test]
fn test_invalid_public_key_hash() {
let (platform, state, version) = setup_platform(None, Network::Testnet, None);

let request = GetIdentitiesForNonUniquePublicKeyHashRequestV0 {
public_key_hash: vec![0; 8],
prove: false,
};

let result = platform
.query_identities_for_non_unique_public_key_hash_v0(request, &state, version)
.expect("expected query to succeed");

assert!(matches!(
result.errors.as_slice(),
[QueryError::InvalidArgument(msg)] if msg == &"public key hash must be 20 bytes long".to_string()
));
}

#[test]
fn test_identity_not_found() {
let (platform, state, version) = setup_platform(None, Network::Testnet, None);

let public_key_hash = vec![0; 20];
let request = GetIdentitiesForNonUniquePublicKeyHashRequestV0 {
public_key_hash: public_key_hash.clone(),
prove: false,
};

let result = platform
.query_identities_for_non_unique_public_key_hash_v0(request, &state, version)
.expect("expected query to succeed");

assert!(result.errors.is_empty());
}

#[test]
fn test_identity_absence_proof() {
let (platform, state, version) = setup_platform(None, Network::Testnet, None);

let public_key_hash = vec![0; 20];
let request = GetIdentitiesForNonUniquePublicKeyHashRequestV0 {
public_key_hash: public_key_hash.clone(),
prove: true,
};

let result = platform
.query_identities_for_non_unique_public_key_hash_v0(request, &state, version)
.expect("expected query to succeed");

assert!(matches!(
result.data,
Some(GetIdentitiesForNonUniquePublicKeyHashResponseV0 {
result: Some(
get_identities_for_non_unique_public_key_hash_response_v0::Result::Proof(_)
),
metadata: Some(_),
})
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod balance;
mod balance_and_revision;
mod balances;
mod identities_contract_keys;
mod identities_for_non_unique_public_key_hash;
mod identity;
mod identity_by_public_key_hash;
mod identity_contract_nonce;
Expand Down
15 changes: 14 additions & 1 deletion packages/rs-drive-abci/src/query/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use dapi_grpc::platform::v0::{
GetEvonodesProposedEpochBlocksByIdsRequest, GetEvonodesProposedEpochBlocksByRangeRequest,
GetEvonodesProposedEpochBlocksResponse, GetIdentitiesBalancesRequest,
GetIdentitiesBalancesResponse, GetIdentitiesContractKeysRequest,
GetIdentitiesContractKeysResponse, GetIdentityBalanceAndRevisionRequest,
GetIdentitiesContractKeysResponse, GetIdentitiesForNonUniquePublicKeyHashRequest,
GetIdentitiesForNonUniquePublicKeyHashResponse, GetIdentityBalanceAndRevisionRequest,
GetIdentityBalanceAndRevisionResponse, GetIdentityBalanceRequest, GetIdentityBalanceResponse,
GetIdentityByPublicKeyHashRequest, GetIdentityByPublicKeyHashResponse,
GetIdentityContractNonceRequest, GetIdentityContractNonceResponse, GetIdentityKeysRequest,
Expand Down Expand Up @@ -404,6 +405,18 @@ impl PlatformService for QueryService {
.await
}

async fn get_identities_for_non_unique_public_key_hash(
&self,
request: Request<GetIdentitiesForNonUniquePublicKeyHashRequest>,
) -> Result<Response<GetIdentitiesForNonUniquePublicKeyHashResponse>, Status> {
self.handle_blocking_query(
request,
Platform::<DefaultCoreRPC>::query_identities_for_non_unique_public_key_hash,
"get_identities_for_non_unique_public_key_hash",
)
.await
}

async fn wait_for_state_transition_result(
&self,
_request: Request<WaitForStateTransitionResultRequest>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
mod v0;

use crate::drive::Drive;
use crate::error::{drive::DriveError, Error};
use dpp::identity::Identity;

use dpp::version::PlatformVersion;
use grovedb::TransactionArg;

impl Drive {
/// Retrieves all full identities associated with a given non-unique public key hash.
///
/// This function fetches all identity data associated with a specified public key hash,
/// using the version specified in `PlatformVersion` to determine the correct method implementation.
///
/// # Parameters
///
/// - `public_key_hash`: A 20-byte array representing the non-unique public key hash to look up.
/// - `limit`: An optional limit on the number of identities to retrieve.
/// - `transaction`: A `TransactionArg` representing the transaction context.
/// - `platform_version`: A reference to the `PlatformVersion`, which selects the method version for identity fetching.
///
/// # Returns
///
/// Returns a `Result` containing a `Vec<Identity>` where:
/// - Each `Identity` represents a verified identity associated with the public key hash.
///
/// # Errors
///
/// Returns an `Error` if:
/// - The provided public key hash does not correspond to any identities.
/// - The method version specified in `PlatformVersion` is unsupported.
///
pub fn fetch_full_identities_for_non_unique_public_key_hash(
&self,
public_key_hash: [u8; 20],
limit: Option<u16>,
transaction: TransactionArg,
platform_version: &PlatformVersion,
) -> Result<Vec<Identity>, Error> {
match platform_version
.drive
.methods
.identity
.fetch
.public_key_hashes
.fetch_full_identities_for_non_unique_public_key_hash
{
0 => self.fetch_full_identities_for_non_unique_public_key_hash_v0(
public_key_hash,
limit,
transaction,
platform_version,
),
version => Err(Error::Drive(DriveError::UnknownVersionMismatch {
method: "fetch_full_identities_for_non_unique_public_key_hash".to_string(),
known_versions: vec![0],
received: version,
})),
}
}
}
Loading
Loading