get_output_distribution

This commit is contained in:
hinto.janai 2024-12-18 18:09:01 -05:00
parent ce6838bd6f
commit aca28552ab
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
8 changed files with 78 additions and 31 deletions

View file

@ -14,9 +14,11 @@ 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`].
@ -308,6 +310,23 @@ pub(crate) async fn database_size(
Ok((database_size, free_space)) Ok((database_size, free_space))
} }
/// [`BlockchainReadRequest::OutputDistribution`]
pub(crate) 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(crate) async fn output_histogram(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,

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;
@ -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

@ -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

@ -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 {