node/rpc/
mod.rs

1mod rpc_state;
2use std::{collections::BTreeMap, str::FromStr};
3
4use ark_ff::fields::arithmetic::InvalidBigInt;
5use ledger::{
6    scan_state::{
7        currency::{Amount, Balance, Fee, Nonce, Slot},
8        transaction_logic::{signed_command, signed_command::SignedCommandPayload, valid, Memo},
9    },
10    transaction_pool::{diff, ValidCommandWithHash},
11    Account, AccountId,
12};
13use mina_p2p_messages::{
14    bigint::BigInt,
15    v2::{
16        LedgerHash, MinaBaseSignedCommandPayloadBodyStableV2, MinaBaseSignedCommandStableV2,
17        MinaBaseTransactionStatusStableV2, MinaBaseUserCommandStableV2,
18        MinaBaseZkappCommandTStableV1WireStableV1, MinaTransactionTransactionStableV2,
19        SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponse, StateHash, TransactionHash,
20        TransactionSnarkWorkTStableV2,
21    },
22};
23use openmina_core::{
24    block::{AppliedBlock, ArcBlockWithHash},
25    consensus::{ConsensusConstants, ConsensusTime},
26};
27use openmina_node_account::AccountPublicKey;
28use p2p::bootstrap::P2pNetworkKadBootstrapStats;
29pub use rpc_state::*;
30
31mod rpc_actions;
32pub use rpc_actions::*;
33
34mod rpc_reducer;
35pub use rpc_reducer::collect_rpc_peers_info;
36
37mod rpc_impls;
38
39mod heartbeat;
40pub use heartbeat::{NodeHeartbeat, ProducedBlockInfo, SignedNodeHeartbeat};
41
42pub use openmina_core::requests::{RpcId, RpcIdType};
43
44use ledger::scan_state::scan_state::{transaction_snark::OneOrTwo, AvailableJobMessage};
45use mina_p2p_messages::v2::{CurrencyFeeStableV1, NonZeroCurvePoint};
46use openmina_core::snark::SnarkJobId;
47use redux::Timestamp;
48use serde::{Deserialize, Serialize};
49
50use crate::{
51    external_snark_worker::{
52        ExternalSnarkWorkerError, ExternalSnarkWorkerWorkError, SnarkWorkSpecError,
53    },
54    ledger::{
55        read::{LedgerReadId, LedgerReadKind, LedgerStatus},
56        write::LedgerWriteKind,
57    },
58    p2p::{
59        connection::{
60            incoming::P2pConnectionIncomingInitOpts, outgoing::P2pConnectionOutgoingInitOpts,
61        },
62        PeerId,
63    },
64    service::Queues,
65    snark_pool::{JobCommitment, JobState, JobSummary},
66    stats::{
67        actions::{ActionStatsForBlock, ActionStatsSnapshot},
68        block_producer::{
69            BlockProductionAttempt, BlockProductionAttemptWonSlot, VrfEvaluatorStats,
70        },
71        sync::SyncStatsSnapshot,
72    },
73};
74
75#[derive(Serialize, Deserialize, Debug, Clone)]
76pub enum RpcRequest {
77    StateGet(Option<String>),
78    StatusGet,
79    HeartbeatGet,
80    ActionStatsGet(ActionStatsQuery),
81    SyncStatsGet(SyncStatsQuery),
82    BlockProducerStatsGet,
83    MessageProgressGet,
84    PeersGet,
85    P2pConnectionOutgoing(P2pConnectionOutgoingInitOpts),
86    P2pConnectionIncoming(P2pConnectionIncomingInitOpts),
87    ScanStateSummaryGet(RpcScanStateSummaryGetQuery),
88    SnarkPoolGet,
89    SnarkPoolJobGet { job_id: SnarkJobId },
90    SnarkPoolCompletedJobsGet,
91    SnarkPoolPendingJobsGet,
92    SnarkerConfig,
93    SnarkerJobCommit { job_id: SnarkJobId },
94    SnarkerJobSpec { job_id: SnarkJobId },
95    SnarkerWorkers,
96    HealthCheck,
97    ReadinessCheck,
98    DiscoveryRoutingTable,
99    DiscoveryBoostrapStats,
100    TransactionPoolGet,
101    LedgerAccountsGet(AccountQuery),
102    TransactionInject(Vec<MinaBaseUserCommandStableV2>),
103    TransitionFrontierUserCommandsGet,
104    BestChain(MaxLength),
105    ConsensusConstantsGet,
106    TransactionStatusGet(MinaBaseUserCommandStableV2),
107    GetBlock(GetBlockQuery),
108    PooledUserCommands(PooledUserCommandsQuery),
109    PooledZkappCommands(PooledZkappsCommandsQuery),
110    GenesisBlockGet,
111    ConsensusTimeGet(ConsensusTimeQuery),
112    LedgerStatusGet(LedgerHash),
113    LedgerAccountDelegatorsGet(LedgerHash, AccountId),
114}
115
116#[derive(Serialize, Deserialize, Debug, Clone)]
117pub enum ConsensusTimeQuery {
118    Now,
119    BestTip,
120}
121
122pub type MaxLength = u32;
123
124#[derive(Serialize, Deserialize, Debug, Clone)]
125pub struct RpcInjectPayment {
126    fee: u64,
127    amount: u64,
128    to: AccountPublicKey,
129    from: AccountPublicKey,
130    memo: String,
131    nonce: u32,
132    valid_until: u32,
133    signature_field: BigInt,
134    signature_scalar: BigInt,
135}
136// MinaBaseUserCommandStableV2
137impl TryFrom<RpcInjectPayment> for MinaBaseUserCommandStableV2 {
138    type Error = InvalidBigInt;
139
140    fn try_from(value: RpcInjectPayment) -> Result<Self, Self::Error> {
141        let signature = mina_signer::Signature {
142            rx: value.signature_field.try_into()?,
143            s: value.signature_scalar.try_into()?,
144        };
145        println!("Signature: {signature}");
146        let sc = signed_command::SignedCommand {
147            payload: SignedCommandPayload::create(
148                Fee::from_u64(value.fee),
149                value.from.clone().try_into().map_err(|_| InvalidBigInt)?,
150                Nonce::from_u32(value.nonce),
151                Some(Slot::from_u32(value.valid_until)),
152                Memo::from_str(&value.memo).unwrap(),
153                signed_command::Body::Payment(signed_command::PaymentPayload {
154                    receiver_pk: value.to.try_into().map_err(|_| InvalidBigInt)?,
155                    amount: Amount::from_u64(value.amount),
156                }),
157            ),
158            signer: value.from.try_into().map_err(|_| InvalidBigInt)?,
159            signature,
160        };
161
162        Ok(MinaBaseUserCommandStableV2::SignedCommand(sc.into()))
163    }
164}
165
166#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
167pub enum ActionStatsQuery {
168    SinceStart,
169    ForLatestBlock,
170    ForBlockWithId(u64),
171}
172
173#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
174pub struct SyncStatsQuery {
175    pub limit: Option<usize>,
176}
177
178#[derive(Serialize, Deserialize, Debug, Clone)]
179pub enum RpcScanStateSummaryGetQuery {
180    ForBestTip,
181    ForBlockWithHash(StateHash),
182    ForBlockWithHeight(u32),
183}
184
185#[derive(Serialize, Deserialize, Debug, Clone)]
186#[serde(tag = "kind")]
187pub enum ActionStatsResponse {
188    SinceStart { stats: ActionStatsSnapshot },
189    ForBlock(ActionStatsForBlock),
190}
191
192#[derive(Serialize, Deserialize, Debug, Clone, strum_macros::Display)]
193pub enum PeerConnectionStatus {
194    Disconnecting,
195    Disconnected,
196    Connecting,
197    Connected,
198}
199
200#[derive(Serialize, Deserialize, Debug, Clone)]
201pub struct RpcPeerInfo {
202    pub peer_id: PeerId,
203    pub best_tip: Option<StateHash>,
204    pub best_tip_height: Option<u32>,
205    pub best_tip_global_slot: Option<u32>,
206    pub best_tip_timestamp: Option<u64>,
207    pub connection_status: PeerConnectionStatus,
208    pub connecting_details: Option<String>,
209    pub address: Option<String>,
210    pub incoming: bool,
211    pub is_libp2p: bool,
212    pub time: u64,
213}
214
215#[derive(Serialize, Deserialize, Debug, Clone)]
216pub struct RpcScanStateSummary {
217    pub block: RpcScanStateSummaryBlock,
218    pub scan_state: Vec<Vec<RpcScanStateSummaryScanStateJob>>,
219}
220
221#[derive(Serialize, Deserialize, Debug, Clone)]
222pub struct RpcScanStateSummaryBlock {
223    pub hash: StateHash,
224    pub height: u32,
225    pub global_slot: u32,
226    pub transactions: Vec<RpcScanStateSummaryBlockTransaction>,
227    pub completed_works: Vec<SnarkJobId>,
228}
229
230#[derive(Serialize, Deserialize, Debug, Clone)]
231pub struct RpcScanStateSummaryBlockTransaction {
232    /// None if hashing fails.
233    pub hash: Option<TransactionHash>,
234    pub kind: RpcScanStateSummaryBlockTransactionKind,
235    pub status: MinaBaseTransactionStatusStableV2,
236}
237
238#[derive(Serialize, Deserialize, Debug, Clone)]
239pub enum RpcScanStateSummaryBlockTransactionKind {
240    Payment,
241    StakeDelegation,
242    Zkapp,
243    FeeTransfer,
244    Coinbase,
245}
246
247#[derive(Serialize, Deserialize, Debug, Clone)]
248#[serde(tag = "status")]
249pub enum RpcScanStateSummaryScanStateJob {
250    Empty,
251    Todo {
252        job_id: SnarkJobId,
253        bundle_job_id: SnarkJobId,
254        job: RpcScanStateSummaryScanStateJobKind,
255        seq_no: u64,
256    },
257    Pending {
258        job_id: SnarkJobId,
259        bundle_job_id: SnarkJobId,
260        job: Box<RpcScanStateSummaryScanStateJobKind>,
261        seq_no: u64,
262        commitment: Option<Box<JobCommitment>>,
263        snark: Option<Box<RpcSnarkPoolJobSnarkWork>>,
264    },
265    Done {
266        job_id: SnarkJobId,
267        bundle_job_id: SnarkJobId,
268        job: Box<RpcScanStateSummaryScanStateJobKind>,
269        seq_no: u64,
270        snark: Box<RpcSnarkPoolJobSnarkWorkDone>,
271    },
272}
273
274#[derive(Serialize, Deserialize, Debug, Clone)]
275#[serde(tag = "kind")]
276pub enum RpcScanStateSummaryScanStateJobKind {
277    Base(RpcScanStateSummaryBlockTransaction),
278    Merge,
279}
280
281#[derive(Serialize, Deserialize, Debug, Clone)]
282pub enum RpcScanStateSummaryScanStateJobStatus {
283    Todo,
284    Done,
285}
286
287#[derive(Serialize, Debug, Clone)]
288pub struct RpcSnarkPoolJobSummary {
289    pub time: Timestamp,
290    pub id: SnarkJobId,
291    pub commitment: Option<JobCommitment>,
292    pub snark: Option<RpcSnarkPoolJobSnarkWork>,
293}
294
295#[derive(Serialize, Debug, Clone)]
296pub struct RpcSnarkPoolJobFull {
297    pub time: Timestamp,
298    pub id: SnarkJobId,
299    pub job: OneOrTwo<AvailableJobMessage>,
300    pub commitment: Option<JobCommitment>,
301    pub snark: Option<RpcSnarkPoolJobSnarkWork>,
302}
303
304#[derive(Serialize, Deserialize, Debug, Clone)]
305pub struct RpcSnarkPoolJobSnarkWork {
306    pub snarker: NonZeroCurvePoint,
307    pub fee: CurrencyFeeStableV1,
308    pub received_t: Timestamp,
309    pub sender: PeerId,
310}
311
312#[derive(Serialize, Deserialize, Debug, Clone)]
313pub struct RpcSnarkPoolJobSnarkWorkDone {
314    pub snarker: NonZeroCurvePoint,
315    pub fee: CurrencyFeeStableV1,
316}
317
318#[derive(Serialize, Deserialize, Debug, Clone)]
319#[serde(tag = "kind")]
320pub enum RpcSnarkerJobCommitResponse {
321    Ok,
322    JobNotFound,
323    JobTaken,
324    SnarkerBusy,
325}
326
327#[derive(Serialize, Deserialize, Debug, Clone)]
328#[serde(tag = "kind")]
329pub enum RpcSnarkerJobSpecResponse {
330    Ok(SnarkWorkerWorkerRpcsVersionedGetWorkV2TResponse),
331    Err(SnarkWorkSpecError),
332    JobNotFound,
333}
334
335#[derive(Serialize, Deserialize, Debug, Clone)]
336pub struct RpcMessageProgressResponse {
337    pub messages_stats: BTreeMap<PeerId, MessagesStats>,
338    pub staking_ledger_sync: Option<LedgerSyncProgress>,
339    pub next_epoch_ledger_sync: Option<LedgerSyncProgress>,
340    pub root_ledger_sync: Option<RootLedgerSyncProgress>,
341}
342
343#[derive(Serialize, Deserialize, Debug, Clone)]
344pub struct MessagesStats {
345    pub current_request: Option<CurrentMessageProgress>,
346    pub responses: BTreeMap<String, usize>,
347}
348
349#[derive(Serialize, Deserialize, Debug, Clone)]
350pub struct LedgerSyncProgress {
351    pub fetched: u64,
352    pub estimation: u64,
353}
354
355#[derive(Serialize, Deserialize, Debug, Clone)]
356pub struct RootLedgerSyncProgress {
357    pub fetched: u64,
358    pub estimation: u64,
359    pub staged: Option<RootStagedLedgerSyncProgress>,
360}
361
362#[derive(Serialize, Deserialize, Debug, Clone)]
363pub struct RootStagedLedgerSyncProgress {
364    pub fetched: u64,
365    pub total: u64,
366}
367
368#[derive(Serialize, Deserialize, Debug, Clone)]
369pub struct CurrentMessageProgress {
370    pub name: String,
371    pub received_bytes: usize,
372    pub total_bytes: usize,
373}
374
375#[derive(Serialize, Deserialize, Debug, Clone, thiserror::Error)]
376pub enum RpcStateGetError {
377    #[error("failed to parse filter expression: {0}")]
378    FilterError(String),
379}
380
381pub type RpcStateGetResponse = Result<serde_json::Value, RpcStateGetError>;
382pub type RpcStatusGetResponse = Option<RpcNodeStatus>;
383pub type RpcHeartbeatGetResponse = Option<SignedNodeHeartbeat>;
384pub type RpcActionStatsGetResponse = Option<ActionStatsResponse>;
385pub type RpcSyncStatsGetResponse = Option<Vec<SyncStatsSnapshot>>;
386pub type RpcBlockProducerStatsGetResponse = Option<RpcBlockProducerStats>;
387pub type RpcPeersGetResponse = Vec<RpcPeerInfo>;
388pub type RpcP2pConnectionOutgoingResponse = Result<(), String>;
389pub type RpcScanStateSummaryGetResponse = Result<RpcScanStateSummary, String>;
390pub type RpcSnarkPoolGetResponse = Vec<RpcSnarkPoolJobSummary>;
391pub type RpcSnarkPoolCompletedJobsResponse = Vec<TransactionSnarkWorkTStableV2>;
392pub type RpcSnarkPoolPendingJobsGetResponse = Vec<JobState>;
393pub type RpcSnarkPoolJobGetResponse = Option<RpcSnarkPoolJobFull>;
394pub type RpcSnarkerConfigGetResponse = Option<RpcSnarkerConfig>;
395pub type RpcTransactionPoolResponse = Vec<ValidCommandWithHash>;
396pub type RpcLedgerSlimAccountsResponse = Vec<AccountSlim>;
397pub type RpcLedgerAccountsResponse = Vec<Account>;
398pub type RpcTransitionFrontierUserCommandsResponse = Vec<MinaBaseUserCommandStableV2>;
399pub type RpcBestChainResponse = Vec<AppliedBlock>;
400pub type RpcConsensusConstantsGetResponse = ConsensusConstants;
401pub type RpcTransactionStatusGetResponse = TransactionStatus;
402pub type RpcPooledUserCommandsResponse = Vec<MinaBaseSignedCommandStableV2>;
403pub type RpcPooledZkappCommandsResponse = Vec<MinaBaseZkappCommandTStableV1WireStableV1>;
404pub type RpcGenesisBlockResponse = Option<ArcBlockWithHash>;
405pub type RpcConsensusTimeGetResponse = Option<ConsensusTime>;
406pub type RpcLedgerStatusGetResponse = Option<LedgerStatus>;
407pub type RpcLedgerAccountDelegatorsGetResponse = Option<Vec<Account>>;
408
409#[derive(Serialize, Deserialize, Debug, Clone, strum_macros::Display)]
410#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
411pub enum TransactionStatus {
412    Pending,
413    Included,
414    Unknown,
415}
416
417// TODO(adonagy): rework this to handle all the possible user commands (enum..)
418#[derive(Serialize, Deserialize, Debug, Clone)]
419pub struct RpcTransactionInjectedPayment {
420    pub amount: Amount,
421    pub fee: Fee,
422    // pub fee_token: TokenId,
423    pub from: AccountPublicKey,
424    pub to: AccountPublicKey,
425    pub hash: String, // TODO(adonagy)
426    // pub id: String, // TODO(adonagy)
427    pub is_delegation: bool,
428    pub memo: String, // TODO(adonagy)
429    // pub memo: Memo, // TODO(adonagy)
430    pub nonce: Nonce,
431}
432
433// TODO(adonagy): remove this, not needed anymore
434// #[derive(Serialize, Deserialize, Debug, Clone)]
435// pub enum RpcTransactionInjectedCommand {
436//     Payment(valid::UserCommand),
437//     Delegation(valid::UserCommand),
438//     Zkapp(valid::UserCommand),
439// }
440
441pub type RpcTransactionInjectSuccess = Vec<valid::UserCommand>;
442pub type RpcTransactionInjectRejected = Vec<(valid::UserCommand, diff::Error)>;
443/// Errors
444pub type RpcTransactionInjectFailure = Vec<String>;
445
446#[derive(Serialize, Deserialize, Debug, Clone)]
447#[serde(untagged)]
448pub enum RpcTransactionInjectResponse {
449    Success(RpcTransactionInjectSuccess),
450    Rejected(RpcTransactionInjectRejected),
451    Failure(RpcTransactionInjectFailure),
452}
453
454// impl From<ValidCommandWithHash> for RpcTransactionInjectedCommand {
455//     fn from(value: ValidCommandWithHash) -> Self {
456//         match value.data {
457//             transaction_logic::valid::UserCommand::SignedCommand(ref signedcmd) => {
458//                 match signedcmd.payload.body {
459//                     transaction_logic::signed_command::Body::Payment(_) => {
460//                         Self::Payment(value.data.clone())
461//                     }
462//                     transaction_logic::signed_command::Body::StakeDelegation(_) => {
463//                         Self::Delegation(value.data.clone())
464//                     }
465//                 }
466//             }
467//             transaction_logic::valid::UserCommand::ZkAppCommand(_) => {
468//                 Self::Zkapp(value.data.clone())
469//             }
470//         }
471//     }
472// }
473
474// impl From<ValidCommandWithHash> for RpcTransactionInjectedCommand {
475//     fn from(value: ValidCommandWithHash) -> Self {
476//         match value.data {
477//             transaction_logic::valid::UserCommand::SignedCommand(signedcmd) => {
478//                 match signedcmd.payload.body {
479//                     transaction_logic::signed_command::Body::Payment(ref payment) => {
480//                         Self::RpcPayment(RpcTransactionInjectedPayment {
481//                             amount: payment.amount,
482//                             fee: signedcmd.fee(),
483//                             // fee_token: signedcmd.fee_token(),
484//                             from: signedcmd.fee_payer_pk().clone().into(),
485//                             to: payment.receiver_pk.clone().into(),
486//                             hash: value.hash.to_string(),
487//                             is_delegation: false,
488//                             // memo: signedcmd.payload.common.memo.clone(),
489//                             memo: signedcmd.payload.common.memo.to_string(),
490//                             nonce: signedcmd.nonce(),
491//                         })
492//                     }
493//                     transaction_logic::signed_command::Body::StakeDelegation(_) => {
494//                         todo!("inject stake delegation")
495//                     }
496//                 }
497//             }
498//             transaction_logic::valid::UserCommand::ZkAppCommand(_) => {
499//                 Self::Zkapp(value.data.clone())
500//             }
501//         }
502//     }
503// }
504
505#[derive(Serialize, Debug, Clone)]
506pub struct AccountSlim {
507    pub public_key: AccountPublicKey,
508    pub balance: Balance,
509    pub nonce: Nonce,
510}
511
512impl From<Account> for AccountSlim {
513    fn from(value: Account) -> Self {
514        Self {
515            public_key: AccountPublicKey::from(value.public_key),
516            balance: value.balance,
517            nonce: value.nonce,
518        }
519    }
520}
521
522#[derive(Serialize, Debug, Clone)]
523pub struct RpcNodeStatus {
524    pub chain_id: Option<String>,
525    pub transition_frontier: RpcNodeStatusTransitionFrontier,
526    pub ledger: RpcNodeStatusLedger,
527    pub snark_pool: RpcNodeStatusSnarkPool,
528    pub transaction_pool: RpcNodeStatusTransactionPool,
529    pub current_block_production_attempt: Option<BlockProductionAttempt>,
530    pub previous_block_production_attempt: Option<BlockProductionAttempt>,
531    pub peers: Vec<RpcPeerInfo>,
532    pub resources_status: RpcNodeStatusResources,
533    pub service_queues: Queues,
534    pub network_info: RpcNodeStatusNetworkInfo,
535    pub block_producer: Option<AccountPublicKey>,
536    pub coinbase_receiver: Option<AccountPublicKey>,
537}
538
539#[derive(Serialize, Debug, Clone)]
540pub struct RpcNodeStatusNetworkInfo {
541    pub bind_ip: String,
542    pub external_ip: Option<String>,
543    pub client_port: Option<u16>,
544    pub libp2p_port: Option<u16>,
545}
546
547#[derive(Serialize, Debug, Clone)]
548pub struct RpcNodeStatusLedger {
549    pub alive_masks_after_last_commit: usize,
550    pub pending_writes: Vec<(LedgerWriteKind, redux::Timestamp)>,
551    pub pending_reads: Vec<(LedgerReadId, LedgerReadKind, redux::Timestamp)>,
552}
553
554#[derive(Serialize, Debug, Clone)]
555pub struct RpcNodeStatusResources {
556    pub p2p_malloc_size: usize,
557    pub transition_frontier: serde_json::Value,
558    pub snark_pool: serde_json::Value,
559}
560
561#[derive(Serialize, Deserialize, Debug, Clone)]
562pub struct RpcNodeStatusTransitionFrontier {
563    pub best_tip: Option<RpcNodeStatusTransitionFrontierBlockSummary>,
564    pub sync: RpcNodeStatusTransitionFrontierSync,
565}
566
567#[derive(Serialize, Deserialize, Debug, Clone)]
568pub struct RpcNodeStatusTransitionFrontierSync {
569    pub time: Option<redux::Timestamp>,
570    pub status: String,
571    pub phase: String,
572    pub target: Option<RpcNodeStatusTransitionFrontierBlockSummary>,
573}
574
575#[derive(Serialize, Deserialize, Debug, Clone)]
576pub struct RpcNodeStatusTransitionFrontierBlockSummary {
577    pub hash: StateHash,
578    pub height: u32,
579    pub global_slot: u32,
580}
581
582#[derive(Serialize, Deserialize, Debug, Default, Clone)]
583pub struct RpcNodeStatusTransactionPool {
584    pub transactions: usize,
585    pub transactions_for_propagation: usize,
586    pub transaction_candidates: usize,
587}
588
589#[derive(Serialize, Deserialize, Debug, Default, Clone)]
590pub struct RpcNodeStatusSnarkPool {
591    pub total_jobs: usize,
592    pub snarks: usize,
593}
594
595#[derive(Serialize, Deserialize, Debug, Clone)]
596pub struct RpcBlockProducerStats {
597    pub current_time: redux::Timestamp,
598    pub current_global_slot: Option<u32>,
599    pub current_epoch: Option<u32>,
600    pub epoch_start: Option<u32>,
601    pub epoch_end: Option<u32>,
602    pub public_key: AccountPublicKey,
603    pub attempts: Vec<BlockProductionAttempt>,
604    pub future_won_slots: Vec<BlockProductionAttemptWonSlot>,
605    pub current_epoch_vrf_stats: Option<VrfEvaluatorStats>,
606    pub vrf_stats: BTreeMap<u32, VrfEvaluatorStats>,
607}
608
609#[derive(Serialize, Deserialize, Debug, Clone)]
610pub struct RpcSnarkerConfig {
611    pub public_key: NonZeroCurvePoint,
612    pub fee: CurrencyFeeStableV1,
613}
614
615#[derive(Serialize, Debug, Clone)]
616pub struct RpcSnarkWorker {
617    pub time: Option<Timestamp>,
618    pub id: Option<String>,
619    pub status: RpcSnarkWorkerStatus,
620}
621
622#[derive(Serialize, Deserialize, Debug, Clone)]
623#[serde(tag = "kind")]
624pub enum RpcSnarkWorkerStatus {
625    None,
626    Starting,
627    Idle,
628    Working {
629        job_id: SnarkJobId,
630        summary: JobSummary,
631    },
632    WorkReady {
633        job_id: SnarkJobId,
634    },
635    WorkError {
636        job_id: SnarkJobId,
637        error: ExternalSnarkWorkerWorkError,
638    },
639    Cancelling {
640        job_id: SnarkJobId,
641    },
642    Cancelled {
643        job_id: SnarkJobId,
644    },
645    Error {
646        error: ExternalSnarkWorkerError,
647        permanent: bool,
648    },
649    Killing,
650}
651
652pub type RpcSnarkerWorkersResponse = Vec<RpcSnarkWorker>;
653
654impl From<&MinaTransactionTransactionStableV2> for RpcScanStateSummaryBlockTransactionKind {
655    fn from(value: &MinaTransactionTransactionStableV2) -> Self {
656        match value {
657            MinaTransactionTransactionStableV2::Command(v) => (&**v).into(),
658            MinaTransactionTransactionStableV2::FeeTransfer(_) => Self::FeeTransfer,
659            MinaTransactionTransactionStableV2::Coinbase(_) => Self::Coinbase,
660        }
661    }
662}
663
664impl From<&MinaBaseUserCommandStableV2> for RpcScanStateSummaryBlockTransactionKind {
665    fn from(value: &MinaBaseUserCommandStableV2) -> Self {
666        match value {
667            MinaBaseUserCommandStableV2::SignedCommand(v) => match &v.payload.body {
668                MinaBaseSignedCommandPayloadBodyStableV2::Payment(_) => Self::Payment,
669                MinaBaseSignedCommandPayloadBodyStableV2::StakeDelegation(_) => {
670                    Self::StakeDelegation
671                }
672            },
673            MinaBaseUserCommandStableV2::ZkappCommand(_) => Self::Zkapp,
674        }
675    }
676}
677
678pub type RpcHealthCheckResponse = Result<(), String>;
679pub type RpcReadinessCheckResponse = Result<(), String>;
680
681pub type RpcDiscoveryRoutingTableResponse = Option<discovery::RpcDiscoveryRoutingTable>;
682pub type RpcDiscoveryBoostrapStatsResponse = Option<P2pNetworkKadBootstrapStats>;
683
684#[derive(Serialize, Deserialize, Debug, Clone)]
685pub enum GetBlockQuery {
686    Hash(StateHash),
687    Height(u32),
688}
689
690pub type RpcGetBlockResponse = Option<AppliedBlock>;
691
692#[derive(Serialize, Deserialize, Debug, Clone)]
693pub struct PooledCommandsQuery<ID> {
694    pub public_key: Option<AccountPublicKey>,
695    pub hashes: Option<Vec<TransactionHash>>,
696    pub ids: Option<Vec<ID>>,
697}
698
699pub type PooledUserCommandsQuery = PooledCommandsQuery<MinaBaseSignedCommandStableV2>;
700pub type PooledZkappsCommandsQuery = PooledCommandsQuery<MinaBaseZkappCommandTStableV1WireStableV1>;
701
702pub mod discovery {
703    use p2p::{
704        libp2p_identity::DecodingError, ConnectionType, P2pNetworkKadBucket, P2pNetworkKadDist,
705        P2pNetworkKadEntry, P2pNetworkKadKey, P2pNetworkKadRoutingTable, PeerId,
706    };
707    use serde::{Deserialize, Serialize};
708
709    #[derive(Serialize, Deserialize, Debug, Clone)]
710    pub struct RpcDiscoveryRoutingTable {
711        this_key: P2pNetworkKadKey,
712        buckets: Vec<RpcKBucket>,
713    }
714
715    impl TryFrom<&P2pNetworkKadRoutingTable> for RpcDiscoveryRoutingTable {
716        type Error = DecodingError;
717
718        fn try_from(value: &P2pNetworkKadRoutingTable) -> Result<Self, Self::Error> {
719            let mut buckets = Vec::new();
720
721            for (i, b) in value.buckets.iter().enumerate() {
722                buckets.push((b, P2pNetworkKadDist::from(i), &value.this_key).try_into()?);
723            }
724
725            Ok(RpcDiscoveryRoutingTable {
726                this_key: value.this_key,
727                buckets,
728            })
729        }
730    }
731
732    #[derive(Serialize, Deserialize, Debug, Clone)]
733    pub struct RpcKBucket {
734        max_dist: P2pNetworkKadDist,
735        entries: Vec<RpcEntry>,
736    }
737
738    impl<const K: usize>
739        TryFrom<(
740            &P2pNetworkKadBucket<K>,
741            P2pNetworkKadDist,
742            &P2pNetworkKadKey,
743        )> for RpcKBucket
744    {
745        type Error = DecodingError;
746
747        fn try_from(
748            (bucket, max_dist, this_key): (
749                &P2pNetworkKadBucket<K>,
750                P2pNetworkKadDist,
751                &P2pNetworkKadKey,
752            ),
753        ) -> Result<Self, Self::Error> {
754            let mut entries = Vec::new();
755
756            for entry in bucket.iter() {
757                entries.push((entry, this_key).try_into()?);
758            }
759            Ok(RpcKBucket { max_dist, entries })
760        }
761    }
762
763    #[derive(Serialize, Deserialize, Debug, Clone)]
764    pub struct RpcEntry {
765        peer_id: PeerId,
766        libp2p: p2p::libp2p_identity::PeerId,
767        key: P2pNetworkKadKey,
768        dist: P2pNetworkKadDist,
769        addrs: Vec<p2p::multiaddr::Multiaddr>,
770        connection: ConnectionType,
771    }
772
773    impl TryFrom<(&P2pNetworkKadEntry, &P2pNetworkKadKey)> for RpcEntry {
774        type Error = DecodingError;
775
776        fn try_from(
777            (value, this_key): (&P2pNetworkKadEntry, &P2pNetworkKadKey),
778        ) -> Result<Self, Self::Error> {
779            Ok(RpcEntry {
780                peer_id: value.peer_id,
781                libp2p: value.peer_id.try_into()?,
782                key: value.key,
783                dist: this_key.distance(&value.key),
784                addrs: value.addresses().clone(),
785                connection: value.connection,
786            })
787        }
788    }
789}