Skip to main content

cuprate_rpc_types/
json.rs

1//! JSON types from the [`/json_rpc`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#json-rpc-methods) endpoint.
2//!
3//! All types are originally defined in [`rpc/core_rpc_server_commands_defs.h`](https://github.com/monero-project/monero/blob/"cc73fe71162d564ffda8e549b79a350bca53c454"/src/rpc/core_rpc_server_commands_defs.h).
4
5//---------------------------------------------------------------------------------------------------- Import
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use cuprate_hex::{Hex, HexVec};
10use cuprate_types::rpc::{
11    AuxPow, GetMinerDataTxBacklogEntry, HardForkEntry, HardForkInfo, TxBacklogEntry,
12};
13
14use crate::{
15    base::{AccessResponseBase, ResponseBase},
16    macros::define_request_and_response,
17    misc::{
18        BlockHeader, ChainInfo, ConnectionInfo, Distribution, GetBan, HistogramEntry, SetBan, Span,
19        Status, SyncInfoPeer,
20    },
21    rpc_call::RpcCallValue,
22};
23
24#[cfg(any(feature = "epee", feature = "serde"))]
25use crate::defaults::{default, default_one, default_true};
26
27//---------------------------------------------------------------------------------------------------- Definitions
28// This generates 2 structs:
29//
30// - `GetBlockTemplateRequest`
31// - `GetBlockTemplateResponse`
32//
33// with some interconnected documentation.
34define_request_and_response! {
35    // The markdown tag for Monero RPC documentation. Not necessarily the endpoint.
36    get_block_template,
37
38    // The commit hash and `$file.$extension` in which this type is defined in
39    // the Monero codebase in the `rpc/` directory, followed by the specific lines.
40    "cc73fe71162d564ffda8e549b79a350bca53c454" => core_rpc_server_commands_defs.h => 943..=994,
41
42    // The base type name.
43    //
44    // After the type name, 2 optional idents are allowed:
45    // - `restricted`
46    // - `empty`
47    //
48    // These have to be within `()` and will affect the
49    // [`crate::RpcCall`] implementation on the request type.
50    //
51    // This type is not either restricted or empty so nothing is
52    // here, but the correct syntax is shown in a comment below:
53    GetBlockTemplate /* (restricted, empty) */,
54
55    // The request type.
56    //
57    // If there are any additional attributes (`/// docs` or `#[derive]`s)
58    // for the struct, they go here.
59    Request {
60        // Within the `{}` is an infinite matching pattern of:
61        // ```
62        // $ATTRIBUTES
63        // $FIELD_NAME: $FIELD_TYPE,
64        // ```
65        // The struct generated and all fields are `pub`.
66
67        // This optional expression can be placed after
68        // a `field: field_type`. this indicates to the
69        // macro to (de)serialize this field using this
70        // default expression if it doesn't exist in epee.
71        //
72        // See `cuprate_epee_encoding::epee_object` for info.
73        //
74        // The default function must be specified twice:
75        //
76        // 1. As an expression
77        // 2. As a string literal
78        //
79        // For example: `extra_nonce: HexVec /* = default::<HexVec>(), "default" */,`
80        //
81        // This is a HACK since `serde`'s default attribute only takes in
82        // string literals and macros (stringify) within attributes do not work.
83        extra_nonce: HexVec = default::<HexVec>(), "default",
84        prev_block: HexVec = default::<HexVec>(), "default",
85
86        // Another optional expression:
87        // This indicates to the macro to (de)serialize
88        // this field as another type in epee.
89        //
90        // See `cuprate_epee_encoding::epee_object` for info.
91        reserve_size: u64 /* as Type */,
92
93        wallet_address: String,
94    },
95
96    // The response type.
97    //
98    // If `Response {/* fields */}` is used,
99    // this will generate a struct as-is.
100    //
101    // If a type found in [`crate::base`] is used,
102    // It acts as a "base" that gets flattened into
103    // the actual request type.
104    //
105    // "Flatten" means the field(s) of a struct gets inlined
106    // directly into the struct during (de)serialization, see:
107    // <https://serde.rs/field-attrs.html#flatten>.
108    ResponseBase {
109        // This is using [`crate::base::ResponseBase`],
110        // so the type we generate will contain this field:
111        // ```
112        // base: crate::base::ResponseBase,
113        // ```
114        //
115        // This is flattened with serde and epee, so during
116        // (de)serialization, it will act as if there are 2 extra fields here:
117        // ```
118        // status: crate::Status,
119        // untrusted: bool,
120        // ```
121        blockhashing_blob: HexVec,
122        blocktemplate_blob: HexVec,
123        difficulty_top64: u64,
124        difficulty: u64,
125        expected_reward: u64,
126        height: u64,
127        /// This is a [`Hex<32>`] that is sometimes empty.
128        next_seed_hash: HexVec,
129        prev_hash: Hex<32>,
130        reserved_offset: u64,
131        seed_hash: Hex<32>,
132        seed_height: u64,
133        wide_difficulty: String,
134    }
135}
136
137define_request_and_response! {
138    get_block_count,
139    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
140    core_rpc_server_commands_defs.h => 919..=933,
141    GetBlockCount (empty),
142
143    Request {},
144
145    ResponseBase {
146        count: u64,
147    }
148}
149
150define_request_and_response! {
151    on_get_block_hash,
152    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
153    core_rpc_server_commands_defs.h => 935..=939,
154
155    OnGetBlockHash,
156
157    #[cfg_attr(feature = "serde", serde(transparent))]
158    #[repr(transparent)]
159    #[derive(Copy)]
160    Request {
161        /// This is `std::vector<u64>` in `monerod` but
162        /// it must be a 1 length array or else it will error.
163        block_height: [u64; 1],
164    },
165
166    #[cfg_attr(feature = "serde", serde(transparent))]
167    #[repr(transparent)]
168    Response {
169        block_hash: Hex<32>,
170    }
171}
172
173define_request_and_response! {
174    submit_block,
175    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
176    core_rpc_server_commands_defs.h => 1114..=1128,
177
178    SubmitBlock,
179
180    #[cfg_attr(feature = "serde", serde(transparent))]
181    #[repr(transparent)]
182    Request {
183        // This is `std::vector<std::string>` in `monerod` but
184        // it must be a 1 length array or else it will error.
185        block_blob: [HexVec; 1],
186    },
187
188    // FIXME: `cuprate_test_utils` only has an `error` response for this.
189    ResponseBase {
190        block_id: Hex<32>,
191    }
192}
193
194define_request_and_response! {
195    generateblocks,
196    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
197    core_rpc_server_commands_defs.h => 1130..=1161,
198
199    GenerateBlocks (restricted),
200
201    Request {
202        amount_of_blocks: u64,
203        prev_block: HexVec = default::<HexVec>(), "default",
204        starting_nonce: u32,
205        wallet_address: String,
206    },
207
208    ResponseBase {
209        blocks: Vec<Hex<32>>,
210        height: u64,
211    }
212}
213
214define_request_and_response! {
215    get_last_block_header,
216    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
217    core_rpc_server_commands_defs.h => 1214..=1238,
218
219    GetLastBlockHeader,
220
221    #[derive(Copy)]
222    Request {
223        fill_pow_hash: bool = default::<bool>(), "default",
224    },
225
226    AccessResponseBase {
227        block_header: BlockHeader,
228    }
229}
230
231define_request_and_response! {
232    get_block_header_by_hash,
233    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
234    core_rpc_server_commands_defs.h => 1240..=1269,
235    GetBlockHeaderByHash,
236
237    Request {
238        hash: Hex<32> = default::<Hex<32>>(), "default",
239        hashes: Vec<Hex<32>> = default::<Vec<Hex<32>>>(), "default",
240        fill_pow_hash: bool = default::<bool>(), "default",
241    },
242
243    AccessResponseBase {
244        block_header: BlockHeader,
245        #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
246        block_headers: Vec<BlockHeader>,
247    }
248}
249
250define_request_and_response! {
251    get_block_header_by_height,
252    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
253    core_rpc_server_commands_defs.h => 1271..=1296,
254
255    GetBlockHeaderByHeight,
256
257    #[derive(Copy)]
258    Request {
259        height: u64,
260        fill_pow_hash: bool = default::<bool>(), "default",
261    },
262
263    AccessResponseBase {
264        block_header: BlockHeader,
265    }
266}
267
268define_request_and_response! {
269    get_block_headers_range,
270    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
271    core_rpc_server_commands_defs.h => 1756..=1783,
272
273    GetBlockHeadersRange,
274
275    #[derive(Copy)]
276    Request {
277        start_height: u64,
278        end_height: u64,
279        fill_pow_hash: bool = default::<bool>(), "default",
280    },
281
282    AccessResponseBase {
283        headers: Vec<BlockHeader>,
284    }
285}
286
287define_request_and_response! {
288    get_block,
289    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
290    core_rpc_server_commands_defs.h => 1298..=1313,
291    GetBlock,
292
293    Request {
294        // `monerod` has both `hash` and `height` fields.
295        // In the RPC handler, if `hash.is_empty()`, it will use it, else, it uses `height`.
296        // <https://github.com/monero-project/monero/blob/"cc73fe71162d564ffda8e549b79a350bca53c454"/src/rpc/core_rpc_server.cpp#L2674>
297
298        /// This is a [`Hex<32>`] that is sometimes empty.
299        hash: HexVec = default::<HexVec>(), "default",
300        height: u64 = default::<u64>(), "default",
301        fill_pow_hash: bool = default::<bool>(), "default",
302    },
303
304    AccessResponseBase {
305        blob: HexVec,
306        block_header: BlockHeader,
307        /// `cuprate_types::json::block::Block` should be used
308        /// to create this JSON string in a type-safe manner.
309        json: String,
310        miner_tx_hash: Hex<32>,
311        #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
312        tx_hashes: Vec<Hex<32>>,
313    }
314}
315
316define_request_and_response! {
317    get_connections,
318    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
319    core_rpc_server_commands_defs.h => 1734..=1754,
320
321    GetConnections (restricted, empty),
322
323    Request {},
324
325    ResponseBase {
326        connections: Vec<ConnectionInfo>,
327    }
328}
329
330define_request_and_response! {
331    get_info,
332    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
333    core_rpc_server_commands_defs.h => 693..=789,
334    GetInfo (empty),
335    Request {},
336
337    AccessResponseBase {
338        adjusted_time: u64,
339        alt_blocks_count: u64,
340        block_size_limit: u64,
341        block_size_median: u64,
342        block_weight_limit: u64,
343        block_weight_median: u64,
344        bootstrap_daemon_address: String,
345        busy_syncing: bool,
346        cumulative_difficulty_top64: u64,
347        cumulative_difficulty: u64,
348        database_size: u64,
349        difficulty_top64: u64,
350        difficulty: u64,
351        free_space: u64,
352        grey_peerlist_size: u64,
353        height: u64,
354        height_without_bootstrap: u64,
355        incoming_connections_count: u64,
356        mainnet: bool,
357        nettype: String,
358        offline: bool,
359        outgoing_connections_count: u64,
360        restricted: bool,
361        rpc_connections_count: u64,
362        stagenet: bool,
363        start_time: u64,
364        synchronized: bool,
365        target_height: u64,
366        target: u64,
367        testnet: bool,
368        top_block_hash: Hex<32>,
369        tx_count: u64,
370        tx_pool_size: u64,
371        update_available: bool,
372        version: String,
373        was_bootstrap_ever_used: bool,
374        white_peerlist_size: u64,
375        wide_cumulative_difficulty: String,
376        wide_difficulty: String,
377    }
378}
379
380define_request_and_response! {
381    hard_fork_info,
382    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
383    core_rpc_server_commands_defs.h => 1958..=1995,
384    HardForkInfo,
385
386    #[derive(Copy)]
387    Request {
388        version: u8,
389    },
390
391    AccessResponseBase {
392        /// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
393        #[cfg_attr(feature = "serde", serde(flatten))]
394        hard_fork_info: HardForkInfo,
395    }
396}
397
398define_request_and_response! {
399    set_bans,
400    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
401    core_rpc_server_commands_defs.h => 2032..=2067,
402
403    SetBans (restricted),
404
405    Request {
406        bans: Vec<SetBan>,
407    },
408
409    ResponseBase {}
410}
411
412define_request_and_response! {
413    get_bans,
414    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
415    core_rpc_server_commands_defs.h => 1997..=2030,
416    GetBans (restricted, empty),
417    Request {},
418
419    ResponseBase {
420        bans: Vec<GetBan>,
421    }
422}
423
424define_request_and_response! {
425    banned,
426    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
427    core_rpc_server_commands_defs.h => 2069..=2094,
428
429    Banned (restricted),
430
431    Request {
432        address: String,
433    },
434
435    Response {
436        banned: bool,
437        seconds: u32,
438        status: Status,
439    }
440}
441
442define_request_and_response! {
443    flush_txpool,
444    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
445    core_rpc_server_commands_defs.h => 2096..=2116,
446
447    FlushTxpool (restricted),
448
449    Request {
450        txids: Vec<Hex<32>> = default::<Vec<Hex<32>>>(), "default",
451    },
452
453    #[repr(transparent)]
454    Response {
455        status: Status,
456    }
457}
458
459define_request_and_response! {
460    get_output_histogram,
461    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
462    core_rpc_server_commands_defs.h => 2118..=2168,
463    GetOutputHistogram,
464
465    Request {
466        amounts: Vec<u64> = default::<Vec<u64>>(), "default",
467        min_count: u64 = default::<u64>(), "default",
468        max_count: u64 = default::<u64>(), "default",
469        unlocked: bool = default::<bool>(), "default",
470        recent_cutoff: u64 = default::<u64>(), "default",
471    },
472
473    AccessResponseBase {
474        histogram: Vec<HistogramEntry>,
475    }
476}
477
478define_request_and_response! {
479    get_coinbase_tx_sum,
480    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
481    core_rpc_server_commands_defs.h => 2213..=2248,
482
483    GetCoinbaseTxSum (restricted),
484
485    Request {
486        height: u64,
487        count: u64,
488    },
489
490    AccessResponseBase {
491        emission_amount: u64,
492        emission_amount_top64: u64,
493        fee_amount: u64,
494        fee_amount_top64: u64,
495        wide_emission_amount: String,
496        wide_fee_amount: String,
497    }
498}
499
500define_request_and_response! {
501    get_version,
502    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
503    core_rpc_server_commands_defs.h => 2170..=2211,
504
505    GetVersion (empty),
506    Request {},
507
508    ResponseBase {
509        version: u32,
510        release: bool,
511        current_height: u64 = default::<u64>(), "default",
512        #[cfg_attr(feature = "serde", serde(skip_serializing_if = "crate::free::is_zero"))]
513        target_height: u64 = default::<u64>(), "default",
514        hard_forks: Vec<HardForkEntry>,
515    }
516}
517
518define_request_and_response! {
519    get_fee_estimate,
520    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
521    core_rpc_server_commands_defs.h => 2250..=2277,
522
523    GetFeeEstimate,
524
525    Request {
526        grace_blocks: u64 = default::<u64>(), "default",
527    },
528
529    AccessResponseBase {
530        fee: u64,
531        fees: Vec<u64>,
532        quantization_mask: u64 = default_one::<u64>(), "default_one",
533    }
534}
535
536define_request_and_response! {
537    get_alternate_chains,
538    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
539    core_rpc_server_commands_defs.h => 2279..=2310,
540    GetAlternateChains (restricted, empty),
541    Request {},
542
543    ResponseBase {
544        chains: Vec<ChainInfo>,
545    }
546}
547
548define_request_and_response! {
549    relay_tx,
550    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
551    core_rpc_server_commands_defs.h => 2361..=2381,
552
553    RelayTx (restricted),
554
555    Request {
556        txids: Vec<Hex<32>> = default::<Vec<Hex<32>>>(), "default",
557    },
558
559    #[repr(transparent)]
560    Response {
561        status: Status,
562    }
563}
564
565define_request_and_response! {
566    sync_info,
567    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
568    core_rpc_server_commands_defs.h => 2383..=2443,
569
570    SyncInfo (restricted, empty),
571
572    Request {},
573
574    AccessResponseBase {
575        height: u64,
576        next_needed_pruning_seed: u32,
577        overview: String,
578        peers: Vec<SyncInfoPeer>,
579        spans: Vec<Span>,
580        target_height: u64,
581    }
582}
583
584define_request_and_response! {
585    get_txpool_backlog,
586    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
587    core_rpc_server_commands_defs.h => 1637..=1664,
588    GetTxpoolBacklog (empty),
589    Request {},
590
591    AccessResponseBase {
592        // Monero serializes this as a POD blob rather than a JSON array. We handle that with custom
593        // seralisation code for this type.
594        backlog: Vec<TxBacklogEntry>,
595    }
596}
597
598define_request_and_response! {
599    get_output_distribution,
600    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
601    core_rpc_server_commands_defs.h => 2445..=2520,
602
603    /// This type is also used in the (undocumented)
604    /// [`/get_output_distribution.bin`](https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.h#L138)
605    /// binary endpoint.
606    GetOutputDistribution,
607
608    Request {
609        amounts: Vec<u64>,
610        binary: bool = default_true(), "default_true",
611        compress: bool = default::<bool>(), "default",
612        cumulative: bool = default::<bool>(), "default",
613        from_height: u64 = default::<u64>(), "default",
614        to_height: u64 = default::<u64>(), "default",
615    },
616
617    AccessResponseBase {
618        distributions: Vec<Distribution>,
619    }
620}
621
622define_request_and_response! {
623    get_miner_data,
624    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
625    core_rpc_server_commands_defs.h => 996..=1044,
626    GetMinerData (empty),
627    Request {},
628
629    ResponseBase {
630        major_version: u8,
631        height: u64,
632        prev_id: Hex<32>,
633        seed_hash: Hex<32>,
634        difficulty: String,
635        median_weight: u64,
636        already_generated_coins: u64,
637        tx_backlog: Vec<GetMinerDataTxBacklogEntry>,
638    }
639}
640
641define_request_and_response! {
642    prune_blockchain,
643    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
644    core_rpc_server_commands_defs.h => 2747..=2772,
645
646    PruneBlockchain (restricted),
647
648    #[derive(Copy)]
649    Request {
650        check: bool = default::<bool>(), "default",
651    },
652
653    ResponseBase {
654        pruned: bool,
655        pruning_seed: u32,
656    }
657}
658
659define_request_and_response! {
660    calc_pow,
661    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
662    core_rpc_server_commands_defs.h => 1046..=1066,
663
664    CalcPow (restricted),
665
666    Request {
667        major_version: u8,
668        height: u64,
669        block_blob: HexVec,
670        seed_hash: Hex<32>,
671    },
672
673    #[cfg_attr(feature = "serde", serde(transparent))]
674    #[repr(transparent)]
675    Response {
676        pow_hash: Hex<32>,
677    }
678}
679
680define_request_and_response! {
681    flush_cache,
682    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
683    core_rpc_server_commands_defs.h => 2774..=2796,
684
685    FlushCache (restricted),
686
687    #[derive(Copy)]
688    Request {
689        bad_txs: bool,
690        bad_blocks: bool,
691    },
692
693    ResponseBase {}
694}
695
696define_request_and_response! {
697    add_aux_pow,
698    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
699    core_rpc_server_commands_defs.h => 1068..=1112,
700
701    AddAuxPow,
702
703    Request {
704        blocktemplate_blob: HexVec,
705        aux_pow: Vec<AuxPow>,
706    },
707
708    ResponseBase {
709      blocktemplate_blob: HexVec,
710      blockhashing_blob: HexVec,
711      merkle_root: Hex<32>,
712      merkle_tree_depth: u64,
713      aux_pow: Vec<AuxPow>,
714    }
715}
716
717define_request_and_response! {
718    UNDOCUMENTED_METHOD,
719    "cc73fe71162d564ffda8e549b79a350bca53c454" =>
720    core_rpc_server_commands_defs.h => 2798..=2823,
721
722    GetTxIdsLoose,
723
724    Request {
725        txid_template: String,
726        num_matching_bits: u32,
727    },
728    ResponseBase {
729        txids: Vec<Hex<32>>,
730    }
731}
732
733//---------------------------------------------------------------------------------------------------- Request
734/// JSON-RPC requests.
735///
736/// This enum contains all [`crate::json`] requests.
737///
738/// See also: [`JsonRpcResponse`].
739///
740/// TODO: document and test (de)serialization behavior after figuring out `method/params`.
741#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
742#[cfg_attr(feature = "serde", derive(Serialize))]
743#[cfg_attr(
744    feature = "serde",
745    serde(rename_all = "snake_case", tag = "method", content = "params")
746)]
747pub enum JsonRpcRequest {
748    #[cfg_attr(feature = "serde", serde(alias = "getblockcount"))]
749    GetBlockCount(GetBlockCountRequest),
750    #[cfg_attr(feature = "serde", serde(alias = "on_getblockhash"))]
751    OnGetBlockHash(OnGetBlockHashRequest),
752    #[cfg_attr(feature = "serde", serde(alias = "getblocktemplate"))]
753    GetBlockTemplate(GetBlockTemplateRequest),
754    GetMinerData(GetMinerDataRequest),
755    CalcPow(CalcPowRequest),
756    AddAuxPow(AddAuxPowRequest),
757    #[cfg_attr(feature = "serde", serde(alias = "submitblock"))]
758    SubmitBlock(SubmitBlockRequest),
759    #[cfg_attr(feature = "serde", serde(alias = "generateblocks"))]
760    GenerateBlocks(GenerateBlocksRequest), // TODO: this only has 1 endpoint: generateblocks no generate_blocks
761    #[cfg_attr(feature = "serde", serde(alias = "getlastblockheader"))]
762    GetLastBlockHeader(GetLastBlockHeaderRequest),
763    #[cfg_attr(feature = "serde", serde(alias = "getblockheaderbyhash"))]
764    GetBlockHeaderByHash(GetBlockHeaderByHashRequest),
765    #[cfg_attr(feature = "serde", serde(alias = "getblockheaderbyheight"))]
766    GetBlockHeaderByHeight(GetBlockHeaderByHeightRequest),
767    #[cfg_attr(feature = "serde", serde(alias = "getblockheadersrange"))]
768    GetBlockHeadersRange(GetBlockHeadersRangeRequest),
769    #[cfg_attr(feature = "serde", serde(alias = "getblock"))]
770    GetBlock(GetBlockRequest),
771    GetConnections(GetConnectionsRequest),
772    GetInfo(GetInfoRequest),
773    HardForkInfo(HardForkInfoRequest),
774    SetBans(SetBansRequest),
775    GetBans(GetBansRequest),
776    Banned(BannedRequest),
777    FlushTxpool(FlushTxpoolRequest),
778    GetOutputHistogram(GetOutputHistogramRequest),
779    GetVersion(GetVersionRequest),
780    GetCoinbaseTxSum(GetCoinbaseTxSumRequest),
781    GetFeeEstimate(GetFeeEstimateRequest),
782    GetAlternateChains(GetAlternateChainsRequest),
783    RelayTx(RelayTxRequest),
784    SyncInfo(SyncInfoRequest),
785    GetTxpoolBacklog(GetTxpoolBacklogRequest),
786    GetOutputDistribution(GetOutputDistributionRequest),
787    PruneBlockchain(PruneBlockchainRequest),
788    FlushCache(FlushCacheRequest),
789    GetTxIdsLoose(GetTxIdsLooseRequest),
790}
791
792#[cfg(feature = "serde")]
793impl<'de> Deserialize<'de> for JsonRpcRequest {
794    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
795        use serde::de::Error;
796
797        fn default_params() -> serde_json::Value {
798            serde_json::Value::Object(Default::default())
799        }
800
801        #[derive(Deserialize)]
802        struct Helper {
803            method: String,
804            #[serde(default = "default_params")]
805            params: serde_json::Value,
806        }
807
808        let Helper { method, mut params } = Helper::deserialize(deserializer)?;
809
810        // monerod's JSON parser silently drops `null` and empty arrays without
811        // storing them, so we just inject an empty `{}` section.
812        if params.is_null() || params.as_array().is_some_and(Vec::is_empty) {
813            params = serde_json::Value::Object(Default::default());
814        }
815
816        // Deserialize `params` (a `serde_json::Value`) into the concrete request type.
817        macro_rules! de {
818            ($T:ty) => {
819                serde_json::from_value::<$T>(params).map_err(D::Error::custom)?
820            };
821        }
822
823        Ok(match method.as_str() {
824            "get_block_count" | "getblockcount" => Self::GetBlockCount(de!(GetBlockCountRequest)),
825            "on_get_block_hash" | "on_getblockhash" => {
826                Self::OnGetBlockHash(de!(OnGetBlockHashRequest))
827            }
828            "get_block_template" | "getblocktemplate" => {
829                Self::GetBlockTemplate(de!(GetBlockTemplateRequest))
830            }
831            "get_miner_data" => Self::GetMinerData(de!(GetMinerDataRequest)),
832            "calc_pow" => Self::CalcPow(de!(CalcPowRequest)),
833            "add_aux_pow" => Self::AddAuxPow(de!(AddAuxPowRequest)),
834            "submit_block" | "submitblock" => Self::SubmitBlock(de!(SubmitBlockRequest)),
835            "generateblocks" => Self::GenerateBlocks(de!(GenerateBlocksRequest)),
836            "get_last_block_header" | "getlastblockheader" => {
837                Self::GetLastBlockHeader(de!(GetLastBlockHeaderRequest))
838            }
839            "get_block_header_by_hash" | "getblockheaderbyhash" => {
840                Self::GetBlockHeaderByHash(de!(GetBlockHeaderByHashRequest))
841            }
842            "get_block_header_by_height" | "getblockheaderbyheight" => {
843                Self::GetBlockHeaderByHeight(de!(GetBlockHeaderByHeightRequest))
844            }
845            "get_block_headers_range" | "getblockheadersrange" => {
846                Self::GetBlockHeadersRange(de!(GetBlockHeadersRangeRequest))
847            }
848            "get_block" | "getblock" => Self::GetBlock(de!(GetBlockRequest)),
849            "get_connections" => Self::GetConnections(de!(GetConnectionsRequest)),
850            "get_info" => Self::GetInfo(de!(GetInfoRequest)),
851            "hard_fork_info" => Self::HardForkInfo(de!(HardForkInfoRequest)),
852            "set_bans" => Self::SetBans(de!(SetBansRequest)),
853            "get_bans" => Self::GetBans(de!(GetBansRequest)),
854            "banned" => Self::Banned(de!(BannedRequest)),
855            "flush_txpool" => Self::FlushTxpool(de!(FlushTxpoolRequest)),
856            "get_output_histogram" => Self::GetOutputHistogram(de!(GetOutputHistogramRequest)),
857            "get_version" => Self::GetVersion(de!(GetVersionRequest)),
858            "get_coinbase_tx_sum" => Self::GetCoinbaseTxSum(de!(GetCoinbaseTxSumRequest)),
859            "get_fee_estimate" => Self::GetFeeEstimate(de!(GetFeeEstimateRequest)),
860            "get_alternate_chains" => Self::GetAlternateChains(de!(GetAlternateChainsRequest)),
861            "relay_tx" => Self::RelayTx(de!(RelayTxRequest)),
862            "sync_info" => Self::SyncInfo(de!(SyncInfoRequest)),
863            "get_txpool_backlog" => Self::GetTxpoolBacklog(de!(GetTxpoolBacklogRequest)),
864            "get_output_distribution" => {
865                Self::GetOutputDistribution(de!(GetOutputDistributionRequest))
866            }
867            "prune_blockchain" => Self::PruneBlockchain(de!(PruneBlockchainRequest)),
868            "flush_cache" => Self::FlushCache(de!(FlushCacheRequest)),
869            "get_tx_ids_loose" => Self::GetTxIdsLoose(de!(GetTxIdsLooseRequest)),
870            other => return Err(D::Error::unknown_variant(other, &[])),
871        })
872    }
873}
874
875impl RpcCallValue for JsonRpcRequest {
876    fn is_restricted(&self) -> bool {
877        match self {
878            Self::GetBlockTemplate(x) => x.is_restricted(),
879            Self::GetBlockCount(x) => x.is_restricted(),
880            Self::OnGetBlockHash(x) => x.is_restricted(),
881            Self::SubmitBlock(x) => x.is_restricted(),
882            Self::GetLastBlockHeader(x) => x.is_restricted(),
883            Self::GetBlockHeaderByHash(x) => x.is_restricted(),
884            Self::GetBlockHeaderByHeight(x) => x.is_restricted(),
885            Self::GetBlockHeadersRange(x) => x.is_restricted(),
886            Self::GetBlock(x) => x.is_restricted(),
887            Self::GetInfo(x) => x.is_restricted(),
888            Self::HardForkInfo(x) => x.is_restricted(),
889            Self::GetOutputHistogram(x) => x.is_restricted(),
890            Self::GetVersion(x) => x.is_restricted(),
891            Self::GetFeeEstimate(x) => x.is_restricted(),
892            Self::GetTxpoolBacklog(x) => x.is_restricted(),
893            Self::GetMinerData(x) => x.is_restricted(),
894            Self::AddAuxPow(x) => x.is_restricted(),
895            Self::GetTxIdsLoose(x) => x.is_restricted(),
896            Self::GenerateBlocks(x) => x.is_restricted(),
897            Self::GetConnections(x) => x.is_restricted(),
898            Self::SetBans(x) => x.is_restricted(),
899            Self::GetBans(x) => x.is_restricted(),
900            Self::Banned(x) => x.is_restricted(),
901            Self::FlushTxpool(x) => x.is_restricted(),
902            Self::GetCoinbaseTxSum(x) => x.is_restricted(),
903            Self::GetAlternateChains(x) => x.is_restricted(),
904            Self::RelayTx(x) => x.is_restricted(),
905            Self::SyncInfo(x) => x.is_restricted(),
906            Self::PruneBlockchain(x) => x.is_restricted(),
907            Self::CalcPow(x) => x.is_restricted(),
908            Self::FlushCache(x) => x.is_restricted(),
909            Self::GetOutputDistribution(x) => x.is_restricted(),
910        }
911    }
912
913    fn is_empty(&self) -> bool {
914        match self {
915            Self::GetBlockTemplate(x) => x.is_empty(),
916            Self::GetBlockCount(x) => x.is_empty(),
917            Self::OnGetBlockHash(x) => x.is_empty(),
918            Self::SubmitBlock(x) => x.is_empty(),
919            Self::GetLastBlockHeader(x) => x.is_empty(),
920            Self::GetBlockHeaderByHash(x) => x.is_empty(),
921            Self::GetBlockHeaderByHeight(x) => x.is_empty(),
922            Self::GetBlockHeadersRange(x) => x.is_empty(),
923            Self::GetBlock(x) => x.is_empty(),
924            Self::GetInfo(x) => x.is_empty(),
925            Self::HardForkInfo(x) => x.is_empty(),
926            Self::GetOutputHistogram(x) => x.is_empty(),
927            Self::GetVersion(x) => x.is_empty(),
928            Self::GetFeeEstimate(x) => x.is_empty(),
929            Self::GetTxpoolBacklog(x) => x.is_empty(),
930            Self::GetMinerData(x) => x.is_empty(),
931            Self::AddAuxPow(x) => x.is_empty(),
932            Self::GetTxIdsLoose(x) => x.is_empty(),
933            Self::GenerateBlocks(x) => x.is_empty(),
934            Self::GetConnections(x) => x.is_empty(),
935            Self::SetBans(x) => x.is_empty(),
936            Self::GetBans(x) => x.is_empty(),
937            Self::Banned(x) => x.is_empty(),
938            Self::FlushTxpool(x) => x.is_empty(),
939            Self::GetCoinbaseTxSum(x) => x.is_empty(),
940            Self::GetAlternateChains(x) => x.is_empty(),
941            Self::RelayTx(x) => x.is_empty(),
942            Self::SyncInfo(x) => x.is_empty(),
943            Self::PruneBlockchain(x) => x.is_empty(),
944            Self::CalcPow(x) => x.is_empty(),
945            Self::FlushCache(x) => x.is_empty(),
946            Self::GetOutputDistribution(x) => x.is_empty(),
947        }
948    }
949}
950
951//---------------------------------------------------------------------------------------------------- Response
952/// JSON-RPC responses.
953///
954/// This enum contains all [`crate::json`] responses.
955///
956/// See also: [`JsonRpcRequest`].
957///
958/// # (De)serialization
959/// The `serde` implementation will (de)serialize from
960/// the inner variant itself, e.g. [`JsonRpcRequest::Banned`]
961/// has the same (de)serialization as [`BannedResponse`].
962///
963/// ```rust
964/// use cuprate_rpc_types::{misc::*, json::*};
965///
966/// let response = JsonRpcResponse::Banned(BannedResponse {
967///     banned: true,
968///     seconds: 123,
969///     status: Status::Ok,
970/// });
971/// let json = serde_json::to_string(&response).unwrap();
972/// assert_eq!(json, r#"{"banned":true,"seconds":123,"status":"OK"}"#);
973/// let response: JsonRpcResponse = serde_json::from_str(&json).unwrap();
974/// ```
975#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
976#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
977#[cfg_attr(feature = "serde", serde(untagged, rename_all = "snake_case"))]
978pub enum JsonRpcResponse {
979    GetBlockTemplate(GetBlockTemplateResponse),
980    GetBlockCount(GetBlockCountResponse),
981    OnGetBlockHash(OnGetBlockHashResponse),
982    SubmitBlock(SubmitBlockResponse),
983    GenerateBlocks(GenerateBlocksResponse),
984    GetLastBlockHeader(GetLastBlockHeaderResponse),
985    GetBlockHeaderByHash(GetBlockHeaderByHashResponse),
986    GetBlockHeaderByHeight(GetBlockHeaderByHeightResponse),
987    GetBlockHeadersRange(GetBlockHeadersRangeResponse),
988    GetBlock(GetBlockResponse),
989    GetConnections(GetConnectionsResponse),
990    GetInfo(GetInfoResponse),
991    HardForkInfo(HardForkInfoResponse),
992    SetBans(SetBansResponse),
993    GetBans(GetBansResponse),
994    Banned(BannedResponse),
995    FlushTxpool(FlushTxpoolResponse),
996    GetOutputHistogram(GetOutputHistogramResponse),
997    GetCoinbaseTxSum(GetCoinbaseTxSumResponse),
998    GetVersion(GetVersionResponse),
999    GetFeeEstimate(GetFeeEstimateResponse),
1000    GetAlternateChains(GetAlternateChainsResponse),
1001    RelayTx(RelayTxResponse),
1002    SyncInfo(SyncInfoResponse),
1003    GetTxpoolBacklog(GetTxpoolBacklogResponse),
1004    GetOutputDistribution(GetOutputDistributionResponse),
1005    GetMinerData(GetMinerDataResponse),
1006    PruneBlockchain(PruneBlockchainResponse),
1007    CalcPow(CalcPowResponse),
1008    FlushCache(FlushCacheResponse),
1009    AddAuxPow(AddAuxPowResponse),
1010    GetTxIdsLoose(GetTxIdsLooseResponse),
1011}
1012
1013//---------------------------------------------------------------------------------------------------- Tests
1014#[cfg(test)]
1015mod test {
1016    use std::fmt::Debug;
1017
1018    use hex_literal::hex;
1019    use pretty_assertions::assert_eq;
1020    use serde::de::DeserializeOwned;
1021    use serde_json::{from_str, from_value, Value};
1022
1023    use cuprate_test_utils::rpc::data::json;
1024    use cuprate_types::HardFork;
1025
1026    use super::*;
1027
1028    #[expect(clippy::needless_pass_by_value)]
1029    fn test_json_request<T: DeserializeOwned + PartialEq + Debug>(
1030        cuprate_test_utils_example_data: &str,
1031        expected_type: T,
1032    ) {
1033        let value = from_str::<Value>(cuprate_test_utils_example_data).unwrap();
1034        let Value::Object(map) = value else {
1035            unreachable!();
1036        };
1037
1038        let params = map.get("params").unwrap();
1039        let response = from_value::<T>(params.clone()).unwrap();
1040        assert_eq!(response, expected_type);
1041    }
1042
1043    #[expect(clippy::needless_pass_by_value)]
1044    fn test_json_response<T: DeserializeOwned + PartialEq + Debug>(
1045        cuprate_test_utils_example_data: &str,
1046        expected_type: T,
1047    ) {
1048        let value = from_str::<Value>(cuprate_test_utils_example_data).unwrap();
1049        let Value::Object(map) = value else {
1050            unreachable!();
1051        };
1052
1053        let result = map.get("result").unwrap().clone();
1054        let response = from_value::<T>(result).unwrap();
1055        assert_eq!(response, expected_type);
1056    }
1057
1058    #[test]
1059    fn get_block_template_request() {
1060        test_json_request(json::GET_BLOCK_TEMPLATE_REQUEST, GetBlockTemplateRequest {
1061            reserve_size: 60,
1062            extra_nonce: HexVec::default(),
1063            prev_block: HexVec::default(),
1064            wallet_address: "44GBHzv6ZyQdJkjqZje6KLZ3xSyN1hBSFAnLP6EAqJtCRVzMzZmeXTC2AHKDS9aEDTRKmo6a6o9r9j86pYfhCWDkKjbtcns".into(),
1065        });
1066    }
1067
1068    #[test]
1069    fn get_block_template_response() {
1070        test_json_response(json::GET_BLOCK_TEMPLATE_RESPONSE, GetBlockTemplateResponse {
1071            base: ResponseBase::OK,
1072            blockhashing_blob: HexVec(hex!("1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a00000000e0c20372be23d356347091025c5b5e8f2abf83ab618378565cce2b703491523401").into()),
1073            blocktemplate_blob: HexVec(hex!("1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a0000000002c681c30101ff8a81c3010180e0a596bb11033b7eedf47baf878f3490cb20b696079c34bd017fe59b0d070e74d73ffabc4bb0e05f011decb630f3148d0163b3bd39690dde4078e4cfb69fecf020d6278a27bad10c58023c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into()),
1074            difficulty_top64: 0,
1075            difficulty: 283305047039,
1076            expected_reward: 600000000000,
1077            height: 3195018,
1078            next_seed_hash: HexVec::new(),
1079            prev_hash: Hex(hex!("9d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a")),
1080            reserved_offset: 131,
1081            seed_hash: Hex(hex!("e2aa0b7b55042cd48b02e395d78fa66a29815ccc1584e38db2d1f0e8485cd44f")),
1082            seed_height: 3194880,
1083            wide_difficulty: "0x41f64bf3ff".into(),
1084        });
1085    }
1086
1087    #[test]
1088    fn get_block_count_response() {
1089        test_json_response(
1090            json::GET_BLOCK_COUNT_RESPONSE,
1091            GetBlockCountResponse {
1092                base: ResponseBase::OK,
1093                count: 3195019,
1094            },
1095        );
1096    }
1097
1098    #[test]
1099    fn get_block_hash_request() {
1100        test_json_request(
1101            json::ON_GET_BLOCK_HASH_REQUEST,
1102            OnGetBlockHashRequest {
1103                block_height: [912345],
1104            },
1105        );
1106    }
1107
1108    #[test]
1109    fn get_block_hash_response() {
1110        test_json_response(
1111            json::ON_GET_BLOCK_HASH_RESPONSE,
1112            OnGetBlockHashResponse {
1113                block_hash: Hex(hex!(
1114                    "e22cf75f39ae720e8b71b3d120a5ac03f0db50bba6379e2850975b4859190bc6"
1115                )),
1116            },
1117        );
1118    }
1119
1120    #[test]
1121    fn submit_block_request() {
1122        test_json_request(json::SUBMIT_BLOCK_REQUEST, SubmitBlockRequest {
1123            block_blob: [HexVec(hex!("0707e6bdfedc053771512f1bc27c62731ae9e8f2443db64ce742f4e57f5cf8d393de28551e441a0000000002fb830a01ffbf830a018cfe88bee283060274c0aae2ef5730e680308d9c00b6da59187ad0352efe3c71d36eeeb28782f29f2501bd56b952c3ddc3e350c2631d3a5086cac172c56893831228b17de296ff4669de020200000000").into())],
1124        });
1125    }
1126
1127    #[test]
1128    fn generate_blocks_request() {
1129        test_json_request(json::GENERATE_BLOCKS_REQUEST, GenerateBlocksRequest {
1130            amount_of_blocks: 1,
1131            prev_block: HexVec::default(),
1132            wallet_address: "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A".into(),
1133            starting_nonce: 0
1134        });
1135    }
1136
1137    #[test]
1138    fn generate_blocks_response() {
1139        test_json_response(
1140            json::GENERATE_BLOCKS_RESPONSE,
1141            GenerateBlocksResponse {
1142                base: ResponseBase::OK,
1143                blocks: vec![Hex(hex!(
1144                    "49b712db7760e3728586f8434ee8bc8d7b3d410dac6bb6e98bf5845c83b917e4"
1145                ))],
1146                height: 9783,
1147            },
1148        );
1149    }
1150
1151    #[test]
1152    fn get_last_block_header_response() {
1153        test_json_response(
1154            json::GET_LAST_BLOCK_HEADER_RESPONSE,
1155            GetLastBlockHeaderResponse {
1156                base: AccessResponseBase::OK,
1157                block_header: BlockHeader {
1158                    block_size: 200419,
1159                    block_weight: 200419,
1160                    cumulative_difficulty: 366125734645190820,
1161                    cumulative_difficulty_top64: 0,
1162                    depth: 0,
1163                    difficulty: 282052561854,
1164                    difficulty_top64: 0,
1165                    hash: Hex(hex!(
1166                        "57238217820195ac4c08637a144a885491da167899cf1d20e8e7ce0ae0a3434e"
1167                    )),
1168                    height: 3195020,
1169                    long_term_weight: 200419,
1170                    major_version: HardFork::V16,
1171                    miner_tx_hash: Hex(hex!(
1172                        "7a42667237d4f79891bb407c49c712a9299fb87fce799833a7b633a3a9377dbd"
1173                    )),
1174                    minor_version: 16,
1175                    nonce: 1885649739,
1176                    num_txes: 37,
1177                    orphan_status: false,
1178                    pow_hash: HexVec::new(),
1179                    prev_hash: Hex(hex!(
1180                        "22c72248ae9c5a2863c94735d710a3525c499f70707d1c2f395169bc5c8a0da3"
1181                    )),
1182                    reward: 615702960000,
1183                    timestamp: 1721245548,
1184                    wide_cumulative_difficulty: "0x514bd6a74a7d0a4".into(),
1185                    wide_difficulty: "0x41aba48bbe".into(),
1186                },
1187            },
1188        );
1189    }
1190
1191    #[test]
1192    fn get_block_header_by_hash_request() {
1193        test_json_request(
1194            json::GET_BLOCK_HEADER_BY_HASH_REQUEST,
1195            GetBlockHeaderByHashRequest {
1196                hash: Hex(hex!(
1197                    "e22cf75f39ae720e8b71b3d120a5ac03f0db50bba6379e2850975b4859190bc6"
1198                )),
1199                hashes: vec![],
1200                fill_pow_hash: false,
1201            },
1202        );
1203    }
1204
1205    #[test]
1206    fn get_block_header_by_hash_response() {
1207        test_json_response(
1208            json::GET_BLOCK_HEADER_BY_HASH_RESPONSE,
1209            GetBlockHeaderByHashResponse {
1210                base: AccessResponseBase::OK,
1211                block_headers: vec![],
1212                block_header: BlockHeader {
1213                    block_size: 210,
1214                    block_weight: 210,
1215                    cumulative_difficulty: 754734824984346,
1216                    cumulative_difficulty_top64: 0,
1217                    depth: 2282676,
1218                    difficulty: 815625611,
1219                    difficulty_top64: 0,
1220                    hash: Hex(hex!(
1221                        "e22cf75f39ae720e8b71b3d120a5ac03f0db50bba6379e2850975b4859190bc6"
1222                    )),
1223                    height: 912345,
1224                    long_term_weight: 210,
1225                    major_version: HardFork::V1,
1226                    miner_tx_hash: Hex(hex!(
1227                        "c7da3965f25c19b8eb7dd8db48dcd4e7c885e2491db77e289f0609bf8e08ec30"
1228                    )),
1229                    minor_version: 2,
1230                    nonce: 1646,
1231                    num_txes: 0,
1232                    orphan_status: false,
1233                    pow_hash: HexVec::new(),
1234                    prev_hash: Hex(hex!(
1235                        "b61c58b2e0be53fad5ef9d9731a55e8a81d972b8d90ed07c04fd37ca6403ff78"
1236                    )),
1237                    reward: 7388968946286,
1238                    timestamp: 1452793716,
1239                    wide_cumulative_difficulty: "0x2ae6d65248f1a".into(),
1240                    wide_difficulty: "0x309d758b".into(),
1241                },
1242            },
1243        );
1244    }
1245
1246    #[test]
1247    fn block_header_by_height_request() {
1248        test_json_request(
1249            json::GET_BLOCK_HEADER_BY_HEIGHT_REQUEST,
1250            GetBlockHeaderByHeightRequest {
1251                height: 912345,
1252                fill_pow_hash: false,
1253            },
1254        );
1255    }
1256
1257    #[test]
1258    fn block_header_by_height_response() {
1259        test_json_response(
1260            json::GET_BLOCK_HEADER_BY_HEIGHT_RESPONSE,
1261            GetBlockHeaderByHeightResponse {
1262                base: AccessResponseBase::OK,
1263                block_header: BlockHeader {
1264                    block_size: 210,
1265                    block_weight: 210,
1266                    cumulative_difficulty: 754734824984346,
1267                    cumulative_difficulty_top64: 0,
1268                    depth: 2282677,
1269                    difficulty: 815625611,
1270                    difficulty_top64: 0,
1271                    hash: Hex(hex!(
1272                        "e22cf75f39ae720e8b71b3d120a5ac03f0db50bba6379e2850975b4859190bc6"
1273                    )),
1274                    height: 912345,
1275                    long_term_weight: 210,
1276                    major_version: HardFork::V1,
1277                    miner_tx_hash: Hex(hex!(
1278                        "c7da3965f25c19b8eb7dd8db48dcd4e7c885e2491db77e289f0609bf8e08ec30"
1279                    )),
1280                    minor_version: 2,
1281                    nonce: 1646,
1282                    num_txes: 0,
1283                    orphan_status: false,
1284                    pow_hash: HexVec::new(),
1285                    prev_hash: Hex(hex!(
1286                        "b61c58b2e0be53fad5ef9d9731a55e8a81d972b8d90ed07c04fd37ca6403ff78"
1287                    )),
1288                    reward: 7388968946286,
1289                    timestamp: 1452793716,
1290                    wide_cumulative_difficulty: "0x2ae6d65248f1a".into(),
1291                    wide_difficulty: "0x309d758b".into(),
1292                },
1293            },
1294        );
1295    }
1296
1297    #[test]
1298    fn block_headers_range_request() {
1299        test_json_request(
1300            json::GET_BLOCK_HEADERS_RANGE_REQUEST,
1301            GetBlockHeadersRangeRequest {
1302                start_height: 1545999,
1303                end_height: 1546000,
1304                fill_pow_hash: false,
1305            },
1306        );
1307    }
1308
1309    #[test]
1310    fn block_headers_range_response() {
1311        test_json_response(
1312            json::GET_BLOCK_HEADERS_RANGE_RESPONSE,
1313            GetBlockHeadersRangeResponse {
1314                base: AccessResponseBase::OK,
1315                headers: vec![
1316                    BlockHeader {
1317                        block_size: 301413,
1318                        block_weight: 301413,
1319                        cumulative_difficulty: 13185267971483472,
1320                        cumulative_difficulty_top64: 0,
1321                        depth: 1649024,
1322                        difficulty: 134636057921,
1323                        difficulty_top64: 0,
1324                        hash: Hex(hex!(
1325                            "86d1d20a40cefcf3dd410ff6967e0491613b77bf73ea8f1bf2e335cf9cf7d57a"
1326                        )),
1327                        height: 1545999,
1328                        long_term_weight: 301413,
1329                        major_version: HardFork::V6,
1330                        miner_tx_hash: Hex(hex!(
1331                            "9909c6f8a5267f043c3b2b079fb4eacc49ef9c1dee1c028eeb1a259b95e6e1d9"
1332                        )),
1333                        minor_version: 6,
1334                        nonce: 3246403956,
1335                        num_txes: 20,
1336                        orphan_status: false,
1337                        pow_hash: HexVec::new(),
1338                        prev_hash: Hex(hex!(
1339                            "0ef6e948f77b8f8806621003f5de24b1bcbea150bc0e376835aea099674a5db5"
1340                        )),
1341                        reward: 5025593029981,
1342                        timestamp: 1523002893,
1343                        wide_cumulative_difficulty: "0x2ed7ee6db56750".into(),
1344                        wide_difficulty: "0x1f58ef3541".into(),
1345                    },
1346                    BlockHeader {
1347                        block_size: 13322,
1348                        block_weight: 13322,
1349                        cumulative_difficulty: 13185402687569710,
1350                        cumulative_difficulty_top64: 0,
1351                        depth: 1649023,
1352                        difficulty: 134716086238,
1353                        difficulty_top64: 0,
1354                        hash: Hex(hex!(
1355                            "b408bf4cfcd7de13e7e370c84b8314c85b24f0ba4093ca1d6eeb30b35e34e91a"
1356                        )),
1357                        height: 1546000,
1358                        long_term_weight: 13322,
1359                        major_version: HardFork::V7,
1360                        miner_tx_hash: Hex(hex!(
1361                            "7f749c7c64acb35ef427c7454c45e6688781fbead9bbf222cb12ad1a96a4e8f6"
1362                        )),
1363                        minor_version: 7,
1364                        nonce: 3737164176,
1365                        num_txes: 1,
1366                        orphan_status: false,
1367                        pow_hash: HexVec::new(),
1368                        prev_hash: Hex(hex!(
1369                            "86d1d20a40cefcf3dd410ff6967e0491613b77bf73ea8f1bf2e335cf9cf7d57a"
1370                        )),
1371                        reward: 4851952181070,
1372                        timestamp: 1523002931,
1373                        wide_cumulative_difficulty: "0x2ed80dcb69bf2e".into(),
1374                        wide_difficulty: "0x1f5db457de".into(),
1375                    },
1376                ],
1377            },
1378        );
1379    }
1380
1381    #[test]
1382    fn get_block_request() {
1383        test_json_request(
1384            json::GET_BLOCK_REQUEST,
1385            GetBlockRequest {
1386                height: 2751506,
1387                hash: HexVec::new(),
1388                fill_pow_hash: false,
1389            },
1390        );
1391    }
1392
1393    #[test]
1394    fn get_block_response() {
1395        test_json_response(json::GET_BLOCK_RESPONSE, GetBlockResponse {
1396            base: AccessResponseBase::OK,
1397            blob: HexVec(hex!("1010c58bab9b06b27bdecfc6cd0a46172d136c08831cf67660377ba992332363228b1b722781e7807e07f502cef8a70101ff92f8a7010180e0a596bb1103d7cbf826b665d7a532c316982dc8dbc24f285cbc18bbcc27c7164cd9b3277a85d034019f629d8b36bd16a2bfce3ea80c31dc4d8762c67165aec21845494e32b7582fe00211000000297a787a000000000000000000000000").into()),
1398            block_header: BlockHeader {
1399                block_size: 106,
1400                block_weight: 106,
1401                cumulative_difficulty: 236046001376524168,
1402                cumulative_difficulty_top64: 0,
1403                depth: 443517,
1404                difficulty: 313732272488,
1405                difficulty_top64: 0,
1406                hash: Hex(hex!("43bd1f2b6556dcafa413d8372974af59e4e8f37dbf74dc6b2a9b7212d0577428")),
1407                height: 2751506,
1408                long_term_weight: 176470,
1409                major_version: HardFork::V16,
1410                miner_tx_hash: Hex(hex!("e49b854c5f339d7410a77f2a137281d8042a0ffc7ef9ab24cd670b67139b24cd")),
1411                minor_version: 16,
1412                nonce: 4110909056,
1413                num_txes: 0,
1414                orphan_status: false,
1415                pow_hash: HexVec::new(),
1416                prev_hash: Hex(hex!("b27bdecfc6cd0a46172d136c08831cf67660377ba992332363228b1b722781e7")),
1417                reward: 600000000000,
1418                timestamp: 1667941829,
1419                wide_cumulative_difficulty: "0x3469a966eb2f788".into(),
1420                wide_difficulty: "0x490be69168".into()
1421            },
1422            json: "{\n  \"major_version\": 16, \n  \"minor_version\": 16, \n  \"timestamp\": 1667941829, \n  \"prev_id\": \"b27bdecfc6cd0a46172d136c08831cf67660377ba992332363228b1b722781e7\", \n  \"nonce\": 4110909056, \n  \"miner_tx\": {\n    \"version\": 2, \n    \"unlock_time\": 2751566, \n    \"vin\": [ {\n        \"gen\": {\n          \"height\": 2751506\n        }\n      }\n    ], \n    \"vout\": [ {\n        \"amount\": 600000000000, \n        \"target\": {\n          \"tagged_key\": {\n            \"key\": \"d7cbf826b665d7a532c316982dc8dbc24f285cbc18bbcc27c7164cd9b3277a85\", \n            \"view_tag\": \"d0\"\n          }\n        }\n      }\n    ], \n    \"extra\": [ 1, 159, 98, 157, 139, 54, 189, 22, 162, 191, 206, 62, 168, 12, 49, 220, 77, 135, 98, 198, 113, 101, 174, 194, 24, 69, 73, 78, 50, 183, 88, 47, 224, 2, 17, 0, 0, 0, 41, 122, 120, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n    ], \n    \"rct_signatures\": {\n      \"type\": 0\n    }\n  }, \n  \"tx_hashes\": [ ]\n}".into(),
1423            miner_tx_hash: Hex(hex!("e49b854c5f339d7410a77f2a137281d8042a0ffc7ef9ab24cd670b67139b24cd")),
1424            tx_hashes: vec![],
1425        });
1426    }
1427
1428    #[test]
1429    fn get_connections_response() {
1430        test_json_response(
1431            json::GET_CONNECTIONS_RESPONSE,
1432            GetConnectionsResponse {
1433                base: ResponseBase::OK,
1434                connections: vec![
1435                    ConnectionInfo {
1436                        address:
1437                            "3evk3kezfjg44ma6tvesy7rbxwwpgpympj45xar5fo4qajrsmkoaqdqd.onion:18083"
1438                                .into(),
1439                        address_type: cuprate_types::AddressType::Tor,
1440                        avg_download: 0,
1441                        avg_upload: 0,
1442                        connection_id: "22ef856d0f1d44cc95e84fecfd065fe2".into(),
1443                        current_download: 0,
1444                        current_upload: 0,
1445                        height: 3195026,
1446                        host: "3evk3kezfjg44ma6tvesy7rbxwwpgpympj45xar5fo4qajrsmkoaqdqd.onion"
1447                            .into(),
1448                        incoming: false,
1449                        ip: String::new(),
1450                        live_time: 76651,
1451                        local_ip: false,
1452                        localhost: false,
1453                        peer_id: "0000000000000001".into(),
1454                        port: String::new(),
1455                        pruning_seed: 0,
1456                        recv_count: 240328,
1457                        recv_idle_time: 34,
1458                        rpc_credits_per_hash: 0,
1459                        rpc_port: 0,
1460                        send_count: 3406572,
1461                        send_idle_time: 30,
1462                        state: cuprate_types::ConnectionState::Normal,
1463                        support_flags: 0,
1464                    },
1465                    ConnectionInfo {
1466                        address:
1467                            "4iykytmumafy5kjahdqc7uzgcs34s2vwsadfjpk4znvsa5vmcxeup2qd.onion:18083"
1468                                .into(),
1469                        address_type: cuprate_types::AddressType::Tor,
1470                        avg_download: 0,
1471                        avg_upload: 0,
1472                        connection_id: "c7734e15936f485a86d2b0534f87e499".into(),
1473                        current_download: 0,
1474                        current_upload: 0,
1475                        height: 3195024,
1476                        host: "4iykytmumafy5kjahdqc7uzgcs34s2vwsadfjpk4znvsa5vmcxeup2qd.onion"
1477                            .into(),
1478                        incoming: false,
1479                        ip: String::new(),
1480                        live_time: 76755,
1481                        local_ip: false,
1482                        localhost: false,
1483                        peer_id: "0000000000000001".into(),
1484                        port: String::new(),
1485                        pruning_seed: 389,
1486                        recv_count: 237657,
1487                        recv_idle_time: 120,
1488                        rpc_credits_per_hash: 0,
1489                        rpc_port: 0,
1490                        send_count: 3370566,
1491                        send_idle_time: 120,
1492                        state: cuprate_types::ConnectionState::Normal,
1493                        support_flags: 0,
1494                    },
1495                ],
1496            },
1497        );
1498    }
1499
1500    #[test]
1501    fn get_info_response() {
1502        test_json_response(
1503            json::GET_INFO_RESPONSE,
1504            GetInfoResponse {
1505                base: AccessResponseBase::OK,
1506                adjusted_time: 1721245289,
1507                alt_blocks_count: 16,
1508                block_size_limit: 600000,
1509                block_size_median: 300000,
1510                block_weight_limit: 600000,
1511                block_weight_median: 300000,
1512                bootstrap_daemon_address: String::new(),
1513                busy_syncing: false,
1514                cumulative_difficulty: 366127702242611947,
1515                cumulative_difficulty_top64: 0,
1516                database_size: 235169075200,
1517                difficulty: 280716748706,
1518                difficulty_top64: 0,
1519                free_space: 30521749504,
1520                grey_peerlist_size: 4996,
1521                height: 3195028,
1522                height_without_bootstrap: 3195028,
1523                incoming_connections_count: 62,
1524                mainnet: true,
1525                nettype: "mainnet".into(),
1526                offline: false,
1527                outgoing_connections_count: 1143,
1528                restricted: false,
1529                rpc_connections_count: 1,
1530                stagenet: false,
1531                start_time: 1720462427,
1532                synchronized: true,
1533                target: 120,
1534                target_height: 0,
1535                testnet: false,
1536                top_block_hash: Hex(hex!(
1537                    "bdf06d18ed1931a8ee62654e9b6478cc459bc7072628b8e36f4524d339552946"
1538                )),
1539                tx_count: 43205750,
1540                tx_pool_size: 12,
1541                update_available: false,
1542                version: "0.18.3.3-release".into(),
1543                was_bootstrap_ever_used: false,
1544                white_peerlist_size: 1000,
1545                wide_cumulative_difficulty: "0x514bf349299d2eb".into(),
1546                wide_difficulty: "0x415c05a7a2".into(),
1547            },
1548        );
1549    }
1550
1551    #[test]
1552    fn hard_fork_info_request() {
1553        test_json_request(
1554            json::HARD_FORK_INFO_REQUEST,
1555            HardForkInfoRequest { version: 16 },
1556        );
1557    }
1558
1559    #[test]
1560    fn hard_fork_info_response() {
1561        test_json_response(
1562            json::HARD_FORK_INFO_RESPONSE,
1563            HardForkInfoResponse {
1564                base: AccessResponseBase::OK,
1565                hard_fork_info: HardForkInfo {
1566                    earliest_height: 2689608,
1567                    enabled: true,
1568                    state: 0,
1569                    threshold: 0,
1570                    version: 16,
1571                    votes: 10080,
1572                    voting: 16,
1573                    window: 10080,
1574                },
1575            },
1576        );
1577    }
1578
1579    #[test]
1580    fn set_bans_request() {
1581        test_json_request(
1582            json::SET_BANS_REQUEST,
1583            SetBansRequest {
1584                bans: vec![SetBan {
1585                    host: "192.168.1.51".into(),
1586                    ip: 0,
1587                    ban: true,
1588                    seconds: 30,
1589                }],
1590            },
1591        );
1592    }
1593
1594    #[test]
1595    fn set_bans_response() {
1596        test_json_response(
1597            json::SET_BANS_RESPONSE,
1598            SetBansResponse {
1599                base: ResponseBase::OK,
1600            },
1601        );
1602    }
1603
1604    #[test]
1605    fn get_bans_response() {
1606        test_json_response(
1607            json::GET_BANS_RESPONSE,
1608            GetBansResponse {
1609                base: ResponseBase::OK,
1610                bans: vec![
1611                    GetBan {
1612                        host: "104.248.206.131".into(),
1613                        ip: 2211379304,
1614                        seconds: 689754,
1615                    },
1616                    GetBan {
1617                        host: "209.222.252.0/24".into(),
1618                        ip: 0,
1619                        seconds: 689754,
1620                    },
1621                ],
1622            },
1623        );
1624    }
1625
1626    #[test]
1627    fn banned_request() {
1628        test_json_request(
1629            json::BANNED_REQUEST,
1630            BannedRequest {
1631                address: "95.216.203.255".into(),
1632            },
1633        );
1634    }
1635
1636    #[test]
1637    fn banned_response() {
1638        test_json_response(
1639            json::BANNED_RESPONSE,
1640            BannedResponse {
1641                banned: true,
1642                seconds: 689655,
1643                status: Status::Ok,
1644            },
1645        );
1646    }
1647
1648    #[test]
1649    fn flush_transaction_pool_request() {
1650        test_json_request(
1651            json::FLUSH_TRANSACTION_POOL_REQUEST,
1652            FlushTxpoolRequest {
1653                txids: vec![Hex(hex!(
1654                    "dc16fa8eaffe1484ca9014ea050e13131d3acf23b419f33bb4cc0b32b6c49308"
1655                ))],
1656            },
1657        );
1658    }
1659
1660    #[test]
1661    fn flush_transaction_pool_response() {
1662        test_json_response(
1663            json::FLUSH_TRANSACTION_POOL_RESPONSE,
1664            FlushTxpoolResponse { status: Status::Ok },
1665        );
1666    }
1667
1668    #[test]
1669    fn get_output_histogram_request() {
1670        test_json_request(
1671            json::GET_OUTPUT_HISTOGRAM_REQUEST,
1672            GetOutputHistogramRequest {
1673                amounts: vec![20000000000],
1674                min_count: 0,
1675                max_count: 0,
1676                unlocked: false,
1677                recent_cutoff: 0,
1678            },
1679        );
1680    }
1681
1682    #[test]
1683    fn get_output_histogram_response() {
1684        test_json_response(
1685            json::GET_OUTPUT_HISTOGRAM_RESPONSE,
1686            GetOutputHistogramResponse {
1687                base: AccessResponseBase::OK,
1688                histogram: vec![HistogramEntry {
1689                    amount: 20000000000,
1690                    recent_instances: 0,
1691                    total_instances: 381490,
1692                    unlocked_instances: 0,
1693                }],
1694            },
1695        );
1696    }
1697
1698    #[test]
1699    fn get_coinbase_tx_sum_request() {
1700        test_json_request(
1701            json::GET_COINBASE_TX_SUM_REQUEST,
1702            GetCoinbaseTxSumRequest {
1703                height: 1563078,
1704                count: 2,
1705            },
1706        );
1707    }
1708
1709    #[test]
1710    fn get_coinbase_tx_sum_response() {
1711        test_json_response(
1712            json::GET_COINBASE_TX_SUM_RESPONSE,
1713            GetCoinbaseTxSumResponse {
1714                base: AccessResponseBase::OK,
1715                emission_amount: 9387854817320,
1716                emission_amount_top64: 0,
1717                fee_amount: 83981380000,
1718                fee_amount_top64: 0,
1719                wide_emission_amount: "0x889c7c06828".into(),
1720                wide_fee_amount: "0x138dae29a0".into(),
1721            },
1722        );
1723    }
1724
1725    #[test]
1726    fn get_version_response() {
1727        test_json_response(
1728            json::GET_VERSION_RESPONSE,
1729            GetVersionResponse {
1730                base: ResponseBase::OK,
1731                current_height: 3195051,
1732                hard_forks: [
1733                    (1, HardFork::V1),
1734                    (1009827, HardFork::V2),
1735                    (1141317, HardFork::V3),
1736                    (1220516, HardFork::V4),
1737                    (1288616, HardFork::V5),
1738                    (1400000, HardFork::V6),
1739                    (1546000, HardFork::V7),
1740                    (1685555, HardFork::V8),
1741                    (1686275, HardFork::V9),
1742                    (1788000, HardFork::V10),
1743                    (1788720, HardFork::V11),
1744                    (1978433, HardFork::V12),
1745                    (2210000, HardFork::V13),
1746                    (2210720, HardFork::V14),
1747                    (2688888, HardFork::V15),
1748                    (2689608, HardFork::V16),
1749                ]
1750                .into_iter()
1751                .map(|(height, hf_version)| HardForkEntry { height, hf_version })
1752                .collect(),
1753                release: true,
1754                version: 196621,
1755                target_height: 0,
1756            },
1757        );
1758    }
1759
1760    #[test]
1761    fn get_fee_estimate_response() {
1762        test_json_response(
1763            json::GET_FEE_ESTIMATE_RESPONSE,
1764            GetFeeEstimateResponse {
1765                base: AccessResponseBase::OK,
1766                fee: 20000,
1767                fees: vec![20000, 80000, 320000, 4000000],
1768                quantization_mask: 10000,
1769            },
1770        );
1771    }
1772
1773    #[test]
1774    fn get_alternate_chains_response() {
1775        test_json_response(
1776            json::GET_ALTERNATE_CHAINS_RESPONSE,
1777            GetAlternateChainsResponse {
1778                base: ResponseBase::OK,
1779                chains: vec![
1780                    ChainInfo {
1781                        block_hash: Hex(hex!(
1782                            "4826c7d45d7cf4f02985b5c405b0e5d7f92c8d25e015492ce19aa3b209295dce"
1783                        )),
1784                        block_hashes: vec![Hex(hex!(
1785                            "4826c7d45d7cf4f02985b5c405b0e5d7f92c8d25e015492ce19aa3b209295dce"
1786                        ))],
1787                        difficulty: 357404825113208373,
1788                        difficulty_top64: 0,
1789                        height: 3167471,
1790                        length: 1,
1791                        main_chain_parent_block: Hex(hex!(
1792                            "69b5075ea627d6ba06b1c30b7e023884eeaef5282cf58ec847dab838ddbcdd86"
1793                        )),
1794                        wide_difficulty: "0x4f5c1cb79e22635".into(),
1795                    },
1796                    ChainInfo {
1797                        block_hash: Hex(hex!(
1798                            "33ee476f5a1c5b9d889274cbbe171f5e0112df7ed69021918042525485deb401"
1799                        )),
1800                        block_hashes: vec![Hex(hex!(
1801                            "33ee476f5a1c5b9d889274cbbe171f5e0112df7ed69021918042525485deb401"
1802                        ))],
1803                        difficulty: 354736121711617293,
1804                        difficulty_top64: 0,
1805                        height: 3157465,
1806                        length: 1,
1807                        main_chain_parent_block: Hex(hex!(
1808                            "fd522fcc4cefe5c8c0e5c5600981b3151772c285df3a4e38e5c4011cf466d2cb"
1809                        )),
1810                        wide_difficulty: "0x4ec469f8b9ee50d".into(),
1811                    },
1812                ],
1813            },
1814        );
1815    }
1816
1817    #[test]
1818    fn relay_tx_request() {
1819        test_json_request(
1820            json::RELAY_TX_REQUEST,
1821            RelayTxRequest {
1822                txids: vec![Hex(hex!(
1823                    "9fd75c429cbe52da9a52f2ffc5fbd107fe7fd2099c0d8de274dc8a67e0c98613"
1824                ))],
1825            },
1826        );
1827    }
1828
1829    #[test]
1830    fn relay_tx_response() {
1831        test_json_response(
1832            json::RELAY_TX_RESPONSE,
1833            RelayTxResponse { status: Status::Ok },
1834        );
1835    }
1836
1837    #[test]
1838    fn sync_info_response() {
1839        test_json_response(json::SYNC_INFO_RESPONSE, SyncInfoResponse {
1840            base: AccessResponseBase::OK,
1841            height: 3195157,
1842            next_needed_pruning_seed: 0,
1843            overview: "[]".into(),
1844            spans: vec![],
1845            peers: vec![
1846                SyncInfoPeer {
1847                    info: ConnectionInfo {
1848                        address: "142.93.128.65:44986".into(),
1849                        address_type: cuprate_types::AddressType::Ipv4,
1850                        avg_download: 1,
1851                        avg_upload: 1,
1852                        connection_id: "a5803c4c2dac49e7b201dccdef54c862".into(),
1853                        current_download: 2,
1854                        current_upload: 1,
1855                        height: 3195157,
1856                        host: "142.93.128.65".into(),
1857                        incoming: true,
1858                        ip: "142.93.128.65".into(),
1859                        live_time: 18,
1860                        local_ip: false,
1861                        localhost: false,
1862                        peer_id: "6830e9764d3e5687".into(),
1863                        port: "44986".into(),
1864                        pruning_seed: 0,
1865                        recv_count: 20340,
1866                        recv_idle_time: 0,
1867                        rpc_credits_per_hash: 0,
1868                        rpc_port: 18089,
1869                        send_count: 32235,
1870                        send_idle_time: 6,
1871                        state: cuprate_types::ConnectionState::Normal,
1872                        support_flags: 1
1873                    }
1874                },
1875                SyncInfoPeer {
1876                    info: ConnectionInfo {
1877                        address: "4iykytmumafy5kjahdqc7uzgcs34s2vwsadfjpk4znvsa5vmcxeup2qd.onion:18083".into(),
1878                        address_type: cuprate_types::AddressType::Tor,
1879                        avg_download: 0,
1880                        avg_upload: 0,
1881                        connection_id: "277f7c821bc546878c8bd29977e780f5".into(),
1882                        current_download: 0,
1883                        current_upload: 0,
1884                        height: 3195157,
1885                        host: "4iykytmumafy5kjahdqc7uzgcs34s2vwsadfjpk4znvsa5vmcxeup2qd.onion".into(),
1886                        incoming: false,
1887                        ip: String::new(),
1888                        live_time: 2246,
1889                        local_ip: false,
1890                        localhost: false,
1891                        peer_id: "0000000000000001".into(),
1892                        port: String::new(),
1893                        pruning_seed: 389,
1894                        recv_count: 65164,
1895                        recv_idle_time: 15,
1896                        rpc_credits_per_hash: 0,
1897                        rpc_port: 0,
1898                        send_count: 99120,
1899                        send_idle_time: 15,
1900                        state: cuprate_types::ConnectionState::Normal,
1901                        support_flags: 0
1902                    }
1903                }
1904            ],
1905            target_height: 0,
1906        });
1907    }
1908
1909    // TODO: enable test after binary string imp}
1910    // #[test]
1911    // fn asdf() {
1912    //     test_json_response(json::GET_TRANSACTION_POOL_BACKLOG_RESPONSE => GetTransactionPoolBacklogResponse {
1913    //         base: ResponseBase::OK,
1914    //         backlog: "...Binary...".into(),
1915    //     });
1916    // }
1917
1918    #[test]
1919    fn get_output_distribution_request() {
1920        test_json_request(
1921            json::GET_OUTPUT_DISTRIBUTION_REQUEST,
1922            GetOutputDistributionRequest {
1923                amounts: vec![628780000],
1924                from_height: 1462078,
1925                binary: true,
1926                compress: false,
1927                cumulative: false,
1928                to_height: 0,
1929            },
1930        );
1931    }
1932
1933    // TODO: enable test after binary string imp}
1934    // #[test]
1935    // fn get_output_distribution_response() {
1936    //     test_json_response(json::GET_OUTPUT_DISTRIBUTION_RESPONSE => GetOutputDistributionResponse {
1937    //         base: AccessResponseBase::OK,
1938    //         distributions: vec![Distribution::Uncompressed(DistributionUncompressed {
1939    //             start_height: 1462078,
1940    //             base: 0,
1941    //             distribution: vec![],
1942    //             amount: 2628780000,
1943    //             binary: true,
1944    //         })],
1945    //     });
1946    // }
1947
1948    #[test]
1949    fn get_miner_data_response() {
1950        test_json_response(
1951            json::GET_MINER_DATA_RESPONSE,
1952            GetMinerDataResponse {
1953                base: ResponseBase::OK,
1954                already_generated_coins: 18186022843595960691,
1955                difficulty: "0x48afae42de".into(),
1956                height: 2731375,
1957                major_version: 16,
1958                median_weight: 300000,
1959                prev_id: Hex(hex!(
1960                    "78d50c5894d187c4946d54410990ca59a75017628174a9e8c7055fa4ca5c7c6d"
1961                )),
1962                seed_hash: Hex(hex!(
1963                    "a6b869d50eca3a43ec26fe4c369859cf36ae37ce6ecb76457d31ffeb8a6ca8a6"
1964                )),
1965                tx_backlog: vec![
1966                    GetMinerDataTxBacklogEntry {
1967                        fee: 30700000,
1968                        id: Hex(hex!(
1969                            "9868490d6bb9207fdd9cf17ca1f6c791b92ca97de0365855ea5c089f67c22208"
1970                        )),
1971                        weight: 1535,
1972                    },
1973                    GetMinerDataTxBacklogEntry {
1974                        fee: 44280000,
1975                        id: Hex(hex!(
1976                            "b6000b02bbec71e18ad704bcae09fb6e5ae86d897ced14a718753e76e86c0a0a"
1977                        )),
1978                        weight: 2214,
1979                    },
1980                ],
1981            },
1982        );
1983    }
1984
1985    #[test]
1986    fn prune_blockchain_request() {
1987        test_json_request(
1988            json::PRUNE_BLOCKCHAIN_REQUEST,
1989            PruneBlockchainRequest { check: true },
1990        );
1991    }
1992
1993    #[test]
1994    fn prune_blockchain_response() {
1995        test_json_response(
1996            json::PRUNE_BLOCKCHAIN_RESPONSE,
1997            PruneBlockchainResponse {
1998                base: ResponseBase::OK,
1999                pruned: true,
2000                pruning_seed: 387,
2001            },
2002        );
2003    }
2004
2005    #[test]
2006    fn calc_pow_request() {
2007        test_json_request(json::CALC_POW_REQUEST, CalcPowRequest {
2008            major_version: 14,
2009            height: 2286447,
2010            block_blob: HexVec(hex!("0e0ed286da8006ecdc1aab3033cf1716c52f13f9d8ae0051615a2453643de94643b550d543becd0000000002abc78b0101ffefc68b0101fcfcf0d4b422025014bb4a1eade6622fd781cb1063381cad396efa69719b41aa28b4fce8c7ad4b5f019ce1dc670456b24a5e03c2d9058a2df10fec779e2579753b1847b74ee644f16b023c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000051399a1bc46a846474f5b33db24eae173a26393b976054ee14f9feefe99925233802867097564c9db7a36af5bb5ed33ab46e63092bd8d32cef121608c3258edd55562812e21cc7e3ac73045745a72f7d74581d9a0849d6f30e8b2923171253e864f4e9ddea3acb5bc755f1c4a878130a70c26297540bc0b7a57affb6b35c1f03d8dbd54ece8457531f8cba15bb74516779c01193e212050423020e45aa2c15dcb").into()),
2011            seed_hash: Hex(hex!("d432f499205150873b2572b5f033c9c6e4b7c6f3394bd2dd93822cd7085e7307")),
2012        });
2013    }
2014
2015    #[test]
2016    fn calc_pow_response() {
2017        test_json_response(
2018            json::CALC_POW_RESPONSE,
2019            CalcPowResponse {
2020                pow_hash: Hex(hex!(
2021                    "d0402d6834e26fb94a9ce38c6424d27d2069896a9b8b1ce685d79936bca6e0a8"
2022                )),
2023            },
2024        );
2025    }
2026
2027    #[test]
2028    fn flush_cache_request() {
2029        test_json_request(
2030            json::FLUSH_CACHE_REQUEST,
2031            FlushCacheRequest {
2032                bad_txs: true,
2033                bad_blocks: true,
2034            },
2035        );
2036    }
2037
2038    #[test]
2039    fn flush_cache_response() {
2040        test_json_response(
2041            json::FLUSH_CACHE_RESPONSE,
2042            FlushCacheResponse {
2043                base: ResponseBase::OK,
2044            },
2045        );
2046    }
2047
2048    #[test]
2049    fn add_aux_pow_request() {
2050        test_json_request(json::ADD_AUX_POW_REQUEST, AddAuxPowRequest {
2051            blocktemplate_blob: HexVec(hex!("1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a0000000002c681c30101ff8a81c3010180e0a596bb11033b7eedf47baf878f3490cb20b696079c34bd017fe59b0d070e74d73ffabc4bb0e05f011decb630f3148d0163b3bd39690dde4078e4cfb69fecf020d6278a27bad10c58023c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into()),
2052            aux_pow: vec![AuxPow {
2053                id: Hex(hex!("3200b4ea97c3b2081cd4190b58e49572b2319fed00d030ad51809dff06b5d8c8")),
2054                hash: Hex(hex!("7b35762de164b20885e15dbe656b1138db06bb402fa1796f5765a23933d8859a"))
2055            }]
2056        });
2057    }
2058
2059    #[test]
2060    fn add_aux_pow_response() {
2061        test_json_response(json::ADD_AUX_POW_RESPONSE, AddAuxPowResponse {
2062            base: ResponseBase::OK,
2063            aux_pow: vec![AuxPow {
2064                hash: Hex(hex!("7b35762de164b20885e15dbe656b1138db06bb402fa1796f5765a23933d8859a")),
2065                id: Hex(hex!("3200b4ea97c3b2081cd4190b58e49572b2319fed00d030ad51809dff06b5d8c8")),
2066            }],
2067            blockhashing_blob: HexVec(hex!("1010ee97e2a106e9f8ebe8887e5b609949ac8ea6143e560ed13552b110cb009b21f0cfca1eaccf00000000b2685c1283a646bc9020c758daa443be145b7370ce5a6efacb3e614117032e2c22").into()),
2068            blocktemplate_blob: HexVec(hex!("1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a0000000002c681c30101ff8a81c3010180e0a596bb11033b7eedf47baf878f3490cb20b696079c34bd017fe59b0d070e74d73ffabc4bb0e05f011decb630f3148d0163b3bd39690dde4078e4cfb69fecf020d6278a27bad10c58023c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into()),
2069            merkle_root: Hex(hex!("7b35762de164b20885e15dbe656b1138db06bb402fa1796f5765a23933d8859a")),
2070            merkle_tree_depth: 0,
2071        });
2072    }
2073}