diff --git a/grpc/src/grpc.rs b/grpc/src/grpc.rs index 1ad405d2c..c04229f14 100644 --- a/grpc/src/grpc.rs +++ b/grpc/src/grpc.rs @@ -11,9 +11,12 @@ use celestia_proto::cosmos::auth::v1beta1::query_client::QueryClient as AuthQuer use celestia_proto::cosmos::bank::v1beta1::query_client::QueryClient as BankQueryClient; pub use celestia_proto::cosmos::base::abci::v1beta1::GasInfo; use celestia_proto::cosmos::base::node::v1beta1::service_client::ServiceClient as ConfigServiceClient; +use celestia_proto::cosmos::base::node::v1beta1::ConfigResponse; use celestia_proto::cosmos::base::tendermint::v1beta1::service_client::ServiceClient as TendermintServiceClient; use celestia_proto::cosmos::staking::v1beta1::query_client::QueryClient as StakingQueryClient; use celestia_proto::cosmos::tx::v1beta1::service_client::ServiceClient as TxServiceClient; +use celestia_proto::tendermint_celestia_mods::rpc::grpc::block_api_client::BlockApiClient; +use celestia_proto::tendermint_celestia_mods::rpc::grpc::StatusResponse; use celestia_types::blob::BlobParams; use celestia_types::block::Block; use celestia_types::consts::appconsts; @@ -50,6 +53,8 @@ mod celestia_tx; mod blob; // cosmos.tx mod cosmos_tx; +// tendermint.rpc.grpc +mod tendermint_rpc; pub use crate::grpc::celestia_tx::{TxStatus, TxStatusResponse}; pub use crate::grpc::cosmos_tx::{BroadcastMode, GetTxResponse}; @@ -176,10 +181,25 @@ where // cosmos.base.node - /// Get Minimum Gas price + /// Get node's minimum gas price #[grpc_method(ConfigServiceClient::config)] async fn get_min_gas_price(&self) -> Result; + /// Get node's config + #[grpc_method(ConfigServiceClient::config)] + async fn get_node_config(&self) -> Result; + + // tendermint.rpc.grpc + // TODO: expose all api's from this module + + /// Get node's status + /// + /// Please note that this uses `tendermint.rpc.grpc.BlockAPI` from + /// `celestia-core` fork of commetbft rather than `cosmos.base.node.v1beta1.Service` + /// to get more celestia specific info. + #[grpc_method(BlockApiClient::status)] + async fn get_node_status(&self) -> Result; + // cosmos.base.tendermint /// Get latest block @@ -320,7 +340,7 @@ pub(crate) trait IntoGrpcParam { macro_rules! make_empty_params { ($request_type:ident) => { - impl crate::grpc::IntoGrpcParam<$request_type> for () { + impl $crate::grpc::IntoGrpcParam<$request_type> for () { fn into_parameter(self) -> $request_type { $request_type {} } @@ -328,4 +348,15 @@ macro_rules! make_empty_params { }; } +macro_rules! make_response_identity { + ($response_type:ident) => { + impl $crate::grpc::FromGrpcResponse<$response_type> for $response_type { + fn try_from_response(self) -> $crate::Result<$response_type> { + Ok(self) + } + } + }; +} + pub(crate) use make_empty_params; +pub(crate) use make_response_identity; diff --git a/grpc/src/grpc/node.rs b/grpc/src/grpc/node.rs index 7fd0451ea..74a0fcb6b 100644 --- a/grpc/src/grpc/node.rs +++ b/grpc/src/grpc/node.rs @@ -1,6 +1,6 @@ use celestia_proto::cosmos::base::node::v1beta1::{ConfigRequest, ConfigResponse}; -use crate::grpc::{make_empty_params, FromGrpcResponse}; +use crate::grpc::{make_empty_params, make_response_identity, FromGrpcResponse}; use crate::{Error, Result}; impl FromGrpcResponse for ConfigResponse { @@ -19,4 +19,6 @@ impl FromGrpcResponse for ConfigResponse { } } +make_response_identity!(ConfigResponse); + make_empty_params!(ConfigRequest); diff --git a/grpc/src/grpc/tendermint_rpc.rs b/grpc/src/grpc/tendermint_rpc.rs new file mode 100644 index 000000000..cc8bb9a44 --- /dev/null +++ b/grpc/src/grpc/tendermint_rpc.rs @@ -0,0 +1,138 @@ +use celestia_proto::tendermint_celestia_mods::rpc::grpc::{ + StatusRequest, StatusResponse as RawStatusResponse, +}; +use celestia_types::{Hash, Height}; +use tendermint::{validator, AppHash, Time}; +use tendermint_proto::v0_38::p2p::DefaultNodeInfo; +#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))] +use wasm_bindgen::prelude::wasm_bindgen; +#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))] +use wasm_bindgen::JsValue; + +use crate::grpc::{make_empty_params, make_response_identity}; + +/// A state of the blockchain synchronization of consensus node. +#[derive(Clone, Debug, PartialEq, Eq)] +// #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +#[cfg_attr( + all(target_arch = "wasm32", feature = "wasm-bindgen"), + wasm_bindgen(getter_with_clone) +)] +pub struct SyncInfo { + /// Hash of the latest block synced by the node + #[cfg_attr( + all(target_arch = "wasm32", feature = "wasm-bindgen"), + wasm_bindgen(js_name = latestBlockHash) + )] + pub latest_block_hash: Hash, + + /// App hash of the latest block synced by the node + #[cfg_attr( + all(target_arch = "wasm32", feature = "wasm-bindgen"), + wasm_bindgen(js_name = latestAppHash) + )] + pub latest_app_hash: AppHash, + + /// Height of the latest block synced by the node + #[cfg_attr( + all(target_arch = "wasm32", feature = "wasm-bindgen"), + wasm_bindgen(skip) + )] + pub latest_block_height: Height, + + /// Time of the latest block synced by the node + #[cfg_attr( + all(target_arch = "wasm32", feature = "wasm-bindgen"), + wasm_bindgen(skip) + )] + pub latest_block_time: Time, + + /// Hash of the earliest block synced by the node + #[cfg_attr( + all(target_arch = "wasm32", feature = "wasm-bindgen"), + wasm_bindgen(js_name = earliestBlockHash) + )] + pub earliest_block_hash: Hash, + + /// App hash of the earliest block synced by the node + #[cfg_attr( + all(target_arch = "wasm32", feature = "wasm-bindgen"), + wasm_bindgen(js_name = earliestAppHash) + )] + pub earliest_app_hash: AppHash, + + /// Height of the earliest block synced by the node + #[cfg_attr( + all(target_arch = "wasm32", feature = "wasm-bindgen"), + wasm_bindgen(skip) + )] + pub earliest_block_height: Height, + + /// Time of the earliest block synced by the node + #[cfg_attr( + all(target_arch = "wasm32", feature = "wasm-bindgen"), + wasm_bindgen(skip) + )] + pub earliest_block_time: Time, + + /// Indicates if node is still during initial sync + #[cfg_attr( + all(target_arch = "wasm32", feature = "wasm-bindgen"), + wasm_bindgen(js_name = catchingUp) + )] + pub catching_up: bool, +} + +#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))] +#[wasm_bindgen] +impl SyncInfo { + /// Height of the latest block synced by the node + #[wasm_bindgen(getter, js_name = latestBlockHeight)] + pub fn js_latest_block_height(&self) -> u64 { + self.latest_block_height.value() + } + + /// Time of the latest block synced by the node + #[wasm_bindgen(getter, js_name = latestBlockTime)] + pub fn js_latest_block_time(&self) -> Result { + Ok(self + .latest_block_time + .duration_since(Time::unix_epoch()) + .map_err(|e| JsError::new(&e.to_string()))? + .as_secs_f64() + * 1000.0) + } + + /// Height of the earliest block synced by the node + #[wasm_bindgen(getter, js_name = earliestBlockHeight)] + pub fn js_earliest_block_height(&self) -> u64 { + self.earliest_block_height.value() + } + + /// Time of the earliest block synced by the node + #[wasm_bindgen(getter, js_name = earliestBlockTime)] + pub fn js_earliest_block_time(&self) -> Result { + Ok(self + .earliest_block_time + .duration_since(Time::unix_epoch()) + .map_err(|e| JsError::new(&e.to_string()))? + .as_secs_f64() + * 1000.0) + } +} + +/// A state of the blockchain synchronization of consensus node. +#[derive(Clone, Debug, PartialEq)] +// #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +#[cfg_attr( + all(target_arch = "wasm32", feature = "wasm-bindgen"), + wasm_bindgen(getter_with_clone) +)] +pub struct StatusResponse { + node_info: DefaultNodeInfo, + sync_info: SyncInfo, + validator_info: validator::Info, +} + +make_response_identity!(StatusResponse); +make_empty_params!(StatusRequest); diff --git a/grpc/src/js_client/grpc_client.rs b/grpc/src/js_client/grpc_client.rs index ae8572586..c57306cd0 100644 --- a/grpc/src/js_client/grpc_client.rs +++ b/grpc/src/js_client/grpc_client.rs @@ -1,5 +1,6 @@ use wasm_bindgen::prelude::*; +use celestia_proto::tendermint_celestia_mods::rpc::grpc::StatusResponse; use celestia_types::blob::BlobParams; use celestia_types::block::Block; use celestia_types::state::auth::{JsAuthParams, JsBaseAccount}; @@ -107,11 +108,20 @@ impl GrpcClient { .collect()) } - /// Get Minimum Gas price + /// Get node's minimum gas price pub async fn get_min_gas_price(&self) -> Result { self.client.get_min_gas_price().await } + /// Get node's status + /// + /// Please note that this uses `tendermint.rpc.grpc.BlockAPI` from + /// `celestia-core` fork of commetbft rather than `cosmos.base.node.v1beta1.Service` + /// to get more celestia specific info. + pub async fn get_node_status(&self) -> Result { + self.client.get_node_status().await + } + /// Get latest block pub async fn get_latest_block(&self) -> Result { self.client.get_latest_block().await