@@ -12,7 +12,7 @@ use node::{
12
12
RpcGetBlockResponse , RpcPooledUserCommandsResponse , RpcPooledZkappCommandsResponse ,
13
13
RpcRequest , RpcSnarkPoolCompletedJobsResponse , RpcSnarkPoolPendingJobsGetResponse ,
14
14
RpcSyncStatsGetResponse , RpcTransactionInjectResponse , RpcTransactionStatusGetResponse ,
15
- SyncStatsQuery ,
15
+ SyncStatsQuery , RpcStatusGetResponse , RpcNodeStatus , RpcBestChainResponse
16
16
} ,
17
17
stats:: sync:: SyncKind ,
18
18
BuildEnv ,
@@ -24,6 +24,7 @@ use openmina_core::{
24
24
use openmina_node_common:: rpc:: RpcSender ;
25
25
use snark:: GraphQLPendingSnarkWork ;
26
26
use std:: str:: FromStr ;
27
+ use tokio:: sync:: OnceCell ;
27
28
use transaction:: GraphQLTransactionStatus ;
28
29
use warp:: { Filter , Rejection , Reply } ;
29
30
use zkapp:: GraphQLZkapp ;
@@ -81,6 +82,8 @@ pub enum ConversionError {
81
82
Custom ( String ) ,
82
83
#[ error( transparent) ]
83
84
FieldHelpers ( #[ from] FieldHelpersError ) ,
85
+ #[ error( "Failed to convert integer to i32" ) ]
86
+ Integer ,
84
87
}
85
88
86
89
impl From < ConversionError > for Error {
@@ -89,19 +92,54 @@ impl From<ConversionError> for Error {
89
92
}
90
93
}
91
94
92
- pub ( crate ) struct Context ( RpcSender ) ;
95
+ /// Context for the GraphQL API
96
+ ///
97
+ /// This is used to share state between the GraphQL queries and mutations.
98
+ ///
99
+ /// The caching used here is only valid for the lifetime of the context
100
+ /// i.e. for one request which is the goal as we can have multiple sources for one request.
101
+ /// This optimizes the number of request to the state machine
102
+ pub ( crate ) struct Context {
103
+ rpc_sender : RpcSender ,
104
+ statemachine_status_cache : OnceCell < Option < RpcNodeStatus > > ,
105
+ best_tip_cache : OnceCell < Option < AppliedBlock > > ,
106
+ }
93
107
94
108
impl juniper:: Context for Context { }
95
109
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
- // }
110
+ impl Context {
111
+ pub fn new ( rpc_sender : RpcSender ) -> Self {
112
+ Self {
113
+ rpc_sender,
114
+ statemachine_status_cache : OnceCell :: new ( ) ,
115
+ best_tip_cache : OnceCell :: new ( ) ,
116
+ }
117
+ }
118
+
119
+ pub ( crate ) async fn get_or_fetch_status ( & self ) -> RpcStatusGetResponse {
120
+ self . statemachine_status_cache
121
+ . get_or_init ( || async {
122
+ self . rpc_sender
123
+ . oneshot_request ( RpcRequest :: StatusGet )
124
+ . await
125
+ . flatten ( )
126
+ } )
127
+ . await
128
+ . clone ( )
129
+ }
130
+
131
+ pub ( crate ) async fn get_or_fetch_best_tip ( & self ) -> Option < AppliedBlock > {
132
+ self . best_tip_cache
133
+ . get_or_init ( || async {
134
+ self . rpc_sender
135
+ . oneshot_request ( RpcRequest :: BestChain ( 1 ) )
136
+ . await
137
+ . and_then ( |blocks : RpcBestChainResponse | blocks. first ( ) . cloned ( ) )
138
+ } )
139
+ . await
140
+ . clone ( )
141
+ }
142
+ }
105
143
106
144
#[ derive( Clone , Copy , Debug , GraphQLEnum ) ]
107
145
#[ allow( clippy:: upper_case_acronyms) ]
@@ -185,7 +223,7 @@ impl Query {
185
223
let token_id = TokenIdKeyHash :: from_str ( & token) ?;
186
224
let public_key = AccountPublicKey :: from_str ( & public_key) ?;
187
225
let accounts: Vec < Account > = context
188
- . 0
226
+ . rpc_sender
189
227
. oneshot_request ( RpcRequest :: LedgerAccountsGet (
190
228
AccountQuery :: PubKeyWithTokenId ( public_key, token_id) ,
191
229
) )
@@ -201,7 +239,7 @@ impl Query {
201
239
202
240
async fn sync_status ( context : & Context ) -> juniper:: FieldResult < SyncStatus > {
203
241
let state: RpcSyncStatsGetResponse = context
204
- . 0
242
+ . rpc_sender
205
243
. oneshot_request ( RpcRequest :: SyncStatsGet ( SyncStatsQuery { limit : Some ( 1 ) } ) )
206
244
. await
207
245
. ok_or ( Error :: StateMachineEmptyResponse ) ?;
@@ -225,7 +263,7 @@ impl Query {
225
263
context : & Context ,
226
264
) -> juniper:: FieldResult < Vec < GraphQLBlock > > {
227
265
let best_chain: Vec < AppliedBlock > = context
228
- . 0
266
+ . rpc_sender
229
267
. oneshot_request ( RpcRequest :: BestChain ( max_length as u32 ) )
230
268
. await
231
269
. ok_or ( Error :: StateMachineEmptyResponse ) ?;
@@ -246,7 +284,7 @@ impl Query {
246
284
context : & Context ,
247
285
) -> juniper:: FieldResult < constants:: GraphQLGenesisConstants > {
248
286
let consensus_constants: ConsensusConstants = context
249
- . 0
287
+ . rpc_sender
250
288
. oneshot_request ( RpcRequest :: ConsensusConstantsGet )
251
289
. await
252
290
. ok_or ( Error :: StateMachineEmptyResponse ) ?;
@@ -285,7 +323,7 @@ impl Query {
285
323
. into ( ) ) ;
286
324
} ;
287
325
let res: RpcTransactionStatusGetResponse = context
288
- . 0
326
+ . rpc_sender
289
327
. oneshot_request ( RpcRequest :: TransactionStatusGet ( tx) )
290
328
. await
291
329
. ok_or ( Error :: StateMachineEmptyResponse ) ?;
@@ -311,7 +349,7 @@ impl Query {
311
349
} ;
312
350
313
351
let res: Option < RpcGetBlockResponse > = context
314
- . 0
352
+ . rpc_sender
315
353
. oneshot_request ( RpcRequest :: GetBlock ( query. clone ( ) ) )
316
354
. await ;
317
355
@@ -461,7 +499,7 @@ where
461
499
R : TryFrom < MinaBaseUserCommandStableV2 > ,
462
500
{
463
501
let res: RpcTransactionInjectResponse = context
464
- . 0
502
+ . rpc_sender
465
503
. oneshot_request ( RpcRequest :: TransactionInject ( vec ! [ cmd] ) )
466
504
. await
467
505
. ok_or ( Error :: StateMachineEmptyResponse ) ?;
@@ -527,7 +565,7 @@ impl Mutation {
527
565
. map_err ( |e| Error :: Conversion ( ConversionError :: Base58Check ( e) ) ) ?;
528
566
529
567
let accounts: Vec < Account > = context
530
- . 0
568
+ . rpc_sender
531
569
. oneshot_request ( RpcRequest :: LedgerAccountsGet (
532
570
AccountQuery :: PubKeyWithTokenId ( public_key, token_id) ,
533
571
) )
@@ -557,7 +595,7 @@ impl Mutation {
557
595
558
596
// Grab the sender's account to get the infered nonce
559
597
let accounts: Vec < Account > = context
560
- . 0
598
+ . rpc_sender
561
599
. oneshot_request ( RpcRequest :: LedgerAccountsGet (
562
600
AccountQuery :: PubKeyWithTokenId ( public_key, token_id) ,
563
601
) )
@@ -577,7 +615,7 @@ impl Mutation {
577
615
pub fn routes (
578
616
rpc_sernder : RpcSender ,
579
617
) -> impl Filter < Error = Rejection , Extract = impl Reply > + Clone {
580
- let state = warp:: any ( ) . map ( move || Context ( rpc_sernder. clone ( ) ) ) ;
618
+ let state = warp:: any ( ) . map ( move || Context :: new ( rpc_sernder. clone ( ) ) ) ;
581
619
let schema = RootNode :: new ( Query , Mutation , EmptySubscription :: < Context > :: new ( ) ) ;
582
620
let graphql_filter = juniper_warp:: make_graphql_filter ( schema, state. boxed ( ) ) ;
583
621
let graphiql_filter = juniper_warp:: graphiql_filter ( "/graphql" , None ) ;
0 commit comments