From f1dea834b008f304d09377731d1f4376015d1c4a Mon Sep 17 00:00:00 2001 From: "hinto.janai" Date: Sun, 8 Sep 2024 18:33:30 -0400 Subject: [PATCH] `get_block_headers_range` --- binaries/cuprated/src/rpc/constants.rs | 2 +- binaries/cuprated/src/rpc/json.rs | 75 +++++++++++++++++++++----- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/binaries/cuprated/src/rpc/constants.rs b/binaries/cuprated/src/rpc/constants.rs index a48e4902..3d0485dd 100644 --- a/binaries/cuprated/src/rpc/constants.rs +++ b/binaries/cuprated/src/rpc/constants.rs @@ -11,7 +11,7 @@ pub const OUTPUT_HISTOGRAM_RECENT_CUTOFF_RESTRICTION: usize = 3 * 86400; pub const DEFAULT_PAYMENT_DIFFICULTY: usize = 1000; pub const DEFAULT_PAYMENT_CREDITS_PER_HASH: usize = 100; -pub const RESTRICTED_BLOCK_HEADER_RANGE: usize = 1000; +pub const RESTRICTED_BLOCK_HEADER_RANGE: u64 = 1000; pub const RESTRICTED_TRANSACTIONS_COUNT: usize = 100; pub const RESTRICTED_SPENT_KEY_IMAGES_COUNT: usize = 5000; pub const RESTRICTED_BLOCK_COUNT: usize = 1000; diff --git a/binaries/cuprated/src/rpc/json.rs b/binaries/cuprated/src/rpc/json.rs index 42bd4b26..a9a45713 100644 --- a/binaries/cuprated/src/rpc/json.rs +++ b/binaries/cuprated/src/rpc/json.rs @@ -35,9 +35,7 @@ use cuprate_rpc_types::{ }; use cuprate_types::{blockchain::BlockchainReadRequest, Chain}; -use crate::rpc::CupratedRpcHandlerState; - -use super::RESTRICTED_BLOCK_COUNT; +use crate::rpc::{CupratedRpcHandlerState, RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE}; /// Map a [`JsonRpcRequest`] to the function that will lead to a [`JsonRpcResponse`]. pub(super) async fn map_request( @@ -161,8 +159,9 @@ async fn get_block_header_by_hash( request: GetBlockHeaderByHashRequest, ) -> Result { if state.restricted && request.hashes.len() > RESTRICTED_BLOCK_COUNT { - let err = anyhow!("Too many block headers requested in restricted mode"); - return Err(err); + return Err(anyhow!( + "Too many block headers requested in restricted mode" + )); } async fn get( @@ -171,13 +170,13 @@ async fn get_block_header_by_hash( fill_pow_hash: bool, ) -> Result { let Ok(bytes) = hex::decode(&hex) else { - let err = anyhow!("Failed to parse hex representation of block hash. Hex = {hex}."); - return Err(err); + return Err(anyhow!( + "Failed to parse hex representation of block hash. Hex = {hex}." + )); }; let Ok(hash) = bytes.try_into() else { - let err = anyhow!("TODO"); - return Err(err); + return Err(anyhow!("TODO")); }; let BlockchainResponse::BlockByHash(block) = state @@ -227,11 +226,10 @@ async fn get_block_header_by_height( let height = chain_height.saturating_sub(1); if request.height > usize_to_u64(height) { - let err = anyhow!( + return Err(anyhow!( "Requested block height: {} greater than current top block height: {height}", request.height - ); - return Err(err); + )); } let BlockchainResponse::Block(block) = state @@ -251,10 +249,59 @@ async fn get_block_header_by_height( } async fn get_block_headers_range( - state: CupratedRpcHandlerState, + mut state: CupratedRpcHandlerState, request: GetBlockHeadersRangeRequest, ) -> Result { - todo!() + let BlockchainResponse::ChainHeight(chain_height, _) = state + .blockchain + .ready() + .await? + .call(BlockchainReadRequest::ChainHeight) + .await? + else { + unreachable!(); + }; + + let height = chain_height.saturating_sub(1); + let height_u64 = usize_to_u64(height); + + if request.start_height >= height_u64 + || request.end_height >= height_u64 + || 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.ready().await?; + for block in request.start_height..=request.end_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()); + } + + Ok(GetBlockHeadersRangeResponse { + base: AccessResponseBase::ok(), + headers, + }) } async fn get_block(