diff --git a/binaries/cuprated/src/rpc/blockchain.rs b/binaries/cuprated/src/rpc/blockchain.rs index bda998c5..848c3449 100644 --- a/binaries/cuprated/src/rpc/blockchain.rs +++ b/binaries/cuprated/src/rpc/blockchain.rs @@ -1,7 +1,10 @@ //! These are convenience functions that make //! sending [`BlockchainReadRequest`] less verbose. -use std::sync::Arc; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; use anyhow::{anyhow, Error}; use futures::StreamExt; @@ -13,7 +16,8 @@ use cuprate_helper::{ map::split_u128_into_low_high_bits, }; use cuprate_types::{ - blockchain::BlockchainReadRequest, Chain, ExtendedBlockHeader, VerifiedBlockInformation, + blockchain::BlockchainReadRequest, Chain, ExtendedBlockHeader, OutputOnChain, + VerifiedBlockInformation, }; use crate::rpc::{CupratedRpcHandlerState, RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE}; @@ -148,6 +152,24 @@ pub(super) async fn key_image_spent( Ok(is_spent) } +/// [`BlockchainResponse::Outputs`] +pub(super) async fn outputs( + state: &mut CupratedRpcHandlerState, + outputs: HashMap>, +) -> Result>, Error> { + let BlockchainResponse::Outputs(outputs) = state + .blockchain + .ready() + .await? + .call(BlockchainReadRequest::Outputs(outputs)) + .await? + else { + unreachable!(); + }; + + Ok(outputs) +} + // FindBlock([u8; 32]), // FilterUnknownHashes(HashSet<[u8; 32]>), // BlockExtendedHeaderInRange(Range, Chain), diff --git a/binaries/cuprated/src/rpc/other.rs b/binaries/cuprated/src/rpc/other.rs index b5650a5e..02273d4a 100644 --- a/binaries/cuprated/src/rpc/other.rs +++ b/binaries/cuprated/src/rpc/other.rs @@ -1,8 +1,11 @@ +use std::collections::{HashMap, HashSet}; + use anyhow::{anyhow, Error}; +use cuprate_helper::cast::usize_to_u64; use cuprate_rpc_types::{ base::{AccessResponseBase, ResponseBase}, - misc::{KeyImageSpentStatus, Status}, + misc::{KeyImageSpentStatus, OutKey, Status}, other::{ GetAltBlocksHashesRequest, GetAltBlocksHashesResponse, GetHeightRequest, GetHeightResponse, GetLimitRequest, GetLimitResponse, GetNetStatsRequest, GetNetStatsResponse, GetOutsRequest, @@ -27,7 +30,7 @@ use crate::{ rpc::{blockchain, helper}, }; -use super::RESTRICTED_SPENT_KEY_IMAGES_COUNT; +use super::{MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT, RESTRICTED_SPENT_KEY_IMAGES_COUNT}; /// Map a [`OtherRequest`] to the function that will lead to a [`OtherResponse`]. pub(super) async fn map_request( @@ -47,12 +50,8 @@ pub(super) async fn map_request( Req::SendRawTransaction(r) => { Resp::SendRawTransaction(send_raw_transaction(state, r).await?) } - Req::StartMining(r) => Resp::StartMining(start_mining(state, r).await?), - Req::StopMining(r) => Resp::StopMining(stop_mining(state, r).await?), - Req::MiningStatus(r) => Resp::MiningStatus(mining_status(state, r).await?), Req::SaveBc(r) => Resp::SaveBc(save_bc(state, r).await?), Req::GetPeerList(r) => Resp::GetPeerList(get_peer_list(state, r).await?), - Req::SetLogHashRate(r) => Resp::SetLogHashRate(set_log_hash_rate(state, r).await?), Req::SetLogLevel(r) => Resp::SetLogLevel(set_log_level(state, r).await?), Req::SetLogCategories(r) => Resp::SetLogCategories(set_log_categories(state, r).await?), Req::SetBootstrapDaemon(r) => { @@ -77,6 +76,14 @@ pub(super) async fn map_request( Resp::GetTransactionPoolHashes(get_transaction_pool_hashes(state, r).await?) } Req::GetPublicNodes(r) => Resp::GetPublicNodes(get_public_nodes(state, r).await?), + + // Unsupported requests. + Req::StartMining(_) + | Req::StopMining(_) + | Req::MiningStatus(_) + | Req::SetLogHashRate(_) => { + return Err(anyhow!("Mining RPC calls are not supported by Cuprate")) + } }) } @@ -156,7 +163,7 @@ async fn start_mining( state: CupratedRpcHandlerState, request: StartMiningRequest, ) -> Result { - todo!(); + unreachable!(); Ok(StartMiningResponse { base: ResponseBase::ok(), }) @@ -167,7 +174,7 @@ async fn stop_mining( state: CupratedRpcHandlerState, request: StopMiningRequest, ) -> Result { - todo!(); + unreachable!(); Ok(StopMiningResponse { base: ResponseBase::ok(), }) @@ -178,6 +185,7 @@ async fn mining_status( state: CupratedRpcHandlerState, request: MiningStatusRequest, ) -> Result { + unreachable!(); Ok(MiningStatusResponse { base: ResponseBase::ok(), ..todo!() @@ -211,7 +219,7 @@ async fn set_log_hash_rate( state: CupratedRpcHandlerState, request: SetLogHashRateRequest, ) -> Result { - todo!(); + unreachable!(); Ok(SetLogHashRateResponse { base: ResponseBase::ok(), }) @@ -336,12 +344,42 @@ async fn get_net_stats( /// async fn get_outs( - state: CupratedRpcHandlerState, + mut state: CupratedRpcHandlerState, request: GetOutsRequest, ) -> Result { + if state.restricted && request.outputs.len() > MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT { + return Err(anyhow!("Too many outs requested")); + } + + let mut outputs = HashMap::>::with_capacity(request.outputs.len()); + for out in request.outputs { + outputs + .entry(out.amount) + .and_modify(|set| { + set.insert(out.index); + }) + .or_insert_with(|| HashSet::from([out.index])); + } + + let outs = blockchain::outputs(&mut state, outputs) + .await? + .into_iter() + .flat_map(|(amount, index_map)| { + index_map.into_iter().map(|(index, out)| OutKey { + key: todo!(), + mask: todo!(), + unlocked: todo!(), + height: usize_to_u64(out.height), + txid: todo!(), + }) + }) + .collect::>(); + + // TODO: check txpool + Ok(GetOutsResponse { base: ResponseBase::ok(), - ..todo!() + outs, }) }