cuprated/rpc/handlers/
shared.rs

1//! RPC handler functions that are shared between different endpoint/methods.
2//!
3//! TODO:
4//! Some handlers have `todo!()`s for other Cuprate internals that must be completed, see:
5//! <https://github.com/Cuprate/cuprate/pull/355>
6
7use std::{
8    collections::{HashMap, HashSet},
9    num::NonZero,
10};
11
12use anyhow::{anyhow, Error};
13use cuprate_types::OutputDistributionInput;
14use monero_serai::transaction::Timelock;
15
16use cuprate_constants::rpc::MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT;
17use cuprate_helper::cast::usize_to_u64;
18use cuprate_hex::Hex;
19use cuprate_rpc_interface::RpcHandler;
20use cuprate_rpc_types::{
21    bin::{
22        GetOutsRequest, GetOutsResponse, GetTransactionPoolHashesRequest,
23        GetTransactionPoolHashesResponse,
24    },
25    json::{GetOutputDistributionRequest, GetOutputDistributionResponse},
26    misc::{Distribution, OutKeyBin},
27};
28
29use crate::rpc::{
30    handlers::helper,
31    service::{blockchain, blockchain_context, txpool},
32    CupratedRpcHandler,
33};
34
35/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L912-L957>
36///
37/// Shared between:
38/// - Other JSON's `/get_outs`
39/// - Binary's `/get_outs.bin`
40pub(super) async fn get_outs(
41    mut state: CupratedRpcHandler,
42    request: GetOutsRequest,
43) -> Result<GetOutsResponse, Error> {
44    if state.is_restricted() && request.outputs.len() > MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT {
45        return Err(anyhow!("Too many outs requested"));
46    }
47
48    let outputs = blockchain::outputs_vec(
49        &mut state.blockchain_read,
50        request.outputs,
51        request.get_txid,
52    )
53    .await?;
54    let mut outs = Vec::<OutKeyBin>::with_capacity(outputs.len());
55    let blockchain_ctx = state.blockchain_context.blockchain_context();
56
57    for (_, index_vec) in outputs {
58        for (_, out) in index_vec {
59            let out_key = OutKeyBin {
60                key: out.key.0,
61                mask: out.commitment.0,
62                unlocked: cuprate_consensus_rules::transactions::output_unlocked(
63                    &out.time_lock,
64                    blockchain_ctx.chain_height,
65                    blockchain_ctx.current_adjusted_timestamp_for_time_lock(),
66                    blockchain_ctx.current_hf,
67                ),
68                height: usize_to_u64(out.height),
69                txid: out.txid.unwrap_or_default(),
70            };
71
72            outs.push(out_key);
73        }
74    }
75
76    Ok(GetOutsResponse {
77        base: helper::access_response_base(false),
78        outs,
79    })
80}
81
82/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L1713-L1739>
83///
84/// Shared between:
85/// - Other JSON's `/get_transaction_pool_hashes`
86/// - Binary's `/get_transaction_pool_hashes.bin`
87///
88/// Returns transaction hashes.
89pub(super) async fn get_transaction_pool_hashes(
90    mut state: CupratedRpcHandler,
91) -> Result<Vec<[u8; 32]>, Error> {
92    let include_sensitive_txs = !state.is_restricted();
93    txpool::all_hashes(&mut state.txpool_read, include_sensitive_txs).await
94}
95
96/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3352-L3398>
97///
98/// Shared between:
99/// - Other JSON's `/get_output_distribution`
100/// - Binary's `/get_output_distribution.bin`
101///
102/// Returns transaction hashes.
103pub(super) async fn get_output_distribution(
104    mut state: CupratedRpcHandler,
105    request: GetOutputDistributionRequest,
106) -> Result<GetOutputDistributionResponse, Error> {
107    if state.is_restricted() && request.amounts != [0] {
108        return Err(anyhow!(
109            "Restricted RPC can only get output distribution for RCT outputs. Use your own node."
110        ));
111    }
112
113    let input = OutputDistributionInput {
114        amounts: request.amounts,
115        cumulative: request.cumulative,
116        from_height: request.from_height,
117
118        // 0 / `None` is placeholder for the whole chain
119        to_height: NonZero::new(request.to_height),
120    };
121
122    let distributions = blockchain::output_distribution(&mut state.blockchain_read, input).await?;
123
124    Ok(GetOutputDistributionResponse {
125        base: helper::access_response_base(false),
126        distributions: todo!(
127            "This type contains binary strings: <https://github.com/monero-project/monero/issues/9422>"
128        ),
129    })
130}