-
Notifications
You must be signed in to change notification settings - Fork 39
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(sdk): asset lock quorum and core locked height verification #2030
base: v1.7-dev
Are you sure you want to change the base?
Changes from all commits
b3f5f17
9de013f
6362883
f984ced
bff31d5
e3a5538
4df0c40
f41f2bc
3517779
d9cada9
0c04b42
c9c4a21
f57e455
b5dfc6a
1f1c957
c4cc766
5d33c31
727cc20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
//! Configuration of dash networks (devnet, testnet, mainnet, etc.). | ||
//! | ||
//! See also: | ||
//! * https://github.com/dashpay/dash/blob/develop/src/chainparams.cpp | ||
|
||
/* | ||
Mainnet: | ||
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_400_60; | ||
consensus.llmqTypeDIP0024InstantSend = Consensus::LLMQType::LLMQ_60_75; | ||
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67; | ||
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_400_85; | ||
|
||
Testnet: | ||
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_50_60; | ||
consensus.llmqTypeDIP0024InstantSend = Consensus::LLMQType::LLMQ_60_75; | ||
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_25_67; | ||
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_50_60; | ||
|
||
Devnet: | ||
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_DEVNET; | ||
consensus.llmqTypeDIP0024InstantSend = Consensus::LLMQType::LLMQ_DEVNET_DIP0024; | ||
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_DEVNET_PLATFORM; | ||
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_DEVNET; | ||
|
||
*/ | ||
|
||
use dashcore_rpc::json::QuorumType; | ||
|
||
/// Dash network types. | ||
#[derive(Eq, PartialEq, Clone, Debug)] | ||
pub enum NetworkType { | ||
/// Mock implementation; in practice, feaults to Devnet config for Mock mode. Errors when used in non-mock mode. | ||
Mock, | ||
/// Mainnet network, used for production. | ||
Mainnet, | ||
/// Testnet network, used for testing and development. | ||
Testnet, | ||
/// Devnet network, used local for development. | ||
Devnet, | ||
/// Custom network configuration. | ||
Custom(QuorumParams), | ||
} | ||
|
||
impl NetworkType { | ||
pub fn instant_lock_quorum_type(&self) -> QuorumType { | ||
self.to_quorum_params().instant_lock_quorum_type | ||
} | ||
|
||
pub(crate) fn to_quorum_params(&self) -> QuorumParams { | ||
match self { | ||
NetworkType::Mainnet => QuorumParams::new_mainnet(), | ||
NetworkType::Testnet => QuorumParams::new_testnet(), | ||
NetworkType::Devnet => QuorumParams::new_devnet(), | ||
NetworkType::Custom(config) => config.clone(), | ||
NetworkType::Mock => QuorumParams::new_mock(), | ||
} | ||
} | ||
} | ||
|
||
/// Configuration of Dash Core Quorums. | ||
/// | ||
/// In most cases, you should use the [`new_mainnet`] or [`new_testnet`] functions to create a new instance. | ||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
pub struct QuorumParams { | ||
pub instant_lock_quorum_type: QuorumType, | ||
} | ||
|
||
impl QuorumParams { | ||
pub fn new_mainnet() -> Self { | ||
QuorumParams { | ||
instant_lock_quorum_type: QuorumType::Llmq400_60, | ||
} | ||
} | ||
|
||
pub fn new_testnet() -> Self { | ||
QuorumParams { | ||
instant_lock_quorum_type: QuorumType::Llmq50_60, | ||
} | ||
} | ||
|
||
pub fn new_devnet() -> Self { | ||
QuorumParams { | ||
// FIXME: local devnet uses regtest | ||
instant_lock_quorum_type: QuorumType::LlmqTest, | ||
} | ||
} | ||
|
||
pub fn new_mock() -> Self { | ||
Self::new_devnet() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
//! [AssetLockProof] utilities | ||
|
||
use crate::{Error, Sdk}; | ||
use dapi_grpc::platform::v0::get_epochs_info_request::{self, GetEpochsInfoRequestV0}; | ||
use dapi_grpc::platform::v0::GetEpochsInfoRequest; | ||
use dapi_grpc::platform::VersionedGrpcResponse; | ||
use dpp::dashcore::hashes::Hash; | ||
use dpp::prelude::AssetLockProof; | ||
use drive_proof_verifier::error::ContextProviderError; | ||
use drive_proof_verifier::ContextProvider; | ||
use rs_dapi_client::{DapiRequestExecutor, RequestSettings}; | ||
#[async_trait::async_trait] | ||
pub trait AssetLockProofVerifier { | ||
/// Verifies the asset lock proof against the platform. | ||
/// | ||
/// This function will return an error if Dash Platform cannot use the provided asset lock proof. | ||
/// | ||
/// # Errors | ||
/// | ||
/// - [Error::CoreLockedHeightNotYetAvailable] if the core locked height in the proof is higher than the | ||
/// current core locked height on the platform. Try again later. | ||
/// - [Error::QuorumNotFound] if the quorum public key is not yet available on the platform, what implies that | ||
/// the quorum is not (yet) available. Try again later. | ||
/// - other errors when something goes wrong. | ||
async fn verify(&self, sdk: &Sdk) -> Result<(), Error>; | ||
} | ||
|
||
#[async_trait::async_trait] | ||
impl AssetLockProofVerifier for AssetLockProof { | ||
async fn verify(&self, sdk: &Sdk) -> Result<(), Error> { | ||
let context_provider = sdk | ||
.context_provider() | ||
.ok_or(Error::Config("Context Provider not configured".to_string()))?; | ||
|
||
// Retrieve current core chain lock info from the platform | ||
// TODO: implement some caching mechanism to avoid fetching the same data multiple times | ||
let request = GetEpochsInfoRequest { | ||
version: Some(get_epochs_info_request::Version::V0( | ||
GetEpochsInfoRequestV0 { | ||
ascending: false, | ||
count: 1, | ||
prove: true, | ||
start_epoch: None, | ||
}, | ||
)), | ||
}; | ||
let response = sdk.execute(request, RequestSettings::default()).await?; | ||
let platform_core_chain_locked_height = response.metadata()?.core_chain_locked_height; | ||
|
||
match self { | ||
AssetLockProof::Chain(asset_lock) => { | ||
if asset_lock.core_chain_locked_height > platform_core_chain_locked_height { | ||
Err(Error::CoreLockedHeightNotYetAvailable( | ||
asset_lock.core_chain_locked_height, | ||
platform_core_chain_locked_height, | ||
)) | ||
} else { | ||
Ok(()) | ||
} | ||
} | ||
AssetLockProof::Instant(v) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not gonna check if we can verify signature in Drive, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you have any hint how to do that client-side, I would be happy to include this here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @QuantumExplorer can you give me some formula to add it here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From what we discussed, we have no better solution than what's already implemented. |
||
let quorum_hash = v.instant_lock().cyclehash.to_raw_hash().to_byte_array(); | ||
let quorum_type = sdk.quorum_params().instant_lock_quorum_type; | ||
// Try to fetch the quorum public key; if it fails, we assume platform does not have this quorum yet | ||
match context_provider.get_quorum_public_key( | ||
quorum_type as u32, | ||
quorum_hash, | ||
platform_core_chain_locked_height, | ||
) { | ||
Err(ContextProviderError::InvalidQuorum(s)) => Err(Error::QuorumNotFound { | ||
e: ContextProviderError::InvalidQuorum(s), | ||
quorum_hash_hex: hex::encode(quorum_hash), | ||
quorum_type: quorum_type as u32, | ||
core_chain_locked_height: platform_core_chain_locked_height, | ||
}), | ||
Err(e) => Err(e.into()), | ||
Ok(_) => Ok(()), | ||
} | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs discussion how to handle that.