split blockchain/helper functions

This commit is contained in:
hinto.janai 2024-09-08 20:48:31 -04:00
parent 06b583e97d
commit 136e9b70a6
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
4 changed files with 203 additions and 189 deletions

View file

@ -3,6 +3,7 @@
//! Will contain the code to initiate the RPC and a request handler. //! Will contain the code to initiate the RPC and a request handler.
mod bin; mod bin;
mod blockchain;
mod constants; mod constants;
mod handler; mod handler;
mod helper; mod helper;

View file

@ -0,0 +1,142 @@
//! These are convenience functions that make
//! sending [`BlockchainReadRequest`] less verbose.
use std::sync::Arc;
use anyhow::{anyhow, Error};
use futures::StreamExt;
use tower::{Service, ServiceExt};
use cuprate_consensus::BlockchainResponse;
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::{CupratedRpcHandlerState, RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE};
/// [`BlockchainResponse::ChainHeight`].
pub(super) async fn chain_height(
state: &mut CupratedRpcHandlerState,
) -> Result<(u64, [u8; 32]), Error> {
let BlockchainResponse::ChainHeight(height, hash) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::ChainHeight)
.await?
else {
unreachable!();
};
Ok((usize_to_u64(height), hash))
}
/// [`BlockchainResponse::Block`].
pub(super) async fn block(
state: &mut CupratedRpcHandlerState,
height: u64,
) -> Result<VerifiedBlockInformation, Error> {
let BlockchainResponse::Block(block) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::Block(u64_to_usize(height)))
.await?
else {
unreachable!();
};
Ok(block)
}
/// [`BlockchainResponse::BlockByHash`].
pub(super) async fn block_by_hash(
state: &mut CupratedRpcHandlerState,
hash: [u8; 32],
) -> Result<VerifiedBlockInformation, Error> {
let BlockchainResponse::BlockByHash(block) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::BlockByHash(hash))
.await?
else {
unreachable!();
};
Ok(block)
}
/// [`BlockchainResponse::BlockExtendedHeader`].
pub(super) async fn block_extended_header(
state: &mut CupratedRpcHandlerState,
height: u64,
) -> Result<ExtendedBlockHeader, Error> {
let BlockchainResponse::BlockExtendedHeader(header) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::BlockExtendedHeader(u64_to_usize(
height,
)))
.await?
else {
unreachable!();
};
Ok(header)
}
/// [`BlockchainResponse::BlockExtendedHeaderByHash`].
pub(super) async fn block_extended_header_by_hash(
state: &mut CupratedRpcHandlerState,
hash: [u8; 32],
) -> Result<ExtendedBlockHeader, Error> {
let BlockchainResponse::BlockExtendedHeaderByHash(header) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::BlockExtendedHeaderByHash(hash))
.await?
else {
unreachable!();
};
Ok(header)
}
/// [`BlockchainResponse::BlockHash`] with [`Chain::Main`].
pub(super) async fn block_hash(
state: &mut CupratedRpcHandlerState,
height: u64,
) -> Result<[u8; 32], Error> {
let BlockchainResponse::BlockHash(hash) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::BlockHash(
u64_to_usize(height),
Chain::Main,
))
.await?
else {
unreachable!();
};
Ok(hash)
}
// FindBlock([u8; 32]),
// FilterUnknownHashes(HashSet<[u8; 32]>),
// BlockExtendedHeaderInRange(Range<usize>, Chain),
// ChainHeight,
// GeneratedCoins(usize),
// Outputs(HashMap<u64, HashSet<u64>>),
// NumberOutputsWithAmount(Vec<u64>),
// KeyImagesSpent(HashSet<[u8; 32]>),
// CompactChainHistory,
// FindFirstUnknown(Vec<[u8; 32]>),

View file

@ -3,7 +3,7 @@
//! Many of the handlers have bodies with only small differences, //! Many of the handlers have bodies with only small differences,
//! the identical code is extracted and reused here in these functions. //! the identical code is extracted and reused here in these functions.
//! //!
//! They typically map to database requests. //! These build on-top of [`crate::rpc::blockchain`] functions.
use std::sync::Arc; use std::sync::Arc;
@ -20,144 +20,51 @@ use cuprate_types::{
blockchain::BlockchainReadRequest, Chain, ExtendedBlockHeader, VerifiedBlockInformation, blockchain::BlockchainReadRequest, Chain, ExtendedBlockHeader, VerifiedBlockInformation,
}; };
use crate::rpc::{CupratedRpcHandlerState, RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE}; use crate::{
rpc::helper,
/// [`BlockchainResponse::ChainHeight`]. rpc::{CupratedRpcHandlerState, RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE},
pub(super) async fn chain_height(
state: &mut CupratedRpcHandlerState,
) -> Result<(u64, [u8; 32]), Error> {
let BlockchainResponse::ChainHeight(height, hash) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::ChainHeight)
.await?
else {
unreachable!();
}; };
Ok((usize_to_u64(height), hash)) /// 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 CupratedRpcHandlerState,
height: u64,
) -> Result<u64, Error> {
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. /// [`BlockchainResponse::ChainHeight`] minus 1.
pub(super) async fn top_height( pub(super) async fn top_height(
state: &mut CupratedRpcHandlerState, state: &mut CupratedRpcHandlerState,
) -> Result<(u64, [u8; 32]), Error> { ) -> Result<(u64, [u8; 32]), Error> {
let BlockchainResponse::ChainHeight(height, hash) = state let (chain_height, hash) = helper::chain_height().await?;
.blockchain let height = chain_height.saturating_sub(1);
.ready()
.await?
.call(BlockchainReadRequest::ChainHeight)
.await?
else {
unreachable!();
};
Ok((usize_to_u64(height), hash)) Ok((usize_to_u64(height), hash))
} }
/// [`BlockchainResponse::Block`].
pub(super) async fn block(
state: &mut CupratedRpcHandlerState,
height: u64,
) -> Result<VerifiedBlockInformation, Error> {
let BlockchainResponse::Block(block) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::Block(u64_to_usize(height)))
.await?
else {
unreachable!();
};
Ok(block)
}
/// [`BlockchainResponse::BlockByHash`].
pub(super) async fn block_by_hash(
state: &mut CupratedRpcHandlerState,
hash: [u8; 32],
) -> Result<VerifiedBlockInformation, Error> {
let BlockchainResponse::BlockByHash(block) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::BlockByHash(hash))
.await?
else {
unreachable!();
};
Ok(block)
}
/// [`BlockchainResponse::BlockExtendedHeader`].
pub(super) async fn block_extended_header(
state: &mut CupratedRpcHandlerState,
height: u64,
) -> Result<ExtendedBlockHeader, Error> {
let BlockchainResponse::BlockExtendedHeader(header) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::BlockExtendedHeader(u64_to_usize(
height,
)))
.await?
else {
unreachable!();
};
Ok(header)
}
/// [`BlockchainResponse::BlockExtendedHeaderByHash`].
pub(super) async fn block_extended_header_by_hash(
state: &mut CupratedRpcHandlerState,
hash: [u8; 32],
) -> Result<ExtendedBlockHeader, Error> {
let BlockchainResponse::BlockExtendedHeaderByHash(header) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::BlockExtendedHeaderByHash(hash))
.await?
else {
unreachable!();
};
Ok(header)
}
/// [`BlockchainResponse::BlockHash`] with [`Chain::Main`].
pub(super) async fn block_hash(
state: &mut CupratedRpcHandlerState,
height: u64,
) -> Result<[u8; 32], Error> {
let BlockchainResponse::BlockHash(hash) = state
.blockchain
.ready()
.await?
.call(BlockchainReadRequest::BlockHash(
u64_to_usize(height),
Chain::Main,
))
.await?
else {
unreachable!();
};
Ok(hash)
}
// FindBlock([u8; 32]),
// FilterUnknownHashes(HashSet<[u8; 32]>),
// BlockExtendedHeaderInRange(Range<usize>, Chain),
// ChainHeight,
// GeneratedCoins(usize),
// Outputs(HashMap<u64, HashSet<u64>>),
// NumberOutputsWithAmount(Vec<u64>),
// KeyImagesSpent(HashSet<[u8; 32]>),
// CompactChainHistory,
// FindFirstUnknown(Vec<[u8; 32]>),

View file

@ -36,7 +36,7 @@ use cuprate_rpc_types::{
use cuprate_types::{blockchain::BlockchainReadRequest, Chain}; use cuprate_types::{blockchain::BlockchainReadRequest, Chain};
use crate::{ use crate::{
rpc::helper, rpc::{blockchain, helper},
rpc::{CupratedRpcHandlerState, RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE}, rpc::{CupratedRpcHandlerState, RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE},
}; };
@ -104,7 +104,7 @@ async fn get_block_count(
) -> Result<GetBlockCountResponse, Error> { ) -> Result<GetBlockCountResponse, Error> {
Ok(GetBlockCountResponse { Ok(GetBlockCountResponse {
base: ResponseBase::ok(), base: ResponseBase::ok(),
count: helper::top_height(&mut state).await?, count: helper::top_height(&mut state).await?.0,
}) })
} }
@ -113,7 +113,7 @@ async fn on_get_block_hash(
request: OnGetBlockHashRequest, request: OnGetBlockHashRequest,
) -> Result<OnGetBlockHashResponse, Error> { ) -> Result<OnGetBlockHashResponse, Error> {
let [height] = request.block_height; let [height] = request.block_height;
let hash = helper::block_hash(&mut state, height).await?; let hash = blockchain::block_hash(&mut state, height).await?;
let block_hash = hex::encode(hash); let block_hash = hex::encode(hash);
Ok(OnGetBlockHashResponse { block_hash }) Ok(OnGetBlockHashResponse { block_hash })
@ -145,7 +145,7 @@ async fn get_last_block_header(
request: GetLastBlockHeaderRequest, request: GetLastBlockHeaderRequest,
) -> Result<GetLastBlockHeaderResponse, Error> { ) -> Result<GetLastBlockHeaderResponse, Error> {
Ok(GetLastBlockHeaderResponse { Ok(GetLastBlockHeaderResponse {
base: ResponseBase::ok(), base: AccessResponseBase::ok(),
block_header: todo!(), block_header: todo!(),
}) })
} }
@ -165,17 +165,8 @@ async fn get_block_header_by_hash(
hex: String, hex: String,
fill_pow_hash: bool, fill_pow_hash: bool,
) -> Result<BlockHeader, Error> { ) -> Result<BlockHeader, Error> {
let Ok(bytes) = hex::decode(&hex) else { let hash = helper::hex_to_hash(hex)?;
return Err(anyhow!( let block = blockchain::block_by_hash(state, hash).await?;
"Failed to parse hex representation of block hash. Hex = {hex}."
));
};
let Ok(hash) = bytes.try_into() else {
return Err(anyhow!("TODO"));
};
let block = helper::block_by_hash(state, hash).await?;
let block_header = BlockHeader::from(&block); let block_header = BlockHeader::from(&block);
Ok(block_header) Ok(block_header)
@ -200,16 +191,8 @@ async fn get_block_header_by_height(
mut state: CupratedRpcHandlerState, mut state: CupratedRpcHandlerState,
request: GetBlockHeaderByHeightRequest, request: GetBlockHeaderByHeightRequest,
) -> Result<GetBlockHeaderByHeightResponse, Error> { ) -> Result<GetBlockHeaderByHeightResponse, Error> {
let (height, _) = helper::top_height(&mut state).await?; helper::check_height(&mut state, request.height).await?;
let block = blockchain::block(&mut state, request.height).await?;
if request.height > height {
return Err(anyhow!(
"Requested block height: {} greater than current top block height: {height}",
request.height
));
}
let block = helper::block(&mut state, height).await?;
Ok(GetBlockHeaderByHeightResponse { Ok(GetBlockHeaderByHeightResponse {
base: AccessResponseBase::ok(), base: AccessResponseBase::ok(),
@ -221,10 +204,10 @@ async fn get_block_headers_range(
mut state: CupratedRpcHandlerState, mut state: CupratedRpcHandlerState,
request: GetBlockHeadersRangeRequest, request: GetBlockHeadersRangeRequest,
) -> Result<GetBlockHeadersRangeResponse, Error> { ) -> Result<GetBlockHeadersRangeResponse, Error> {
let (height, _) = helper::top_height(&mut state).await?; let (top_height, _) = helper::top_height(&mut state).await?;
if request.start_height >= height if request.start_height >= top_height
|| request.end_height >= height || request.end_height >= top_height
|| request.start_height > request.end_height || request.start_height > request.end_height
{ {
return Err(anyhow!("Invalid start/end heights")); return Err(anyhow!("Invalid start/end heights"));
@ -243,8 +226,8 @@ async fn get_block_headers_range(
{ {
let ready = state.blockchain.ready().await?; let ready = state.blockchain.ready().await?;
for height in request.start_height..=request.end_height {
let height = u64_to_usize(height); let height = u64_to_usize(height);
for block in request.start_height..=request.end_height {
let task = tokio::task::spawn(ready.call(BlockchainReadRequest::Block(height))); let task = tokio::task::spawn(ready.call(BlockchainReadRequest::Block(height)));
tasks.push(task); tasks.push(task);
} }
@ -267,31 +250,12 @@ async fn get_block(
mut state: CupratedRpcHandlerState, mut state: CupratedRpcHandlerState,
request: GetBlockRequest, request: GetBlockRequest,
) -> Result<GetBlockResponse, Error> { ) -> Result<GetBlockResponse, Error> {
let block = if !request.hash.is_empty() { let block = if request.hash.is_empty() {
let hex = request.hash; helper::check_height(&mut state, request.height).await?;
blockchain::block(&mut state, request.height).await?
let Ok(bytes) = hex::decode(&hex) else {
return Err(anyhow!(
"Failed to parse hex representation of block hash. Hex = {hex}."
));
};
let Ok(hash) = bytes.try_into() else {
return Err(anyhow!("TODO"));
};
helper::block_by_hash(&mut state, hash).await?
} else { } else {
let (height, _) = helper::top_height(&mut state).await?; let hash = helper::hex_to_hash(request.hash)?;
blockchain::block_by_hash(&mut state, hash).await?
if request.height > height {
return Err(anyhow!(
"Requested block height: {} greater than current top block height: {height}",
request.height
));
}
helper::block(&mut state, height).await?
}; };
let block_header = (&block).into(); let block_header = (&block).into();
@ -458,7 +422,7 @@ async fn get_version(
request: GetVersionRequest, request: GetVersionRequest,
) -> Result<GetVersionResponse, Error> { ) -> Result<GetVersionResponse, Error> {
Ok(GetVersionResponse { Ok(GetVersionResponse {
base: AccessResponseBase::ok(), base: ResponseBase::ok(),
version: todo!(), version: todo!(),
release: todo!(), release: todo!(),
current_height: todo!(), current_height: todo!(),
@ -484,7 +448,7 @@ async fn get_alternate_chains(
request: GetAlternateChainsRequest, request: GetAlternateChainsRequest,
) -> Result<GetAlternateChainsResponse, Error> { ) -> Result<GetAlternateChainsResponse, Error> {
Ok(GetAlternateChainsResponse { Ok(GetAlternateChainsResponse {
base: AccessResponseBase::ok(), base: ResponseBase::ok(),
chains: todo!(), chains: todo!(),
}) })
} }
@ -516,7 +480,7 @@ async fn get_transaction_pool_backlog(
request: GetTransactionPoolBacklogRequest, request: GetTransactionPoolBacklogRequest,
) -> Result<GetTransactionPoolBacklogResponse, Error> { ) -> Result<GetTransactionPoolBacklogResponse, Error> {
Ok(GetTransactionPoolBacklogResponse { Ok(GetTransactionPoolBacklogResponse {
base: AccessResponseBase::ok(), base: ResponseBase::ok(),
backlog: todo!(), backlog: todo!(),
}) })
} }
@ -526,7 +490,7 @@ async fn get_miner_data(
request: GetMinerDataRequest, request: GetMinerDataRequest,
) -> Result<GetMinerDataResponse, Error> { ) -> Result<GetMinerDataResponse, Error> {
Ok(GetMinerDataResponse { Ok(GetMinerDataResponse {
base: AccessResponseBase::ok(), base: ResponseBase::ok(),
major_version: todo!(), major_version: todo!(),
height: todo!(), height: todo!(),
prev_id: todo!(), prev_id: todo!(),
@ -543,7 +507,7 @@ async fn prune_blockchain(
request: PruneBlockchainRequest, request: PruneBlockchainRequest,
) -> Result<PruneBlockchainResponse, Error> { ) -> Result<PruneBlockchainResponse, Error> {
Ok(PruneBlockchainResponse { Ok(PruneBlockchainResponse {
base: AccessResponseBase::ok(), base: ResponseBase::ok(),
pruned: todo!(), pruned: todo!(),
pruning_seed: todo!(), pruning_seed: todo!(),
}) })