diff --git a/binaries/cuprated/src/rpc/handler.rs b/binaries/cuprated/src/rpc/handler.rs index fd9be38f..5db473d5 100644 --- a/binaries/cuprated/src/rpc/handler.rs +++ b/binaries/cuprated/src/rpc/handler.rs @@ -180,7 +180,7 @@ impl CupratedRpcHandler { } impl RpcHandler for CupratedRpcHandler { - fn restricted(&self) -> bool { + fn is_restricted(&self) -> bool { self.restricted } } diff --git a/binaries/cuprated/src/rpc/json.rs b/binaries/cuprated/src/rpc/json.rs index 00bbaea0..b445931b 100644 --- a/binaries/cuprated/src/rpc/json.rs +++ b/binaries/cuprated/src/rpc/json.rs @@ -32,7 +32,8 @@ use cuprate_rpc_types::{ GetConnectionsRequest, GetConnectionsResponse, GetFeeEstimateRequest, GetFeeEstimateResponse, GetInfoRequest, GetInfoResponse, GetLastBlockHeaderRequest, GetLastBlockHeaderResponse, GetMinerDataRequest, GetMinerDataResponse, - GetOutputHistogramRequest, GetOutputHistogramResponse, GetTransactionPoolBacklogRequest, + GetOutputDistributionRequest, GetOutputDistributionResponse, GetOutputHistogramRequest, + GetOutputHistogramResponse, GetTransactionPoolBacklogRequest, GetTransactionPoolBacklogResponse, GetTxIdsLooseRequest, GetTxIdsLooseResponse, GetVersionRequest, GetVersionResponse, HardForkInfoRequest, HardForkInfoResponse, JsonRpcRequest, JsonRpcResponse, OnGetBlockHashRequest, OnGetBlockHashResponse, @@ -41,8 +42,8 @@ use cuprate_rpc_types::{ SyncInfoResponse, }, misc::{ - AuxPow, BlockHeader, ChainInfo, GetBan, GetMinerDataTxBacklogEntry, HardforkEntry, - HistogramEntry, Status, SyncInfoPeer, TxBacklogEntry, + AuxPow, BlockHeader, ChainInfo, Distribution, GetBan, GetMinerDataTxBacklogEntry, + HardforkEntry, HistogramEntry, Status, SyncInfoPeer, TxBacklogEntry, }, CORE_RPC_VERSION, }; @@ -109,6 +110,9 @@ pub(super) async fn map_request( Req::GetTransactionPoolBacklog(r) => { Resp::GetTransactionPoolBacklog(get_transaction_pool_backlog(state, r).await?) } + Req::GetOutputDistribution(r) => { + Resp::GetOutputDistribution(get_output_distribution(state, r).await?) + } Req::GetMinerData(r) => Resp::GetMinerData(get_miner_data(state, r).await?), Req::PruneBlockchain(r) => Resp::PruneBlockchain(prune_blockchain(state, r).await?), Req::CalcPow(r) => Resp::CalcPow(calc_pow(state, r).await?), @@ -217,7 +221,7 @@ async fn get_block_header_by_hash( mut state: CupratedRpcHandler, request: GetBlockHeaderByHashRequest, ) -> Result { - if state.restricted() && request.hashes.len() > RESTRICTED_BLOCK_COUNT { + if state.is_restricted() && request.hashes.len() > RESTRICTED_BLOCK_COUNT { return Err(anyhow!( "Too many block headers requested in restricted mode" )); @@ -282,7 +286,7 @@ async fn get_block_headers_range( request.end_height.saturating_sub(request.start_height) + 1 > RESTRICTED_BLOCK_HEADER_RANGE }; - if state.restricted() && too_many_blocks() { + if state.is_restricted() && too_many_blocks() { return Err(anyhow!("Too many block headers requested.")); } @@ -374,7 +378,7 @@ async fn get_info( mut state: CupratedRpcHandler, request: GetInfoRequest, ) -> Result { - let restricted = state.restricted(); + let restricted = state.is_restricted(); let context = blockchain_context::context(&mut state.blockchain_context).await?; let c = context.unchecked_blockchain_context(); @@ -866,6 +870,39 @@ async fn get_transaction_pool_backlog( }) } +/// +async fn get_output_distribution( + mut state: CupratedRpcHandler, + request: GetOutputDistributionRequest, +) -> Result { + if state.is_restricted() && request.amounts != [1, 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 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::, _>>()?; + + Ok(GetOutputDistributionResponse { + base: AccessResponseBase::OK, + distributions, + }) +} + /// async fn get_miner_data( mut state: CupratedRpcHandler, diff --git a/rpc/interface/src/route/bin.rs b/rpc/interface/src/route/bin.rs index f7e3a01c..6d4fb9a3 100644 --- a/rpc/interface/src/route/bin.rs +++ b/rpc/interface/src/route/bin.rs @@ -72,7 +72,7 @@ macro_rules! generate_endpoints_inner { paste::paste! { { // Check if restricted. - if [<$variant Request>]::IS_RESTRICTED && $handler.restricted() { + if [<$variant Request>]::IS_RESTRICTED && $handler.is_restricted() { // TODO: mimic `monerod` behavior. return Err(StatusCode::FORBIDDEN); } diff --git a/rpc/interface/src/route/json_rpc.rs b/rpc/interface/src/route/json_rpc.rs index 7efb8513..bb865860 100644 --- a/rpc/interface/src/route/json_rpc.rs +++ b/rpc/interface/src/route/json_rpc.rs @@ -37,7 +37,7 @@ pub(crate) async fn json_rpc( // Return early if this RPC server is restricted and // the requested method is only for non-restricted RPC. - if request.body.is_restricted() && handler.restricted() { + if request.body.is_restricted() && handler.is_restricted() { let error_object = ErrorObject { code: ErrorCode::ServerError(-1 /* TODO */), message: Cow::Borrowed("Restricted. TODO: mimic monerod message"), diff --git a/rpc/interface/src/route/other.rs b/rpc/interface/src/route/other.rs index 3ff84487..3993bd0f 100644 --- a/rpc/interface/src/route/other.rs +++ b/rpc/interface/src/route/other.rs @@ -75,7 +75,7 @@ macro_rules! generate_endpoints_inner { paste::paste! { { // Check if restricted. - if [<$variant Request>]::IS_RESTRICTED && $handler.restricted() { + if [<$variant Request>]::IS_RESTRICTED && $handler.is_restricted() { // TODO: mimic `monerod` behavior. return Err(StatusCode::FORBIDDEN); } diff --git a/rpc/interface/src/rpc_handler.rs b/rpc/interface/src/rpc_handler.rs index 1d2676c7..c5c57686 100644 --- a/rpc/interface/src/rpc_handler.rs +++ b/rpc/interface/src/rpc_handler.rs @@ -46,5 +46,5 @@ pub trait RpcHandler: /// /// will automatically be denied access when using the /// [`axum::Router`] provided by [`RouterBuilder`](crate::RouterBuilder). - fn restricted(&self) -> bool; + fn is_restricted(&self) -> bool; } diff --git a/rpc/interface/src/rpc_handler_dummy.rs b/rpc/interface/src/rpc_handler_dummy.rs index 9d5009e4..ac48ceca 100644 --- a/rpc/interface/src/rpc_handler_dummy.rs +++ b/rpc/interface/src/rpc_handler_dummy.rs @@ -39,7 +39,7 @@ pub struct RpcHandlerDummy { } impl RpcHandler for RpcHandlerDummy { - fn restricted(&self) -> bool { + fn is_restricted(&self) -> bool { self.restricted } } @@ -85,6 +85,7 @@ impl Service for RpcHandlerDummy { Req::GetTransactionPoolBacklog(_) => { Resp::GetTransactionPoolBacklog(Default::default()) } + Req::GetOutputDistribution(_) => Resp::GetOutputDistribution(Default::default()), Req::GetMinerData(_) => Resp::GetMinerData(Default::default()), Req::PruneBlockchain(_) => Resp::PruneBlockchain(Default::default()), Req::CalcPow(_) => Resp::CalcPow(Default::default()), diff --git a/rpc/types/src/json.rs b/rpc/types/src/json.rs index cb55e64a..d4087da3 100644 --- a/rpc/types/src/json.rs +++ b/rpc/types/src/json.rs @@ -1623,6 +1623,7 @@ pub enum JsonRpcRequest { RelayTx(RelayTxRequest), SyncInfo(SyncInfoRequest), GetTransactionPoolBacklog(GetTransactionPoolBacklogRequest), + GetOutputDistribution(GetOutputDistributionRequest), GetMinerData(GetMinerDataRequest), PruneBlockchain(PruneBlockchainRequest), CalcPow(CalcPowRequest), @@ -1648,6 +1649,7 @@ impl RpcCallValue for JsonRpcRequest { Self::GetVersion(x) => x.is_restricted(), Self::GetFeeEstimate(x) => x.is_restricted(), Self::GetTransactionPoolBacklog(x) => x.is_restricted(), + Self::GetOutputDistribution(x) => x.is_restricted(), Self::GetMinerData(x) => x.is_restricted(), Self::AddAuxPow(x) => x.is_restricted(), Self::GetTxIdsLoose(x) => x.is_restricted(), @@ -1683,6 +1685,7 @@ impl RpcCallValue for JsonRpcRequest { Self::GetVersion(x) => x.is_empty(), Self::GetFeeEstimate(x) => x.is_empty(), Self::GetTransactionPoolBacklog(x) => x.is_empty(), + Self::GetOutputDistribution(x) => x.is_empty(), Self::GetMinerData(x) => x.is_empty(), Self::AddAuxPow(x) => x.is_empty(), Self::GetTxIdsLoose(x) => x.is_empty(), @@ -1755,6 +1758,7 @@ pub enum JsonRpcResponse { RelayTx(RelayTxResponse), SyncInfo(SyncInfoResponse), GetTransactionPoolBacklog(GetTransactionPoolBacklogResponse), + GetOutputDistribution(GetOutputDistributionResponse), GetMinerData(GetMinerDataResponse), PruneBlockchain(PruneBlockchainResponse), CalcPow(CalcPowResponse),