diff --git a/binaries/cuprated/src/rpc/request/blockchain.rs b/binaries/cuprated/src/rpc/request/blockchain.rs index e5ff3a1..3e37a48 100644 --- a/binaries/cuprated/src/rpc/request/blockchain.rs +++ b/binaries/cuprated/src/rpc/request/blockchain.rs @@ -14,9 +14,11 @@ use cuprate_helper::cast::{u64_to_usize, usize_to_u64}; use cuprate_types::{ blockchain::{BlockchainReadRequest, BlockchainResponse}, 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`]. @@ -308,6 +310,23 @@ pub(crate) async fn database_size( Ok((database_size, free_space)) } +/// [`BlockchainReadRequest::OutputDistribution`] +pub(crate) async fn output_distribution( + blockchain_read: &mut BlockchainReadHandle, + input: OutputDistributionInput, +) -> Result, Error> { + let BlockchainResponse::OutputDistribution(data) = blockchain_read + .ready() + .await? + .call(BlockchainReadRequest::OutputDistribution(input)) + .await? + else { + unreachable!(); + }; + + Ok(data) +} + /// [`BlockchainReadRequest::OutputHistogram`] pub(crate) async fn output_histogram( blockchain_read: &mut BlockchainReadHandle, diff --git a/binaries/cuprated/src/rpc/shared.rs b/binaries/cuprated/src/rpc/shared.rs index 48ae0f9..6db30b8 100644 --- a/binaries/cuprated/src/rpc/shared.rs +++ b/binaries/cuprated/src/rpc/shared.rs @@ -1,8 +1,12 @@ //! 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 cuprate_types::OutputDistributionInput; use monero_serai::transaction::Timelock; use cuprate_constants::rpc::MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT; @@ -97,36 +101,35 @@ pub(super) async fn get_transaction_pool_hashes( /// /// /// Shared between: -/// - JSON-RPC's `get_output_distribution` +/// - Other JSON's `/get_output_distribution` /// - Binary's `/get_output_distribution.bin` +/// +/// Returns transaction hashes. pub(super) async fn get_output_distribution( mut state: CupratedRpcHandler, request: GetOutputDistributionRequest, ) -> Result { - if state.is_restricted() && request.amounts != [1, 0] { + if state.is_restricted() && request.amounts != [0] { return Err(anyhow!( "Restricted RPC can only get output distribution for RCT outputs. Use your own node." )); } - // 0 is placeholder for the whole chain - let req_to_height = if request.to_height == 0 { - helper::top_height(&mut state).await?.0.saturating_sub(1) - } else { - request.to_height + let input = OutputDistributionInput { + amounts: request.amounts, + cumulative: request.cumulative, + from_height: request.from_height, + + // 0 / `None` is placeholder for the whole chain + to_height: NonZero::new(request.to_height), }; - let distributions = request.amounts.into_iter().map(|amount| { - fn get_output_distribution() -> Result { - 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::, _>>()?; + let distributions = blockchain::output_distribution(&mut state.blockchain_read, input).await?; Ok(GetOutputDistributionResponse { base: helper::access_response_base(false), - distributions, + distributions: todo!( + "This type contains binary strings: " + ), }) } diff --git a/rpc/interface/src/route/json_rpc.rs b/rpc/interface/src/route/json_rpc.rs index 9d814c2..f871b75 100644 --- a/rpc/interface/src/route/json_rpc.rs +++ b/rpc/interface/src/route/json_rpc.rs @@ -1,15 +1,10 @@ //! JSON-RPC 2.0 endpoint route functions. //---------------------------------------------------------------------------------------------------- Import -use std::borrow::Cow; - use axum::{extract::State, http::StatusCode, Json}; use tower::ServiceExt; -use cuprate_json_rpc::{ - error::{ErrorCode, ErrorObject}, - Id, Response, -}; +use cuprate_json_rpc::{Id, Response}; use cuprate_rpc_types::{ json::{JsonRpcRequest, JsonRpcResponse}, RpcCallValue, diff --git a/storage/blockchain/src/service/read.rs b/storage/blockchain/src/service/read.rs index 069a7d0..ca660bd 100644 --- a/storage/blockchain/src/service/read.rs +++ b/storage/blockchain/src/service/read.rs @@ -30,7 +30,7 @@ use cuprate_helper::map::combine_low_high_bits_to_u128; use cuprate_types::{ blockchain::{BlockchainReadRequest, BlockchainResponse}, rpc::OutputHistogramInput, - Chain, ChainId, ExtendedBlockHeader, OutputOnChain, TxsInBlock, + Chain, ChainId, ExtendedBlockHeader, OutputDistributionInput, OutputOnChain, TxsInBlock, }; use crate::{ @@ -142,6 +142,7 @@ fn map_request( R::Transactions { tx_hashes } => transactions(env, tx_hashes), R::TotalRctOutputs => total_rct_outputs(env), 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? */ @@ -832,3 +833,8 @@ fn tx_output_indexes(env: &ConcreteEnv, tx_hash: &[u8; 32]) -> ResponseResult { Ok(BlockchainResponse::TxOutputIndexes(o_indexes.0)) } + +/// [`BlockchainReadRequest::OutputDistribution`] +fn output_distribution(env: &ConcreteEnv, input: OutputDistributionInput) -> ResponseResult { + Ok(BlockchainResponse::OutputDistribution(todo!())) +} diff --git a/types/types/src/blockchain.rs b/types/types/src/blockchain.rs index 6ae7bf2..8e6eadf 100644 --- a/types/types/src/blockchain.rs +++ b/types/types/src/blockchain.rs @@ -11,9 +11,12 @@ use std::{ use monero_serai::block::Block; use crate::{ - rpc::{ChainInfo, CoinbaseTxSum, OutputHistogramEntry, OutputHistogramInput}, + rpc::{ + ChainInfo, CoinbaseTxSum, OutputDistributionData, OutputHistogramEntry, + OutputHistogramInput, + }, types::{Chain, ExtendedBlockHeader, OutputOnChain, TxsInBlock, VerifiedBlockInformation}, - AltBlockInformation, BlockCompleteEntry, ChainId, TxInBlockchain, + AltBlockInformation, BlockCompleteEntry, ChainId, OutputDistributionInput, TxInBlockchain, }; //---------------------------------------------------------------------------------------------------- ReadRequest @@ -154,6 +157,12 @@ pub enum BlockchainReadRequest { /// TODO: document fields after impl. OutputHistogram(OutputHistogramInput), + /// Get the distribution for an output amount. + /// + /// - TODO: document fields after impl. + /// - TODO: + OutputDistribution(OutputDistributionInput), + /// Get the coinbase amount and the fees amount for /// `N` last blocks starting at particular height. /// @@ -352,6 +361,9 @@ pub enum BlockchainResponse { free_space: u64, }, + /// Response to [`BlockchainReadRequest::OutputDistribution`]. + OutputDistribution(Vec), + /// Response to [`BlockchainReadRequest::OutputHistogram`]. OutputHistogram(Vec), diff --git a/types/types/src/lib.rs b/types/types/src/lib.rs index c2ac90e..76642a9 100644 --- a/types/types/src/lib.rs +++ b/types/types/src/lib.rs @@ -24,9 +24,9 @@ pub use transaction_verification_data::{ CachedVerificationState, TransactionVerificationData, TxVersion, }; pub use types::{ - AltBlockInformation, BlockTemplate, Chain, ChainId, ExtendedBlockHeader, OutputOnChain, - TxInBlockchain, TxInPool, TxRelayChecks, TxsInBlock, VerifiedBlockInformation, - VerifiedTransactionInformation, + AltBlockInformation, BlockTemplate, Chain, ChainId, ExtendedBlockHeader, + OutputDistributionInput, OutputOnChain, TxInBlockchain, TxInPool, TxRelayChecks, TxsInBlock, + VerifiedBlockInformation, VerifiedTransactionInformation, }; //---------------------------------------------------------------------------------------------------- Feature-gated diff --git a/types/types/src/rpc/types.rs b/types/types/src/rpc/types.rs index ce628b7..4b4b472 100644 --- a/types/types/src/rpc/types.rs +++ b/types/types/src/rpc/types.rs @@ -253,6 +253,7 @@ define_struct_and_impl_epee! { 45..=50 )] OutputDistributionData { + amount: u64, distribution: Vec, start_height: u64, base: u64, diff --git a/types/types/src/types.rs b/types/types/src/types.rs index d165e38..242515f 100644 --- a/types/types/src/types.rs +++ b/types/types/src/types.rs @@ -208,6 +208,17 @@ bitflags::bitflags! { } } +/// Used in RPC's `get_output_distribution`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct OutputDistributionInput { + pub amounts: Vec, + pub cumulative: bool, + pub from_height: u64, + + /// [`None`] means the entire blockchain. + pub to_height: Option>, +} + //---------------------------------------------------------------------------------------------------- Tests #[cfg(test)] mod test {