cuprate_rpc_interface/route/
bin.rs

1//! Binary route functions.
2
3//---------------------------------------------------------------------------------------------------- Import
4use axum::{body::Bytes, extract::State, http::StatusCode};
5use tower::ServiceExt;
6
7use cuprate_epee_encoding::from_bytes;
8use cuprate_rpc_types::{
9    bin::{
10        BinRequest, BinResponse, GetBlocksByHeightRequest, GetBlocksRequest, GetHashesRequest,
11        GetOutputIndexesRequest, GetOutsRequest, GetTransactionPoolHashesRequest,
12    },
13    json::GetOutputDistributionRequest,
14    RpcCall,
15};
16
17use crate::rpc_handler::RpcHandler;
18
19//---------------------------------------------------------------------------------------------------- Routes
20/// This macro generates route functions that expect input.
21///
22/// See below for usage.
23macro_rules! generate_endpoints_with_input {
24    ($(
25        // Syntax:
26        // Function name => Expected input type
27        $endpoint:ident => $variant:ident
28    ),*) => { paste::paste! {
29        $(
30            /// TODO
31            pub(crate) async fn $endpoint<H: RpcHandler>(
32                State(handler): State<H>,
33                mut request: Bytes,
34            ) -> Result<Bytes, StatusCode> {
35                // Serialize into the request type.
36                let request = BinRequest::$variant(
37                    from_bytes(&mut request).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
38                );
39
40                generate_endpoints_inner!($variant, handler, request)
41            }
42        )*
43    }};
44}
45
46/// This macro generates route functions that expect _no_ input.
47///
48/// See below for usage.
49macro_rules! generate_endpoints_with_no_input {
50    ($(
51        // Syntax:
52        // Function name => Expected input type (that is empty)
53        $endpoint:ident => $variant:ident
54    ),*) => { paste::paste! {
55        $(
56            /// TODO
57            pub(crate) async fn $endpoint<H: RpcHandler>(
58                State(handler): State<H>,
59            ) -> Result<Bytes, StatusCode> {
60                const REQUEST: BinRequest = BinRequest::$variant([<$variant Request>] {});
61                generate_endpoints_inner!($variant, handler, REQUEST)
62            }
63        )*
64    }};
65}
66
67/// De-duplicated inner function body for:
68/// - [`generate_endpoints_with_input`]
69/// - [`generate_endpoints_with_no_input`]
70macro_rules! generate_endpoints_inner {
71    ($variant:ident, $handler:ident, $request:expr_2021) => {
72        paste::paste! {
73            {
74                // Check if restricted.
75                //
76                // INVARIANT:
77                // The RPC handler functions in `cuprated` depend on this line existing,
78                // the functions themselves do not check if they are being called
79                // from an (un)restricted context. This line must be here or all
80                // methods will be allowed to be called freely.
81                if [<$variant Request>]::IS_RESTRICTED && $handler.is_restricted() {
82                    // TODO: mimic `monerod` behavior.
83                    return Err(StatusCode::FORBIDDEN);
84                }
85
86                // Send request.
87                let Ok(response) = $handler.oneshot($request).await else {
88                    return Err(StatusCode::INTERNAL_SERVER_ERROR);
89                };
90
91                let BinResponse::$variant(response) = response else {
92                    panic!("RPC handler returned incorrect response");
93                };
94
95                // Serialize to bytes and respond.
96                match cuprate_epee_encoding::to_bytes(response) {
97                    Ok(bytes) => Ok(bytes.freeze()),
98                    Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
99                }
100            }
101        }
102    };
103}
104
105generate_endpoints_with_input! {
106    get_blocks => GetBlocks,
107    get_blocks_by_height => GetBlocksByHeight,
108    get_hashes => GetHashes,
109    get_o_indexes => GetOutputIndexes,
110    get_outs => GetOuts,
111    get_output_distribution => GetOutputDistribution
112}
113
114generate_endpoints_with_no_input! {
115    get_transaction_pool_hashes => GetTransactionPoolHashes
116}
117
118//---------------------------------------------------------------------------------------------------- Tests
119#[cfg(test)]
120mod test {
121    // use super::*;
122}