node/rpc/
mod.rs

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