Skip to content

Commit c827402

Browse files
author
Adrian Nagy
committed
feat(GraphQL): expand daemonStatus endpoint with consensus times
1 parent 449c214 commit c827402

File tree

16 files changed

+304
-27
lines changed

16 files changed

+304
-27
lines changed

core/src/block/block_with_hash.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ impl<T: AsRef<Block>> BlockWithHash<T> {
6161
global_slot(self.header())
6262
}
6363

64+
pub fn slot(&self) -> u32 {
65+
slot(self.header())
66+
}
67+
6468
pub fn global_slot_since_genesis(&self) -> u32 {
6569
global_slot_since_genesis(self.header())
6670
}
@@ -180,6 +184,10 @@ impl<T: AsRef<BlockHeader>> BlockHeaderWithHash<T> {
180184
global_slot(self.header())
181185
}
182186

187+
pub fn slot(&self) -> u32 {
188+
slot(self.header())
189+
}
190+
183191
pub fn global_slot_since_genesis(&self) -> u32 {
184192
global_slot_since_genesis(self.header())
185193
}
@@ -251,6 +259,15 @@ fn global_slot(header: &BlockHeader) -> u32 {
251259
consensus_state(header).global_slot()
252260
}
253261

262+
fn slot(header: &BlockHeader) -> u32 {
263+
let slot_struct = &consensus_state(header).curr_global_slot_since_hard_fork;
264+
slot_struct
265+
.slot_number
266+
.as_u32()
267+
.checked_rem(slot_struct.slots_per_epoch.as_u32())
268+
.expect("division by zero")
269+
}
270+
254271
fn global_slot_since_genesis(header: &BlockHeader) -> u32 {
255272
consensus_state(header).global_slot_since_genesis.as_u32()
256273
}

core/src/consensus.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use mina_p2p_messages::v2::{
22
self, BlockTimeTimeStableV1,
33
ConsensusProofOfStakeDataConsensusStateValueStableV2 as MinaConsensusState, StateHash,
44
};
5+
use redux::Timestamp;
56
use serde::{Deserialize, Serialize};
67
use time::{macros::format_description, OffsetDateTime};
78

@@ -30,6 +31,15 @@ pub enum ConsensusLongRangeForkDecisionReason {
3031
StateHash,
3132
}
3233

34+
#[derive(Debug, Clone, Serialize, Deserialize)]
35+
pub struct ConsensusTime {
36+
pub start_time: Timestamp,
37+
pub end_time: Timestamp,
38+
pub epoch: u32,
39+
pub global_slot: u32,
40+
pub slot: u32,
41+
}
42+
3343
// TODO(binier): do we need to verify constants? Probably they are verified
3444
// using block proof verification, but check just to be sure.
3545
pub fn is_short_range_fork(a: &MinaConsensusState, b: &MinaConsensusState) -> bool {

node/common/src/service/rpc/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ pub mod transition_frontier;
99

1010
use node::rpc::{
1111
RpcBestChainResponse, RpcBlockProducerStatsGetResponse, RpcConsensusConstantsGetResponse,
12-
RpcDiscoveryBoostrapStatsResponse, RpcDiscoveryRoutingTableResponse, RpcGenesisBlockResponse,
13-
RpcGetBlockResponse, RpcHealthCheckResponse, RpcHeartbeatGetResponse,
12+
RpcConsensusTimeGetResponse, RpcDiscoveryBoostrapStatsResponse, RpcDiscoveryRoutingTableResponse,
13+
RpcGenesisBlockResponse, RpcGetBlockResponse, RpcHealthCheckResponse, RpcHeartbeatGetResponse,
1414
RpcLedgerAccountsResponse, RpcLedgerSlimAccountsResponse, RpcMessageProgressResponse,
1515
RpcPeersGetResponse, RpcPooledUserCommandsResponse, RpcPooledZkappCommandsResponse,
1616
RpcReadinessCheckResponse, RpcRequest, RpcSnarkPoolCompletedJobsResponse,
@@ -325,6 +325,7 @@ impl node::rpc_effectful::RpcService for NodeService {
325325
RpcPooledZkappCommandsResponse
326326
);
327327
rpc_service_impl!(respond_genesis_block, RpcGenesisBlockResponse);
328+
rpc_service_impl!(respond_consensus_time_get, RpcConsensusTimeGetResponse);
328329
}
329330

330331
#[cfg(test)]

node/native/src/graphql/constants.rs

Lines changed: 142 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,120 @@
11
use juniper::GraphQLObject;
2-
use openmina_core::{consensus::ConsensusConstants, constants::ConstraintConstants};
2+
use node::rpc::{
3+
ConsensusTimeQuery, PeerConnectionStatus, RpcConsensusTimeGetResponse, RpcPeerInfo, RpcRequest,
4+
};
5+
use openmina_core::{
6+
consensus::{ConsensusConstants, ConsensusTime},
7+
constants::ConstraintConstants,
8+
};
39

4-
use super::ConversionError;
10+
use super::{Context, ConversionError, Error};
11+
12+
#[derive(Clone, Debug, Copy)]
13+
pub(crate) struct GraphQLDaemonStatus;
14+
15+
#[juniper::graphql_object(context = Context)]
16+
impl GraphQLDaemonStatus {
17+
async fn consensus_configuration(
18+
&self,
19+
context: &Context,
20+
) -> juniper::FieldResult<GraphQLConsensusConfiguration> {
21+
let consensus_constants: ConsensusConstants = context
22+
.0
23+
.oneshot_request(RpcRequest::ConsensusConstantsGet)
24+
.await
25+
.ok_or(Error::StateMachineEmptyResponse)?;
26+
Ok(GraphQLConsensusConfiguration::from(consensus_constants))
27+
}
28+
29+
async fn peers(&self, context: &Context) -> juniper::FieldResult<Vec<GraphQLRpcPeerInfo>> {
30+
let peers: Vec<RpcPeerInfo> = context
31+
.0
32+
.oneshot_request(RpcRequest::PeersGet)
33+
.await
34+
.ok_or(Error::StateMachineEmptyResponse)?;
35+
36+
let connected_peers = peers
37+
.iter()
38+
.filter(|peer| matches!(peer.connection_status, PeerConnectionStatus::Connected))
39+
.map(GraphQLRpcPeerInfo::from)
40+
.collect();
41+
42+
Ok(connected_peers)
43+
}
44+
45+
async fn consensus_time_now(
46+
&self,
47+
context: &Context,
48+
) -> juniper::FieldResult<GraphQLConsensusTime> {
49+
let consensus_time: RpcConsensusTimeGetResponse = context
50+
.0
51+
.oneshot_request(RpcRequest::ConsensusTimeGet(ConsensusTimeQuery::Now))
52+
.await
53+
.ok_or(Error::StateMachineEmptyResponse)?;
54+
55+
match consensus_time {
56+
Some(consensus_time) => Ok(GraphQLConsensusTime::from(consensus_time)),
57+
None => Err(juniper::FieldError::new(
58+
"No consensus time found",
59+
juniper::Value::Null,
60+
)),
61+
}
62+
}
63+
64+
async fn consensus_time_best_tip(
65+
&self,
66+
context: &Context,
67+
) -> juniper::FieldResult<GraphQLConsensusTime> {
68+
let consensus_time_res: RpcConsensusTimeGetResponse = context
69+
.0
70+
.oneshot_request(RpcRequest::ConsensusTimeGet(ConsensusTimeQuery::BestTip))
71+
.await
72+
.ok_or(Error::StateMachineEmptyResponse)?;
73+
74+
match consensus_time_res {
75+
Some(consensus_time) => Ok(GraphQLConsensusTime::from(consensus_time)),
76+
None => Err(juniper::FieldError::new(
77+
"No consensus time found",
78+
juniper::Value::Null,
79+
)),
80+
}
81+
}
82+
}
83+
84+
#[derive(GraphQLObject, Clone, Debug)]
85+
pub struct GraphQLRpcPeerInfo {
86+
pub peer_id: String,
87+
pub best_tip: Option<String>,
88+
pub best_tip_height: Option<String>,
89+
pub best_tip_global_slot: Option<String>,
90+
pub best_tip_timestamp: Option<String>,
91+
pub connection_status: String,
92+
pub connecting_details: Option<String>,
93+
pub address: Option<String>,
94+
pub incoming: bool,
95+
pub is_libp2p: bool,
96+
pub time: String,
97+
}
98+
99+
impl From<&RpcPeerInfo> for GraphQLRpcPeerInfo {
100+
fn from(peer: &RpcPeerInfo) -> Self {
101+
Self {
102+
peer_id: peer.peer_id.to_string(),
103+
best_tip: peer.best_tip.as_ref().map(|hash| hash.to_string()),
104+
best_tip_height: peer.best_tip_height.map(|height| height.to_string()),
105+
best_tip_global_slot: peer.best_tip_global_slot.map(|slot| slot.to_string()),
106+
best_tip_timestamp: peer
107+
.best_tip_timestamp
108+
.map(|timestamp| timestamp.to_string()),
109+
connection_status: peer.connection_status.to_string(),
110+
connecting_details: peer.connecting_details.clone(),
111+
address: peer.address.clone(),
112+
incoming: peer.incoming,
113+
is_libp2p: peer.is_libp2p,
114+
time: peer.time.to_string(),
115+
}
116+
}
117+
}
5118

6119
#[derive(GraphQLObject, Debug)]
7120
pub struct GraphQLGenesisConstants {
@@ -25,11 +138,6 @@ impl GraphQLGenesisConstants {
25138
}
26139
}
27140

28-
#[derive(GraphQLObject, Debug)]
29-
pub struct GraphQLDaemonStatus {
30-
pub consensus_configuration: GraphQLConsensusConfiguration,
31-
}
32-
33141
#[derive(GraphQLObject, Debug)]
34142
pub struct GraphQLConsensusConfiguration {
35143
pub epoch_duration: i32,
@@ -48,3 +156,30 @@ impl From<ConsensusConstants> for GraphQLConsensusConfiguration {
48156
}
49157
}
50158
}
159+
160+
#[derive(GraphQLObject, Debug)]
161+
pub struct GraphQLConsensusTime {
162+
pub start_time: String,
163+
pub end_time: String,
164+
pub epoch: String,
165+
pub global_slot: String,
166+
pub slot: String,
167+
}
168+
169+
impl From<ConsensusTime> for GraphQLConsensusTime {
170+
fn from(consensus_time: ConsensusTime) -> Self {
171+
let start_time: u64 = consensus_time.start_time.into();
172+
let end_time: u64 = consensus_time.end_time.into();
173+
174+
let start_time_ms = start_time.checked_div(1_000_000).expect("division by zero");
175+
let end_time_ms = end_time.checked_div(1_000_000).expect("division by zero");
176+
177+
GraphQLConsensusTime {
178+
start_time: start_time_ms.to_string(),
179+
end_time: end_time_ms.to_string(),
180+
epoch: consensus_time.epoch.to_string(),
181+
global_slot: consensus_time.global_slot.to_string(),
182+
slot: consensus_time.slot.to_string(),
183+
}
184+
}
185+
}

node/native/src/graphql/mod.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,20 @@ impl From<ConversionError> for Error {
8989
}
9090
}
9191

92-
struct Context(RpcSender);
92+
pub(crate) struct Context(RpcSender);
9393

9494
impl juniper::Context for Context {}
9595

96+
// impl Context {
97+
// pub(crate) async fn get_or_fetch_status(&self) -> RpcStatusGetResponse {
98+
// let result: RpcStatusGetResponse = self
99+
// .0
100+
// .oneshot_request(RpcRequest::StatusGet)
101+
// .await
102+
// .flatten();
103+
// }
104+
// }
105+
96106
#[derive(Clone, Copy, Debug, GraphQLEnum)]
97107
#[allow(clippy::upper_case_acronyms)]
98108
enum SyncStatus {
@@ -227,16 +237,9 @@ impl Query {
227237
}
228238

229239
async fn daemon_status(
230-
context: &Context,
240+
_context: &Context,
231241
) -> juniper::FieldResult<constants::GraphQLDaemonStatus> {
232-
let consensus_constants: ConsensusConstants = context
233-
.0
234-
.oneshot_request(RpcRequest::ConsensusConstantsGet)
235-
.await
236-
.ok_or(Error::StateMachineEmptyResponse)?;
237-
Ok(constants::GraphQLDaemonStatus {
238-
consensus_configuration: consensus_constants.into(),
239-
})
242+
Ok(constants::GraphQLDaemonStatus)
240243
}
241244

242245
async fn genesis_constants(

node/src/action_kind.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ pub enum ActionKind {
473473
RpcBlockGet,
474474
RpcBlockProducerStatsGet,
475475
RpcConsensusConstantsGet,
476+
RpcConsensusTimeGet,
476477
RpcDiscoveryBoostrapStats,
477478
RpcDiscoveryRoutingTable,
478479
RpcFinish,
@@ -525,6 +526,7 @@ pub enum ActionKind {
525526
RpcEffectfulBlockGet,
526527
RpcEffectfulBlockProducerStatsGet,
527528
RpcEffectfulConsensusConstantsGet,
529+
RpcEffectfulConsensusTimeGet,
528530
RpcEffectfulDiscoveryBoostrapStats,
529531
RpcEffectfulDiscoveryRoutingTable,
530532
RpcEffectfulGenesisBlock,
@@ -728,7 +730,7 @@ pub enum ActionKind {
728730
}
729731

730732
impl ActionKind {
731-
pub const COUNT: u16 = 618;
733+
pub const COUNT: u16 = 620;
732734
}
733735

734736
impl std::fmt::Display for ActionKind {
@@ -1100,6 +1102,7 @@ impl ActionKindGet for RpcAction {
11001102
Self::ConsensusConstantsGet { .. } => ActionKind::RpcConsensusConstantsGet,
11011103
Self::TransactionStatusGet { .. } => ActionKind::RpcTransactionStatusGet,
11021104
Self::BlockGet { .. } => ActionKind::RpcBlockGet,
1105+
Self::ConsensusTimeGet { .. } => ActionKind::RpcConsensusTimeGet,
11031106
Self::PooledUserCommands { .. } => ActionKind::RpcPooledUserCommands,
11041107
Self::PooledZkappCommands { .. } => ActionKind::RpcPooledZkappCommands,
11051108
Self::GenesisBlock { .. } => ActionKind::RpcGenesisBlock,
@@ -1176,6 +1179,7 @@ impl ActionKindGet for RpcEffectfulAction {
11761179
Self::PooledUserCommands { .. } => ActionKind::RpcEffectfulPooledUserCommands,
11771180
Self::PooledZkappCommands { .. } => ActionKind::RpcEffectfulPooledZkappCommands,
11781181
Self::GenesisBlock { .. } => ActionKind::RpcEffectfulGenesisBlock,
1182+
Self::ConsensusTimeGet { .. } => ActionKind::RpcEffectfulConsensusTimeGet,
11791183
}
11801184
}
11811185
}

node/src/event_source/event.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ impl std::fmt::Display for Event {
7878
RpcRequest::PooledUserCommands(..) => write!(f, "PooledUserCommands"),
7979
RpcRequest::PooledZkappCommands(..) => write!(f, "PooledZkappCommands"),
8080
RpcRequest::GenesisBlockGet => write!(f, "GenesisBlock"),
81+
RpcRequest::ConsensusTimeGet(..) => write!(f, "ConsensusTimeGet"),
8182
}
8283
}
8384
Self::ExternalSnarkWorker(event) => {

node/src/event_source/event_source_effects.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,8 @@ pub fn event_source_effects<S: Service>(store: &mut Store<S>, action: EventSourc
402402
}
403403
RpcRequest::PooledZkappCommands(query) => {
404404
store.dispatch(RpcAction::PooledZkappCommands { rpc_id, query });
405+
RpcRequest::ConsensusTimeGet(query) => {
406+
store.dispatch(RpcAction::ConsensusTimeGet { rpc_id, query });
405407
}
406408
RpcRequest::GenesisBlockGet => {
407409
store.dispatch(RpcAction::GenesisBlock { rpc_id });

node/src/rpc/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use mina_p2p_messages::v2::{
1717
TransactionSnarkWorkTStableV2,
1818
};
1919
use openmina_core::block::{AppliedBlock, ArcBlockWithHash};
20-
use openmina_core::consensus::ConsensusConstants;
20+
use openmina_core::consensus::{ConsensusConstants, ConsensusTime};
2121
use openmina_node_account::AccountPublicKey;
2222
use p2p::bootstrap::P2pNetworkKadBootstrapStats;
2323
pub use rpc_state::*;
@@ -94,6 +94,13 @@ pub enum RpcRequest {
9494
PooledUserCommands(PooledUserCommandsQuery),
9595
PooledZkappCommands(PooledZkappsCommandsQuery),
9696
GenesisBlockGet,
97+
ConsensusTimeGet(ConsensusTimeQuery),
98+
}
99+
100+
#[derive(Serialize, Deserialize, Debug, Clone)]
101+
pub enum ConsensusTimeQuery {
102+
Now,
103+
BestTip,
97104
}
98105

99106
pub type MaxLength = u32;
@@ -166,7 +173,7 @@ pub enum ActionStatsResponse {
166173
ForBlock(ActionStatsForBlock),
167174
}
168175

169-
#[derive(Serialize, Deserialize, Debug, Clone)]
176+
#[derive(Serialize, Deserialize, Debug, Clone, strum_macros::Display)]
170177
pub enum PeerConnectionStatus {
171178
Disconnecting,
172179
Disconnected,
@@ -379,6 +386,7 @@ pub type RpcTransactionStatusGetResponse = TransactionStatus;
379386
pub type RpcPooledUserCommandsResponse = Vec<MinaBaseSignedCommandStableV2>;
380387
pub type RpcPooledZkappCommandsResponse = Vec<MinaBaseZkappCommandTStableV1WireStableV1>;
381388
pub type RpcGenesisBlockResponse = Option<ArcBlockWithHash>;
389+
pub type RpcConsensusTimeGetResponse = Option<ConsensusTime>;
382390

383391
#[derive(Serialize, Deserialize, Debug, Clone, strum_macros::Display)]
384392
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]

0 commit comments

Comments
 (0)