1use ledger::{
2 transaction_pool::{diff, ValidCommandWithHash},
3 Account, AccountId,
4};
5use mina_p2p_messages::v2::{LedgerHash, MinaBaseUserCommandStableV2, TokenIdKeyHash};
6use openmina_core::{block::AppliedBlock, snark::SnarkJobId, ActionEvent};
7use openmina_node_account::AccountPublicKey;
8use p2p::PeerId;
9use serde::{Deserialize, Serialize};
10
11use crate::{
12 external_snark_worker::SnarkWorkId,
13 p2p::connection::{
14 incoming::P2pConnectionIncomingInitOpts,
15 outgoing::{P2pConnectionOutgoingError, P2pConnectionOutgoingInitOpts},
16 P2pConnectionResponse,
17 },
18};
19
20use super::{
21 ActionStatsQuery, ConsensusTimeQuery, GetBlockQuery, PooledUserCommandsQuery,
22 PooledZkappsCommandsQuery, RpcId, RpcLedgerAccountDelegatorsGetResponse,
23 RpcLedgerStatusGetResponse, RpcScanStateSummaryGetQuery, RpcScanStateSummaryScanStateJob,
24 SyncStatsQuery,
25};
26
27#[derive(Serialize, Deserialize, Debug, Clone, ActionEvent)]
28pub enum RpcAction {
29 GlobalStateGet {
30 rpc_id: RpcId,
31 filter: Option<String>,
32 },
33 StatusGet {
34 rpc_id: RpcId,
35 },
36 HeartbeatGet {
37 rpc_id: RpcId,
38 },
39
40 ActionStatsGet {
42 rpc_id: RpcId,
43 query: ActionStatsQuery,
44 },
45 SyncStatsGet {
46 rpc_id: RpcId,
47 query: SyncStatsQuery,
48 },
49 BlockProducerStatsGet {
50 rpc_id: RpcId,
51 },
52
53 MessageProgressGet {
54 rpc_id: RpcId,
55 },
56
57 PeersGet {
58 rpc_id: RpcId,
59 },
60
61 P2pConnectionOutgoingInit {
62 rpc_id: RpcId,
63 opts: P2pConnectionOutgoingInitOpts,
64 },
65 P2pConnectionOutgoingPending {
66 rpc_id: RpcId,
67 },
68 P2pConnectionOutgoingError {
69 rpc_id: RpcId,
70 error: P2pConnectionOutgoingError,
71 },
72 P2pConnectionOutgoingSuccess {
73 rpc_id: RpcId,
74 },
75
76 P2pConnectionIncomingInit {
77 rpc_id: RpcId,
78 opts: P2pConnectionIncomingInitOpts,
79 },
80 P2pConnectionIncomingPending {
81 rpc_id: RpcId,
82 },
83 P2pConnectionIncomingRespond {
84 rpc_id: RpcId,
85 response: P2pConnectionResponse,
86 },
87 P2pConnectionIncomingAnswerReady {
88 rpc_id: RpcId,
89 peer_id: PeerId,
90 answer: P2pConnectionResponse,
91 },
92 P2pConnectionIncomingError {
93 rpc_id: RpcId,
94 error: String,
95 },
96 P2pConnectionIncomingSuccess {
97 rpc_id: RpcId,
98 },
99
100 ScanStateSummaryGetInit {
101 rpc_id: RpcId,
102 query: RpcScanStateSummaryGetQuery,
103 },
104 ScanStateSummaryLedgerGetInit {
105 rpc_id: RpcId,
106 },
107 ScanStateSummaryGetPending {
108 rpc_id: RpcId,
109 block: Option<AppliedBlock>,
110 },
111 ScanStateSummaryGetSuccess {
112 rpc_id: RpcId,
113 scan_state: Result<Vec<Vec<RpcScanStateSummaryScanStateJob>>, String>,
114 },
115
116 SnarkPoolAvailableJobsGet {
117 rpc_id: RpcId,
118 },
119 SnarkPoolJobGet {
120 job_id: SnarkWorkId,
121 rpc_id: RpcId,
122 },
123 SnarkPoolCompletedJobsGet {
124 rpc_id: RpcId,
125 },
126 SnarkPoolPendingJobsGet {
127 rpc_id: RpcId,
128 },
129 SnarkerConfigGet {
130 rpc_id: RpcId,
131 },
132 SnarkerJobCommit {
133 rpc_id: RpcId,
134 job_id: SnarkJobId,
135 },
136 SnarkerJobSpec {
137 rpc_id: RpcId,
138 job_id: SnarkJobId,
139 },
140
141 SnarkerWorkersGet {
142 rpc_id: RpcId,
143 },
144
145 HealthCheck {
146 rpc_id: RpcId,
147 },
148 ReadinessCheck {
149 rpc_id: RpcId,
150 },
151
152 DiscoveryRoutingTable {
153 rpc_id: RpcId,
154 },
155 DiscoveryBoostrapStats {
156 rpc_id: RpcId,
157 },
158
159 TransactionPool {
160 rpc_id: RpcId,
161 },
162 #[action_event(level = info)]
163 LedgerAccountsGetInit {
164 rpc_id: RpcId,
165 account_query: AccountQuery,
166 },
167 #[action_event(level = info)]
168 LedgerAccountsGetPending {
169 rpc_id: RpcId,
170 },
171 #[action_event(level = info)]
172 LedgerAccountsGetSuccess {
173 rpc_id: RpcId,
174 accounts: Vec<Account>,
175 account_query: AccountQuery,
176 },
177 #[action_event(level = info)]
178 TransactionInjectInit {
179 rpc_id: RpcId,
180 commands: Vec<MinaBaseUserCommandStableV2>,
181 },
182 #[action_event(level = info)]
183 TransactionInjectPending {
184 rpc_id: RpcId,
185 },
186 #[action_event(level = info)]
187 TransactionInjectSuccess {
188 rpc_id: RpcId,
189 response: Vec<ValidCommandWithHash>,
190 },
191 #[action_event(level = info)]
192 TransactionInjectRejected {
193 rpc_id: RpcId,
194 response: Vec<(ValidCommandWithHash, diff::Error)>,
195 },
196 #[action_event(level = warn)]
197 TransactionInjectFailure {
198 rpc_id: RpcId,
199 errors: Vec<String>,
200 },
201 #[action_event(level = info)]
202 TransitionFrontierUserCommandsGet {
203 rpc_id: RpcId,
204 },
205
206 BestChain {
207 rpc_id: RpcId,
208 max_length: u32,
209 },
210 ConsensusConstantsGet {
211 rpc_id: RpcId,
212 },
213
214 TransactionStatusGet {
215 rpc_id: RpcId,
216 tx: MinaBaseUserCommandStableV2,
217 },
218
219 BlockGet {
220 rpc_id: RpcId,
221 query: GetBlockQuery,
222 },
223 ConsensusTimeGet {
224 rpc_id: RpcId,
225 query: ConsensusTimeQuery,
226 },
227 LedgerStatusGetInit {
228 rpc_id: RpcId,
229 ledger_hash: LedgerHash,
230 },
231 LedgerStatusGetPending {
232 rpc_id: RpcId,
233 },
234 LedgerStatusGetSuccess {
235 rpc_id: RpcId,
236 response: RpcLedgerStatusGetResponse,
237 },
238 #[action_event(level = info)]
239 LedgerAccountDelegatorsGetInit {
240 rpc_id: RpcId,
241 ledger_hash: LedgerHash,
242 account_id: AccountId,
243 },
244 #[action_event(level = info)]
245 LedgerAccountDelegatorsGetPending {
246 rpc_id: RpcId,
247 },
248 #[action_event(level = info)]
249 LedgerAccountDelegatorsGetSuccess {
250 rpc_id: RpcId,
251 response: RpcLedgerAccountDelegatorsGetResponse,
252 },
253
254 PooledUserCommands {
255 rpc_id: RpcId,
256 query: PooledUserCommandsQuery,
257 },
258 PooledZkappCommands {
259 rpc_id: RpcId,
260 query: PooledZkappsCommandsQuery,
261 },
262 GenesisBlock {
263 rpc_id: RpcId,
264 },
265
266 Finish {
267 rpc_id: RpcId,
268 },
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
272pub enum AccountQuery {
273 All,
274 SinglePublicKey(AccountPublicKey),
275 MultipleIds(Vec<AccountId>),
276 PubKeyWithTokenId(AccountPublicKey, TokenIdKeyHash),
277}
278
279impl redux::EnablingCondition<crate::State> for RpcAction {
280 fn is_enabled(&self, state: &crate::State, _time: redux::Timestamp) -> bool {
281 match self {
282 RpcAction::GlobalStateGet { .. } => true,
283 RpcAction::StatusGet { .. } => true,
284 RpcAction::HeartbeatGet { .. } => true,
285 RpcAction::ActionStatsGet { .. } => true,
286 RpcAction::SyncStatsGet { .. } => true,
287 RpcAction::BlockProducerStatsGet { .. } => true,
288 RpcAction::MessageProgressGet { .. } => true,
289 RpcAction::PeersGet { .. } => true,
290 RpcAction::P2pConnectionOutgoingInit { rpc_id, .. } => {
291 !state.rpc.requests.contains_key(rpc_id)
292 }
293 RpcAction::P2pConnectionOutgoingPending { rpc_id } => state
294 .rpc
295 .requests
296 .get(rpc_id)
297 .is_some_and(|v| v.status.is_init()),
298 RpcAction::P2pConnectionOutgoingError { rpc_id, .. } => state
299 .rpc
300 .requests
301 .get(rpc_id)
302 .is_some_and(|v| v.status.is_pending()),
303 RpcAction::P2pConnectionOutgoingSuccess { rpc_id } => state
304 .rpc
305 .requests
306 .get(rpc_id)
307 .is_some_and(|v| v.status.is_pending()),
308 RpcAction::P2pConnectionIncomingInit { rpc_id, .. } => {
309 !state.rpc.requests.contains_key(rpc_id)
310 }
311 RpcAction::P2pConnectionIncomingPending { rpc_id } => state
312 .rpc
313 .requests
314 .get(rpc_id)
315 .is_some_and(|v| v.status.is_init()),
316 RpcAction::P2pConnectionIncomingRespond { rpc_id, .. }
317 | RpcAction::P2pConnectionIncomingAnswerReady { rpc_id, .. } => state
318 .rpc
319 .requests
320 .get(rpc_id)
321 .is_some_and(|v| v.status.is_init() || v.status.is_pending()),
322 RpcAction::P2pConnectionIncomingError { rpc_id, .. } => state
323 .rpc
324 .requests
325 .get(rpc_id)
326 .is_some_and(|v| v.status.is_init() || v.status.is_pending()),
327 RpcAction::P2pConnectionIncomingSuccess { rpc_id } => state
328 .rpc
329 .requests
330 .get(rpc_id)
331 .is_some_and(|v| v.status.is_pending()),
332 RpcAction::ScanStateSummaryGetInit { .. } => true,
333 RpcAction::ScanStateSummaryLedgerGetInit { rpc_id, .. } => state
334 .rpc
335 .requests
336 .get(rpc_id)
337 .is_some_and(|v| v.status.is_init()),
338 RpcAction::ScanStateSummaryGetPending { rpc_id, .. } => state
339 .rpc
340 .requests
341 .get(rpc_id)
342 .is_some_and(|v| v.status.is_init()),
343 RpcAction::ScanStateSummaryGetSuccess { rpc_id, .. } => state
344 .rpc
345 .requests
346 .get(rpc_id)
347 .is_some_and(|v| v.status.is_pending()),
348 RpcAction::SnarkPoolAvailableJobsGet { .. } => true,
349 RpcAction::SnarkPoolJobGet { .. } => true,
350 RpcAction::SnarkPoolCompletedJobsGet { .. } => true,
351 RpcAction::SnarkPoolPendingJobsGet { .. } => true,
352 RpcAction::SnarkerConfigGet { .. } => true,
353 RpcAction::SnarkerJobCommit { .. } => true,
354 RpcAction::SnarkerJobSpec { .. } => true,
355 RpcAction::SnarkerWorkersGet { .. } => true,
356 RpcAction::HealthCheck { .. } => true,
357 RpcAction::ReadinessCheck { .. } => true,
358 RpcAction::DiscoveryRoutingTable { .. } => true,
359 RpcAction::DiscoveryBoostrapStats { .. } => true,
360 RpcAction::TransactionPool { .. } => true,
361 RpcAction::ConsensusConstantsGet { .. } => true,
362 RpcAction::BestChain { .. } => state.transition_frontier.best_tip().is_some(),
363 RpcAction::TransactionStatusGet { .. } => true,
364 RpcAction::PooledUserCommands { .. } => true,
365 RpcAction::PooledZkappCommands { .. } => true,
366 RpcAction::GenesisBlock { .. } => true,
367 RpcAction::LedgerAccountsGetInit { .. } => {
368 state.transition_frontier.best_tip().is_some()
369 }
370 RpcAction::LedgerAccountsGetPending { rpc_id, .. } => state
371 .rpc
372 .requests
373 .get(rpc_id)
374 .is_some_and(|v| v.status.is_init()),
375 RpcAction::LedgerAccountsGetSuccess { rpc_id, .. } => state
376 .rpc
377 .requests
378 .get(rpc_id)
379 .is_some_and(|v| v.status.is_pending()),
380
381 RpcAction::TransactionInjectInit { .. } => true,
382 RpcAction::TransactionInjectPending { rpc_id } => state
383 .rpc
384 .requests
385 .get(rpc_id)
386 .is_some_and(|v| v.status.is_init()),
387 RpcAction::TransactionInjectSuccess { rpc_id, .. } => state
388 .rpc
389 .requests
390 .get(rpc_id)
391 .is_some_and(|v| v.status.is_pending()),
392 RpcAction::TransactionInjectRejected { rpc_id, .. } => state
393 .rpc
394 .requests
395 .get(rpc_id)
396 .is_some_and(|v| v.status.is_pending()),
397 RpcAction::TransactionInjectFailure { rpc_id, .. } => state
398 .rpc
399 .requests
400 .get(rpc_id)
401 .is_some_and(|v| v.status.is_pending()),
402 RpcAction::TransitionFrontierUserCommandsGet { .. } => true,
403 RpcAction::BlockGet { .. } => true,
404 RpcAction::ConsensusTimeGet { .. } => true,
405 RpcAction::LedgerStatusGetInit { .. } => state.transition_frontier.best_tip().is_some(),
406 RpcAction::LedgerStatusGetPending { rpc_id } => state
407 .rpc
408 .requests
409 .get(rpc_id)
410 .is_some_and(|v| v.status.is_init()),
411 RpcAction::LedgerStatusGetSuccess { rpc_id, .. } => state
412 .rpc
413 .requests
414 .get(rpc_id)
415 .is_some_and(|v| v.status.is_pending()),
416 RpcAction::LedgerAccountDelegatorsGetInit { .. } => {
417 state.transition_frontier.best_tip().is_some()
418 }
419 RpcAction::LedgerAccountDelegatorsGetPending { rpc_id } => state
420 .rpc
421 .requests
422 .get(rpc_id)
423 .is_some_and(|v| v.status.is_init()),
424 RpcAction::LedgerAccountDelegatorsGetSuccess { rpc_id, .. } => state
425 .rpc
426 .requests
427 .get(rpc_id)
428 .is_some_and(|v| v.status.is_pending()),
429 RpcAction::Finish { rpc_id } => state
430 .rpc
431 .requests
432 .get(rpc_id)
433 .is_some_and(|v| v.status.is_finished()),
434 }
435 }
436}