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(sdk): get node status #2139

Merged
merged 28 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c044004
feat: get node statuses in sdk
pauldelucia Sep 18, 2024
94235ee
fixes
pauldelucia Sep 18, 2024
45ebe6c
error handling
pauldelucia Sep 18, 2024
6d1af4c
return references instead of clones
pauldelucia Sep 19, 2024
7f098fc
fix
pauldelucia Sep 19, 2024
ea65946
Merge branch 'v1.3-dev' into feat/get-node-status-in-sdk
pauldelucia Sep 19, 2024
af067ed
Merge branch 'v1.3-dev' into feat/get-node-status-in-sdk
pauldelucia Sep 19, 2024
e4e26c4
Merge branch 'v1.4-dev' into feat/get-node-status-in-sdk
lklimek Sep 25, 2024
5537a05
Merge branch 'v1.4-dev' into feat/get-node-status-in-sdk
lklimek Sep 26, 2024
e409956
refactor
lklimek Sep 26, 2024
fa4bb87
chore(sdk): status tests
lklimek Sep 26, 2024
bad801c
chore: minor improvements
lklimek Sep 26, 2024
18d3df8
refactor(dapi-client): impl IntoIterator for address list
lklimek Sep 27, 2024
9a86b8f
fix: get status connecting to wrong node
lklimek Sep 27, 2024
beadf24
chore: fix dump of evonode
lklimek Sep 27, 2024
4263ed9
chore: fix mocking
lklimek Sep 27, 2024
99335cd
chore:remove unused bincode
lklimek Sep 27, 2024
e58541d
test(e2e): test vectors
lklimek Sep 27, 2024
ddbda44
chore: impl From<EvoNode> for GetStatusRequest
lklimek Sep 27, 2024
1ff4fce
feat(sdk): EvonodeStatus additional fields
lklimek Sep 27, 2024
9a22712
test(sdk): regen test vectors
lklimek Sep 27, 2024
1912407
chore: more meaningful msg
lklimek Sep 27, 2024
5491d3f
chore: fix features
lklimek Sep 27, 2024
c66c815
Merge remote-tracking branch 'origin/v1.4-dev' into feat/get-node-sta…
lklimek Sep 27, 2024
baa706f
chore: fix build
lklimek Sep 27, 2024
b2caae8
chore: apply review feedback
lklimek Sep 27, 2024
821af1f
refactor: move EvoNodeStatus to separate file
lklimek Sep 27, 2024
7f9c668
refactor: apply rabbit's feedback
lklimek Sep 27, 2024
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
9 changes: 7 additions & 2 deletions packages/dapi-grpc/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig {
// Derive features for versioned messages
//
// "GetConsensusParamsRequest" is excluded as this message does not support proofs
const VERSIONED_REQUESTS: [&str; 29] = [
const VERSIONED_REQUESTS: [&str; 30] = [
"GetDataContractHistoryRequest",
"GetDataContractRequest",
"GetDataContractsRequest",
Expand Down Expand Up @@ -77,9 +77,13 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig {
"GetTotalCreditsInPlatformRequest",
"GetEvonodesProposedEpochBlocksByIdsRequest",
"GetEvonodesProposedEpochBlocksByRangeRequest",
"GetStatusRequest",
];

// "GetConsensusParamsResponse" is excluded as this message does not support proofs
// The following responses are excluded as they don't support proofs:
// - "GetConsensusParamsResponse"
// - "GetStatusResponse"
//
// "GetEvonodesProposedEpochBlocksResponse" is used for 2 Requests
const VERSIONED_RESPONSES: [&str; 29] = [
"GetDataContractHistoryResponse",
Expand Down Expand Up @@ -213,6 +217,7 @@ impl MappingConfig {
///
/// * `protobuf_file` - Path to the protobuf file to use as input.
/// * `out_dir` - Output directory where subdirectories for generated files will be created.
///
/// Depending on the features, either `client`, `server` or `client_server` subdirectory
/// will be created inside `out_dir`.
fn new(protobuf_file: PathBuf, out_dir: PathBuf) -> Self {
Expand Down
11 changes: 10 additions & 1 deletion packages/rs-dapi-client/src/address_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ pub enum AddressListError {

/// A structure to manage DAPI addresses to select from
/// for [DapiRequest](crate::DapiRequest) execution.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct AddressList {
addresses: HashSet<Address>,
base_ban_period: Duration,
Expand Down Expand Up @@ -221,3 +221,12 @@ impl FromIterator<Uri> for AddressList {
address_list
}
}

impl IntoIterator for AddressList {
type Item = Address;
type IntoIter = std::collections::hash_set::IntoIter<Address>;

fn into_iter(self) -> Self::IntoIter {
self.addresses.into_iter()
}
}
5 changes: 5 additions & 0 deletions packages/rs-dapi-client/src/dapi_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ impl DapiClient {
dump_dir: None,
}
}

/// Return the [DapiClient] address list.
pub fn address_list(&self) -> &Arc<RwLock<AddressList>> {
&self.address_list
}
}

#[async_trait]
Expand Down
1 change: 0 additions & 1 deletion packages/rs-dapi-client/src/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ impl DapiClient {
response: &MockResult<R>,
dump_dir: Option<PathBuf>,
) where
R: Mockable,
<R as TransportRequest>::Response: Mockable,
{
let path = match dump_dir {
Expand Down
1 change: 1 addition & 0 deletions packages/rs-dapi-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod transport;

pub use address_list::Address;
pub use address_list::AddressList;
pub use connection_pool::ConnectionPool;
pub use dapi_client::DapiRequestExecutor;
pub use dapi_client::{DapiClient, DapiClientError};
use dapi_grpc::mock::Mockable;
Expand Down
9 changes: 9 additions & 0 deletions packages/rs-dapi-client/src/transport/grpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,3 +421,12 @@ impl_transport_request_grpc!(
},
subscribe_to_transactions_with_proofs
);

// rpc getStatus(GetStatusRequest) returns (GetStatusResponse);
impl_transport_request_grpc!(
platform_proto::GetStatusRequest,
platform_proto::GetStatusResponse,
PlatformGrpcClient,
RequestSettings::default(),
get_status
);
13 changes: 7 additions & 6 deletions packages/rs-drive-proof-verifier/src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ use crate::from_request::TryFromRequest;
use crate::provider::DataContractProvider;
use crate::verify::verify_tenderdash_proof;
use crate::{types, types::*, ContextProvider, Error};
use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::get_evonodes_proposed_epoch_blocks_by_range_request_v0::Start;
use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0;
use dapi_grpc::platform::v0::get_path_elements_request::GetPathElementsRequestV0;
use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_request::{
self, GetProtocolVersionUpgradeVoteStatusRequestV0,
};
use dapi_grpc::platform::v0::security_level_map::KeyKindRequestType as GrpcKeyKind;
use dapi_grpc::platform::v0::{get_contested_resource_identity_votes_request, get_data_contract_history_request, get_data_contract_request, get_data_contracts_request, get_epochs_info_request, get_evonodes_proposed_epoch_blocks_by_ids_request, get_evonodes_proposed_epoch_blocks_by_range_request, get_identities_balances_request, get_identities_contract_keys_request, get_identity_balance_and_revision_request, get_identity_balance_request, get_identity_by_public_key_hash_request, get_identity_contract_nonce_request, get_identity_keys_request, get_identity_nonce_request, get_identity_request, get_path_elements_request, get_prefunded_specialized_balance_request, GetContestedResourceVotersForIdentityRequest, GetContestedResourceVotersForIdentityResponse, GetPathElementsRequest, GetPathElementsResponse, GetProtocolVersionUpgradeStateRequest, GetProtocolVersionUpgradeStateResponse, GetProtocolVersionUpgradeVoteStatusRequest, GetProtocolVersionUpgradeVoteStatusResponse, Proof, ResponseMetadata};
use dapi_grpc::platform::v0::{
get_contested_resource_identity_votes_request, get_data_contract_history_request, get_data_contract_request, get_data_contracts_request, get_epochs_info_request, get_evonodes_proposed_epoch_blocks_by_ids_request, get_evonodes_proposed_epoch_blocks_by_range_request, get_identities_balances_request, get_identities_contract_keys_request, get_identity_balance_and_revision_request, get_identity_balance_request, get_identity_by_public_key_hash_request, get_identity_contract_nonce_request, get_identity_keys_request, get_identity_nonce_request, get_identity_request, get_path_elements_request, get_prefunded_specialized_balance_request, GetContestedResourceVotersForIdentityRequest, GetContestedResourceVotersForIdentityResponse, GetPathElementsRequest, GetPathElementsResponse, GetProtocolVersionUpgradeStateRequest, GetProtocolVersionUpgradeStateResponse, GetProtocolVersionUpgradeVoteStatusRequest, GetProtocolVersionUpgradeVoteStatusResponse, Proof, ResponseMetadata
};
use dapi_grpc::platform::{
v0::{self as platform, key_request_type, KeyRequestType as GrpcKeyType},
VersionedGrpcResponse,
Expand All @@ -35,15 +38,14 @@ use drive::drive::identity::key::fetch::{
use drive::drive::Drive;
use drive::error::proof::ProofError;
use drive::query::contested_resource_votes_given_by_identity_query::ContestedResourceVotesGivenByIdentityQuery;
use drive::query::proposer_block_count_query::ProposerQueryType;
use drive::query::vote_poll_contestant_votes_query::ContestedDocumentVotePollVotesDriveQuery;
use drive::query::vote_poll_vote_state_query::ContestedDocumentVotePollDriveQuery;
use drive::query::vote_polls_by_document_type_query::VotePollsByDocumentTypeQuery;
use drive::query::{DriveDocumentQuery, VotePollsByEndDateDriveQuery};
use std::array::TryFromSliceError;
use std::collections::BTreeMap;
use std::num::TryFromIntError;
use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::get_evonodes_proposed_epoch_blocks_by_range_request_v0::Start;
use drive::query::proposer_block_count_query::ProposerQueryType;

/// Parse and verify the received proof and retrieve the requested object, if any.
///
Expand Down Expand Up @@ -78,7 +80,7 @@ pub trait FromProof<Req> {
///
/// * `Ok(Some(object, metadata))` when the requested object was found in the proof.
/// * `Ok(None)` when the requested object was not found in the proof; this can be interpreted as proof of non-existence.
/// For collections, returns Ok(None) if none of the requested objects were found.
/// For collections, returns Ok(None) if none of the requested objects were found.
/// * `Err(Error)` when either the provided data is invalid or proof validation failed.
fn maybe_from_proof<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
request: I,
Expand Down Expand Up @@ -108,7 +110,7 @@ pub trait FromProof<Req> {
///
/// * `Ok(Some((object, metadata)))` when the requested object was found in the proof.
/// * `Ok(None)` when the requested object was not found in the proof; this can be interpreted as proof of non-existence.
/// For collections, returns Ok(None) if none of the requested objects were found.
/// For collections, returns Ok(None) if none of the requested objects were found.
/// * `Err(Error)` when either the provided data is invalid or proof validation failed.
fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
request: I,
Expand Down Expand Up @@ -1714,7 +1716,6 @@ impl FromProof<platform::GetTotalCreditsInPlatformRequest> for TotalCreditsInPla
))
}
}

impl FromProof<platform::GetEvonodesProposedEpochBlocksByIdsRequest> for ProposerBlockCounts {
type Request = platform::GetEvonodesProposedEpochBlocksByIdsRequest;
type Response = platform::GetEvonodesProposedEpochBlocksResponse;
Expand Down
164 changes: 163 additions & 1 deletion packages/rs-drive-proof-verifier/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! In this case, the [FromProof](crate::FromProof) trait is implemented for dedicated object type
//! defined in this module.

use dapi_grpc::platform::v0::GetStatusResponse;
use dpp::data_contract::document_type::DocumentType;
use dpp::fee::Credits;
use dpp::platform_value::Value;
Expand All @@ -25,13 +26,15 @@ use dpp::{
util::deserializer::ProtocolVersion,
};
use drive::grovedb::Element;
use hex::ToHex;
use std::collections::{BTreeMap, BTreeSet};

use crate::Error;
use dpp::block::block_info::BlockInfo;
use dpp::core_types::validator_set::ValidatorSet;
use dpp::dashcore::QuorumHash;
use dpp::voting::vote_info_storage::contested_document_vote_poll_winner_info::ContestedDocumentVotePollWinnerInfo;
use drive::grovedb::query_result_type::Path;

#[cfg(feature = "mocks")]
use {
bincode::{Decode, Encode},
Expand Down Expand Up @@ -614,3 +617,162 @@ pub struct ProposerBlockCountByRange(pub u64);
#[derive(Debug)]
#[cfg_attr(feature = "mocks", derive(serde::Serialize, serde::Deserialize))]
pub struct ProposerBlockCountById(pub u64);

#[derive(Debug, Clone)]
#[cfg_attr(
feature = "mocks",
derive(Encode, Decode, PlatformSerialize, PlatformDeserialize),
platform_serialize(unversioned)
)]
/// Status of a network node.
///
/// Some fields may be `None` if the information is not available, eg. when the node is not fully functional.
pub struct EvonodeStatus {
Copy link
Member

Choose a reason for hiding this comment

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

Let's have it nested as proto otherwise it's too messy

Copy link
Contributor

Choose a reason for hiding this comment

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

done

/// The Identifier of the Evonode
pub pro_tx_hash: Option<[u8; ProTxHash::LEN]>, // We don't use ProTxHash as it doesn't implement Encode/Decode
/// The latest block height stored on the Evonode
pub latest_block_height: Option<u64>,
/// Version of DAPI service
pub dapi_version: Option<String>,
/// Version of Drive-ABCI service
pub drive_version: Option<String>,
/// Version of Tenderdash service
pub tenderdash_version: Option<String>,
/// Tenderdash P2P protocol version information
pub tenderdash_p2p_protocol: Option<u32>,
/// Tenderdash block protocol version information
pub tenderdash_block_protocol: Option<u32>,
/// Latest supported Drive protocol version
pub drive_latest_protocol: Option<u32>,
/// Current active Drive protocol version
pub drive_current_protocol: Option<u32>,
/// Local time of the node, in seconds since the Unix epoch
pub local_time: Option<u64>,
/// Last block time, in seconds since the Unix epoch
pub block_time: Option<u64>,
/// Genesis time, in seconds since the Unix epoch
pub genesis_time: Option<u64>,
/// Time of the current epoch
pub epoch_time: Option<u32>,
/// Tenderdash node ID (public key derived from the private key)
pub tenderdash_node_id: Option<Vec<u8>>,
/// Information if the node is catching up the Platform chain (Tenderdash)
pub catching_up: Option<bool>,
/// Latest platfom block hash
pub latest_block_hash: Option<Vec<u8>>,
/// Latest platform app hash
pub latest_app_hash: Option<Vec<u8>>,
/// Earliest block hash stored by the node
pub earliest_block_hash: Option<Vec<u8>>,
/// Earliest app hash stored by the node
pub earliest_app_hash: Option<Vec<u8>>,
/// Earliest block height stored by the node
pub earliest_block_height: Option<u64>,
/// Maximum block height of the peers
pub max_peer_block_height: Option<u64>,
/// Core chain locked height used by the node
pub core_chain_locked_height: Option<u32>,
/// Network chain ID
pub chain_id: Option<String>,
/// Number of peers in the addressbook
pub peers_count: Option<u32>,
/// Information if the node is listening for incoming connections
pub listening: Option<bool>,
/// State sync total time
pub sync_total_time: Option<u64>,
/// State sync remaining time
pub sync_remaining_time: Option<u64>,
/// State sync total snapshots
pub sync_total_snapshots: Option<u32>,
/// State sync chunk process average time
pub sync_chunk_process_avg_time: Option<u64>,
/// State sync snapshot height
pub sync_snapshot_height: Option<u64>,
/// State sync snapshot chunks count
pub sync_snapshot_chunks_count: Option<u64>,
/// State sync backfilled blocks
pub sync_backfilled_blocks: Option<u64>,
/// State sync backfill blocks total
pub sync_backfill_blocks_total: Option<u64>,
}

impl TryFrom<GetStatusResponse> for EvonodeStatus {
type Error = Error;
fn try_from(response: GetStatusResponse) -> Result<Self, Self::Error> {
use dapi_grpc::platform::v0::get_status_response::Version;
match response.version {
Some(Version::V0(v0)) => {
let node = v0.node;
let chain = v0.chain;
let protx: Option<[u8; ProTxHash::LEN]> = node
.as_ref()
.and_then(|n| {
n.pro_tx_hash.as_ref().map(|h| {
h.clone().try_into().map_err(|_| Error::ProtocolError {
error: format!(
"unvalid protxhash length: {:?}",
h.encode_hex::<String>()
),
})
})
})
.transpose()?;

let software = v0.version.as_ref().and_then(|v| v.software.clone());
let protocol = v0.version.as_ref().and_then(|v| v.protocol.clone());

let tenderdash_protocol = protocol.as_ref().and_then(|p| p.tenderdash.clone());
let drive_protocol = protocol.as_ref().and_then(|p| p.drive.clone());

let time = v0.time;
let network = v0.network;
let state_sync = v0.state_sync;

Ok(Self {
pro_tx_hash: protx,
latest_block_height: chain.as_ref().map(|c| c.latest_block_height),
dapi_version: software.as_ref().map(|s| s.dapi.clone()),
drive_version: software.as_ref().and_then(|s| s.drive.clone()),
tenderdash_version: software.as_ref().and_then(|s| s.tenderdash.clone()),
tenderdash_p2p_protocol: tenderdash_protocol.as_ref().map(|p| p.p2p),
tenderdash_block_protocol: tenderdash_protocol.as_ref().map(|p| p.block),
drive_latest_protocol: drive_protocol.as_ref().map(|d| d.latest),
drive_current_protocol: drive_protocol.as_ref().map(|d| d.current),
local_time: time.as_ref().map(|t| t.local),
block_time: time.as_ref().and_then(|t| t.block),
genesis_time: time.as_ref().and_then(|t| t.genesis),
epoch_time: time.as_ref().and_then(|t| t.epoch),
tenderdash_node_id: node.as_ref().map(|n| n.id.clone()),
catching_up: chain.as_ref().map(|c| c.catching_up),
latest_block_hash: chain.as_ref().map(|c| c.latest_block_hash.clone()),
latest_app_hash: chain.as_ref().map(|c| c.latest_app_hash.clone()),
earliest_block_hash: chain.as_ref().map(|c| c.earliest_block_hash.clone()),
earliest_app_hash: chain.as_ref().map(|c| c.earliest_app_hash.clone()),
earliest_block_height: chain.as_ref().map(|c| c.earliest_block_height),
max_peer_block_height: chain.as_ref().map(|c| c.max_peer_block_height),
core_chain_locked_height: chain
.as_ref()
.and_then(|c| c.core_chain_locked_height),
chain_id: network.as_ref().map(|n| n.chain_id.clone()),
peers_count: network.as_ref().map(|n| n.peers_count),
listening: network.as_ref().map(|n| n.listening),
sync_total_time: state_sync.as_ref().map(|s| s.total_synced_time),
sync_remaining_time: state_sync.as_ref().map(|s| s.remaining_time),
sync_total_snapshots: state_sync.as_ref().map(|s| s.total_snapshots),
sync_chunk_process_avg_time: state_sync
.as_ref()
.map(|s| s.chunk_process_avg_time),
sync_snapshot_height: state_sync.as_ref().map(|s| s.snapshot_height),
sync_snapshot_chunks_count: state_sync
.as_ref()
.map(|s| s.snapshot_chunks_count),
sync_backfilled_blocks: state_sync.as_ref().map(|s| s.backfilled_blocks),
sync_backfill_blocks_total: state_sync
.as_ref()
.map(|s| s.backfill_blocks_total),
})
}
None => Err(Error::EmptyVersion),
}
}
}
23 changes: 22 additions & 1 deletion packages/rs-drive-proof-verifier/src/unproved.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::types::CurrentQuorumsInfo;
use crate::types::{CurrentQuorumsInfo, EvonodeStatus};
use crate::Error;
use dapi_grpc::platform::v0::ResponseMetadata;
use dapi_grpc::platform::v0::{self as platform};
use dapi_grpc::tonic::async_trait;
use dpp::bls_signatures::PublicKey as BlsPublicKey;
use dpp::core_types::validator::v0::ValidatorV0;
use dpp::core_types::validator_set::v0::ValidatorSetV0;
Expand Down Expand Up @@ -273,3 +274,23 @@ impl FromUnproved<platform::GetCurrentQuorumsInfoRequest> for CurrentQuorumsInfo
Ok((Some(info), metadata))
}
}

#[async_trait]
impl FromUnproved<platform::GetStatusRequest> for EvonodeStatus {
type Request = platform::GetStatusRequest;
type Response = platform::GetStatusResponse;

fn maybe_from_unproved_with_metadata<I: Into<Self::Request>, O: Into<Self::Response>>(
_request: I,
response: O,
_network: Network,
_platform_version: &PlatformVersion,
) -> Result<(Option<Self>, ResponseMetadata), Error>
where
Self: Sized,
{
let status = Self::try_from(response.into())?;
// we use default response metadata, as this request does not return any metadata
Ok((Some(status), Default::default()))
}
}
2 changes: 1 addition & 1 deletion packages/rs-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ serde = { version = "1.0.197", default-features = false, features = [
], optional = true }
serde_json = { version = "1.0", features = ["preserve_order"], optional = true }
tracing = { version = "0.1.40" }
hex = { version = "0.4.3"}
hex = { version = "0.4.3" }
dotenvy = { version = "0.15.7", optional = true }
envy = { version = "0.4.2", optional = true }
futures = { version = "0.3.30" }
Expand Down
Loading
Loading