Skip to content

Commit

Permalink
feat: get identities for non unique public key hash
Browse files Browse the repository at this point in the history
  • Loading branch information
QuantumExplorer committed Nov 10, 2024
1 parent 3b7ca92 commit 0f0b255
Show file tree
Hide file tree
Showing 39 changed files with 1,069 additions and 39 deletions.
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

0 comments on commit 0f0b255

Please sign in to comment.