From f86baa2eeff35bc23f425d13701299313ff3707e Mon Sep 17 00:00:00 2001
From: "hinto.janai" <hinto.janai@protonmail.com>
Date: Sun, 8 Sep 2024 20:32:52 -0400
Subject: [PATCH] add `helper.rs`

---
 binaries/cuprated/src/rpc/helper.rs | 163 ++++++++++++++++++++++++++++
 1 file changed, 163 insertions(+)
 create mode 100644 binaries/cuprated/src/rpc/helper.rs

diff --git a/binaries/cuprated/src/rpc/helper.rs b/binaries/cuprated/src/rpc/helper.rs
new file mode 100644
index 0000000..96166ff
--- /dev/null
+++ b/binaries/cuprated/src/rpc/helper.rs
@@ -0,0 +1,163 @@
+//! 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.
+//!
+//! They typically map to database requests.
+
+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::ChainHeight`] minus 1.
+pub(super) async fn top_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]>),