mina_p2p_messages/
rpc.rs

1//! Mina RPC methods
2use std::collections::BTreeMap;
3
4use binprot::{BinProtRead, BinProtWrite};
5use binprot_derive::{BinProtRead, BinProtWrite};
6use serde::{Deserialize, Serialize};
7
8use crate::{
9    common::*,
10    core,
11    core::InetAddrV1Versioned,
12    list::List,
13    rpc_kernel::*,
14    string::CharString,
15    v2,
16    v2::MinaBaseSparseLedgerBaseStableV2,
17    versioned::{Ver, Versioned},
18};
19
20macro_rules! mina_rpc {
21    ($name:ident, $tag:literal, $version:literal, $query:ty, $response:ty $(,)?) => {
22        #[derive(Debug)]
23        pub struct $name;
24        impl crate::rpc_kernel::RpcMethod for $name {
25            const NAME: crate::rpc_kernel::RpcTag = $tag.as_bytes();
26            const NAME_STR: &'static str = $tag;
27            const VERSION: crate::versioned::Ver = $version;
28            type Query = $query;
29            type Response = $response;
30        }
31    };
32}
33
34mina_rpc!(
35    SendArchiveDiffUnversioned,
36    "Send_archive_diff",
37    0,
38    v2::ArchiveRpc,
39    ()
40);
41
42mina_rpc!(
43    VersionedRpcMenuV1,
44    "__Versioned_rpc.Menu",
45    1,
46    (),
47    List<(CharString, Ver)>
48);
49
50mina_rpc!(
51    GetSomeInitialPeersV1ForV2,
52    "get_some_initial_peers",
53    1,
54    (),
55    List<v2::NetworkPeerPeerStableV1>
56);
57
58pub type GetStagedLedgerAuxAndPendingCoinbasesAtHashV2Response = Option<(
59    v2::TransactionSnarkScanStateStableV2,
60    LedgerHashV1,
61    v2::MinaBasePendingCoinbaseStableV2,
62    List<v2::MinaStateProtocolStateValueStableV2>,
63)>;
64
65mina_rpc!(
66    GetStagedLedgerAuxAndPendingCoinbasesAtHashV2,
67    "get_staged_ledger_aux_and_pending_coinbases_at_hash",
68    2,
69    StateHashV1,
70    GetStagedLedgerAuxAndPendingCoinbasesAtHashV2Response,
71);
72
73mina_rpc!(
74    AnswerSyncLedgerQueryV2,
75    "answer_sync_ledger_query",
76    3,
77    (LedgerHashV1, v2::MinaLedgerSyncLedgerQueryStableV1),
78    RpcResult<v2::MinaLedgerSyncLedgerAnswerStableV2, core::Error>
79);
80
81mina_rpc!(
82    GetTransitionChainV2,
83    "get_transition_chain",
84    2,
85    List<StateHashV1>,
86    Option<List<v2::MinaBlockBlockStableV2>>
87);
88
89pub type GetTransitionChainProofV1ForV2Response = Option<(StateHashV1, List<StateBodyHashV1>)>;
90mina_rpc!(
91    GetTransitionChainProofV1ForV2,
92    "get_transition_chain_proof",
93    1,
94    StateHashV1,
95    GetTransitionChainProofV1ForV2Response,
96);
97
98mina_rpc!(
99    GetTransitionKnowledgeV1,
100    "Get_transition_knowledge",
101    1,
102    (),
103    List<StateHashV1Versioned>
104);
105
106mina_rpc!(
107    GetTransitionKnowledgeV1ForV2,
108    "Get_transition_knowledge",
109    1,
110    (),
111    List<StateHashV1>
112);
113
114// pub struct ConsensusDataConsensusStateValue;
115#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite)]
116pub struct WithHashV1<A, H> {
117    pub data: A,
118    pub hash: H,
119}
120pub type WithHashV1Versioned<A, H> = Versioned<WithHashV1<A, H>, 1>;
121
122#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite)]
123pub struct ProofCarryingDataWithHashV1<A, B> {
124    pub data: A,
125    pub proof: B,
126}
127pub type ProofCarryingDataWithHashV1Versioned<A, B> =
128    Versioned<ProofCarryingDataWithHashV1<A, B>, 1>;
129
130pub type GetAncestryV2Query =
131    WithHashV1<v2::ConsensusProofOfStakeDataConsensusStateValueStableV2, StateHashV1>;
132pub type GetAncestryV2Response = Option<
133    ProofCarryingDataWithHashV1<
134        v2::MinaBlockBlockStableV2,
135        (List<StateBodyHashV1>, v2::MinaBlockBlockStableV2),
136    >,
137>;
138mina_rpc!(
139    GetAncestryV2,
140    "get_ancestry",
141    2,
142    GetAncestryV2Query,
143    GetAncestryV2Response,
144);
145
146mina_rpc!(BanNotifyV1, "ban_notify", 1, core::Time, ());
147
148#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite)]
149pub struct ProofCarryingDataStableV1<A, B> {
150    pub data: A,
151    pub proof: B,
152}
153pub type ProofCarryingDataStableV1Versioned<A, B> = Versioned<ProofCarryingDataStableV1<A, B>, 1>;
154pub type GetBestTipV2Response = Option<
155    ProofCarryingDataStableV1<
156        v2::MinaBlockBlockStableV2,
157        (
158            List<v2::MinaBaseStateBodyHashStableV1>,
159            v2::MinaBlockBlockStableV2,
160        ),
161    >,
162>;
163mina_rpc!(GetBestTipV2, "get_best_tip", 2, (), GetBestTipV2Response);
164
165#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, BinProtRead, BinProtWrite)]
166pub struct NodeStatusV2 {
167    node_ip_addr: InetAddrV1Versioned,
168    node_peer_id: v2::NetworkPeerPeerIdStableV1,
169    sync_status: v2::SyncStatusTStableV1,
170    peers: List<v2::NetworkPeerPeerIdStableV1>,
171    block_producers: List<v2::NonZeroCurvePoint>,
172    protocol_state_hash: v2::StateHash,
173    ban_statuses: List<(
174        v2::NetworkPeerPeerIdStableV1,
175        v2::TrustSystemPeerStatusStableV1,
176    )>,
177    k_block_hashes_and_timestamps: List<(v2::StateHash, CharString)>,
178    git_commit: CharString,
179    uptime_minutes: i32,
180    block_height_opt: Option<i32>,
181}
182mina_rpc!(GetNodeStatusV2, "get_node_status", 2, (), RpcResult<NodeStatusV2, core::Error>);
183
184mina_rpc!(GetEpochLedgerV2, "get_epoch_ledger", 2, LedgerHashV1, RpcResult<MinaBaseSparseLedgerBaseStableV2, CharString>);
185
186/// Registry for uniformly JSONifying RPC payload data.
187///
188/// ```
189/// let r = mina_p2p_messages::JSONifyPayloadRegistry::new();
190/// let mut d = &b"\x01\x00"[..];
191/// let jsonifier = r.get("get_some_initial_peers", 1).unwrap();
192/// let json = jsonifier.read_query(&mut d).unwrap();
193/// ```
194pub struct JSONifyPayloadRegistry {
195    table: BTreeMap<(&'static [u8], Ver), Box<dyn JSONinifyPayloadReader>>,
196}
197
198impl Default for JSONifyPayloadRegistry {
199    fn default() -> Self {
200        Self::v2()
201    }
202}
203
204impl JSONifyPayloadRegistry {
205    #[deprecated = "Use `[v2]` method instead."]
206    pub fn new() -> Self {
207        Self::v2()
208    }
209
210    /// Creates registry with Mina V2 specific RPC methods.
211    pub fn v2() -> Self {
212        let mut this = Self {
213            table: BTreeMap::new(),
214        };
215        this.insert(VersionedRpcMenuV1);
216        this.insert(GetSomeInitialPeersV1ForV2);
217        this.insert(GetStagedLedgerAuxAndPendingCoinbasesAtHashV2);
218        this.insert(AnswerSyncLedgerQueryV2);
219        this.insert(GetTransitionChainV2);
220        this.insert(GetTransitionChainProofV1ForV2);
221        this.insert(GetTransitionKnowledgeV1ForV2);
222        this.insert(BanNotifyV1);
223        this.insert(GetAncestryV2);
224        this.insert(GetBestTipV2);
225        this.insert(GetNodeStatusV2);
226        this.insert(GetEpochLedgerV2);
227        this
228    }
229
230    pub fn get<'a, 'b: 'a>(
231        &'a self,
232        name: &'b [u8],
233        version: Ver,
234    ) -> Option<&'a dyn JSONinifyPayloadReader> {
235        self.table.get(&(name, version)).map(Box::as_ref)
236    }
237
238    fn insert<T>(&mut self, t: T)
239    where
240        T: RpcMethod + 'static,
241        T::Query: Serialize,
242        T::Response: Serialize,
243    {
244        self.table.insert((T::NAME, T::VERSION), Box::new(t));
245    }
246}
247
248#[cfg(test)]
249mod tests {
250    use crate::JSONifyPayloadRegistry;
251
252    #[test]
253    fn jsonify_registry_content_v2() {
254        let r = JSONifyPayloadRegistry::v2();
255        for (name, version) in [
256            ("__Versioned_rpc.Menu", 1),
257            ("get_some_initial_peers", 1),
258            ("get_staged_ledger_aux_and_pending_coinbases_at_hash", 2),
259            ("answer_sync_ledger_query", 2),
260            ("get_transition_chain", 2),
261            ("get_transition_chain_proof", 1),
262            ("Get_transition_knowledge", 1),
263            ("get_ancestry", 2),
264            ("ban_notify", 1),
265            ("get_best_tip", 2),
266            ("get_node_status", 2),
267            ("get_epoch_ledger", 2),
268        ] {
269            assert!(r.get(name.as_bytes(), version).is_some());
270        }
271    }
272
273    #[test]
274    fn jsonify_registry_query() {
275        let r = JSONifyPayloadRegistry::v2();
276        let payload =
277            hex::decode("220101e7dd9b0d45abb2e4dec2c5d22e1f1bd8ae5133047914209a0229e90a62ecfb0e")
278                .unwrap();
279        let mut ptr = payload.as_slice();
280        let jsonify = r.get(b"get_transition_chain", 1).unwrap();
281        let json = jsonify.read_query(&mut ptr).unwrap();
282        let expected = serde_json::json!([
283            "0x0efbec620ae929029a201479043351aed81b1f2ed2c5c2dee4b2ab450d9bdde7"
284        ]);
285        assert_eq!(json, expected);
286    }
287}