Compare commits

...

2 commits

Author SHA1 Message Date
hinto.janai
21e42c1f54
module cleanup 2024-12-18 20:26:54 -05:00
hinto.janai
aca28552ab
get_output_distribution 2024-12-18 18:09:01 -05:00
25 changed files with 223 additions and 187 deletions

View file

@ -18,9 +18,6 @@ pub const VERSION_BUILD: &str = if cfg!(debug_assertions) {
pub const PANIC_CRITICAL_SERVICE_ERROR: &str = pub const PANIC_CRITICAL_SERVICE_ERROR: &str =
"A service critical to Cuprate's function returned an unexpected error."; "A service critical to Cuprate's function returned an unexpected error.";
/// The error message returned when an unsupported RPC call is requested.
pub const UNSUPPORTED_RPC_CALL: &str = "This RPC call is not supported by Cuprate.";
pub const EXAMPLE_CONFIG: &str = include_str!("../Cuprated.toml"); pub const EXAMPLE_CONFIG: &str = include_str!("../Cuprated.toml");
#[cfg(test)] #[cfg(test)]

View file

@ -2,13 +2,9 @@
//! //!
//! Will contain the code to initiate the RPC and a request handler. //! Will contain the code to initiate the RPC and a request handler.
mod bin;
mod constants; mod constants;
mod handler; mod handlers;
mod helper; mod rpc_handler;
mod json; mod service;
mod other;
mod request;
mod shared;
pub use handler::CupratedRpcHandler; pub use rpc_handler::CupratedRpcHandler;

View file

@ -3,3 +3,6 @@
/// The string message used in RPC response fields for when /// The string message used in RPC response fields for when
/// `cuprated` does not support a field that `monerod` has. /// `cuprated` does not support a field that `monerod` has.
pub(super) const FIELD_NOT_SUPPORTED: &str = "`cuprated` does not support this field."; pub(super) const FIELD_NOT_SUPPORTED: &str = "`cuprated` does not support this field.";
/// The error message returned when an unsupported RPC call is requested.
pub(super) const UNSUPPORTED_RPC_CALL: &str = "This RPC call is not supported by Cuprate.";

View file

@ -0,0 +1,18 @@
//! RPC handler functions.
//!
//! These are the glue (async) functions that connect all the
//! internal `cuprated` functions and fulfill the request.
//!
//! - JSON-RPC handlers are in [`json_rpc`]
//! - Other JSON endpoint handlers are in [`other_json`]
//! - Other binary endpoint handlers are in [`bin`]
//!
//! - [`helper`] contains helper functions used by many handlers
//! - [`shared`] contains shared functions used by multiple handlers
pub(super) mod bin;
pub(super) mod json_rpc;
pub(super) mod other_json;
mod helper;
mod shared;

View file

@ -26,13 +26,13 @@ use cuprate_types::{
}; };
use crate::rpc::{ use crate::rpc::{
helper, handlers::{helper, shared},
request::{blockchain, txpool}, service::{blockchain, txpool},
shared, CupratedRpcHandler, CupratedRpcHandler,
}; };
/// Map a [`BinRequest`] to the function that will lead to a [`BinResponse`]. /// Map a [`BinRequest`] to the function that will lead to a [`BinResponse`].
pub(super) async fn map_request( pub async fn map_request(
state: CupratedRpcHandler, state: CupratedRpcHandler,
request: BinRequest, request: BinRequest,
) -> Result<BinResponse, Error> { ) -> Result<BinResponse, Error> {

View file

@ -3,7 +3,7 @@
//! Many of the handlers have bodies with only small differences, //! Many of the handlers have bodies with only small differences,
//! the identical code is extracted and reused here in these functions. //! the identical code is extracted and reused here in these functions.
//! //!
//! These build on-top of [`crate::rpc::request`] functions. //! These build on-top of [`crate::rpc::service`] functions.
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
@ -17,9 +17,9 @@ use cuprate_rpc_types::{
}; };
use cuprate_types::HardFork; use cuprate_types::HardFork;
use crate::{ use crate::rpc::{
rpc::request::{blockchain, blockchain_context}, service::{blockchain, blockchain_context},
rpc::CupratedRpcHandler, CupratedRpcHandler,
}; };
/// Map some data into a [`BlockHeader`]. /// Map some data into a [`BlockHeader`].

View file

@ -58,19 +58,18 @@ use cuprate_types::{
}; };
use crate::{ use crate::{
constants::{UNSUPPORTED_RPC_CALL, VERSION_BUILD}, constants::VERSION_BUILD,
rpc::{ rpc::{
helper, constants::{FIELD_NOT_SUPPORTED, UNSUPPORTED_RPC_CALL},
request::{address_book, blockchain, blockchain_context, blockchain_manager, txpool}, handlers::{helper, shared},
shared, CupratedRpcHandler, service::{address_book, blockchain, blockchain_context, blockchain_manager, txpool},
CupratedRpcHandler,
}, },
statics::START_INSTANT_UNIX, statics::START_INSTANT_UNIX,
}; };
use super::constants::FIELD_NOT_SUPPORTED;
/// Map a [`JsonRpcRequest`] to the function that will lead to a [`JsonRpcResponse`]. /// Map a [`JsonRpcRequest`] to the function that will lead to a [`JsonRpcResponse`].
pub(super) async fn map_request( pub async fn map_request(
state: CupratedRpcHandler, state: CupratedRpcHandler,
request: JsonRpcRequest, request: JsonRpcRequest,
) -> Result<JsonRpcResponse, Error> { ) -> Result<JsonRpcResponse, Error> {

View file

@ -43,19 +43,17 @@ use cuprate_types::{
use monero_serai::transaction::{Input, Timelock, Transaction}; use monero_serai::transaction::{Input, Timelock, Transaction};
use crate::{ use crate::{
constants::UNSUPPORTED_RPC_CALL,
rpc::{ rpc::{
helper, constants::UNSUPPORTED_RPC_CALL,
request::{blockchain, blockchain_context, blockchain_manager, txpool}, handlers::{helper, shared},
shared, CupratedRpcHandler, service::{address_book, blockchain, blockchain_context, blockchain_manager, txpool},
CupratedRpcHandler,
}, },
statics::START_INSTANT_UNIX, statics::START_INSTANT_UNIX,
}; };
use super::request::address_book;
/// Map a [`OtherRequest`] to the function that will lead to a [`OtherResponse`]. /// Map a [`OtherRequest`] to the function that will lead to a [`OtherResponse`].
pub(super) async fn map_request( pub async fn map_request(
state: CupratedRpcHandler, state: CupratedRpcHandler,
request: OtherRequest, request: OtherRequest,
) -> Result<OtherResponse, Error> { ) -> Result<OtherResponse, Error> {

View file

@ -1,8 +1,12 @@
//! RPC handler functions that are shared between different endpoint/methods. //! RPC handler functions that are shared between different endpoint/methods.
use std::collections::{HashMap, HashSet}; use std::{
collections::{HashMap, HashSet},
num::NonZero,
};
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use cuprate_types::OutputDistributionInput;
use monero_serai::transaction::Timelock; use monero_serai::transaction::Timelock;
use cuprate_constants::rpc::MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT; use cuprate_constants::rpc::MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT;
@ -19,8 +23,8 @@ use cuprate_rpc_types::{
}; };
use crate::rpc::{ use crate::rpc::{
helper, handlers::helper,
request::{blockchain, txpool}, service::{blockchain, txpool},
CupratedRpcHandler, CupratedRpcHandler,
}; };
@ -97,36 +101,35 @@ pub(super) async fn get_transaction_pool_hashes(
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3352-L3398> /// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3352-L3398>
/// ///
/// Shared between: /// Shared between:
/// - JSON-RPC's `get_output_distribution` /// - Other JSON's `/get_output_distribution`
/// - Binary's `/get_output_distribution.bin` /// - Binary's `/get_output_distribution.bin`
///
/// Returns transaction hashes.
pub(super) async fn get_output_distribution( pub(super) async fn get_output_distribution(
mut state: CupratedRpcHandler, mut state: CupratedRpcHandler,
request: GetOutputDistributionRequest, request: GetOutputDistributionRequest,
) -> Result<GetOutputDistributionResponse, Error> { ) -> Result<GetOutputDistributionResponse, Error> {
if state.is_restricted() && request.amounts != [1, 0] { if state.is_restricted() && request.amounts != [0] {
return Err(anyhow!( return Err(anyhow!(
"Restricted RPC can only get output distribution for RCT outputs. Use your own node." "Restricted RPC can only get output distribution for RCT outputs. Use your own node."
)); ));
} }
// 0 is placeholder for the whole chain let input = OutputDistributionInput {
let req_to_height = if request.to_height == 0 { amounts: request.amounts,
helper::top_height(&mut state).await?.0.saturating_sub(1) cumulative: request.cumulative,
} else { from_height: request.from_height,
request.to_height
// 0 / `None` is placeholder for the whole chain
to_height: NonZero::new(request.to_height),
}; };
let distributions = request.amounts.into_iter().map(|amount| { let distributions = blockchain::output_distribution(&mut state.blockchain_read, input).await?;
fn get_output_distribution() -> Result<Distribution, Error> {
todo!("https://github.com/monero-project/monero/blob/893916ad091a92e765ce3241b94e706ad012b62a/src/rpc/rpc_handler.cpp#L29");
Err(anyhow!("Failed to get output distribution"))
}
get_output_distribution()
}).collect::<Result<Vec<Distribution>, _>>()?;
Ok(GetOutputDistributionResponse { Ok(GetOutputDistributionResponse {
base: helper::access_response_base(false), base: helper::access_response_base(false),
distributions, distributions: todo!(
"This type contains binary strings: <https://github.com/monero-project/monero/issues/9422>"
),
}) })
} }

View file

@ -19,7 +19,7 @@ use cuprate_rpc_types::{
}; };
use cuprate_txpool::service::TxpoolReadHandle; use cuprate_txpool::service::TxpoolReadHandle;
use crate::rpc::{bin, json, other}; use crate::rpc::handlers;
/// TODO: use real type when public. /// TODO: use real type when public.
#[derive(Clone)] #[derive(Clone)]
@ -217,7 +217,7 @@ impl Service<JsonRpcRequest> for CupratedRpcHandler {
fn call(&mut self, request: JsonRpcRequest) -> Self::Future { fn call(&mut self, request: JsonRpcRequest) -> Self::Future {
let state = self.clone(); let state = self.clone();
Box::pin(json::map_request(state, request)) Box::pin(handlers::json_rpc::map_request(state, request))
} }
} }
@ -232,7 +232,7 @@ impl Service<BinRequest> for CupratedRpcHandler {
fn call(&mut self, request: BinRequest) -> Self::Future { fn call(&mut self, request: BinRequest) -> Self::Future {
let state = self.clone(); let state = self.clone();
Box::pin(bin::map_request(state, request)) Box::pin(handlers::bin::map_request(state, request))
} }
} }
@ -247,6 +247,6 @@ impl Service<OtherRequest> for CupratedRpcHandler {
fn call(&mut self, request: OtherRequest) -> Self::Future { fn call(&mut self, request: OtherRequest) -> Self::Future {
let state = self.clone(); let state = self.clone();
Box::pin(other::map_request(state, request)) Box::pin(handlers::other_json::map_request(state, request))
} }
} }

View file

@ -1,4 +1,4 @@
//! Convenience functions for requests/responses. //! Convenience functions for Cuprate's various [`tower::Service`] requests/responses.
//! //!
//! This module implements many methods for //! This module implements many methods for
//! [`CupratedRpcHandler`](crate::rpc::CupratedRpcHandler) //! [`CupratedRpcHandler`](crate::rpc::CupratedRpcHandler)

View file

@ -17,7 +17,7 @@ use cuprate_rpc_types::misc::ConnectionInfo;
// FIXME: use `anyhow::Error` over `tower::BoxError` in address book. // FIXME: use `anyhow::Error` over `tower::BoxError` in address book.
/// [`AddressBookRequest::PeerlistSize`] /// [`AddressBookRequest::PeerlistSize`]
pub(crate) async fn peerlist_size<Z: NetworkZone>( pub async fn peerlist_size<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
) -> Result<(u64, u64), Error> { ) -> Result<(u64, u64), Error> {
let AddressBookResponse::PeerlistSize { white, grey } = address_book let AddressBookResponse::PeerlistSize { white, grey } = address_book
@ -35,7 +35,7 @@ pub(crate) async fn peerlist_size<Z: NetworkZone>(
} }
/// [`AddressBookRequest::ConnectionInfo`] /// [`AddressBookRequest::ConnectionInfo`]
pub(crate) async fn connection_info<Z: NetworkZone>( pub async fn connection_info<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
) -> Result<Vec<ConnectionInfo>, Error> { ) -> Result<Vec<ConnectionInfo>, Error> {
let AddressBookResponse::ConnectionInfo(vec) = address_book let AddressBookResponse::ConnectionInfo(vec) = address_book
@ -92,7 +92,7 @@ pub(crate) async fn connection_info<Z: NetworkZone>(
} }
/// [`AddressBookRequest::ConnectionCount`] /// [`AddressBookRequest::ConnectionCount`]
pub(crate) async fn connection_count<Z: NetworkZone>( pub async fn connection_count<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
) -> Result<(u64, u64), Error> { ) -> Result<(u64, u64), Error> {
let AddressBookResponse::ConnectionCount { incoming, outgoing } = address_book let AddressBookResponse::ConnectionCount { incoming, outgoing } = address_book
@ -110,7 +110,7 @@ pub(crate) async fn connection_count<Z: NetworkZone>(
} }
/// [`AddressBookRequest::SetBan`] /// [`AddressBookRequest::SetBan`]
pub(crate) async fn set_ban<Z: NetworkZone>( pub async fn set_ban<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
set_ban: cuprate_p2p_core::types::SetBan<Z::Addr>, set_ban: cuprate_p2p_core::types::SetBan<Z::Addr>,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -129,7 +129,7 @@ pub(crate) async fn set_ban<Z: NetworkZone>(
} }
/// [`AddressBookRequest::GetBan`] /// [`AddressBookRequest::GetBan`]
pub(crate) async fn get_ban<Z: NetworkZone>( pub async fn get_ban<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
peer: Z::Addr, peer: Z::Addr,
) -> Result<Option<std::time::Instant>, Error> { ) -> Result<Option<std::time::Instant>, Error> {
@ -148,7 +148,7 @@ pub(crate) async fn get_ban<Z: NetworkZone>(
} }
/// [`AddressBookRequest::GetBans`] /// [`AddressBookRequest::GetBans`]
pub(crate) async fn get_bans<Z: NetworkZone>( pub async fn get_bans<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
) -> Result<Vec<BanState<Z::Addr>>, Error> { ) -> Result<Vec<BanState<Z::Addr>>, Error> {
let AddressBookResponse::GetBans(bans) = address_book let AddressBookResponse::GetBans(bans) = address_book
@ -166,7 +166,7 @@ pub(crate) async fn get_bans<Z: NetworkZone>(
} }
/// [`AddressBookRequest::Peerlist`] /// [`AddressBookRequest::Peerlist`]
pub(crate) async fn peerlist<Z: NetworkZone>( pub async fn peerlist<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>, address_book: &mut impl AddressBook<Z>,
) -> Result<(Vec<Peer>, Vec<Peer>), Error> { ) -> Result<(Vec<Peer>, Vec<Peer>), Error> {
let AddressBookResponse::Peerlist(peerlist) = address_book let AddressBookResponse::Peerlist(peerlist) = address_book

View file

@ -14,13 +14,15 @@ use cuprate_helper::cast::{u64_to_usize, usize_to_u64};
use cuprate_types::{ use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainResponse}, blockchain::{BlockchainReadRequest, BlockchainResponse},
rpc::{ rpc::{
ChainInfo, CoinbaseTxSum, KeyImageSpentStatus, OutputHistogramEntry, OutputHistogramInput, ChainInfo, CoinbaseTxSum, KeyImageSpentStatus, OutputDistributionData,
OutputHistogramEntry, OutputHistogramInput,
}, },
BlockCompleteEntry, Chain, ExtendedBlockHeader, OutputOnChain, TxInBlockchain, BlockCompleteEntry, Chain, ExtendedBlockHeader, OutputDistributionInput, OutputOnChain,
TxInBlockchain,
}; };
/// [`BlockchainReadRequest::Block`]. /// [`BlockchainReadRequest::Block`].
pub(crate) async fn block( pub async fn block(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
height: u64, height: u64,
) -> Result<Block, Error> { ) -> Result<Block, Error> {
@ -39,7 +41,7 @@ pub(crate) async fn block(
} }
/// [`BlockchainReadRequest::BlockByHash`]. /// [`BlockchainReadRequest::BlockByHash`].
pub(crate) async fn block_by_hash( pub async fn block_by_hash(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
hash: [u8; 32], hash: [u8; 32],
) -> Result<Block, Error> { ) -> Result<Block, Error> {
@ -56,7 +58,7 @@ pub(crate) async fn block_by_hash(
} }
/// [`BlockchainReadRequest::BlockExtendedHeader`]. /// [`BlockchainReadRequest::BlockExtendedHeader`].
pub(crate) async fn block_extended_header( pub async fn block_extended_header(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
height: u64, height: u64,
) -> Result<ExtendedBlockHeader, Error> { ) -> Result<ExtendedBlockHeader, Error> {
@ -75,7 +77,7 @@ pub(crate) async fn block_extended_header(
} }
/// [`BlockchainReadRequest::BlockHash`]. /// [`BlockchainReadRequest::BlockHash`].
pub(crate) async fn block_hash( pub async fn block_hash(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
height: u64, height: u64,
chain: Chain, chain: Chain,
@ -96,7 +98,7 @@ pub(crate) async fn block_hash(
} }
/// [`BlockchainReadRequest::FindBlock`]. /// [`BlockchainReadRequest::FindBlock`].
pub(crate) async fn find_block( pub async fn find_block(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
block_hash: [u8; 32], block_hash: [u8; 32],
) -> Result<Option<(Chain, usize)>, Error> { ) -> Result<Option<(Chain, usize)>, Error> {
@ -113,7 +115,7 @@ pub(crate) async fn find_block(
} }
/// [`BlockchainReadRequest::FilterUnknownHashes`]. /// [`BlockchainReadRequest::FilterUnknownHashes`].
pub(crate) async fn filter_unknown_hashes( pub async fn filter_unknown_hashes(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
block_hashes: HashSet<[u8; 32]>, block_hashes: HashSet<[u8; 32]>,
) -> Result<HashSet<[u8; 32]>, Error> { ) -> Result<HashSet<[u8; 32]>, Error> {
@ -130,7 +132,7 @@ pub(crate) async fn filter_unknown_hashes(
} }
/// [`BlockchainReadRequest::BlockExtendedHeaderInRange`] /// [`BlockchainReadRequest::BlockExtendedHeaderInRange`]
pub(crate) async fn block_extended_header_in_range( pub async fn block_extended_header_in_range(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
range: Range<usize>, range: Range<usize>,
chain: Chain, chain: Chain,
@ -150,7 +152,7 @@ pub(crate) async fn block_extended_header_in_range(
} }
/// [`BlockchainReadRequest::ChainHeight`]. /// [`BlockchainReadRequest::ChainHeight`].
pub(crate) async fn chain_height( pub async fn chain_height(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
) -> Result<(u64, [u8; 32]), Error> { ) -> Result<(u64, [u8; 32]), Error> {
let BlockchainResponse::ChainHeight(height, hash) = blockchain_read let BlockchainResponse::ChainHeight(height, hash) = blockchain_read
@ -166,7 +168,7 @@ pub(crate) async fn chain_height(
} }
/// [`BlockchainReadRequest::GeneratedCoins`]. /// [`BlockchainReadRequest::GeneratedCoins`].
pub(crate) async fn generated_coins( pub async fn generated_coins(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
block_height: u64, block_height: u64,
) -> Result<u64, Error> { ) -> Result<u64, Error> {
@ -185,7 +187,7 @@ pub(crate) async fn generated_coins(
} }
/// [`BlockchainReadRequest::Outputs`] /// [`BlockchainReadRequest::Outputs`]
pub(crate) async fn outputs( pub async fn outputs(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
outputs: HashMap<u64, HashSet<u64>>, outputs: HashMap<u64, HashSet<u64>>,
) -> Result<HashMap<u64, HashMap<u64, OutputOnChain>>, Error> { ) -> Result<HashMap<u64, HashMap<u64, OutputOnChain>>, Error> {
@ -202,7 +204,7 @@ pub(crate) async fn outputs(
} }
/// [`BlockchainReadRequest::NumberOutputsWithAmount`] /// [`BlockchainReadRequest::NumberOutputsWithAmount`]
pub(crate) async fn number_outputs_with_amount( pub async fn number_outputs_with_amount(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
output_amounts: Vec<u64>, output_amounts: Vec<u64>,
) -> Result<HashMap<u64, usize>, Error> { ) -> Result<HashMap<u64, usize>, Error> {
@ -221,7 +223,7 @@ pub(crate) async fn number_outputs_with_amount(
} }
/// [`BlockchainReadRequest::KeyImagesSpent`] /// [`BlockchainReadRequest::KeyImagesSpent`]
pub(crate) async fn key_images_spent( pub async fn key_images_spent(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
key_images: Vec<[u8; 32]>, key_images: Vec<[u8; 32]>,
) -> Result<Vec<bool>, Error> { ) -> Result<Vec<bool>, Error> {
@ -238,7 +240,7 @@ pub(crate) async fn key_images_spent(
} }
/// [`BlockchainReadRequest::CompactChainHistory`] /// [`BlockchainReadRequest::CompactChainHistory`]
pub(crate) async fn compact_chain_history( pub async fn compact_chain_history(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
) -> Result<(Vec<[u8; 32]>, u128), Error> { ) -> Result<(Vec<[u8; 32]>, u128), Error> {
let BlockchainResponse::CompactChainHistory { let BlockchainResponse::CompactChainHistory {
@ -257,7 +259,7 @@ pub(crate) async fn compact_chain_history(
} }
/// [`BlockchainReadRequest::FindFirstUnknown`] /// [`BlockchainReadRequest::FindFirstUnknown`]
pub(crate) async fn find_first_unknown( pub async fn find_first_unknown(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
hashes: Vec<[u8; 32]>, hashes: Vec<[u8; 32]>,
) -> Result<Option<(usize, u64)>, Error> { ) -> Result<Option<(usize, u64)>, Error> {
@ -274,9 +276,7 @@ pub(crate) async fn find_first_unknown(
} }
/// [`BlockchainReadRequest::TotalTxCount`] /// [`BlockchainReadRequest::TotalTxCount`]
pub(crate) async fn total_tx_count( pub async fn total_tx_count(blockchain_read: &mut BlockchainReadHandle) -> Result<u64, Error> {
blockchain_read: &mut BlockchainReadHandle,
) -> Result<u64, Error> {
let BlockchainResponse::TotalTxCount(tx_count) = blockchain_read let BlockchainResponse::TotalTxCount(tx_count) = blockchain_read
.ready() .ready()
.await? .await?
@ -290,7 +290,7 @@ pub(crate) async fn total_tx_count(
} }
/// [`BlockchainReadRequest::DatabaseSize`] /// [`BlockchainReadRequest::DatabaseSize`]
pub(crate) async fn database_size( pub async fn database_size(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
) -> Result<(u64, u64), Error> { ) -> Result<(u64, u64), Error> {
let BlockchainResponse::DatabaseSize { let BlockchainResponse::DatabaseSize {
@ -308,8 +308,25 @@ pub(crate) async fn database_size(
Ok((database_size, free_space)) Ok((database_size, free_space))
} }
/// [`BlockchainReadRequest::OutputDistribution`]
pub async fn output_distribution(
blockchain_read: &mut BlockchainReadHandle,
input: OutputDistributionInput,
) -> Result<Vec<OutputDistributionData>, Error> {
let BlockchainResponse::OutputDistribution(data) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::OutputDistribution(input))
.await?
else {
unreachable!();
};
Ok(data)
}
/// [`BlockchainReadRequest::OutputHistogram`] /// [`BlockchainReadRequest::OutputHistogram`]
pub(crate) async fn output_histogram( pub async fn output_histogram(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
input: OutputHistogramInput, input: OutputHistogramInput,
) -> Result<Vec<OutputHistogramEntry>, Error> { ) -> Result<Vec<OutputHistogramEntry>, Error> {
@ -326,7 +343,7 @@ pub(crate) async fn output_histogram(
} }
/// [`BlockchainReadRequest::CoinbaseTxSum`] /// [`BlockchainReadRequest::CoinbaseTxSum`]
pub(crate) async fn coinbase_tx_sum( pub async fn coinbase_tx_sum(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
height: u64, height: u64,
count: u64, count: u64,
@ -347,7 +364,7 @@ pub(crate) async fn coinbase_tx_sum(
} }
/// [`BlockchainReadRequest::AltChains`] /// [`BlockchainReadRequest::AltChains`]
pub(crate) async fn alt_chains( pub async fn alt_chains(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
) -> Result<Vec<ChainInfo>, Error> { ) -> Result<Vec<ChainInfo>, Error> {
let BlockchainResponse::AltChains(vec) = blockchain_read let BlockchainResponse::AltChains(vec) = blockchain_read
@ -363,9 +380,7 @@ pub(crate) async fn alt_chains(
} }
/// [`BlockchainReadRequest::AltChainCount`] /// [`BlockchainReadRequest::AltChainCount`]
pub(crate) async fn alt_chain_count( pub async fn alt_chain_count(blockchain_read: &mut BlockchainReadHandle) -> Result<u64, Error> {
blockchain_read: &mut BlockchainReadHandle,
) -> Result<u64, Error> {
let BlockchainResponse::AltChainCount(count) = blockchain_read let BlockchainResponse::AltChainCount(count) = blockchain_read
.ready() .ready()
.await? .await?
@ -379,7 +394,7 @@ pub(crate) async fn alt_chain_count(
} }
/// [`BlockchainReadRequest::Transactions`]. /// [`BlockchainReadRequest::Transactions`].
pub(crate) async fn transactions( pub async fn transactions(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
tx_hashes: HashSet<[u8; 32]>, tx_hashes: HashSet<[u8; 32]>,
) -> Result<(Vec<TxInBlockchain>, Vec<[u8; 32]>), Error> { ) -> Result<(Vec<TxInBlockchain>, Vec<[u8; 32]>), Error> {
@ -396,9 +411,7 @@ pub(crate) async fn transactions(
} }
/// [`BlockchainReadRequest::TotalRctOutputs`]. /// [`BlockchainReadRequest::TotalRctOutputs`].
pub(crate) async fn total_rct_outputs( pub async fn total_rct_outputs(blockchain_read: &mut BlockchainReadHandle) -> Result<u64, Error> {
blockchain_read: &mut BlockchainReadHandle,
) -> Result<u64, Error> {
let BlockchainResponse::TotalRctOutputs(n) = blockchain_read let BlockchainResponse::TotalRctOutputs(n) = blockchain_read
.ready() .ready()
.await? .await?
@ -412,7 +425,7 @@ pub(crate) async fn total_rct_outputs(
} }
/// [`BlockchainReadRequest::BlockCompleteEntries`]. /// [`BlockchainReadRequest::BlockCompleteEntries`].
pub(crate) async fn block_complete_entries( pub async fn block_complete_entries(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
block_hashes: Vec<[u8; 32]>, block_hashes: Vec<[u8; 32]>,
) -> Result<(Vec<BlockCompleteEntry>, Vec<[u8; 32]>, usize), Error> { ) -> Result<(Vec<BlockCompleteEntry>, Vec<[u8; 32]>, usize), Error> {
@ -433,7 +446,7 @@ pub(crate) async fn block_complete_entries(
} }
/// [`BlockchainReadRequest::BlockCompleteEntriesByHeight`]. /// [`BlockchainReadRequest::BlockCompleteEntriesByHeight`].
pub(crate) async fn block_complete_entries_by_height( pub async fn block_complete_entries_by_height(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
block_heights: Vec<u64>, block_heights: Vec<u64>,
) -> Result<Vec<BlockCompleteEntry>, Error> { ) -> Result<Vec<BlockCompleteEntry>, Error> {
@ -452,7 +465,7 @@ pub(crate) async fn block_complete_entries_by_height(
} }
/// [`BlockchainReadRequest::TxOutputIndexes`]. /// [`BlockchainReadRequest::TxOutputIndexes`].
pub(crate) async fn tx_output_indexes( pub async fn tx_output_indexes(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,
tx_hash: [u8; 32], tx_hash: [u8; 32],
) -> Result<Vec<u64>, Error> { ) -> Result<Vec<u64>, Error> {

View file

@ -16,7 +16,7 @@ use cuprate_types::{
// FIXME: use `anyhow::Error` over `tower::BoxError` in blockchain context. // FIXME: use `anyhow::Error` over `tower::BoxError` in blockchain context.
/// [`BlockChainContextRequest::Context`]. /// [`BlockChainContextRequest::Context`].
pub(crate) async fn context( pub async fn context(
blockchain_context: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
) -> Result<BlockChainContext, Error> { ) -> Result<BlockChainContext, Error> {
let BlockChainContextResponse::Context(context) = blockchain_context let BlockChainContextResponse::Context(context) = blockchain_context
@ -34,7 +34,7 @@ pub(crate) async fn context(
} }
/// [`BlockChainContextRequest::HardForkInfo`]. /// [`BlockChainContextRequest::HardForkInfo`].
pub(crate) async fn hard_fork_info( pub async fn hard_fork_info(
blockchain_context: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
hard_fork: HardFork, hard_fork: HardFork,
) -> Result<HardForkInfo, Error> { ) -> Result<HardForkInfo, Error> {
@ -53,7 +53,7 @@ pub(crate) async fn hard_fork_info(
} }
/// [`BlockChainContextRequest::FeeEstimate`]. /// [`BlockChainContextRequest::FeeEstimate`].
pub(crate) async fn fee_estimate( pub async fn fee_estimate(
blockchain_context: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
grace_blocks: u64, grace_blocks: u64,
) -> Result<FeeEstimate, Error> { ) -> Result<FeeEstimate, Error> {
@ -72,7 +72,7 @@ pub(crate) async fn fee_estimate(
} }
/// [`BlockChainContextRequest::CalculatePow`] /// [`BlockChainContextRequest::CalculatePow`]
pub(crate) async fn calculate_pow( pub async fn calculate_pow(
blockchain_context: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
hardfork: HardFork, hardfork: HardFork,
block: Block, block: Block,
@ -104,7 +104,7 @@ pub(crate) async fn calculate_pow(
} }
/// [`BlockChainContextRequest::BatchGetDifficulties`] /// [`BlockChainContextRequest::BatchGetDifficulties`]
pub(crate) async fn batch_get_difficulties( pub async fn batch_get_difficulties(
blockchain_context: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
difficulties: Vec<(u64, HardFork)>, difficulties: Vec<(u64, HardFork)>,
) -> Result<Vec<u128>, Error> { ) -> Result<Vec<u128>, Error> {

View file

@ -10,12 +10,12 @@ use cuprate_p2p_core::{types::ConnectionId, NetworkZone};
use cuprate_pruning::PruningSeed; use cuprate_pruning::PruningSeed;
use cuprate_rpc_types::misc::Span; use cuprate_rpc_types::misc::Span;
use crate::rpc::handler::{ use crate::rpc::rpc_handler::{
BlockchainManagerHandle, BlockchainManagerRequest, BlockchainManagerResponse, BlockchainManagerHandle, BlockchainManagerRequest, BlockchainManagerResponse,
}; };
/// [`BlockchainManagerRequest::PopBlocks`] /// [`BlockchainManagerRequest::PopBlocks`]
pub(crate) async fn pop_blocks( pub async fn pop_blocks(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
amount: u64, amount: u64,
) -> Result<u64, Error> { ) -> Result<u64, Error> {
@ -34,9 +34,7 @@ pub(crate) async fn pop_blocks(
} }
/// [`BlockchainManagerRequest::Prune`] /// [`BlockchainManagerRequest::Prune`]
pub(crate) async fn prune( pub async fn prune(blockchain_manager: &mut BlockchainManagerHandle) -> Result<PruningSeed, Error> {
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<PruningSeed, Error> {
let BlockchainManagerResponse::Prune(seed) = blockchain_manager let BlockchainManagerResponse::Prune(seed) = blockchain_manager
.ready() .ready()
.await? .await?
@ -50,9 +48,7 @@ pub(crate) async fn prune(
} }
/// [`BlockchainManagerRequest::Pruned`] /// [`BlockchainManagerRequest::Pruned`]
pub(crate) async fn pruned( pub async fn pruned(blockchain_manager: &mut BlockchainManagerHandle) -> Result<bool, Error> {
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<bool, Error> {
let BlockchainManagerResponse::Pruned(pruned) = blockchain_manager let BlockchainManagerResponse::Pruned(pruned) = blockchain_manager
.ready() .ready()
.await? .await?
@ -66,7 +62,7 @@ pub(crate) async fn pruned(
} }
/// [`BlockchainManagerRequest::RelayBlock`] /// [`BlockchainManagerRequest::RelayBlock`]
pub(crate) async fn relay_block( pub async fn relay_block(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
block: Box<Block>, block: Box<Block>,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -83,9 +79,7 @@ pub(crate) async fn relay_block(
} }
/// [`BlockchainManagerRequest::Syncing`] /// [`BlockchainManagerRequest::Syncing`]
pub(crate) async fn syncing( pub async fn syncing(blockchain_manager: &mut BlockchainManagerHandle) -> Result<bool, Error> {
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<bool, Error> {
let BlockchainManagerResponse::Syncing(syncing) = blockchain_manager let BlockchainManagerResponse::Syncing(syncing) = blockchain_manager
.ready() .ready()
.await? .await?
@ -99,9 +93,7 @@ pub(crate) async fn syncing(
} }
/// [`BlockchainManagerRequest::Synced`] /// [`BlockchainManagerRequest::Synced`]
pub(crate) async fn synced( pub async fn synced(blockchain_manager: &mut BlockchainManagerHandle) -> Result<bool, Error> {
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<bool, Error> {
let BlockchainManagerResponse::Synced(syncing) = blockchain_manager let BlockchainManagerResponse::Synced(syncing) = blockchain_manager
.ready() .ready()
.await? .await?
@ -115,7 +107,7 @@ pub(crate) async fn synced(
} }
/// [`BlockchainManagerRequest::Target`] /// [`BlockchainManagerRequest::Target`]
pub(crate) async fn target( pub async fn target(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<std::time::Duration, Error> { ) -> Result<std::time::Duration, Error> {
let BlockchainManagerResponse::Target(target) = blockchain_manager let BlockchainManagerResponse::Target(target) = blockchain_manager
@ -131,9 +123,7 @@ pub(crate) async fn target(
} }
/// [`BlockchainManagerRequest::TargetHeight`] /// [`BlockchainManagerRequest::TargetHeight`]
pub(crate) async fn target_height( pub async fn target_height(blockchain_manager: &mut BlockchainManagerHandle) -> Result<u64, Error> {
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<u64, Error> {
let BlockchainManagerResponse::TargetHeight { height } = blockchain_manager let BlockchainManagerResponse::TargetHeight { height } = blockchain_manager
.ready() .ready()
.await? .await?
@ -147,7 +137,7 @@ pub(crate) async fn target_height(
} }
/// [`BlockchainManagerRequest::GenerateBlocks`] /// [`BlockchainManagerRequest::GenerateBlocks`]
pub(crate) async fn generate_blocks( pub async fn generate_blocks(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
amount_of_blocks: u64, amount_of_blocks: u64,
prev_block: Option<[u8; 32]>, prev_block: Option<[u8; 32]>,
@ -172,7 +162,7 @@ pub(crate) async fn generate_blocks(
} }
// [`BlockchainManagerRequest::Spans`] // [`BlockchainManagerRequest::Spans`]
pub(crate) async fn spans<Z: NetworkZone>( pub async fn spans<Z: NetworkZone>(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<Vec<Span>, Error> { ) -> Result<Vec<Span>, Error> {
// let BlockchainManagerResponse::Spans(vec) = blockchain_manager // let BlockchainManagerResponse::Spans(vec) = blockchain_manager
@ -205,7 +195,7 @@ pub(crate) async fn spans<Z: NetworkZone>(
} }
/// [`BlockchainManagerRequest::NextNeededPruningSeed`] /// [`BlockchainManagerRequest::NextNeededPruningSeed`]
pub(crate) async fn next_needed_pruning_seed( pub async fn next_needed_pruning_seed(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<PruningSeed, Error> { ) -> Result<PruningSeed, Error> {
let BlockchainManagerResponse::NextNeededPruningSeed(seed) = blockchain_manager let BlockchainManagerResponse::NextNeededPruningSeed(seed) = blockchain_manager
@ -221,7 +211,7 @@ pub(crate) async fn next_needed_pruning_seed(
} }
/// [`BlockchainManagerRequest::CreateBlockTemplate`] /// [`BlockchainManagerRequest::CreateBlockTemplate`]
pub(crate) async fn create_block_template( pub async fn create_block_template(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
prev_block: [u8; 32], prev_block: [u8; 32],
account_public_address: String, account_public_address: String,
@ -244,7 +234,7 @@ pub(crate) async fn create_block_template(
} }
/// [`BlockchainManagerRequest::Sync`] /// [`BlockchainManagerRequest::Sync`]
pub(crate) async fn sync(blockchain_manager: &mut BlockchainManagerHandle) -> Result<(), Error> { pub async fn sync(blockchain_manager: &mut BlockchainManagerHandle) -> Result<(), Error> {
let BlockchainManagerResponse::Ok = blockchain_manager let BlockchainManagerResponse::Ok = blockchain_manager
.ready() .ready()
.await? .await?
@ -258,7 +248,7 @@ pub(crate) async fn sync(blockchain_manager: &mut BlockchainManagerHandle) -> Re
} }
/// [`BlockchainManagerRequest::Stop`] /// [`BlockchainManagerRequest::Stop`]
pub(crate) async fn stop(blockchain_manager: &mut BlockchainManagerHandle) -> Result<(), Error> { pub async fn stop(blockchain_manager: &mut BlockchainManagerHandle) -> Result<(), Error> {
let BlockchainManagerResponse::Ok = blockchain_manager let BlockchainManagerResponse::Ok = blockchain_manager
.ready() .ready()
.await? .await?

View file

@ -23,7 +23,7 @@ use cuprate_types::{
// FIXME: use `anyhow::Error` over `tower::BoxError` in txpool. // FIXME: use `anyhow::Error` over `tower::BoxError` in txpool.
/// [`TxpoolReadRequest::Backlog`] /// [`TxpoolReadRequest::Backlog`]
pub(crate) async fn backlog(txpool_read: &mut TxpoolReadHandle) -> Result<Vec<TxEntry>, Error> { pub async fn backlog(txpool_read: &mut TxpoolReadHandle) -> Result<Vec<TxEntry>, Error> {
let TxpoolReadResponse::Backlog(tx_entries) = txpool_read let TxpoolReadResponse::Backlog(tx_entries) = txpool_read
.ready() .ready()
.await .await
@ -39,7 +39,7 @@ pub(crate) async fn backlog(txpool_read: &mut TxpoolReadHandle) -> Result<Vec<Tx
} }
/// [`TxpoolReadRequest::Size`] /// [`TxpoolReadRequest::Size`]
pub(crate) async fn size( pub async fn size(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
include_sensitive_txs: bool, include_sensitive_txs: bool,
) -> Result<u64, Error> { ) -> Result<u64, Error> {
@ -60,7 +60,7 @@ pub(crate) async fn size(
} }
/// TODO /// TODO
pub(crate) async fn pool_info( pub async fn pool_info(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
include_sensitive_txs: bool, include_sensitive_txs: bool,
max_tx_count: usize, max_tx_count: usize,
@ -85,7 +85,7 @@ pub(crate) async fn pool_info(
} }
/// TODO /// TODO
pub(crate) async fn txs_by_hash( pub async fn txs_by_hash(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
tx_hashes: Vec<[u8; 32]>, tx_hashes: Vec<[u8; 32]>,
include_sensitive_txs: bool, include_sensitive_txs: bool,
@ -108,7 +108,7 @@ pub(crate) async fn txs_by_hash(
} }
/// TODO /// TODO
pub(crate) async fn key_images_spent( pub async fn key_images_spent(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
key_images: Vec<[u8; 32]>, key_images: Vec<[u8; 32]>,
include_sensitive_txs: bool, include_sensitive_txs: bool,
@ -131,7 +131,7 @@ pub(crate) async fn key_images_spent(
} }
/// TODO /// TODO
pub(crate) async fn pool( pub async fn pool(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
include_sensitive_txs: bool, include_sensitive_txs: bool,
) -> Result<(Vec<TxInfo>, Vec<SpentKeyImageInfo>), Error> { ) -> Result<(Vec<TxInfo>, Vec<SpentKeyImageInfo>), Error> {
@ -158,7 +158,7 @@ pub(crate) async fn pool(
} }
/// TODO /// TODO
pub(crate) async fn pool_stats( pub async fn pool_stats(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
include_sensitive_txs: bool, include_sensitive_txs: bool,
) -> Result<TxpoolStats, Error> { ) -> Result<TxpoolStats, Error> {
@ -179,25 +179,19 @@ pub(crate) async fn pool_stats(
} }
/// TODO /// TODO
pub(crate) async fn flush( pub async fn flush(txpool_manager: &mut Infallible, tx_hashes: Vec<[u8; 32]>) -> Result<(), Error> {
txpool_manager: &mut Infallible,
tx_hashes: Vec<[u8; 32]>,
) -> Result<(), Error> {
todo!(); todo!();
Ok(()) Ok(())
} }
/// TODO /// TODO
pub(crate) async fn relay( pub async fn relay(txpool_manager: &mut Infallible, tx_hashes: Vec<[u8; 32]>) -> Result<(), Error> {
txpool_manager: &mut Infallible,
tx_hashes: Vec<[u8; 32]>,
) -> Result<(), Error> {
todo!(); todo!();
Ok(()) Ok(())
} }
/// TODO /// TODO
pub(crate) async fn check_maybe_relay_local( pub async fn check_maybe_relay_local(
txpool_manager: &mut Infallible, txpool_manager: &mut Infallible,
tx: Transaction, tx: Transaction,
relay: bool, relay: bool,

View file

@ -1,15 +1,10 @@
//! JSON-RPC 2.0 endpoint route functions. //! JSON-RPC 2.0 endpoint route functions.
//---------------------------------------------------------------------------------------------------- Import //---------------------------------------------------------------------------------------------------- Import
use std::borrow::Cow;
use axum::{extract::State, http::StatusCode, Json}; use axum::{extract::State, http::StatusCode, Json};
use tower::ServiceExt; use tower::ServiceExt;
use cuprate_json_rpc::{ use cuprate_json_rpc::{Id, Response};
error::{ErrorCode, ErrorObject},
Id, Response,
};
use cuprate_rpc_types::{ use cuprate_rpc_types::{
json::{JsonRpcRequest, JsonRpcResponse}, json::{JsonRpcRequest, JsonRpcResponse},
RpcCallValue, RpcCallValue,

View file

@ -6,4 +6,4 @@
pub(crate) mod bin; pub(crate) mod bin;
pub(crate) mod fallback; pub(crate) mod fallback;
pub(crate) mod json_rpc; pub(crate) mod json_rpc;
pub(crate) mod other; pub(crate) mod other_json;

View file

@ -4,7 +4,7 @@
use axum::Router; use axum::Router;
use crate::{ use crate::{
route::{bin, fallback, json_rpc, other}, route::{bin, fallback, json_rpc, other_json},
rpc_handler::RpcHandler, rpc_handler::RpcHandler,
}; };
@ -140,36 +140,36 @@ generate_router_builder! {
json_rpc => "/json_rpc" => json_rpc::json_rpc => (get, post), json_rpc => "/json_rpc" => json_rpc::json_rpc => (get, post),
// Other JSON routes. // Other JSON routes.
other_get_height => "/get_height" => other::get_height => (get, post), other_get_height => "/get_height" => other_json::get_height => (get, post),
other_getheight => "/getheight" => other::get_height => (get, post), other_getheight => "/getheight" => other_json::get_height => (get, post),
other_get_transactions => "/get_transactions" => other::get_transactions => (get, post), other_get_transactions => "/get_transactions" => other_json::get_transactions => (get, post),
other_gettransactions => "/gettransactions" => other::get_transactions => (get, post), other_gettransactions => "/gettransactions" => other_json::get_transactions => (get, post),
other_get_alt_blocks_hashes => "/get_alt_blocks_hashes" => other::get_alt_blocks_hashes => (get, post), other_get_alt_blocks_hashes => "/get_alt_blocks_hashes" => other_json::get_alt_blocks_hashes => (get, post),
other_is_key_image_spent => "/is_key_image_spent" => other::is_key_image_spent => (get, post), other_is_key_image_spent => "/is_key_image_spent" => other_json::is_key_image_spent => (get, post),
other_send_raw_transaction => "/send_raw_transaction" => other::send_raw_transaction => (get, post), other_send_raw_transaction => "/send_raw_transaction" => other_json::send_raw_transaction => (get, post),
other_sendrawtransaction => "/sendrawtransaction" => other::send_raw_transaction => (get, post), other_sendrawtransaction => "/sendrawtransaction" => other_json::send_raw_transaction => (get, post),
other_start_mining => "/start_mining" => other::start_mining => (get, post), other_start_mining => "/start_mining" => other_json::start_mining => (get, post),
other_stop_mining => "/stop_mining" => other::stop_mining => (get, post), other_stop_mining => "/stop_mining" => other_json::stop_mining => (get, post),
other_mining_status => "/mining_status" => other::mining_status => (get, post), other_mining_status => "/mining_status" => other_json::mining_status => (get, post),
other_save_bc => "/save_bc" => other::save_bc => (get, post), other_save_bc => "/save_bc" => other_json::save_bc => (get, post),
other_get_peer_list => "/get_peer_list" => other::get_peer_list => (get, post), other_get_peer_list => "/get_peer_list" => other_json::get_peer_list => (get, post),
other_get_public_nodes => "/get_public_nodes" => other::get_public_nodes => (get, post), other_get_public_nodes => "/get_public_nodes" => other_json::get_public_nodes => (get, post),
other_set_log_hash_rate => "/set_log_hash_rate" => other::set_log_hash_rate => (get, post), other_set_log_hash_rate => "/set_log_hash_rate" => other_json::set_log_hash_rate => (get, post),
other_set_log_level => "/set_log_level" => other::set_log_level => (get, post), other_set_log_level => "/set_log_level" => other_json::set_log_level => (get, post),
other_set_log_categories => "/set_log_categories" => other::set_log_categories => (get, post), other_set_log_categories => "/set_log_categories" => other_json::set_log_categories => (get, post),
other_get_transaction_pool => "/get_transaction_pool" => other::get_transaction_pool => (get, post), other_get_transaction_pool => "/get_transaction_pool" => other_json::get_transaction_pool => (get, post),
other_get_transaction_pool_hashes => "/get_transaction_pool_hashes" => other::get_transaction_pool_hashes => (get, post), other_get_transaction_pool_hashes => "/get_transaction_pool_hashes" => other_json::get_transaction_pool_hashes => (get, post),
other_get_transaction_pool_stats => "/get_transaction_pool_stats" => other::get_transaction_pool_stats => (get, post), other_get_transaction_pool_stats => "/get_transaction_pool_stats" => other_json::get_transaction_pool_stats => (get, post),
other_set_bootstrap_daemon => "/set_bootstrap_daemon" => other::set_bootstrap_daemon => (get, post), other_set_bootstrap_daemon => "/set_bootstrap_daemon" => other_json::set_bootstrap_daemon => (get, post),
other_stop_daemon => "/stop_daemon" => other::stop_daemon => (get, post), other_stop_daemon => "/stop_daemon" => other_json::stop_daemon => (get, post),
other_get_net_stats => "/get_net_stats" => other::get_net_stats => (get, post), other_get_net_stats => "/get_net_stats" => other_json::get_net_stats => (get, post),
other_get_limit => "/get_limit" => other::get_limit => (get, post), other_get_limit => "/get_limit" => other_json::get_limit => (get, post),
other_set_limit => "/set_limit" => other::set_limit => (get, post), other_set_limit => "/set_limit" => other_json::set_limit => (get, post),
other_out_peers => "/out_peers" => other::out_peers => (get, post), other_out_peers => "/out_peers" => other_json::out_peers => (get, post),
other_in_peers => "/in_peers" => other::in_peers => (get, post), other_in_peers => "/in_peers" => other_json::in_peers => (get, post),
other_get_outs => "/get_outs" => other::get_outs => (get, post), other_get_outs => "/get_outs" => other_json::get_outs => (get, post),
other_update => "/update" => other::update => (get, post), other_update => "/update" => other_json::update => (get, post),
other_pop_blocks => "/pop_blocks" => other::pop_blocks => (get, post), other_pop_blocks => "/pop_blocks" => other_json::pop_blocks => (get, post),
// Binary routes. // Binary routes.
bin_get_blocks => "/get_blocks.bin" => bin::get_blocks => (get, post), bin_get_blocks => "/get_blocks.bin" => bin::get_blocks => (get, post),

View file

@ -30,7 +30,7 @@ use cuprate_helper::map::combine_low_high_bits_to_u128;
use cuprate_types::{ use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainResponse}, blockchain::{BlockchainReadRequest, BlockchainResponse},
rpc::OutputHistogramInput, rpc::OutputHistogramInput,
Chain, ChainId, ExtendedBlockHeader, OutputOnChain, TxsInBlock, Chain, ChainId, ExtendedBlockHeader, OutputDistributionInput, OutputOnChain, TxsInBlock,
}; };
use crate::{ use crate::{
@ -142,6 +142,7 @@ fn map_request(
R::Transactions { tx_hashes } => transactions(env, tx_hashes), R::Transactions { tx_hashes } => transactions(env, tx_hashes),
R::TotalRctOutputs => total_rct_outputs(env), R::TotalRctOutputs => total_rct_outputs(env),
R::TxOutputIndexes { tx_hash } => tx_output_indexes(env, &tx_hash), R::TxOutputIndexes { tx_hash } => tx_output_indexes(env, &tx_hash),
R::OutputDistribution(input) => output_distribution(env, input),
} }
/* SOMEDAY: post-request handling, run some code for each request? */ /* SOMEDAY: post-request handling, run some code for each request? */
@ -832,3 +833,8 @@ fn tx_output_indexes(env: &ConcreteEnv, tx_hash: &[u8; 32]) -> ResponseResult {
Ok(BlockchainResponse::TxOutputIndexes(o_indexes.0)) Ok(BlockchainResponse::TxOutputIndexes(o_indexes.0))
} }
/// [`BlockchainReadRequest::OutputDistribution`]
fn output_distribution(env: &ConcreteEnv, input: OutputDistributionInput) -> ResponseResult {
Ok(BlockchainResponse::OutputDistribution(todo!()))
}

View file

@ -11,9 +11,12 @@ use std::{
use monero_serai::block::Block; use monero_serai::block::Block;
use crate::{ use crate::{
rpc::{ChainInfo, CoinbaseTxSum, OutputHistogramEntry, OutputHistogramInput}, rpc::{
ChainInfo, CoinbaseTxSum, OutputDistributionData, OutputHistogramEntry,
OutputHistogramInput,
},
types::{Chain, ExtendedBlockHeader, OutputOnChain, TxsInBlock, VerifiedBlockInformation}, types::{Chain, ExtendedBlockHeader, OutputOnChain, TxsInBlock, VerifiedBlockInformation},
AltBlockInformation, BlockCompleteEntry, ChainId, TxInBlockchain, AltBlockInformation, BlockCompleteEntry, ChainId, OutputDistributionInput, TxInBlockchain,
}; };
//---------------------------------------------------------------------------------------------------- ReadRequest //---------------------------------------------------------------------------------------------------- ReadRequest
@ -154,6 +157,12 @@ pub enum BlockchainReadRequest {
/// TODO: document fields after impl. /// TODO: document fields after impl.
OutputHistogram(OutputHistogramInput), OutputHistogram(OutputHistogramInput),
/// Get the distribution for an output amount.
///
/// - TODO: document fields after impl.
/// - TODO: <https://github.com/monero-project/monero/blob/893916ad091a92e765ce3241b94e706ad012b62a/src/rpc/rpc_handler.cpp#L29>
OutputDistribution(OutputDistributionInput),
/// Get the coinbase amount and the fees amount for /// Get the coinbase amount and the fees amount for
/// `N` last blocks starting at particular height. /// `N` last blocks starting at particular height.
/// ///
@ -352,6 +361,9 @@ pub enum BlockchainResponse {
free_space: u64, free_space: u64,
}, },
/// Response to [`BlockchainReadRequest::OutputDistribution`].
OutputDistribution(Vec<OutputDistributionData>),
/// Response to [`BlockchainReadRequest::OutputHistogram`]. /// Response to [`BlockchainReadRequest::OutputHistogram`].
OutputHistogram(Vec<OutputHistogramEntry>), OutputHistogram(Vec<OutputHistogramEntry>),

View file

@ -24,9 +24,9 @@ pub use transaction_verification_data::{
CachedVerificationState, TransactionVerificationData, TxVersion, CachedVerificationState, TransactionVerificationData, TxVersion,
}; };
pub use types::{ pub use types::{
AltBlockInformation, BlockTemplate, Chain, ChainId, ExtendedBlockHeader, OutputOnChain, AltBlockInformation, BlockTemplate, Chain, ChainId, ExtendedBlockHeader,
TxInBlockchain, TxInPool, TxRelayChecks, TxsInBlock, VerifiedBlockInformation, OutputDistributionInput, OutputOnChain, TxInBlockchain, TxInPool, TxRelayChecks, TxsInBlock,
VerifiedTransactionInformation, VerifiedBlockInformation, VerifiedTransactionInformation,
}; };
//---------------------------------------------------------------------------------------------------- Feature-gated //---------------------------------------------------------------------------------------------------- Feature-gated

View file

@ -253,6 +253,7 @@ define_struct_and_impl_epee! {
45..=50 45..=50
)] )]
OutputDistributionData { OutputDistributionData {
amount: u64,
distribution: Vec<u64>, distribution: Vec<u64>,
start_height: u64, start_height: u64,
base: u64, base: u64,

View file

@ -208,6 +208,17 @@ bitflags::bitflags! {
} }
} }
/// Used in RPC's `get_output_distribution`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OutputDistributionInput {
pub amounts: Vec<u64>,
pub cumulative: bool,
pub from_height: u64,
/// [`None`] means the entire blockchain.
pub to_height: Option<NonZero<u64>>,
}
//---------------------------------------------------------------------------------------------------- Tests //---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)] #[cfg(test)]
mod test { mod test {