Skip to content

Commit b3f5f17

Browse files
committed
feat(sdk): asset lock quorum verify against platform
1 parent 4dbcdba commit b3f5f17

File tree

2 files changed

+80
-6
lines changed

2 files changed

+80
-6
lines changed

packages/rs-sdk/src/error.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ pub enum Error {
4949
/// Epoch not found; we must have at least one epoch
5050
#[error("No epoch found on the Platform; it should never happen")]
5151
EpochNotFound,
52+
/// Quorum not found; try again later
53+
#[error("Quorum {quorum_hash_hex} of type {quorum_type} not yet available on the platform at height {core_chain_locked_height}: {e}; try again later")]
54+
QuorumNotFound {
55+
quorum_hash_hex: String,
56+
quorum_type: u32,
57+
core_chain_locked_height: u32,
58+
e: ContextProviderError,
59+
},
5260
/// SDK operation timeout reached error
5361
#[error("SDK operation timeout {} secs reached: {1}", .0.as_secs())]
5462
TimeoutReached(Duration, String),

packages/rs-sdk/src/platform/transition/put_identity.rs

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1+
use crate::platform::block_info_from_metadata::block_info_from_metadata;
12
use crate::platform::transition::broadcast_identity::BroadcastRequestForNewIdentity;
23
use crate::platform::transition::broadcast_request::BroadcastRequestForStateTransition;
34
use crate::platform::Fetch;
45
use crate::{Error, Sdk};
5-
6+
use dapi_grpc::platform::v0::get_epochs_info_request::{self, GetEpochsInfoRequestV0};
7+
use dapi_grpc::platform::v0::GetEpochsInfoRequest;
68
use dapi_grpc::platform::VersionedGrpcResponse;
79
use dapi_grpc::tonic::Code;
10+
use dpp::dashcore::hashes::Hash;
811
use dpp::dashcore::PrivateKey;
912
use dpp::identity::signer::Signer;
1013
use dpp::prelude::{AssetLockProof, Identity};
11-
use drive_proof_verifier::error::ContextProviderError;
12-
use drive_proof_verifier::DataContractProvider;
13-
14-
use crate::platform::block_info_from_metadata::block_info_from_metadata;
1514
use dpp::state_transition::proof_result::StateTransitionProofResult;
1615
use drive::drive::Drive;
17-
use rs_dapi_client::{DapiClientError, DapiRequest, RequestSettings};
16+
use drive_proof_verifier::error::ContextProviderError;
17+
use drive_proof_verifier::{ContextProvider, DataContractProvider};
18+
use rs_dapi_client::{DapiClientError, DapiRequest, DapiRequestExecutor, RequestSettings};
1819

1920
#[async_trait::async_trait]
2021
/// A trait for putting an identity to platform
@@ -37,6 +38,71 @@ pub trait PutIdentity<S: Signer> {
3738
) -> Result<Identity, Error>;
3839
}
3940

41+
#[async_trait::async_trait]
42+
pub trait AssetLockProofVerifier {
43+
/// Verifies the asset lock proof against the platform
44+
async fn verify(&self, sdk: &Sdk) -> Result<(), Error>;
45+
}
46+
47+
#[async_trait::async_trait]
48+
impl AssetLockProofVerifier for AssetLockProof {
49+
async fn verify(&self, sdk: &Sdk) -> Result<(), Error> {
50+
let context_provider = sdk
51+
.context_provider()
52+
.ok_or(Error::Config("Context Provider not configured".to_string()))?;
53+
54+
// Check status of Platform first
55+
// TODO: implement some caching mechanism to avoid fetching the same data multiple times
56+
let request = GetEpochsInfoRequest {
57+
version: Some(get_epochs_info_request::Version::V0(
58+
GetEpochsInfoRequestV0 {
59+
ascending: false,
60+
count: 1,
61+
prove: true,
62+
start_epoch: None,
63+
},
64+
)),
65+
};
66+
let response = sdk.execute(request, RequestSettings::default()).await?;
67+
68+
let platform_core_chain_locked_height = response.metadata()?.core_chain_locked_height;
69+
let proof = response.proof_owned()?;
70+
let platform_quorum_hash = proof.quorum_hash.try_into().map_err(|e: Vec<u8>| {
71+
Error::Protocol(dpp::ProtocolError::DecodingError(format!(
72+
"Invalid quorum hash size {}, expected 32 bytes",
73+
e.len()
74+
)))
75+
})?;
76+
77+
let platform_quorum_type = proof.quorum_type;
78+
79+
let (quorum_hash, core_chain_locked_height) = match self {
80+
AssetLockProof::Chain(v) => (platform_quorum_hash, v.core_chain_locked_height),
81+
AssetLockProof::Instant(v) => (
82+
v.instant_lock().cyclehash.to_raw_hash().to_byte_array(),
83+
platform_core_chain_locked_height,
84+
),
85+
};
86+
87+
// Try to fetch the quorum public key; if it fails, the
88+
let result = context_provider.get_quorum_public_key(
89+
platform_quorum_type,
90+
quorum_hash,
91+
core_chain_locked_height,
92+
);
93+
94+
match result {
95+
Err(ContextProviderError::InvalidQuorum(s)) => Err(Error::QuorumNotFound {
96+
e: ContextProviderError::InvalidQuorum(s),
97+
quorum_hash_hex: hex::encode(quorum_hash),
98+
quorum_type: platform_quorum_type,
99+
core_chain_locked_height,
100+
}),
101+
Err(e) => Err(e.into()),
102+
Ok(_) => Ok(()),
103+
}
104+
}
105+
}
40106
#[async_trait::async_trait]
41107
impl<S: Signer> PutIdentity<S> for Identity {
42108
async fn put_to_platform(

0 commit comments

Comments
 (0)