diff --git a/Cargo.lock b/Cargo.lock index 5fea18d..e45f7e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -972,6 +972,7 @@ dependencies = [ "cuprate-blockchain", "cuprate-consensus", "cuprate-consensus-rules", + "cuprate-constants", "cuprate-cryptonight", "cuprate-dandelion-tower", "cuprate-database", diff --git a/binaries/cuprated/Cargo.toml b/binaries/cuprated/Cargo.toml index 325406b..7ec8579 100644 --- a/binaries/cuprated/Cargo.toml +++ b/binaries/cuprated/Cargo.toml @@ -12,6 +12,7 @@ repository = "https://github.com/Cuprate/cuprate/tree/main/binaries/cuprated" cuprate-consensus = { path = "../../consensus" } cuprate-fast-sync = { path = "../../consensus/fast-sync" } cuprate-consensus-rules = { path = "../../consensus/rules" } +cuprate-constants = { path = "../../constants", features = ["build", "rpc"] } cuprate-cryptonight = { path = "../../cryptonight" } cuprate-helper = { path = "../../helper" } cuprate-epee-encoding = { path = "../../net/epee-encoding" } diff --git a/binaries/cuprated/src/rpc.rs b/binaries/cuprated/src/rpc.rs index fe8e5f2..a52fc98 100644 --- a/binaries/cuprated/src/rpc.rs +++ b/binaries/cuprated/src/rpc.rs @@ -7,5 +7,6 @@ mod handler; mod json; mod other; mod request; +mod helper; pub use handler::CupratedRpcHandler; diff --git a/binaries/cuprated/src/rpc/helper.rs b/binaries/cuprated/src/rpc/helper.rs new file mode 100644 index 0000000..7c95b1b --- /dev/null +++ b/binaries/cuprated/src/rpc/helper.rs @@ -0,0 +1,168 @@ +//! These are internal helper functions used by the actual RPC handlers. +//! +//! Many of the handlers have bodies with only small differences, +//! the identical code is extracted and reused here in these functions. +//! +//! These build on-top of [`crate::rpc::request`] functions. + +use std::sync::Arc; + +use anyhow::{anyhow, Error}; +use cuprate_rpc_types::misc::{BlockHeader, KeyImageSpentStatus}; +use futures::StreamExt; +use monero_serai::block::Block; +use tower::{Service, ServiceExt}; + +use cuprate_consensus::BlockchainResponse; +use cuprate_constants::rpc::{RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE}; +use cuprate_helper::{ + cast::{u64_to_usize, usize_to_u64}, + map::split_u128_into_low_high_bits, +}; +use cuprate_types::{ + blockchain::BlockchainReadRequest, Chain, ExtendedBlockHeader, VerifiedBlockInformation, +}; + +use crate::{rpc::request::blockchain, rpc::CupratedRpcHandler}; + +fn into_block_header( + height: u64, + top_height: u64, + fill_pow_hash: bool, + block: Block, + header: ExtendedBlockHeader, +) -> BlockHeader { + let block_weight = usize_to_u64(header.block_weight); + let depth = top_height.saturating_sub(height); + let (cumulative_difficulty_top64, cumulative_difficulty) = + split_u128_into_low_high_bits(header.cumulative_difficulty); + + BlockHeader { + block_size: block_weight, + block_weight, + cumulative_difficulty_top64, + cumulative_difficulty, + depth, + difficulty_top64: todo!(), + difficulty: todo!(), + hash: hex::encode(block.hash()), + height, + long_term_weight: usize_to_u64(header.long_term_weight), + major_version: header.version.as_u8(), + miner_tx_hash: hex::encode(block.miner_transaction.hash()), + minor_version: header.vote, + nonce: block.header.nonce, + num_txes: usize_to_u64(block.transactions.len()), + orphan_status: todo!(), + pow_hash: if fill_pow_hash { + todo!() + } else { + String::new() + }, + prev_hash: hex::encode(block.header.previous), + reward: todo!(), + timestamp: block.header.timestamp, + wide_cumulative_difficulty: hex::encode(u128::to_le_bytes(header.cumulative_difficulty)), + wide_difficulty: todo!(), + } +} + +/// Get a [`VerifiedBlockInformation`] and map it to a [`BlockHeader`]. +pub(super) async fn block_header( + state: &mut CupratedRpcHandler, + height: u64, + fill_pow_hash: bool, +) -> Result { + let (top_height, _) = top_height(state).await?; + let block = blockchain::block(&mut state.blockchain_read, height).await?; + let header = blockchain::block_extended_header(&mut state.blockchain_read, height).await?; + + let block_header = into_block_header(height, top_height, fill_pow_hash, block, header); + + Ok(block_header) +} + +/// Same as [`block_header`] but with the block's hash. +pub(super) async fn block_header_by_hash( + state: &mut CupratedRpcHandler, + hash: [u8; 32], + fill_pow_hash: bool, +) -> Result { + let (top_height, _) = top_height(state).await?; + let block = blockchain::block_by_hash(&mut state.blockchain_read, hash).await?; + let header: ExtendedBlockHeader = todo!(); //blockchain::block_extended_header_by_hash(state.blockchain_read, hash).await?; + + let block_header = into_block_header(header.height, top_height, fill_pow_hash, block, header); + + Ok(block_header) +} + +/// TODO +pub(super) async fn top_block_header( + state: &mut CupratedRpcHandler, + fill_pow_hash: bool, +) -> Result { + let block: Block = todo!(); + let header: ExtendedBlockHeader = todo!(); + + let block_header = + into_block_header(header.height, header.height, fill_pow_hash, block, header); + + Ok(block_header) +} + +/// Check if `height` is greater than the [`top_height`]. +/// +/// # Errors +/// This returns the [`top_height`] on [`Ok`] and +/// returns [`Error`] if `height` is greater than [`top_height`]. +pub(super) async fn check_height( + state: &mut CupratedRpcHandler, + height: u64, +) -> Result { + let (top_height, _) = top_height(state).await?; + + if height > top_height { + return Err(anyhow!( + "Requested block height: {height} greater than current top block height: {top_height}", + )); + } + + Ok(top_height) +} + +/// Parse a hexadecimal [`String`] as a 32-byte hash. +pub(super) fn hex_to_hash(hex: String) -> Result<[u8; 32], Error> { + let error = || anyhow!("Failed to parse hex representation of hash. Hex = {hex}."); + + let Ok(bytes) = hex::decode(&hex) else { + return Err(error()); + }; + + let Ok(hash) = bytes.try_into() else { + return Err(error()); + }; + + Ok(hash) +} + +/// [`BlockchainResponse::ChainHeight`] minus 1. +pub(super) async fn top_height(state: &mut CupratedRpcHandler) -> Result<(u64, [u8; 32]), Error> { + let (chain_height, hash) = blockchain::chain_height(state).await?; + let height = chain_height.saturating_sub(1); + Ok((height, hash)) +} + +/// TODO +pub(super) async fn key_image_spent( + state: &mut CupratedRpcHandler, + key_image: [u8; 32], +) -> Result { + if blockchain::key_image_spent(state, key_image).await? { + Ok(KeyImageSpentStatus::SpentInBlockchain) + } else if todo!("key image is spent in tx pool") { + Ok(KeyImageSpentStatus::SpentInPool) + } else { + Ok(KeyImageSpentStatus::Unspent) + } +} diff --git a/binaries/cuprated/src/rpc/json.rs b/binaries/cuprated/src/rpc/json.rs index 88b38b9..2ba6796 100644 --- a/binaries/cuprated/src/rpc/json.rs +++ b/binaries/cuprated/src/rpc/json.rs @@ -1,29 +1,43 @@ use std::sync::Arc; -use anyhow::Error; -use tower::ServiceExt; +use anyhow::{anyhow, Error}; +use cuprate_types::HardFork; +use monero_serai::block::Block; +use tower::{Service, ServiceExt}; -use cuprate_rpc_types::json::{ - AddAuxPowRequest, AddAuxPowResponse, BannedRequest, BannedResponse, CalcPowRequest, - CalcPowResponse, FlushCacheRequest, FlushCacheResponse, FlushTransactionPoolRequest, - FlushTransactionPoolResponse, GenerateBlocksRequest, GenerateBlocksResponse, - GetAlternateChainsRequest, GetAlternateChainsResponse, GetBansRequest, GetBansResponse, - GetBlockCountRequest, GetBlockCountResponse, GetBlockHeaderByHashRequest, - GetBlockHeaderByHashResponse, GetBlockHeaderByHeightRequest, GetBlockHeaderByHeightResponse, - GetBlockHeadersRangeRequest, GetBlockHeadersRangeResponse, GetBlockRequest, GetBlockResponse, - GetCoinbaseTxSumRequest, GetCoinbaseTxSumResponse, GetConnectionsRequest, - GetConnectionsResponse, GetFeeEstimateRequest, GetFeeEstimateResponse, GetInfoRequest, - GetInfoResponse, GetLastBlockHeaderRequest, GetLastBlockHeaderResponse, GetMinerDataRequest, - GetMinerDataResponse, GetOutputHistogramRequest, GetOutputHistogramResponse, - GetTransactionPoolBacklogRequest, GetTransactionPoolBacklogResponse, GetTxIdsLooseRequest, - GetTxIdsLooseResponse, GetVersionRequest, GetVersionResponse, HardForkInfoRequest, - HardForkInfoResponse, JsonRpcRequest, JsonRpcResponse, OnGetBlockHashRequest, - OnGetBlockHashResponse, PruneBlockchainRequest, PruneBlockchainResponse, RelayTxRequest, - RelayTxResponse, SetBansRequest, SetBansResponse, SubmitBlockRequest, SubmitBlockResponse, - SyncInfoRequest, SyncInfoResponse, +use cuprate_consensus::{BlockchainReadRequest, BlockchainResponse}; +use cuprate_constants::{ + build::RELEASE, + rpc::{BLOCK_SIZE_SANITY_LEEWAY, RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE}, +}; +use cuprate_helper::cast::u64_to_usize; +use cuprate_rpc_types::{ + base::{AccessResponseBase, ResponseBase}, + json::{ + AddAuxPowRequest, AddAuxPowResponse, BannedRequest, BannedResponse, CalcPowRequest, + CalcPowResponse, FlushCacheRequest, FlushCacheResponse, FlushTransactionPoolRequest, + FlushTransactionPoolResponse, GenerateBlocksRequest, GenerateBlocksResponse, + GetAlternateChainsRequest, GetAlternateChainsResponse, GetBansRequest, GetBansResponse, + GetBlockCountRequest, GetBlockCountResponse, GetBlockHeaderByHashRequest, + GetBlockHeaderByHashResponse, GetBlockHeaderByHeightRequest, + GetBlockHeaderByHeightResponse, GetBlockHeadersRangeRequest, GetBlockHeadersRangeResponse, + GetBlockRequest, GetBlockResponse, GetCoinbaseTxSumRequest, GetCoinbaseTxSumResponse, + GetConnectionsRequest, GetConnectionsResponse, GetFeeEstimateRequest, + GetFeeEstimateResponse, GetInfoRequest, GetInfoResponse, GetLastBlockHeaderRequest, + GetLastBlockHeaderResponse, GetMinerDataRequest, GetMinerDataResponse, + GetOutputHistogramRequest, GetOutputHistogramResponse, GetTransactionPoolBacklogRequest, + GetTransactionPoolBacklogResponse, GetTxIdsLooseRequest, GetTxIdsLooseResponse, + GetVersionRequest, GetVersionResponse, HardForkInfoRequest, HardForkInfoResponse, + JsonRpcRequest, JsonRpcResponse, OnGetBlockHashRequest, OnGetBlockHashResponse, + PruneBlockchainRequest, PruneBlockchainResponse, RelayTxRequest, RelayTxResponse, + SetBansRequest, SetBansResponse, SubmitBlockRequest, SubmitBlockResponse, SyncInfoRequest, + SyncInfoResponse, + }, + misc::{BlockHeader, Status}, + CORE_RPC_VERSION, }; -use crate::rpc::CupratedRpcHandler; +use crate::rpc::{helper, request::blockchain, CupratedRpcHandler}; /// Map a [`JsonRpcRequest`] to the function that will lead to a [`JsonRpcResponse`]. pub(super) async fn map_request( @@ -83,212 +97,518 @@ pub(super) async fn map_request( }) } +/// async fn get_block_count( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: GetBlockCountRequest, ) -> Result { - todo!() + Ok(GetBlockCountResponse { + base: ResponseBase::ok(), + count: helper::top_height(&mut state).await?.0, + }) } +/// async fn on_get_block_hash( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: OnGetBlockHashRequest, ) -> Result { - todo!() + let [height] = request.block_height; + let hash = blockchain::block_hash(&mut state, height).await?; + let block_hash = hex::encode(hash); + + Ok(OnGetBlockHashResponse { block_hash }) } +/// async fn submit_block( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: SubmitBlockRequest, ) -> Result { - todo!() + let [blob] = request.block_blob; + + let limit = blockchain::cumulative_block_weight_limit(&mut state).await?; + + if blob.len() > limit + BLOCK_SIZE_SANITY_LEEWAY { + return Err(anyhow!("Block size is too big, rejecting block")); + } + + let bytes = hex::decode(blob)?; + let block = Block::read(&mut bytes.as_slice())?; + + // + let block_id = todo!("submit block to DB"); + todo!("relay to P2P"); + todo!("send to txpool"); + + Ok(SubmitBlockResponse { + base: ResponseBase::ok(), + block_id, + }) } +/// async fn generate_blocks( state: CupratedRpcHandler, request: GenerateBlocksRequest, ) -> Result { - todo!() + Ok(GenerateBlocksResponse { + base: ResponseBase::ok(), + blocks: todo!(), + height: todo!(), + }) } +/// async fn get_last_block_header( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: GetLastBlockHeaderRequest, ) -> Result { - todo!() + let (height, _) = helper::top_height(&mut state).await?; + let block_header = helper::block_header(&mut state, height, request.fill_pow_hash).await?; + + Ok(GetLastBlockHeaderResponse { + base: AccessResponseBase::ok(), + block_header, + }) } +/// async fn get_block_header_by_hash( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: GetBlockHeaderByHashRequest, ) -> Result { - todo!() + if state.restricted && request.hashes.len() > RESTRICTED_BLOCK_COUNT { + return Err(anyhow!( + "Too many block headers requested in restricted mode" + )); + } + + async fn get( + state: &mut CupratedRpcHandler, + hex: String, + fill_pow_hash: bool, + ) -> Result { + let hash = helper::hex_to_hash(hex)?; + let block_header = helper::block_header_by_hash(state, hash, fill_pow_hash).await?; + Ok(block_header) + } + + let block_header = get(&mut state, request.hash, request.fill_pow_hash).await?; + + // FIXME PERF: could make a `Vec` on await on all tasks at the same time. + let mut block_headers = Vec::with_capacity(request.hashes.len()); + for hash in request.hashes { + let hash = get(&mut state, hash, request.fill_pow_hash).await?; + block_headers.push(hash); + } + + Ok(GetBlockHeaderByHashResponse { + base: AccessResponseBase::ok(), + block_header, + block_headers, + }) } +/// async fn get_block_header_by_height( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: GetBlockHeaderByHeightRequest, ) -> Result { - todo!() + helper::check_height(&mut state, request.height).await?; + let block_header = + helper::block_header(&mut state, request.height, request.fill_pow_hash).await?; + + Ok(GetBlockHeaderByHeightResponse { + base: AccessResponseBase::ok(), + block_header, + }) } +/// async fn get_block_headers_range( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: GetBlockHeadersRangeRequest, ) -> Result { - todo!() + let (top_height, _) = helper::top_height(&mut state).await?; + + if request.start_height >= top_height + || request.end_height >= top_height + || request.start_height > request.end_height + { + return Err(anyhow!("Invalid start/end heights")); + } + + if state.restricted + && request.end_height.saturating_sub(request.start_height) + 1 + > RESTRICTED_BLOCK_HEADER_RANGE + { + return Err(anyhow!("Too many block headers requested.")); + } + + let block_len = u64_to_usize(request.end_height.saturating_sub(request.start_height)); + let mut tasks = Vec::with_capacity(block_len); + let mut headers = Vec::with_capacity(block_len); + + { + let ready = state.blockchain_read.ready().await?; + for height in request.start_height..=request.end_height { + let height = u64_to_usize(height); + let task = tokio::task::spawn(ready.call(BlockchainReadRequest::Block { height })); + tasks.push(task); + } + } + + for task in tasks { + let BlockchainResponse::Block(header) = task.await?? else { + unreachable!(); + }; + // headers.push((&header).into()); + headers.push(todo!()); + } + + Ok(GetBlockHeadersRangeResponse { + base: AccessResponseBase::ok(), + headers, + }) } +/// async fn get_block( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: GetBlockRequest, ) -> Result { - todo!() + let block = if request.hash.is_empty() { + helper::check_height(&mut state, request.height).await?; + blockchain::block(&mut state, request.height).await? + } else { + let hash = helper::hex_to_hash(request.hash)?; + blockchain::block_by_hash(&mut state, hash).await? + }; + + Ok(todo!()) + + // let block_header = (&block).into(); + // let blob = hex::encode(block.block_blob); + // let miner_tx_hash = hex::encode(block.block.miner_transaction.hash()); + // let tx_hashes = block + // .txs + // .into_iter() + // .map(|tx| hex::encode(tx.tx_hash)) + // .collect(); + + // Ok(GetBlockResponse { + // base: AccessResponseBase::ok(), + // blob, + // json: todo!(), // TODO: make `JSON` type in `cuprate_rpc_types` + // miner_tx_hash, + // tx_hashes, + // block_header, + // }) } +/// async fn get_connections( state: CupratedRpcHandler, request: GetConnectionsRequest, ) -> Result { - todo!() + Ok(GetConnectionsResponse { + base: ResponseBase::ok(), + connections: todo!(), + }) } +/// async fn get_info( state: CupratedRpcHandler, request: GetInfoRequest, ) -> Result { - todo!() + Ok(GetInfoResponse { + base: AccessResponseBase::ok(), + adjusted_time: todo!(), + alt_blocks_count: todo!(), + block_size_limit: todo!(), + block_size_median: todo!(), + block_weight_limit: todo!(), + block_weight_median: todo!(), + bootstrap_daemon_address: todo!(), + busy_syncing: todo!(), + cumulative_difficulty_top64: todo!(), + cumulative_difficulty: todo!(), + database_size: todo!(), + difficulty_top64: todo!(), + difficulty: todo!(), + free_space: todo!(), + grey_peerlist_size: todo!(), + height: todo!(), + height_without_bootstrap: todo!(), + incoming_connections_count: todo!(), + mainnet: todo!(), + nettype: todo!(), + offline: todo!(), + outgoing_connections_count: todo!(), + restricted: todo!(), + rpc_connections_count: todo!(), + stagenet: todo!(), + start_time: todo!(), + synchronized: todo!(), + target_height: todo!(), + target: todo!(), + testnet: todo!(), + top_block_hash: todo!(), + tx_count: todo!(), + tx_pool_size: todo!(), + update_available: todo!(), + version: todo!(), + was_bootstrap_ever_used: todo!(), + white_peerlist_size: todo!(), + wide_cumulative_difficulty: todo!(), + wide_difficulty: todo!(), + }) } +/// async fn hard_fork_info( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: HardForkInfoRequest, ) -> Result { - todo!() + let hard_fork = if request.version > 0 { + HardFork::from_version(request.version)? + } else { + blockchain::current_hard_fork(&mut state).await? + }; + + Ok(HardForkInfoResponse { + base: AccessResponseBase::ok(), + earliest_height: todo!(), + enabled: hard_fork.is_current(), + state: todo!(), + threshold: todo!(), + version: hard_fork.as_u8(), + votes: todo!(), + voting: todo!(), + window: todo!(), + }) } +/// async fn set_bans( state: CupratedRpcHandler, request: SetBansRequest, ) -> Result { - todo!() + todo!(); + + Ok(SetBansResponse { + base: ResponseBase::ok(), + }) } +/// async fn get_bans( state: CupratedRpcHandler, request: GetBansRequest, ) -> Result { - todo!() + Ok(GetBansResponse { + base: ResponseBase::ok(), + bans: todo!(), + }) } +/// async fn banned( state: CupratedRpcHandler, request: BannedRequest, ) -> Result { - todo!() + Ok(BannedResponse { + banned: todo!(), + seconds: todo!(), + status: todo!(), + }) } +/// async fn flush_transaction_pool( state: CupratedRpcHandler, request: FlushTransactionPoolRequest, ) -> Result { - todo!() + todo!(); + Ok(FlushTransactionPoolResponse { status: Status::Ok }) } +/// async fn get_output_histogram( state: CupratedRpcHandler, request: GetOutputHistogramRequest, ) -> Result { - todo!() + Ok(GetOutputHistogramResponse { + base: AccessResponseBase::ok(), + histogram: todo!(), + }) } +/// async fn get_coinbase_tx_sum( state: CupratedRpcHandler, request: GetCoinbaseTxSumRequest, ) -> Result { - todo!() + Ok(GetCoinbaseTxSumResponse { + base: AccessResponseBase::ok(), + emission_amount: todo!(), + emission_amount_top64: todo!(), + fee_amount: todo!(), + fee_amount_top64: todo!(), + wide_emission_amount: todo!(), + wide_fee_amount: todo!(), + }) } +/// async fn get_version( - state: CupratedRpcHandler, + mut state: CupratedRpcHandler, request: GetVersionRequest, ) -> Result { - todo!() + Ok(GetVersionResponse { + base: ResponseBase::ok(), + version: CORE_RPC_VERSION, + release: RELEASE, + current_height: helper::top_height(&mut state).await?.0, + target_height: todo!(), + hard_forks: todo!(), + }) } +/// async fn get_fee_estimate( state: CupratedRpcHandler, request: GetFeeEstimateRequest, ) -> Result { - todo!() + Ok(GetFeeEstimateResponse { + base: AccessResponseBase::ok(), + fee: todo!(), + fees: todo!(), + quantization_mask: todo!(), + }) } +/// async fn get_alternate_chains( state: CupratedRpcHandler, request: GetAlternateChainsRequest, ) -> Result { - todo!() + Ok(GetAlternateChainsResponse { + base: ResponseBase::ok(), + chains: todo!(), + }) } +/// async fn relay_tx( state: CupratedRpcHandler, request: RelayTxRequest, ) -> Result { - todo!() + todo!(); + Ok(RelayTxResponse { status: Status::Ok }) } +/// async fn sync_info( state: CupratedRpcHandler, request: SyncInfoRequest, ) -> Result { - todo!() + Ok(SyncInfoResponse { + base: AccessResponseBase::ok(), + height: todo!(), + next_needed_pruning_seed: todo!(), + overview: todo!(), + peers: todo!(), + spans: todo!(), + target_height: todo!(), + }) } +/// async fn get_transaction_pool_backlog( state: CupratedRpcHandler, request: GetTransactionPoolBacklogRequest, ) -> Result { - todo!() + Ok(GetTransactionPoolBacklogResponse { + base: ResponseBase::ok(), + backlog: todo!(), + }) } +/// async fn get_miner_data( state: CupratedRpcHandler, request: GetMinerDataRequest, ) -> Result { - todo!() + Ok(GetMinerDataResponse { + base: ResponseBase::ok(), + major_version: todo!(), + height: todo!(), + prev_id: todo!(), + seed_hash: todo!(), + difficulty: todo!(), + median_weight: todo!(), + already_generated_coins: todo!(), + tx_backlog: todo!(), + }) } +/// async fn prune_blockchain( state: CupratedRpcHandler, request: PruneBlockchainRequest, ) -> Result { - todo!() + Ok(PruneBlockchainResponse { + base: ResponseBase::ok(), + pruned: todo!(), + pruning_seed: todo!(), + }) } +/// async fn calc_pow( state: CupratedRpcHandler, request: CalcPowRequest, ) -> Result { - todo!() + Ok(CalcPowResponse { pow_hash: todo!() }) } +/// async fn flush_cache( state: CupratedRpcHandler, request: FlushCacheRequest, ) -> Result { - todo!() + todo!(); + + Ok(FlushCacheResponse { + base: ResponseBase::ok(), + }) } +/// async fn add_aux_pow( state: CupratedRpcHandler, request: AddAuxPowRequest, ) -> Result { - todo!() + Ok(AddAuxPowResponse { + base: ResponseBase::ok(), + blocktemplate_blob: todo!(), + blockhashing_blob: todo!(), + merkle_root: todo!(), + merkle_tree_depth: todo!(), + aux_pow: todo!(), + }) } +/// async fn get_tx_ids_loose( state: CupratedRpcHandler, request: GetTxIdsLooseRequest, ) -> Result { - todo!() + Ok(GetTxIdsLooseResponse { + base: ResponseBase::ok(), + txids: todo!(), + }) } diff --git a/binaries/cuprated/src/rpc/request.rs b/binaries/cuprated/src/rpc/request.rs index 17e12b9..d1d9a21 100644 --- a/binaries/cuprated/src/rpc/request.rs +++ b/binaries/cuprated/src/rpc/request.rs @@ -12,8 +12,8 @@ //! the [`blockchain`] modules contains methods for the //! blockchain database [`tower::Service`] API. -mod address_book; -mod blockchain; -mod blockchain_context; -mod blockchain_manager; -mod txpool; +pub(super) mod address_book; +pub(super) mod blockchain; +pub(super) mod blockchain_context; +pub(super) mod blockchain_manager; +pub(super) mod txpool; diff --git a/binaries/cuprated/src/rpc/request/blockchain.rs b/binaries/cuprated/src/rpc/request/blockchain.rs index 8af80e5..7705320 100644 --- a/binaries/cuprated/src/rpc/request/blockchain.rs +++ b/binaries/cuprated/src/rpc/request/blockchain.rs @@ -6,9 +6,10 @@ use std::{ }; use anyhow::Error; -use cuprate_blockchain::service::BlockchainReadHandle; +use monero_serai::block::Block; use tower::{Service, ServiceExt}; +use cuprate_blockchain::service::BlockchainReadHandle; use cuprate_helper::cast::{u64_to_usize, usize_to_u64}; use cuprate_types::{ blockchain::{BlockchainReadRequest, BlockchainResponse}, @@ -16,9 +17,45 @@ use cuprate_types::{ OutputHistogramInput, OutputOnChain, }; +/// [`BlockchainReadRequest::Block`]. +pub(crate) async fn block( + blockchain_read: &mut BlockchainReadHandle, + height: u64, +) -> Result { + let BlockchainResponse::Block(block) = blockchain_read + .ready() + .await? + .call(BlockchainReadRequest::Block { + height: u64_to_usize(height), + }) + .await? + else { + unreachable!(); + }; + + Ok(block) +} + +/// [`BlockchainReadRequest::BlockByHash`]. +pub(crate) async fn block_by_hash( + blockchain_read: &mut BlockchainReadHandle, + hash: [u8; 32], +) -> Result { + let BlockchainResponse::Block(block) = blockchain_read + .ready() + .await? + .call(BlockchainReadRequest::BlockByHash(hash)) + .await? + else { + unreachable!(); + }; + + Ok(block) +} + /// [`BlockchainReadRequest::BlockExtendedHeader`]. -pub(super) async fn block_extended_header( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn block_extended_header( + blockchain_read: &mut BlockchainReadHandle, height: u64, ) -> Result { let BlockchainResponse::BlockExtendedHeader(header) = blockchain_read @@ -36,8 +73,8 @@ pub(super) async fn block_extended_header( } /// [`BlockchainReadRequest::BlockHash`]. -pub(super) async fn block_hash( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn block_hash( + blockchain_read: &mut BlockchainReadHandle, height: u64, chain: Chain, ) -> Result<[u8; 32], Error> { @@ -57,8 +94,8 @@ pub(super) async fn block_hash( } /// [`BlockchainReadRequest::FindBlock`]. -pub(super) async fn find_block( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn find_block( + blockchain_read: &mut BlockchainReadHandle, block_hash: [u8; 32], ) -> Result, Error> { let BlockchainResponse::FindBlock(option) = blockchain_read @@ -74,8 +111,8 @@ pub(super) async fn find_block( } /// [`BlockchainReadRequest::FilterUnknownHashes`]. -pub(super) async fn filter_unknown_hashes( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn filter_unknown_hashes( + blockchain_read: &mut BlockchainReadHandle, block_hashes: HashSet<[u8; 32]>, ) -> Result, Error> { let BlockchainResponse::FilterUnknownHashes(output) = blockchain_read @@ -91,8 +128,8 @@ pub(super) async fn filter_unknown_hashes( } /// [`BlockchainReadRequest::BlockExtendedHeaderInRange`] -pub(super) async fn block_extended_header_in_range( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn block_extended_header_in_range( + blockchain_read: &mut BlockchainReadHandle, range: Range, chain: Chain, ) -> Result, Error> { @@ -111,8 +148,8 @@ pub(super) async fn block_extended_header_in_range( } /// [`BlockchainReadRequest::ChainHeight`]. -pub(super) async fn chain_height( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn chain_height( + blockchain_read: &mut BlockchainReadHandle, ) -> Result<(u64, [u8; 32]), Error> { let BlockchainResponse::ChainHeight(height, hash) = blockchain_read .ready() @@ -127,8 +164,8 @@ pub(super) async fn chain_height( } /// [`BlockchainReadRequest::GeneratedCoins`]. -pub(super) async fn generated_coins( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn generated_coins( + blockchain_read: &mut BlockchainReadHandle, block_height: u64, ) -> Result { let BlockchainResponse::GeneratedCoins(generated_coins) = blockchain_read @@ -146,8 +183,8 @@ pub(super) async fn generated_coins( } /// [`BlockchainReadRequest::Outputs`] -pub(super) async fn outputs( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn outputs( + blockchain_read: &mut BlockchainReadHandle, outputs: HashMap>, ) -> Result>, Error> { let BlockchainResponse::Outputs(outputs) = blockchain_read @@ -163,8 +200,8 @@ pub(super) async fn outputs( } /// [`BlockchainReadRequest::NumberOutputsWithAmount`] -pub(super) async fn number_outputs_with_amount( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn number_outputs_with_amount( + blockchain_read: &mut BlockchainReadHandle, output_amounts: Vec, ) -> Result, Error> { let BlockchainResponse::NumberOutputsWithAmount(map) = blockchain_read @@ -182,8 +219,8 @@ pub(super) async fn number_outputs_with_amount( } /// [`BlockchainReadRequest::KeyImagesSpent`] -pub(super) async fn key_images_spent( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn key_images_spent( + blockchain_read: &mut BlockchainReadHandle, key_images: HashSet<[u8; 32]>, ) -> Result { let BlockchainResponse::KeyImagesSpent(is_spent) = blockchain_read @@ -199,8 +236,8 @@ pub(super) async fn key_images_spent( } /// [`BlockchainReadRequest::CompactChainHistory`] -pub(super) async fn compact_chain_history( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn compact_chain_history( + blockchain_read: &mut BlockchainReadHandle, ) -> Result<(Vec<[u8; 32]>, u128), Error> { let BlockchainResponse::CompactChainHistory { block_ids, @@ -218,8 +255,8 @@ pub(super) async fn compact_chain_history( } /// [`BlockchainReadRequest::FindFirstUnknown`] -pub(super) async fn find_first_unknown( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn find_first_unknown( + blockchain_read: &mut BlockchainReadHandle, hashes: Vec<[u8; 32]>, ) -> Result, Error> { let BlockchainResponse::FindFirstUnknown(resp) = blockchain_read @@ -235,8 +272,8 @@ pub(super) async fn find_first_unknown( } /// [`BlockchainReadRequest::TotalTxCount`] -pub(super) async fn total_tx_count( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn total_tx_count( + blockchain_read: &mut BlockchainReadHandle, ) -> Result { let BlockchainResponse::TotalTxCount(tx_count) = blockchain_read .ready() @@ -251,8 +288,8 @@ pub(super) async fn total_tx_count( } /// [`BlockchainReadRequest::DatabaseSize`] -pub(super) async fn database_size( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn database_size( + blockchain_read: &mut BlockchainReadHandle, ) -> Result<(u64, u64), Error> { let BlockchainResponse::DatabaseSize { database_size, @@ -270,8 +307,8 @@ pub(super) async fn database_size( } /// [`BlockchainReadRequest::OutputHistogram`] -pub(super) async fn output_histogram( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn output_histogram( + blockchain_read: &mut BlockchainReadHandle, input: OutputHistogramInput, ) -> Result, Error> { let BlockchainResponse::OutputHistogram(histogram) = blockchain_read @@ -287,8 +324,8 @@ pub(super) async fn output_histogram( } /// [`BlockchainReadRequest::CoinbaseTxSum`] -pub(super) async fn coinbase_tx_sum( - mut blockchain_read: BlockchainReadHandle, +pub(crate) async fn coinbase_tx_sum( + blockchain_read: &mut BlockchainReadHandle, height: u64, count: u64, ) -> Result {