Skip to content
Closed
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
31 changes: 31 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 getIdentityByNonUniquePublicKeyHash(GetIdentityByNonUniquePublicKeyHashRequest)
returns (GetIdentityByNonUniquePublicKeyHashResponse);
rpc waitForStateTransitionResult(WaitForStateTransitionResultRequest)
returns (WaitForStateTransitionResultResponse);
rpc getConsensusParams(GetConsensusParamsRequest)
Expand Down Expand Up @@ -620,6 +622,35 @@ message GetIdentityByPublicKeyHashResponse {
oneof version { GetIdentityByPublicKeyHashResponseV0 v0 = 1; }
}

message GetIdentityByNonUniquePublicKeyHashRequest {
message GetIdentityByNonUniquePublicKeyHashRequestV0 {
bytes public_key_hash = 1;
optional bytes start_after = 2; // Give one result after a previous result
bool prove = 3;
}
oneof version { GetIdentityByNonUniquePublicKeyHashRequestV0 v0 = 1; }
}

message GetIdentityByNonUniquePublicKeyHashResponse {
message GetIdentityByNonUniquePublicKeyHashResponseV0 {
message IdentityResponse {
optional bytes identity = 1;
}

message IdentityProvedResponse {
Proof grovedb_identity_public_key_hash_proof = 1;
optional bytes identity_proof_bytes = 2; // A hack, we return 2 proofs
}
oneof result {
IdentityResponse identity = 1;
IdentityProvedResponse proof = 2;
}

ResponseMetadata metadata = 3; // Metadata about the blockchain state
}
oneof version { GetIdentityByNonUniquePublicKeyHashResponseV0 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_identity_by_non_unique_public_key_hash_request::Version as RequestVersion;
use dapi_grpc::platform::v0::get_identity_by_non_unique_public_key_hash_response::Version as ResponseVersion;
use dapi_grpc::platform::v0::{
GetIdentityByNonUniquePublicKeyHashRequest, GetIdentityByNonUniquePublicKeyHashResponse,
GetIdentityByPublicKeyHashResponse,
};
use dpp::version::PlatformVersion;

mod v0;

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

let feature_version_bounds = &platform_version
.drive_abci
.query
.identity_based_queries
.identity_by_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(
"identity_by_non_unique_public_key_hash".to_string(),
feature_version_bounds.min_version,
feature_version_bounds.max_version,
platform_version.protocol_version,
feature_version,
),
));
}
Comment on lines +32 to +52
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix mismatch in naming for feature version field.
Here, you reference identity_by_unique_public_key_hash (line 36) while we are in a file specifically for non-unique public key hashes. This can be confusing and could lead to errors if the underlying version bounds differ. Confirm you’re referencing the correct feature.

- .identity_by_unique_public_key_hash;
+ .identity_by_non_unique_public_key_hash;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let feature_version_bounds = &platform_version
.drive_abci
.query
.identity_based_queries
.identity_by_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(
"identity_by_non_unique_public_key_hash".to_string(),
feature_version_bounds.min_version,
feature_version_bounds.max_version,
platform_version.protocol_version,
feature_version,
),
));
}
let feature_version_bounds = &platform_version
.drive_abci
.query
.identity_based_queries
- .identity_by_unique_public_key_hash;
+ .identity_by_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(
"identity_by_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_identity_by_non_unique_public_key_hash_v0(
request_v0,
platform_state,
platform_version,
)?;

Ok(
request.map(|response_v0| GetIdentityByNonUniquePublicKeyHashResponse {
version: Some(ResponseVersion::V0(response_v0)),
}),
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
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_identity_by_non_unique_public_key_hash_request::GetIdentityByNonUniquePublicKeyHashRequestV0;
use dapi_grpc::platform::v0::get_identity_by_non_unique_public_key_hash_response::{
get_identity_by_non_unique_public_key_hash_response_v0, GetIdentityByNonUniquePublicKeyHashResponseV0,
};
use dapi_grpc::platform::v0::get_identity_by_non_unique_public_key_hash_response::get_identity_by_non_unique_public_key_hash_response_v0::{IdentityProvedResponse, IdentityResponse};
use dpp::check_validation_result_with_data;
use dpp::platform_value::{Bytes20, Bytes32};
use dpp::serialization::PlatformSerializable;
use dpp::validation::ValidationResult;
use dpp::version::PlatformVersion;

impl<C> Platform<C> {
pub(super) fn query_identity_by_non_unique_public_key_hash_v0(
&self,
GetIdentityByNonUniquePublicKeyHashRequestV0 {
public_key_hash,
start_after,
prove,
}: GetIdentityByNonUniquePublicKeyHashRequestV0,
platform_state: &PlatformState,
platform_version: &PlatformVersion,
) -> Result<QueryValidationResult<GetIdentityByNonUniquePublicKeyHashResponseV0>, 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 start_after = if let Some(start_after) = start_after {
Some(check_validation_result_with_data!(Bytes32::from_vec(
start_after
)
.map(|bytes| bytes.0)
.map_err(|_| QueryError::InvalidArgument(
"public key hash must be 20 bytes long".to_string()
))))
} else {
None
};
Comment on lines +35 to +45
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix misleading error message for start_after validation.
When parsing start_after as a 32-byte value, the error message still references "20 bytes." This can lead to confusion.

Consider applying the following fix:

-            .map_err(|_| QueryError::InvalidArgument(
-                "public key hash must be 20 bytes long".to_string()
-            ))
+            .map_err(|_| QueryError::InvalidArgument(
+                "start_after must be 32 bytes long".to_string()
+            ))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let start_after = if let Some(start_after) = start_after {
Some(check_validation_result_with_data!(Bytes32::from_vec(
start_after
)
.map(|bytes| bytes.0)
.map_err(|_| QueryError::InvalidArgument(
"public key hash must be 20 bytes long".to_string()
))))
} else {
None
};
let start_after = if let Some(start_after) = start_after {
Some(check_validation_result_with_data!(Bytes32::from_vec(
start_after
)
.map(|bytes| bytes.0)
.map_err(|_| QueryError::InvalidArgument(
"start_after must be 32 bytes long".to_string()
))))
} else {
None
};


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

GetIdentityByNonUniquePublicKeyHashResponseV0 {
result: Some(
get_identity_by_non_unique_public_key_hash_response_v0::Result::Proof(
IdentityProvedResponse {
grovedb_identity_public_key_hash_proof: Some(self.response_proof_v0(
platform_state,
proof.identity_id_public_key_hash_proof,
)),
identity_proof_bytes: proof.identity_proof,
},
),
),
metadata: Some(self.response_metadata_v0(platform_state)),
}
} else {
let maybe_identity = self
.drive
.fetch_full_identity_by_non_unique_public_key_hash(
public_key_hash,
start_after,
None,
platform_version,
)?;

let serialized_identity = maybe_identity
.map(|identity| {
identity
.serialize_consume_to_bytes()
.map_err(Error::Protocol)
})
.transpose()?;

GetIdentityByNonUniquePublicKeyHashResponseV0 {
metadata: Some(self.response_metadata_v0(platform_state)),
result: Some(
get_identity_by_non_unique_public_key_hash_response_v0::Result::Identity(
IdentityResponse {
identity: serialized_identity,
},
),
),
}
};

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

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

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

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

let result = platform
.query_identity_by_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 = GetIdentityByNonUniquePublicKeyHashRequestV0 {
public_key_hash: public_key_hash.clone(),
start_after: None,
prove: false,
};

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

assert_eq!(
result.data,
Some(GetIdentityByNonUniquePublicKeyHashResponseV0 {
metadata: Some(ResponseMetadata {
height: 0,
core_chain_locked_height: 0,
epoch: 0,
time_ms: 0,
protocol_version: 9,
chain_id: "chain_id".to_string()
}),
result: Some(
get_identity_by_non_unique_public_key_hash_response_v0::Result::Identity(
IdentityResponse { identity: None }
)
),
})
);
}

#[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 = GetIdentityByNonUniquePublicKeyHashRequestV0 {
public_key_hash: public_key_hash.clone(),
start_after: None,
prove: true,
};

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

assert!(matches!(
result.data,
Some(GetIdentityByNonUniquePublicKeyHashResponseV0 {
result: Some(
get_identity_by_non_unique_public_key_hash_response_v0::Result::Proof(_)
),
metadata: Some(_),
})
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl<C> Platform<C> {
.drive_abci
.query
.identity_based_queries
.identity_by_public_key_hash;
.identity_by_unique_public_key_hash;

let feature_version = match &version {
RequestVersion::V0(_) => 0,
Expand All @@ -41,7 +41,7 @@ impl<C> Platform<C> {
if !feature_version_bounds.check_version(feature_version) {
return Ok(QueryValidationResult::new_with_error(
QueryError::UnsupportedQueryVersion(
"identity_by_public_key_hash".to_string(),
"identity_by_unique_public_key_hash".to_string(),
feature_version_bounds.min_version,
feature_version_bounds.max_version,
platform_version.protocol_version,
Expand All @@ -52,7 +52,7 @@ impl<C> Platform<C> {

match version {
RequestVersion::V0(request_v0) => {
let request = self.query_identity_by_public_key_hash_v0(
let request = self.query_identity_by_unique_public_key_hash_v0(
request_v0,
platform_state,
platform_version,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use dpp::validation::ValidationResult;
use dpp::version::PlatformVersion;

impl<C> Platform<C> {
pub(super) fn query_identity_by_public_key_hash_v0(
pub(super) fn query_identity_by_unique_public_key_hash_v0(
&self,
GetIdentityByPublicKeyHashRequestV0 {
public_key_hash,
Expand Down Expand Up @@ -91,7 +91,7 @@ mod tests {
};

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

assert!(matches!(
Expand All @@ -111,7 +111,7 @@ mod tests {
};

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

assert!(matches!(
Expand All @@ -131,7 +131,7 @@ mod tests {
};

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

assert!(matches!(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ mod balance_and_revision;
mod balances;
mod identities_contract_keys;
mod identity;
mod identity_by_public_key_hash;
mod identity_by_non_unique_public_key_hash;
mod identity_by_unique_public_key_hash;
mod identity_contract_nonce;
mod identity_nonce;
mod keys;
Loading