cuprated: internal signatures required for RPC (#297)
Some checks failed
CI / fmt (push) Has been cancelled
CI / typo (push) Has been cancelled
CI / ci (macos-latest, stable, bash) (push) Has been cancelled
CI / ci (ubuntu-latest, stable, bash) (push) Has been cancelled
CI / ci (windows-latest, stable-x86_64-pc-windows-gnu, msys2 {0}) (push) Has been cancelled
Doc / build (push) Has been cancelled
Doc / deploy (push) Has been cancelled

* add request methods

* add p2p messages

* add txpool msgs

* add blockchain_context msgs

* add blockchain msgs

* fmt

* blockchain_manager msgs

* blockchain manager msg types

* add DB fn signatures

* add statics module

* p2p msg changes, docs

* txpool docs/types

* blockchain docs/types

* `AlternateChains`, docs

* fixes

* remove blockchain write handle, fix docs

* remove `BlockchainReadRequest::Difficulty`

* remove `BlockchainReadRequest::MinerData`

* fix p2p ban types

* `CurrentRxVm` -> `CurrentRxVms`

* storage: remove `Clone` off write handle

* Update p2p/p2p-core/src/ban.rs

Co-authored-by: Boog900 <boog900@tutanota.com>

* fix merge

---------

Co-authored-by: Boog900 <boog900@tutanota.com>
This commit is contained in:
hinto-janai 2024-10-08 17:57:09 -04:00 committed by GitHub
parent 8be369846e
commit 9923d8d69d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 1336 additions and 158 deletions

View file

@ -69,7 +69,7 @@ pub async fn init_blockchain_manager(
.ready() .ready()
.await .await
.expect(PANIC_CRITICAL_SERVICE_ERROR) .expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockChainContextRequest::GetContext) .call(BlockChainContextRequest::Context)
.await .await
.expect(PANIC_CRITICAL_SERVICE_ERROR) .expect(PANIC_CRITICAL_SERVICE_ERROR)
else { else {

View file

@ -464,7 +464,7 @@ impl super::BlockchainManager {
.ready() .ready()
.await .await
.expect(PANIC_CRITICAL_SERVICE_ERROR) .expect(PANIC_CRITICAL_SERVICE_ERROR)
.call(BlockChainContextRequest::GetContext) .call(BlockChainContextRequest::Context)
.await .await
.expect(PANIC_CRITICAL_SERVICE_ERROR) .expect(PANIC_CRITICAL_SERVICE_ERROR)
else { else {

View file

@ -62,7 +62,7 @@ where
let BlockChainContextResponse::Context(mut blockchain_ctx) = context_svc let BlockChainContextResponse::Context(mut blockchain_ctx) = context_svc
.ready() .ready()
.await? .await?
.call(BlockChainContextRequest::GetContext) .call(BlockChainContextRequest::Context)
.await? .await?
else { else {
unreachable!(); unreachable!();
@ -131,7 +131,7 @@ where
} }
let BlockChainContextResponse::Context(ctx) = context_svc let BlockChainContextResponse::Context(ctx) = context_svc
.oneshot(BlockChainContextRequest::GetContext) .oneshot(BlockChainContextRequest::Context)
.await? .await?
else { else {
unreachable!(); unreachable!();

View file

@ -3,6 +3,7 @@
#![allow( #![allow(
unused_imports, unused_imports,
unreachable_pub, unreachable_pub,
unreachable_code,
unused_crate_dependencies, unused_crate_dependencies,
dead_code, dead_code,
unused_variables, unused_variables,

View file

@ -6,5 +6,6 @@ mod bin;
mod handler; mod handler;
mod json; mod json;
mod other; mod other;
mod request;
pub use handler::{CupratedRpcHandler, CupratedRpcHandlerState}; pub use handler::CupratedRpcHandler;

View file

@ -10,11 +10,11 @@ use cuprate_rpc_types::{
json::{GetOutputDistributionRequest, GetOutputDistributionResponse}, json::{GetOutputDistributionRequest, GetOutputDistributionResponse},
}; };
use crate::rpc::CupratedRpcHandlerState; use crate::rpc::CupratedRpcHandler;
/// Map a [`BinRequest`] to the function that will lead to a [`BinResponse`]. /// Map a [`BinRequest`] to the function that will lead to a [`BinResponse`].
pub(super) async fn map_request( pub(super) async fn map_request(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: BinRequest, request: BinRequest,
) -> Result<BinResponse, Error> { ) -> Result<BinResponse, Error> {
use BinRequest as Req; use BinRequest as Req;
@ -36,49 +36,49 @@ pub(super) async fn map_request(
} }
async fn get_blocks( async fn get_blocks(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetBlocksRequest, request: GetBlocksRequest,
) -> Result<GetBlocksResponse, Error> { ) -> Result<GetBlocksResponse, Error> {
todo!() todo!()
} }
async fn get_blocks_by_height( async fn get_blocks_by_height(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetBlocksByHeightRequest, request: GetBlocksByHeightRequest,
) -> Result<GetBlocksByHeightResponse, Error> { ) -> Result<GetBlocksByHeightResponse, Error> {
todo!() todo!()
} }
async fn get_hashes( async fn get_hashes(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetHashesRequest, request: GetHashesRequest,
) -> Result<GetHashesResponse, Error> { ) -> Result<GetHashesResponse, Error> {
todo!() todo!()
} }
async fn get_output_indexes( async fn get_output_indexes(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetOutputIndexesRequest, request: GetOutputIndexesRequest,
) -> Result<GetOutputIndexesResponse, Error> { ) -> Result<GetOutputIndexesResponse, Error> {
todo!() todo!()
} }
async fn get_outs( async fn get_outs(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetOutsRequest, request: GetOutsRequest,
) -> Result<GetOutsResponse, Error> { ) -> Result<GetOutsResponse, Error> {
todo!() todo!()
} }
async fn get_transaction_pool_hashes( async fn get_transaction_pool_hashes(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetTransactionPoolHashesRequest, request: GetTransactionPoolHashesRequest,
) -> Result<GetTransactionPoolHashesResponse, Error> { ) -> Result<GetTransactionPoolHashesResponse, Error> {
todo!() todo!()
} }
async fn get_output_distribution( async fn get_output_distribution(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetOutputDistributionRequest, request: GetOutputDistributionRequest,
) -> Result<GetOutputDistributionResponse, Error> { ) -> Result<GetOutputDistributionResponse, Error> {
todo!() todo!()

View file

@ -3,51 +3,131 @@
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use anyhow::Error; use anyhow::Error;
use futures::{channel::oneshot::channel, future::BoxFuture}; use futures::future::BoxFuture;
use serde::{Deserialize, Serialize}; use monero_serai::block::Block;
use tower::Service; use tower::Service;
use cuprate_blockchain::service::BlockchainReadHandle; use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle};
use cuprate_helper::asynch::InfallibleOneshotReceiver;
use cuprate_json_rpc::Id;
use cuprate_rpc_interface::RpcHandler; use cuprate_rpc_interface::RpcHandler;
use cuprate_rpc_types::{ use cuprate_rpc_types::{
bin::{BinRequest, BinResponse}, bin::{BinRequest, BinResponse},
json::{JsonRpcRequest, JsonRpcResponse}, json::{JsonRpcRequest, JsonRpcResponse},
other::{OtherRequest, OtherResponse}, other::{OtherRequest, OtherResponse},
}; };
use cuprate_txpool::service::TxpoolReadHandle; use cuprate_txpool::service::{TxpoolReadHandle, TxpoolWriteHandle};
use crate::rpc::{bin, json, other}; use crate::rpc::{bin, json, other};
/// TODO: use real type when public.
#[derive(Clone)]
#[expect(clippy::large_enum_variant)]
pub enum BlockchainManagerRequest {
/// Pop blocks off the top of the blockchain.
///
/// Input is the amount of blocks to pop.
PopBlocks { amount: usize },
/// Start pruning the blockchain.
Prune,
/// Is the blockchain pruned?
Pruned,
/// Relay a block to the network.
RelayBlock(Block),
/// Is the blockchain in the middle of syncing?
///
/// This returning `false` does not necessarily
/// mean [`BlockchainManagerRequest::Synced`] will
/// return `true`, for example, if the network has been
/// cut off and we have no peers, this will return `false`,
/// however, [`BlockchainManagerRequest::Synced`] may return
/// `true` if the latest known chain tip is equal to our height.
Syncing,
/// Is the blockchain fully synced?
Synced,
/// Current target block time.
Target,
/// The height of the next block in the chain.
TargetHeight,
}
/// TODO: use real type when public.
#[derive(Clone)]
pub enum BlockchainManagerResponse {
/// General OK response.
///
/// Response to:
/// - [`BlockchainManagerRequest::Prune`]
/// - [`BlockchainManagerRequest::RelayBlock`]
Ok,
/// Response to [`BlockchainManagerRequest::PopBlocks`]
PopBlocks { new_height: usize },
/// Response to [`BlockchainManagerRequest::Pruned`]
Pruned(bool),
/// Response to [`BlockchainManagerRequest::Syncing`]
Syncing(bool),
/// Response to [`BlockchainManagerRequest::Synced`]
Synced(bool),
/// Response to [`BlockchainManagerRequest::Target`]
Target(std::time::Duration),
/// Response to [`BlockchainManagerRequest::TargetHeight`]
TargetHeight { height: usize },
}
/// TODO: use real type when public.
pub type BlockchainManagerHandle = cuprate_database_service::DatabaseReadService<
BlockchainManagerRequest,
BlockchainManagerResponse,
>;
/// TODO /// TODO
#[derive(Clone)] #[derive(Clone)]
pub struct CupratedRpcHandler { pub struct CupratedRpcHandler {
/// Should this RPC server be [restricted](RpcHandler::restricted)? /// Should this RPC server be [restricted](RpcHandler::restricted)?
// ///
// INVARIANT: /// This is not `pub` on purpose, as it should not be mutated after [`Self::new`].
// We don't need to include this in `state` and check for restricted: bool,
// `self.is_restricted()` because `cuprate-rpc-interface` handles that.
pub restricted: bool,
/// State needed for request -> response mapping.
pub state: CupratedRpcHandlerState,
}
/// TODO
#[derive(Clone)]
pub struct CupratedRpcHandlerState {
/// Read handle to the blockchain database. /// Read handle to the blockchain database.
pub blockchain: BlockchainReadHandle, pub blockchain_read: BlockchainReadHandle,
/// Handle to the blockchain manager.
pub blockchain_manager: BlockchainManagerHandle,
/// Read handle to the transaction pool database. /// Read handle to the transaction pool database.
pub txpool: TxpoolReadHandle, pub txpool_read: TxpoolReadHandle,
/// TODO: handle to txpool service.
pub txpool_manager: std::convert::Infallible,
} }
impl CupratedRpcHandler { impl CupratedRpcHandler {
/// TODO /// Create a new [`Self`].
pub fn init() { pub const fn new(
todo!() restricted: bool,
blockchain_read: BlockchainReadHandle,
blockchain_manager: BlockchainManagerHandle,
txpool_read: TxpoolReadHandle,
txpool_manager: std::convert::Infallible,
) -> Self {
Self {
restricted,
blockchain_read,
blockchain_manager,
txpool_read,
txpool_manager,
}
} }
} }
@ -67,7 +147,7 @@ impl Service<JsonRpcRequest> for CupratedRpcHandler {
} }
fn call(&mut self, request: JsonRpcRequest) -> Self::Future { fn call(&mut self, request: JsonRpcRequest) -> Self::Future {
let state = CupratedRpcHandlerState::clone(&self.state); let state = self.clone();
Box::pin(json::map_request(state, request)) Box::pin(json::map_request(state, request))
} }
} }
@ -82,7 +162,7 @@ impl Service<BinRequest> for CupratedRpcHandler {
} }
fn call(&mut self, request: BinRequest) -> Self::Future { fn call(&mut self, request: BinRequest) -> Self::Future {
let state = CupratedRpcHandlerState::clone(&self.state); let state = self.clone();
Box::pin(bin::map_request(state, request)) Box::pin(bin::map_request(state, request))
} }
} }
@ -97,7 +177,7 @@ impl Service<OtherRequest> for CupratedRpcHandler {
} }
fn call(&mut self, request: OtherRequest) -> Self::Future { fn call(&mut self, request: OtherRequest) -> Self::Future {
let state = CupratedRpcHandlerState::clone(&self.state); let state = self.clone();
Box::pin(other::map_request(state, request)) Box::pin(other::map_request(state, request))
} }
} }

View file

@ -23,11 +23,11 @@ use cuprate_rpc_types::json::{
SyncInfoRequest, SyncInfoResponse, SyncInfoRequest, SyncInfoResponse,
}; };
use crate::rpc::CupratedRpcHandlerState; use crate::rpc::CupratedRpcHandler;
/// Map a [`JsonRpcRequest`] to the function that will lead to a [`JsonRpcResponse`]. /// Map a [`JsonRpcRequest`] to the function that will lead to a [`JsonRpcResponse`].
pub(super) async fn map_request( pub(super) async fn map_request(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: JsonRpcRequest, request: JsonRpcRequest,
) -> Result<JsonRpcResponse, Error> { ) -> Result<JsonRpcResponse, Error> {
use JsonRpcRequest as Req; use JsonRpcRequest as Req;
@ -84,210 +84,210 @@ pub(super) async fn map_request(
} }
async fn get_block_count( async fn get_block_count(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetBlockCountRequest, request: GetBlockCountRequest,
) -> Result<GetBlockCountResponse, Error> { ) -> Result<GetBlockCountResponse, Error> {
todo!() todo!()
} }
async fn on_get_block_hash( async fn on_get_block_hash(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: OnGetBlockHashRequest, request: OnGetBlockHashRequest,
) -> Result<OnGetBlockHashResponse, Error> { ) -> Result<OnGetBlockHashResponse, Error> {
todo!() todo!()
} }
async fn submit_block( async fn submit_block(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: SubmitBlockRequest, request: SubmitBlockRequest,
) -> Result<SubmitBlockResponse, Error> { ) -> Result<SubmitBlockResponse, Error> {
todo!() todo!()
} }
async fn generate_blocks( async fn generate_blocks(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GenerateBlocksRequest, request: GenerateBlocksRequest,
) -> Result<GenerateBlocksResponse, Error> { ) -> Result<GenerateBlocksResponse, Error> {
todo!() todo!()
} }
async fn get_last_block_header( async fn get_last_block_header(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetLastBlockHeaderRequest, request: GetLastBlockHeaderRequest,
) -> Result<GetLastBlockHeaderResponse, Error> { ) -> Result<GetLastBlockHeaderResponse, Error> {
todo!() todo!()
} }
async fn get_block_header_by_hash( async fn get_block_header_by_hash(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetBlockHeaderByHashRequest, request: GetBlockHeaderByHashRequest,
) -> Result<GetBlockHeaderByHashResponse, Error> { ) -> Result<GetBlockHeaderByHashResponse, Error> {
todo!() todo!()
} }
async fn get_block_header_by_height( async fn get_block_header_by_height(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetBlockHeaderByHeightRequest, request: GetBlockHeaderByHeightRequest,
) -> Result<GetBlockHeaderByHeightResponse, Error> { ) -> Result<GetBlockHeaderByHeightResponse, Error> {
todo!() todo!()
} }
async fn get_block_headers_range( async fn get_block_headers_range(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetBlockHeadersRangeRequest, request: GetBlockHeadersRangeRequest,
) -> Result<GetBlockHeadersRangeResponse, Error> { ) -> Result<GetBlockHeadersRangeResponse, Error> {
todo!() todo!()
} }
async fn get_block( async fn get_block(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetBlockRequest, request: GetBlockRequest,
) -> Result<GetBlockResponse, Error> { ) -> Result<GetBlockResponse, Error> {
todo!() todo!()
} }
async fn get_connections( async fn get_connections(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetConnectionsRequest, request: GetConnectionsRequest,
) -> Result<GetConnectionsResponse, Error> { ) -> Result<GetConnectionsResponse, Error> {
todo!() todo!()
} }
async fn get_info( async fn get_info(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetInfoRequest, request: GetInfoRequest,
) -> Result<GetInfoResponse, Error> { ) -> Result<GetInfoResponse, Error> {
todo!() todo!()
} }
async fn hard_fork_info( async fn hard_fork_info(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: HardForkInfoRequest, request: HardForkInfoRequest,
) -> Result<HardForkInfoResponse, Error> { ) -> Result<HardForkInfoResponse, Error> {
todo!() todo!()
} }
async fn set_bans( async fn set_bans(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: SetBansRequest, request: SetBansRequest,
) -> Result<SetBansResponse, Error> { ) -> Result<SetBansResponse, Error> {
todo!() todo!()
} }
async fn get_bans( async fn get_bans(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetBansRequest, request: GetBansRequest,
) -> Result<GetBansResponse, Error> { ) -> Result<GetBansResponse, Error> {
todo!() todo!()
} }
async fn banned( async fn banned(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: BannedRequest, request: BannedRequest,
) -> Result<BannedResponse, Error> { ) -> Result<BannedResponse, Error> {
todo!() todo!()
} }
async fn flush_transaction_pool( async fn flush_transaction_pool(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: FlushTransactionPoolRequest, request: FlushTransactionPoolRequest,
) -> Result<FlushTransactionPoolResponse, Error> { ) -> Result<FlushTransactionPoolResponse, Error> {
todo!() todo!()
} }
async fn get_output_histogram( async fn get_output_histogram(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetOutputHistogramRequest, request: GetOutputHistogramRequest,
) -> Result<GetOutputHistogramResponse, Error> { ) -> Result<GetOutputHistogramResponse, Error> {
todo!() todo!()
} }
async fn get_coinbase_tx_sum( async fn get_coinbase_tx_sum(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetCoinbaseTxSumRequest, request: GetCoinbaseTxSumRequest,
) -> Result<GetCoinbaseTxSumResponse, Error> { ) -> Result<GetCoinbaseTxSumResponse, Error> {
todo!() todo!()
} }
async fn get_version( async fn get_version(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetVersionRequest, request: GetVersionRequest,
) -> Result<GetVersionResponse, Error> { ) -> Result<GetVersionResponse, Error> {
todo!() todo!()
} }
async fn get_fee_estimate( async fn get_fee_estimate(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetFeeEstimateRequest, request: GetFeeEstimateRequest,
) -> Result<GetFeeEstimateResponse, Error> { ) -> Result<GetFeeEstimateResponse, Error> {
todo!() todo!()
} }
async fn get_alternate_chains( async fn get_alternate_chains(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetAlternateChainsRequest, request: GetAlternateChainsRequest,
) -> Result<GetAlternateChainsResponse, Error> { ) -> Result<GetAlternateChainsResponse, Error> {
todo!() todo!()
} }
async fn relay_tx( async fn relay_tx(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: RelayTxRequest, request: RelayTxRequest,
) -> Result<RelayTxResponse, Error> { ) -> Result<RelayTxResponse, Error> {
todo!() todo!()
} }
async fn sync_info( async fn sync_info(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: SyncInfoRequest, request: SyncInfoRequest,
) -> Result<SyncInfoResponse, Error> { ) -> Result<SyncInfoResponse, Error> {
todo!() todo!()
} }
async fn get_transaction_pool_backlog( async fn get_transaction_pool_backlog(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetTransactionPoolBacklogRequest, request: GetTransactionPoolBacklogRequest,
) -> Result<GetTransactionPoolBacklogResponse, Error> { ) -> Result<GetTransactionPoolBacklogResponse, Error> {
todo!() todo!()
} }
async fn get_miner_data( async fn get_miner_data(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetMinerDataRequest, request: GetMinerDataRequest,
) -> Result<GetMinerDataResponse, Error> { ) -> Result<GetMinerDataResponse, Error> {
todo!() todo!()
} }
async fn prune_blockchain( async fn prune_blockchain(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: PruneBlockchainRequest, request: PruneBlockchainRequest,
) -> Result<PruneBlockchainResponse, Error> { ) -> Result<PruneBlockchainResponse, Error> {
todo!() todo!()
} }
async fn calc_pow( async fn calc_pow(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: CalcPowRequest, request: CalcPowRequest,
) -> Result<CalcPowResponse, Error> { ) -> Result<CalcPowResponse, Error> {
todo!() todo!()
} }
async fn flush_cache( async fn flush_cache(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: FlushCacheRequest, request: FlushCacheRequest,
) -> Result<FlushCacheResponse, Error> { ) -> Result<FlushCacheResponse, Error> {
todo!() todo!()
} }
async fn add_aux_pow( async fn add_aux_pow(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: AddAuxPowRequest, request: AddAuxPowRequest,
) -> Result<AddAuxPowResponse, Error> { ) -> Result<AddAuxPowResponse, Error> {
todo!() todo!()
} }
async fn get_tx_ids_loose( async fn get_tx_ids_loose(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetTxIdsLooseRequest, request: GetTxIdsLooseRequest,
) -> Result<GetTxIdsLooseResponse, Error> { ) -> Result<GetTxIdsLooseResponse, Error> {
todo!() todo!()

View file

@ -17,11 +17,11 @@ use cuprate_rpc_types::other::{
StopDaemonResponse, StopMiningRequest, StopMiningResponse, UpdateRequest, UpdateResponse, StopDaemonResponse, StopMiningRequest, StopMiningResponse, UpdateRequest, UpdateResponse,
}; };
use crate::rpc::CupratedRpcHandlerState; use crate::rpc::CupratedRpcHandler;
/// Map a [`OtherRequest`] to the function that will lead to a [`OtherResponse`]. /// Map a [`OtherRequest`] to the function that will lead to a [`OtherResponse`].
pub(super) async fn map_request( pub(super) async fn map_request(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: OtherRequest, request: OtherRequest,
) -> Result<OtherResponse, Error> { ) -> Result<OtherResponse, Error> {
use OtherRequest as Req; use OtherRequest as Req;
@ -71,189 +71,189 @@ pub(super) async fn map_request(
} }
async fn get_height( async fn get_height(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetHeightRequest, request: GetHeightRequest,
) -> Result<GetHeightResponse, Error> { ) -> Result<GetHeightResponse, Error> {
todo!() todo!()
} }
async fn get_transactions( async fn get_transactions(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetTransactionsRequest, request: GetTransactionsRequest,
) -> Result<GetTransactionsResponse, Error> { ) -> Result<GetTransactionsResponse, Error> {
todo!() todo!()
} }
async fn get_alt_blocks_hashes( async fn get_alt_blocks_hashes(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetAltBlocksHashesRequest, request: GetAltBlocksHashesRequest,
) -> Result<GetAltBlocksHashesResponse, Error> { ) -> Result<GetAltBlocksHashesResponse, Error> {
todo!() todo!()
} }
async fn is_key_image_spent( async fn is_key_image_spent(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: IsKeyImageSpentRequest, request: IsKeyImageSpentRequest,
) -> Result<IsKeyImageSpentResponse, Error> { ) -> Result<IsKeyImageSpentResponse, Error> {
todo!() todo!()
} }
async fn send_raw_transaction( async fn send_raw_transaction(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: SendRawTransactionRequest, request: SendRawTransactionRequest,
) -> Result<SendRawTransactionResponse, Error> { ) -> Result<SendRawTransactionResponse, Error> {
todo!() todo!()
} }
async fn start_mining( async fn start_mining(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: StartMiningRequest, request: StartMiningRequest,
) -> Result<StartMiningResponse, Error> { ) -> Result<StartMiningResponse, Error> {
todo!() todo!()
} }
async fn stop_mining( async fn stop_mining(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: StopMiningRequest, request: StopMiningRequest,
) -> Result<StopMiningResponse, Error> { ) -> Result<StopMiningResponse, Error> {
todo!() todo!()
} }
async fn mining_status( async fn mining_status(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: MiningStatusRequest, request: MiningStatusRequest,
) -> Result<MiningStatusResponse, Error> { ) -> Result<MiningStatusResponse, Error> {
todo!() todo!()
} }
async fn save_bc( async fn save_bc(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: SaveBcRequest, request: SaveBcRequest,
) -> Result<SaveBcResponse, Error> { ) -> Result<SaveBcResponse, Error> {
todo!() todo!()
} }
async fn get_peer_list( async fn get_peer_list(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetPeerListRequest, request: GetPeerListRequest,
) -> Result<GetPeerListResponse, Error> { ) -> Result<GetPeerListResponse, Error> {
todo!() todo!()
} }
async fn set_log_hash_rate( async fn set_log_hash_rate(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: SetLogHashRateRequest, request: SetLogHashRateRequest,
) -> Result<SetLogHashRateResponse, Error> { ) -> Result<SetLogHashRateResponse, Error> {
todo!() todo!()
} }
async fn set_log_level( async fn set_log_level(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: SetLogLevelRequest, request: SetLogLevelRequest,
) -> Result<SetLogLevelResponse, Error> { ) -> Result<SetLogLevelResponse, Error> {
todo!() todo!()
} }
async fn set_log_categories( async fn set_log_categories(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: SetLogCategoriesRequest, request: SetLogCategoriesRequest,
) -> Result<SetLogCategoriesResponse, Error> { ) -> Result<SetLogCategoriesResponse, Error> {
todo!() todo!()
} }
async fn set_bootstrap_daemon( async fn set_bootstrap_daemon(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: SetBootstrapDaemonRequest, request: SetBootstrapDaemonRequest,
) -> Result<SetBootstrapDaemonResponse, Error> { ) -> Result<SetBootstrapDaemonResponse, Error> {
todo!() todo!()
} }
async fn get_transaction_pool( async fn get_transaction_pool(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetTransactionPoolRequest, request: GetTransactionPoolRequest,
) -> Result<GetTransactionPoolResponse, Error> { ) -> Result<GetTransactionPoolResponse, Error> {
todo!() todo!()
} }
async fn get_transaction_pool_stats( async fn get_transaction_pool_stats(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetTransactionPoolStatsRequest, request: GetTransactionPoolStatsRequest,
) -> Result<GetTransactionPoolStatsResponse, Error> { ) -> Result<GetTransactionPoolStatsResponse, Error> {
todo!() todo!()
} }
async fn stop_daemon( async fn stop_daemon(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: StopDaemonRequest, request: StopDaemonRequest,
) -> Result<StopDaemonResponse, Error> { ) -> Result<StopDaemonResponse, Error> {
todo!() todo!()
} }
async fn get_limit( async fn get_limit(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetLimitRequest, request: GetLimitRequest,
) -> Result<GetLimitResponse, Error> { ) -> Result<GetLimitResponse, Error> {
todo!() todo!()
} }
async fn set_limit( async fn set_limit(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: SetLimitRequest, request: SetLimitRequest,
) -> Result<SetLimitResponse, Error> { ) -> Result<SetLimitResponse, Error> {
todo!() todo!()
} }
async fn out_peers( async fn out_peers(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: OutPeersRequest, request: OutPeersRequest,
) -> Result<OutPeersResponse, Error> { ) -> Result<OutPeersResponse, Error> {
todo!() todo!()
} }
async fn in_peers( async fn in_peers(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: InPeersRequest, request: InPeersRequest,
) -> Result<InPeersResponse, Error> { ) -> Result<InPeersResponse, Error> {
todo!() todo!()
} }
async fn get_net_stats( async fn get_net_stats(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetNetStatsRequest, request: GetNetStatsRequest,
) -> Result<GetNetStatsResponse, Error> { ) -> Result<GetNetStatsResponse, Error> {
todo!() todo!()
} }
async fn get_outs( async fn get_outs(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetOutsRequest, request: GetOutsRequest,
) -> Result<GetOutsResponse, Error> { ) -> Result<GetOutsResponse, Error> {
todo!() todo!()
} }
async fn update( async fn update(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: UpdateRequest, request: UpdateRequest,
) -> Result<UpdateResponse, Error> { ) -> Result<UpdateResponse, Error> {
todo!() todo!()
} }
async fn pop_blocks( async fn pop_blocks(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: PopBlocksRequest, request: PopBlocksRequest,
) -> Result<PopBlocksResponse, Error> { ) -> Result<PopBlocksResponse, Error> {
todo!() todo!()
} }
async fn get_transaction_pool_hashes( async fn get_transaction_pool_hashes(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetTransactionPoolHashesRequest, request: GetTransactionPoolHashesRequest,
) -> Result<GetTransactionPoolHashesResponse, Error> { ) -> Result<GetTransactionPoolHashesResponse, Error> {
todo!() todo!()
} }
async fn get_public_nodes( async fn get_public_nodes(
state: CupratedRpcHandlerState, state: CupratedRpcHandler,
request: GetPublicNodesRequest, request: GetPublicNodesRequest,
) -> Result<GetPublicNodesResponse, Error> { ) -> Result<GetPublicNodesResponse, Error> {
todo!() todo!()

View file

@ -0,0 +1,19 @@
//! Convenience functions for requests/responses.
//!
//! This module implements many methods for
//! [`CupratedRpcHandler`](crate::rpc::CupratedRpcHandler)
//! that are simple wrappers around the request/response API provided
//! by the multiple [`tower::Service`]s.
//!
//! These exist to prevent noise like `unreachable!()`
//! from being everywhere in the actual handler functions.
//!
//! Each module implements methods for a specific API, e.g.
//! 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;

View file

@ -0,0 +1,104 @@
//! Functions for TODO: doc enum message.
use std::convert::Infallible;
use anyhow::Error;
use tower::ServiceExt;
use cuprate_helper::cast::usize_to_u64;
use cuprate_p2p_core::{
services::{AddressBookRequest, AddressBookResponse},
AddressBook, NetworkZone,
};
/// [`AddressBookRequest::PeerlistSize`]
pub(super) async fn peerlist_size<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>,
) -> Result<(u64, u64), Error> {
let AddressBookResponse::PeerlistSize { white, grey } = address_book
.ready()
.await
.expect("TODO")
.call(AddressBookRequest::PeerlistSize)
.await
.expect("TODO")
else {
unreachable!();
};
Ok((usize_to_u64(white), usize_to_u64(grey)))
}
/// [`AddressBookRequest::ConnectionCount`]
pub(super) async fn connection_count<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>,
) -> Result<(u64, u64), Error> {
let AddressBookResponse::ConnectionCount { incoming, outgoing } = address_book
.ready()
.await
.expect("TODO")
.call(AddressBookRequest::ConnectionCount)
.await
.expect("TODO")
else {
unreachable!();
};
Ok((usize_to_u64(incoming), usize_to_u64(outgoing)))
}
/// [`AddressBookRequest::SetBan`]
pub(super) async fn set_ban<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>,
peer: cuprate_p2p_core::ban::SetBan<Z::Addr>,
) -> Result<(), Error> {
let AddressBookResponse::Ok = address_book
.ready()
.await
.expect("TODO")
.call(AddressBookRequest::SetBan(peer))
.await
.expect("TODO")
else {
unreachable!();
};
Ok(())
}
/// [`AddressBookRequest::GetBan`]
pub(super) async fn get_ban<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>,
peer: Z::Addr,
) -> Result<Option<std::time::Instant>, Error> {
let AddressBookResponse::GetBan { unban_instant } = address_book
.ready()
.await
.expect("TODO")
.call(AddressBookRequest::GetBan(peer))
.await
.expect("TODO")
else {
unreachable!();
};
Ok(unban_instant)
}
/// [`AddressBookRequest::GetBans`]
pub(super) async fn get_bans<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>,
) -> Result<(), Error> {
let AddressBookResponse::GetBans(bans) = address_book
.ready()
.await
.expect("TODO")
.call(AddressBookRequest::GetBans)
.await
.expect("TODO")
else {
unreachable!();
};
Ok(todo!())
}

View file

@ -0,0 +1,308 @@
//! Functions for [`BlockchainReadRequest`].
use std::{
collections::{HashMap, HashSet},
ops::Range,
};
use anyhow::Error;
use cuprate_blockchain::service::BlockchainReadHandle;
use tower::{Service, ServiceExt};
use cuprate_helper::cast::{u64_to_usize, usize_to_u64};
use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainResponse},
Chain, CoinbaseTxSum, ExtendedBlockHeader, MinerData, OutputHistogramEntry,
OutputHistogramInput, OutputOnChain,
};
/// [`BlockchainReadRequest::BlockExtendedHeader`].
pub(super) async fn block_extended_header(
mut blockchain_read: BlockchainReadHandle,
height: u64,
) -> Result<ExtendedBlockHeader, Error> {
let BlockchainResponse::BlockExtendedHeader(header) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::BlockExtendedHeader(u64_to_usize(
height,
)))
.await?
else {
unreachable!();
};
Ok(header)
}
/// [`BlockchainReadRequest::BlockHash`].
pub(super) async fn block_hash(
mut blockchain_read: BlockchainReadHandle,
height: u64,
chain: Chain,
) -> Result<[u8; 32], Error> {
let BlockchainResponse::BlockHash(hash) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::BlockHash(
u64_to_usize(height),
chain,
))
.await?
else {
unreachable!();
};
Ok(hash)
}
/// [`BlockchainReadRequest::FindBlock`].
pub(super) async fn find_block(
mut blockchain_read: BlockchainReadHandle,
block_hash: [u8; 32],
) -> Result<Option<(Chain, usize)>, Error> {
let BlockchainResponse::FindBlock(option) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::FindBlock(block_hash))
.await?
else {
unreachable!();
};
Ok(option)
}
/// [`BlockchainReadRequest::FilterUnknownHashes`].
pub(super) async fn filter_unknown_hashes(
mut blockchain_read: BlockchainReadHandle,
block_hashes: HashSet<[u8; 32]>,
) -> Result<HashSet<[u8; 32]>, Error> {
let BlockchainResponse::FilterUnknownHashes(output) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::FilterUnknownHashes(block_hashes))
.await?
else {
unreachable!();
};
Ok(output)
}
/// [`BlockchainReadRequest::BlockExtendedHeaderInRange`]
pub(super) async fn block_extended_header_in_range(
mut blockchain_read: BlockchainReadHandle,
range: Range<usize>,
chain: Chain,
) -> Result<Vec<ExtendedBlockHeader>, Error> {
let BlockchainResponse::BlockExtendedHeaderInRange(output) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::BlockExtendedHeaderInRange(
range, chain,
))
.await?
else {
unreachable!();
};
Ok(output)
}
/// [`BlockchainReadRequest::ChainHeight`].
pub(super) async fn chain_height(
mut blockchain_read: BlockchainReadHandle,
) -> Result<(u64, [u8; 32]), Error> {
let BlockchainResponse::ChainHeight(height, hash) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::ChainHeight)
.await?
else {
unreachable!();
};
Ok((usize_to_u64(height), hash))
}
/// [`BlockchainReadRequest::GeneratedCoins`].
pub(super) async fn generated_coins(
mut blockchain_read: BlockchainReadHandle,
block_height: u64,
) -> Result<u64, Error> {
let BlockchainResponse::GeneratedCoins(generated_coins) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::GeneratedCoins(u64_to_usize(
block_height,
)))
.await?
else {
unreachable!();
};
Ok(generated_coins)
}
/// [`BlockchainReadRequest::Outputs`]
pub(super) async fn outputs(
mut blockchain_read: BlockchainReadHandle,
outputs: HashMap<u64, HashSet<u64>>,
) -> Result<HashMap<u64, HashMap<u64, OutputOnChain>>, Error> {
let BlockchainResponse::Outputs(outputs) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::Outputs(outputs))
.await?
else {
unreachable!();
};
Ok(outputs)
}
/// [`BlockchainReadRequest::NumberOutputsWithAmount`]
pub(super) async fn number_outputs_with_amount(
mut blockchain_read: BlockchainReadHandle,
output_amounts: Vec<u64>,
) -> Result<HashMap<u64, usize>, Error> {
let BlockchainResponse::NumberOutputsWithAmount(map) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::NumberOutputsWithAmount(
output_amounts,
))
.await?
else {
unreachable!();
};
Ok(map)
}
/// [`BlockchainReadRequest::KeyImagesSpent`]
pub(super) async fn key_images_spent(
mut blockchain_read: BlockchainReadHandle,
key_images: HashSet<[u8; 32]>,
) -> Result<bool, Error> {
let BlockchainResponse::KeyImagesSpent(is_spent) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::KeyImagesSpent(key_images))
.await?
else {
unreachable!();
};
Ok(is_spent)
}
/// [`BlockchainReadRequest::CompactChainHistory`]
pub(super) async fn compact_chain_history(
mut blockchain_read: BlockchainReadHandle,
) -> Result<(Vec<[u8; 32]>, u128), Error> {
let BlockchainResponse::CompactChainHistory {
block_ids,
cumulative_difficulty,
} = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::CompactChainHistory)
.await?
else {
unreachable!();
};
Ok((block_ids, cumulative_difficulty))
}
/// [`BlockchainReadRequest::FindFirstUnknown`]
pub(super) async fn find_first_unknown(
mut blockchain_read: BlockchainReadHandle,
hashes: Vec<[u8; 32]>,
) -> Result<Option<(usize, u64)>, Error> {
let BlockchainResponse::FindFirstUnknown(resp) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::FindFirstUnknown(hashes))
.await?
else {
unreachable!();
};
Ok(resp.map(|(index, height)| (index, usize_to_u64(height))))
}
/// [`BlockchainReadRequest::TotalTxCount`]
pub(super) async fn total_tx_count(
mut blockchain_read: BlockchainReadHandle,
) -> Result<u64, Error> {
let BlockchainResponse::TotalTxCount(tx_count) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::TotalTxCount)
.await?
else {
unreachable!();
};
Ok(usize_to_u64(tx_count))
}
/// [`BlockchainReadRequest::DatabaseSize`]
pub(super) async fn database_size(
mut blockchain_read: BlockchainReadHandle,
) -> Result<(u64, u64), Error> {
let BlockchainResponse::DatabaseSize {
database_size,
free_space,
} = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::DatabaseSize)
.await?
else {
unreachable!();
};
Ok((database_size, free_space))
}
/// [`BlockchainReadRequest::OutputHistogram`]
pub(super) async fn output_histogram(
mut blockchain_read: BlockchainReadHandle,
input: OutputHistogramInput,
) -> Result<Vec<OutputHistogramEntry>, Error> {
let BlockchainResponse::OutputHistogram(histogram) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::OutputHistogram(input))
.await?
else {
unreachable!();
};
Ok(histogram)
}
/// [`BlockchainReadRequest::CoinbaseTxSum`]
pub(super) async fn coinbase_tx_sum(
mut blockchain_read: BlockchainReadHandle,
height: u64,
count: u64,
) -> Result<CoinbaseTxSum, Error> {
let BlockchainResponse::CoinbaseTxSum(sum) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::CoinbaseTxSum {
height: u64_to_usize(height),
count,
})
.await?
else {
unreachable!();
};
Ok(sum)
}

View file

@ -0,0 +1,69 @@
//! Functions for [`BlockChainContextRequest`] and [`BlockChainContextResponse`].
use std::convert::Infallible;
use anyhow::Error;
use tower::{Service, ServiceExt};
use cuprate_consensus::context::{
BlockChainContext, BlockChainContextRequest, BlockChainContextResponse,
BlockChainContextService,
};
use cuprate_types::{FeeEstimate, HardFork, HardForkInfo};
/// [`BlockChainContextRequest::Context`].
pub(super) async fn context(
service: &mut BlockChainContextService,
height: u64,
) -> Result<BlockChainContext, Error> {
let BlockChainContextResponse::Context(context) = service
.ready()
.await
.expect("TODO")
.call(BlockChainContextRequest::Context)
.await
.expect("TODO")
else {
unreachable!();
};
Ok(context)
}
/// [`BlockChainContextRequest::HardForkInfo`].
pub(super) async fn hard_fork_info(
service: &mut BlockChainContextService,
hard_fork: HardFork,
) -> Result<HardForkInfo, Error> {
let BlockChainContextResponse::HardForkInfo(hf_info) = service
.ready()
.await
.expect("TODO")
.call(BlockChainContextRequest::HardForkInfo(hard_fork))
.await
.expect("TODO")
else {
unreachable!();
};
Ok(hf_info)
}
/// [`BlockChainContextRequest::FeeEstimate`].
pub(super) async fn fee_estimate(
service: &mut BlockChainContextService,
grace_blocks: u64,
) -> Result<FeeEstimate, Error> {
let BlockChainContextResponse::FeeEstimate(fee) = service
.ready()
.await
.expect("TODO")
.call(BlockChainContextRequest::FeeEstimate { grace_blocks })
.await
.expect("TODO")
else {
unreachable!();
};
Ok(fee)
}

View file

@ -0,0 +1,141 @@
//! Functions for [`BlockchainManagerRequest`] & [`BlockchainManagerResponse`].
use anyhow::Error;
use monero_serai::block::Block;
use tower::{Service, ServiceExt};
use cuprate_helper::cast::{u64_to_usize, usize_to_u64};
use crate::rpc::handler::{
BlockchainManagerHandle, BlockchainManagerRequest, BlockchainManagerResponse,
};
/// [`BlockchainManagerRequest::PopBlocks`]
pub(super) async fn pop_blocks(
blockchain_manager: &mut BlockchainManagerHandle,
amount: u64,
) -> Result<u64, Error> {
let BlockchainManagerResponse::PopBlocks { new_height } = blockchain_manager
.ready()
.await?
.call(BlockchainManagerRequest::PopBlocks {
amount: u64_to_usize(amount),
})
.await?
else {
unreachable!();
};
Ok(usize_to_u64(new_height))
}
/// [`BlockchainManagerRequest::Prune`]
pub(super) async fn prune(blockchain_manager: &mut BlockchainManagerHandle) -> Result<(), Error> {
let BlockchainManagerResponse::Ok = blockchain_manager
.ready()
.await?
.call(BlockchainManagerRequest::Prune)
.await?
else {
unreachable!();
};
Ok(())
}
/// [`BlockchainManagerRequest::Pruned`]
pub(super) async fn pruned(
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<bool, Error> {
let BlockchainManagerResponse::Pruned(pruned) = blockchain_manager
.ready()
.await?
.call(BlockchainManagerRequest::Pruned)
.await?
else {
unreachable!();
};
Ok(pruned)
}
/// [`BlockchainManagerRequest::RelayBlock`]
pub(super) async fn relay_block(
blockchain_manager: &mut BlockchainManagerHandle,
block: Block,
) -> Result<(), Error> {
let BlockchainManagerResponse::Ok = blockchain_manager
.ready()
.await?
.call(BlockchainManagerRequest::RelayBlock(block))
.await?
else {
unreachable!();
};
Ok(())
}
/// [`BlockchainManagerRequest::Syncing`]
pub(super) async fn syncing(
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<bool, Error> {
let BlockchainManagerResponse::Syncing(syncing) = blockchain_manager
.ready()
.await?
.call(BlockchainManagerRequest::Syncing)
.await?
else {
unreachable!();
};
Ok(syncing)
}
/// [`BlockchainManagerRequest::Synced`]
pub(super) async fn synced(
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<bool, Error> {
let BlockchainManagerResponse::Synced(syncing) = blockchain_manager
.ready()
.await?
.call(BlockchainManagerRequest::Synced)
.await?
else {
unreachable!();
};
Ok(syncing)
}
/// [`BlockchainManagerRequest::Target`]
pub(super) async fn target(
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<std::time::Duration, Error> {
let BlockchainManagerResponse::Target(target) = blockchain_manager
.ready()
.await?
.call(BlockchainManagerRequest::Target)
.await?
else {
unreachable!();
};
Ok(target)
}
/// [`BlockchainManagerRequest::TargetHeight`]
pub(super) async fn target_height(
blockchain_manager: &mut BlockchainManagerHandle,
) -> Result<u64, Error> {
let BlockchainManagerResponse::TargetHeight { height } = blockchain_manager
.ready()
.await?
.call(BlockchainManagerRequest::TargetHeight)
.await?
else {
unreachable!();
};
Ok(usize_to_u64(height))
}

View file

@ -0,0 +1,57 @@
//! Functions for [`TxpoolReadRequest`].
use std::convert::Infallible;
use anyhow::Error;
use tower::{Service, ServiceExt};
use cuprate_helper::cast::usize_to_u64;
use cuprate_txpool::{
service::{
interface::{TxpoolReadRequest, TxpoolReadResponse},
TxpoolReadHandle,
},
TxEntry,
};
/// [`TxpoolReadRequest::Backlog`]
pub(super) async fn backlog(txpool_read: &mut TxpoolReadHandle) -> Result<Vec<TxEntry>, Error> {
let TxpoolReadResponse::Backlog(tx_entries) = txpool_read
.ready()
.await
.expect("TODO")
.call(TxpoolReadRequest::Backlog)
.await
.expect("TODO")
else {
unreachable!();
};
Ok(tx_entries)
}
/// [`TxpoolReadRequest::Size`]
pub(super) async fn size(txpool_read: &mut TxpoolReadHandle) -> Result<u64, Error> {
let TxpoolReadResponse::Size(size) = txpool_read
.ready()
.await
.expect("TODO")
.call(TxpoolReadRequest::Size)
.await
.expect("TODO")
else {
unreachable!();
};
Ok(usize_to_u64(size))
}
/// TODO
#[expect(clippy::needless_pass_by_ref_mut, reason = "TODO: remove after impl")]
pub(super) async fn flush(
txpool_read: &mut TxpoolReadHandle,
tx_hashes: Vec<[u8; 32]>,
) -> Result<(), Error> {
todo!();
Ok(())
}

View file

@ -230,7 +230,7 @@ where
let BlockChainContextResponse::Context(checked_context) = context_svc let BlockChainContextResponse::Context(checked_context) = context_svc
.ready() .ready()
.await? .await?
.call(BlockChainContextRequest::GetContext) .call(BlockChainContextRequest::Context)
.await? .await?
else { else {
panic!("Context service returned wrong response!"); panic!("Context service returned wrong response!");

View file

@ -351,7 +351,7 @@ where
let BlockChainContextResponse::Context(checked_context) = context_svc let BlockChainContextResponse::Context(checked_context) = context_svc
.ready() .ready()
.await? .await?
.call(BlockChainContextRequest::GetContext) .call(BlockChainContextRequest::Context)
.await? .await?
else { else {
panic!("Context service returned wrong response!"); panic!("Context service returned wrong response!");
@ -374,7 +374,7 @@ where
let BlockChainContextResponse::RxVms(rx_vms) = context_svc let BlockChainContextResponse::RxVms(rx_vms) = context_svc
.ready() .ready()
.await? .await?
.call(BlockChainContextRequest::GetCurrentRxVm) .call(BlockChainContextRequest::CurrentRxVms)
.await? .await?
else { else {
panic!("Blockchain context service returned wrong response!"); panic!("Blockchain context service returned wrong response!");
@ -433,7 +433,7 @@ where
context context
} else { } else {
let BlockChainContextResponse::Context(checked_context) = context_svc let BlockChainContextResponse::Context(checked_context) = context_svc
.oneshot(BlockChainContextRequest::GetContext) .oneshot(BlockChainContextRequest::Context)
.await? .await?
else { else {
panic!("Context service returned wrong response!"); panic!("Context service returned wrong response!");

View file

@ -93,7 +93,7 @@ where
let BlockChainContextResponse::Context(checked_context) = context_svc let BlockChainContextResponse::Context(checked_context) = context_svc
.ready() .ready()
.await? .await?
.call(BlockChainContextRequest::GetContext) .call(BlockChainContextRequest::Context)
.await? .await?
else { else {
panic!("Context service returned wrong response!"); panic!("Context service returned wrong response!");
@ -136,7 +136,7 @@ where
let BlockChainContextResponse::RxVms(rx_vms) = context_svc let BlockChainContextResponse::RxVms(rx_vms) = context_svc
.ready() .ready()
.await? .await?
.call(BlockChainContextRequest::GetCurrentRxVm) .call(BlockChainContextRequest::CurrentRxVms)
.await? .await?
else { else {
panic!("Blockchain context service returned wrong response!"); panic!("Blockchain context service returned wrong response!");

View file

@ -31,7 +31,7 @@ mod alt_chains;
mod task; mod task;
mod tokens; mod tokens;
use cuprate_types::Chain; use cuprate_types::{Chain, ChainInfo, FeeEstimate, HardForkInfo};
use difficulty::DifficultyCache; use difficulty::DifficultyCache;
use rx_vms::RandomXVm; use rx_vms::RandomXVm;
use weight::BlockWeightsCache; use weight::BlockWeightsCache;
@ -221,15 +221,18 @@ pub struct NewBlockData {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum BlockChainContextRequest { pub enum BlockChainContextRequest {
/// Get the current blockchain context. /// Get the current blockchain context.
GetContext, Context,
/// Gets the current `RandomX` VM.
GetCurrentRxVm, /// Gets all the current `RandomX` VMs.
CurrentRxVms,
/// Get the next difficulties for these blocks. /// Get the next difficulties for these blocks.
/// ///
/// Inputs: a list of block timestamps and hfs /// Inputs: a list of block timestamps and hfs
/// ///
/// The number of difficulties returned will be one more than the number of timestamps/ hfs. /// The number of difficulties returned will be one more than the number of timestamps/ hfs.
BatchGetDifficulties(Vec<(u64, HardFork)>), BatchGetDifficulties(Vec<(u64, HardFork)>),
/// Add a VM that has been created outside of the blockchain context service to the blockchain context. /// Add a VM that has been created outside of the blockchain context service to the blockchain context.
/// This is useful when batch calculating POW as you may need to create a new VM if you batch a lot of blocks together, /// This is useful when batch calculating POW as you may need to create a new VM if you batch a lot of blocks together,
/// it would be wasteful to then not give this VM to the context service to then use when it needs to init a VM with the same /// it would be wasteful to then not give this VM to the context service to then use when it needs to init a VM with the same
@ -237,8 +240,10 @@ pub enum BlockChainContextRequest {
/// ///
/// This should include the seed used to init this VM and the VM. /// This should include the seed used to init this VM and the VM.
NewRXVM(([u8; 32], Arc<RandomXVm>)), NewRXVM(([u8; 32], Arc<RandomXVm>)),
/// A request to add a new block to the cache. /// A request to add a new block to the cache.
Update(NewBlockData), Update(NewBlockData),
/// Pop blocks from the cache to the specified height. /// Pop blocks from the cache to the specified height.
PopBlocks { PopBlocks {
/// The number of blocks to pop from the top of the chain. /// The number of blocks to pop from the top of the chain.
@ -248,8 +253,22 @@ pub enum BlockChainContextRequest {
/// This will panic if the number of blocks will pop the genesis block. /// This will panic if the number of blocks will pop the genesis block.
numb_blocks: usize, numb_blocks: usize,
}, },
/// Get information on a certain hardfork.
HardForkInfo(HardFork),
/// Get the current fee estimate.
FeeEstimate {
/// TODO
grace_blocks: u64,
},
/// Clear the alt chain context caches. /// Clear the alt chain context caches.
ClearAltCache, ClearAltCache,
/// Get information on all the current alternate chains.
AltChains,
//----------------------------------------------------------------------------------------------------------- AltChainRequests //----------------------------------------------------------------------------------------------------------- AltChainRequests
/// A request for an alt chain context cache. /// A request for an alt chain context cache.
/// ///
@ -261,6 +280,7 @@ pub enum BlockChainContextRequest {
/// An internal token to prevent external crates calling this request. /// An internal token to prevent external crates calling this request.
_token: AltChainRequestToken, _token: AltChainRequestToken,
}, },
/// A request for a difficulty cache of an alternative chin. /// A request for a difficulty cache of an alternative chin.
/// ///
/// This variant is private and is not callable from outside this crate, the block verifier service will /// This variant is private and is not callable from outside this crate, the block verifier service will
@ -271,6 +291,7 @@ pub enum BlockChainContextRequest {
/// An internal token to prevent external crates calling this request. /// An internal token to prevent external crates calling this request.
_token: AltChainRequestToken, _token: AltChainRequestToken,
}, },
/// A request for a block weight cache of an alternative chin. /// A request for a block weight cache of an alternative chin.
/// ///
/// This variant is private and is not callable from outside this crate, the block verifier service will /// This variant is private and is not callable from outside this crate, the block verifier service will
@ -281,6 +302,7 @@ pub enum BlockChainContextRequest {
/// An internal token to prevent external crates calling this request. /// An internal token to prevent external crates calling this request.
_token: AltChainRequestToken, _token: AltChainRequestToken,
}, },
/// A request for a RX VM for an alternative chin. /// A request for a RX VM for an alternative chin.
/// ///
/// Response variant: [`BlockChainContextResponse::AltChainRxVM`]. /// Response variant: [`BlockChainContextResponse::AltChainRxVM`].
@ -295,6 +317,7 @@ pub enum BlockChainContextRequest {
/// An internal token to prevent external crates calling this request. /// An internal token to prevent external crates calling this request.
_token: AltChainRequestToken, _token: AltChainRequestToken,
}, },
/// A request to add an alt chain context cache to the context cache. /// A request to add an alt chain context cache to the context cache.
/// ///
/// This variant is private and is not callable from outside this crate, the block verifier service will /// This variant is private and is not callable from outside this crate, the block verifier service will
@ -310,22 +333,49 @@ pub enum BlockChainContextRequest {
} }
pub enum BlockChainContextResponse { pub enum BlockChainContextResponse {
/// Blockchain context response. /// A generic Ok response.
///
/// Response to:
/// - [`BlockChainContextRequest::NewRXVM`]
/// - [`BlockChainContextRequest::Update`]
/// - [`BlockChainContextRequest::PopBlocks`]
/// - [`BlockChainContextRequest::ClearAltCache`]
/// - [`BlockChainContextRequest::AddAltChainContextCache`]
Ok,
/// Response to [`BlockChainContextRequest::Context`]
Context(BlockChainContext), Context(BlockChainContext),
/// Response to [`BlockChainContextRequest::CurrentRxVms`]
///
/// A map of seed height to `RandomX` VMs. /// A map of seed height to `RandomX` VMs.
RxVms(HashMap<usize, Arc<RandomXVm>>), RxVms(HashMap<usize, Arc<RandomXVm>>),
/// A list of difficulties. /// A list of difficulties.
BatchDifficulties(Vec<u128>), BatchDifficulties(Vec<u128>),
/// Response to [`BlockChainContextRequest::HardForkInfo`]
HardForkInfo(HardForkInfo),
/// Response to [`BlockChainContextRequest::FeeEstimate`]
FeeEstimate(FeeEstimate),
/// Response to [`BlockChainContextRequest::AltChains`]
///
/// If the inner [`Vec::is_empty`], there were no alternate chains.
AltChains(Vec<ChainInfo>),
/// An alt chain context cache. /// An alt chain context cache.
AltChainContextCache(Box<AltChainContextCache>), AltChainContextCache(Box<AltChainContextCache>),
/// A difficulty cache for an alt chain. /// A difficulty cache for an alt chain.
AltChainDifficultyCache(DifficultyCache), AltChainDifficultyCache(DifficultyCache),
/// A randomX VM for an alt chain. /// A randomX VM for an alt chain.
AltChainRxVM(Arc<RandomXVm>), AltChainRxVM(Arc<RandomXVm>),
/// A weight cache for an alt chain /// A weight cache for an alt chain
AltChainWeightCache(BlockWeightsCache), AltChainWeightCache(BlockWeightsCache),
/// A generic Ok response.
Ok,
} }
/// The blockchain context service. /// The blockchain context service.

View file

@ -153,7 +153,7 @@ impl<D: Database + Clone + Send + 'static> ContextTask<D> {
req: BlockChainContextRequest, req: BlockChainContextRequest,
) -> Result<BlockChainContextResponse, tower::BoxError> { ) -> Result<BlockChainContextResponse, tower::BoxError> {
Ok(match req { Ok(match req {
BlockChainContextRequest::GetContext => { BlockChainContextRequest::Context => {
tracing::debug!("Getting blockchain context"); tracing::debug!("Getting blockchain context");
let current_hf = self.hardfork_state.current_hardfork(); let current_hf = self.hardfork_state.current_hardfork();
@ -183,7 +183,7 @@ impl<D: Database + Clone + Send + 'static> ContextTask<D> {
}, },
}) })
} }
BlockChainContextRequest::GetCurrentRxVm => { BlockChainContextRequest::CurrentRxVms => {
BlockChainContextResponse::RxVms(self.rx_vm_cache.get_vms().await) BlockChainContextResponse::RxVms(self.rx_vm_cache.get_vms().await)
} }
BlockChainContextRequest::BatchGetDifficulties(blocks) => { BlockChainContextRequest::BatchGetDifficulties(blocks) => {
@ -325,6 +325,11 @@ impl<D: Database + Clone + Send + 'static> ContextTask<D> {
self.alt_chain_cache_map.add_alt_cache(prev_id, cache); self.alt_chain_cache_map.add_alt_cache(prev_id, cache);
BlockChainContextResponse::Ok BlockChainContextResponse::Ok
} }
BlockChainContextRequest::HardForkInfo(_)
| BlockChainContextRequest::FeeEstimate { .. }
| BlockChainContextRequest::AltChains => {
todo!("finish https://github.com/Cuprate/cuprate/pull/297")
}
}) })
} }

View file

@ -41,7 +41,7 @@ async fn context_invalidated_on_new_block() -> Result<(), tower::BoxError> {
let BlockChainContextResponse::Context(context) = ctx_svc let BlockChainContextResponse::Context(context) = ctx_svc
.clone() .clone()
.oneshot(BlockChainContextRequest::GetContext) .oneshot(BlockChainContextRequest::Context)
.await? .await?
else { else {
panic!("Context service returned wrong response!"); panic!("Context service returned wrong response!");
@ -81,9 +81,8 @@ async fn context_height_correct() -> Result<(), tower::BoxError> {
let ctx_svc = initialize_blockchain_context(TEST_CONTEXT_CONFIG, db).await?; let ctx_svc = initialize_blockchain_context(TEST_CONTEXT_CONFIG, db).await?;
let BlockChainContextResponse::Context(context) = ctx_svc let BlockChainContextResponse::Context(context) =
.oneshot(BlockChainContextRequest::GetContext) ctx_svc.oneshot(BlockChainContextRequest::Context).await?
.await?
else { else {
panic!("context service returned incorrect response!") panic!("context service returned incorrect response!")
}; };

View file

@ -229,6 +229,15 @@ impl<Z: BorshNetworkZone> AddressBook<Z> {
self.banned_peers.contains_key(&peer.ban_id()) self.banned_peers.contains_key(&peer.ban_id())
} }
/// Checks when a peer will be unbanned.
///
/// - If the peer is banned, this returns [`Some`] containing
/// the [`Instant`] the peer will be unbanned
/// - If the peer is not banned, this returns [`None`]
fn peer_unban_instant(&self, peer: &Z::Addr) -> Option<Instant> {
self.banned_peers.get(&peer.ban_id()).copied()
}
fn handle_incoming_peer_list( fn handle_incoming_peer_list(
&mut self, &mut self,
mut peer_list: Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>, mut peer_list: Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>,
@ -408,9 +417,15 @@ impl<Z: BorshNetworkZone> Service<AddressBookRequest<Z>> for AddressBook<Z> {
AddressBookRequest::GetWhitePeers(len) => { AddressBookRequest::GetWhitePeers(len) => {
Ok(AddressBookResponse::Peers(self.get_white_peers(len))) Ok(AddressBookResponse::Peers(self.get_white_peers(len)))
} }
AddressBookRequest::IsPeerBanned(addr) => Ok(AddressBookResponse::IsPeerBanned( AddressBookRequest::GetBan(addr) => Ok(AddressBookResponse::GetBan {
self.is_peer_banned(&addr), unban_instant: self.peer_unban_instant(&addr).map(Instant::into_std),
)), }),
AddressBookRequest::PeerlistSize
| AddressBookRequest::ConnectionCount
| AddressBookRequest::SetBan(_)
| AddressBookRequest::GetBans => {
todo!("finish https://github.com/Cuprate/cuprate/pull/297")
}
}; };
ready(response) ready(response)

23
p2p/p2p-core/src/ban.rs Normal file
View file

@ -0,0 +1,23 @@
//! Data structures related to bans.
use std::time::{Duration, Instant};
use crate::NetZoneAddress;
/// Data within [`crate::services::AddressBookRequest::SetBan`].
pub struct SetBan<A: NetZoneAddress> {
/// Address of the peer.
pub address: A,
/// - If [`Some`], how long this peer should be banned for
/// - If [`None`], the peer will be unbanned
pub ban: Option<Duration>,
}
/// Data within [`crate::services::AddressBookResponse::GetBans`].
pub struct BanState<A: NetZoneAddress> {
/// Address of the peer.
pub address: A,
/// - If [`Some`], the peer is banned until this [`Instant`]
/// - If [`None`], the peer is not currently banned
pub unban_instant: Option<Instant>,
}

View file

@ -105,7 +105,15 @@ impl<N: NetworkZone> Service<AddressBookRequest<N>> for DummyAddressBook {
AddressBookRequest::NewConnection { .. } | AddressBookRequest::IncomingPeerList(_) => { AddressBookRequest::NewConnection { .. } | AddressBookRequest::IncomingPeerList(_) => {
AddressBookResponse::Ok AddressBookResponse::Ok
} }
AddressBookRequest::IsPeerBanned(_) => AddressBookResponse::IsPeerBanned(false), AddressBookRequest::GetBan(_) => AddressBookResponse::GetBan {
unban_instant: None,
},
AddressBookRequest::PeerlistSize
| AddressBookRequest::ConnectionCount
| AddressBookRequest::SetBan(_)
| AddressBookRequest::GetBans => {
todo!("finish https://github.com/Cuprate/cuprate/pull/297")
}
})) }))
} }
} }

View file

@ -75,6 +75,7 @@ use cuprate_wire::{
NetworkAddress, NetworkAddress,
}; };
pub mod ban;
pub mod client; pub mod client;
mod constants; mod constants;
pub mod error; pub mod error;

View file

@ -1,9 +1,13 @@
use std::time::Instant;
use cuprate_pruning::{PruningError, PruningSeed}; use cuprate_pruning::{PruningError, PruningSeed};
use cuprate_wire::{CoreSyncData, PeerListEntryBase}; use cuprate_wire::{CoreSyncData, PeerListEntryBase};
use crate::{ use crate::{
client::InternalPeerID, handles::ConnectionHandle, NetZoneAddress, NetworkAddressIncorrectZone, ban::{BanState, SetBan},
NetworkZone, client::InternalPeerID,
handles::ConnectionHandle,
NetZoneAddress, NetworkAddressIncorrectZone, NetworkZone,
}; };
/// A request to the core sync service for our node's [`CoreSyncData`]. /// A request to the core sync service for our node's [`CoreSyncData`].
@ -86,16 +90,20 @@ pub enum AddressBookRequest<Z: NetworkZone> {
/// The peers rpc credits per hash /// The peers rpc credits per hash
rpc_credits_per_hash: u32, rpc_credits_per_hash: u32,
}, },
/// Tells the address book about a peer list received from a peer. /// Tells the address book about a peer list received from a peer.
IncomingPeerList(Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>), IncomingPeerList(Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>),
/// Takes a random white peer from the peer list. If height is specified /// Takes a random white peer from the peer list. If height is specified
/// then the peer list should retrieve a peer that should have a full /// then the peer list should retrieve a peer that should have a full
/// block at that height according to it's pruning seed /// block at that height according to it's pruning seed
TakeRandomWhitePeer { height: Option<usize> }, TakeRandomWhitePeer { height: Option<usize> },
/// Takes a random gray peer from the peer list. If height is specified /// Takes a random gray peer from the peer list. If height is specified
/// then the peer list should retrieve a peer that should have a full /// then the peer list should retrieve a peer that should have a full
/// block at that height according to it's pruning seed /// block at that height according to it's pruning seed
TakeRandomGrayPeer { height: Option<usize> }, TakeRandomGrayPeer { height: Option<usize> },
/// Takes a random peer from the peer list. If height is specified /// Takes a random peer from the peer list. If height is specified
/// then the peer list should retrieve a peer that should have a full /// then the peer list should retrieve a peer that should have a full
/// block at that height according to it's pruning seed. /// block at that height according to it's pruning seed.
@ -103,17 +111,56 @@ pub enum AddressBookRequest<Z: NetworkZone> {
/// The address book will look in the white peer list first, then the gray /// The address book will look in the white peer list first, then the gray
/// one if no peer is found. /// one if no peer is found.
TakeRandomPeer { height: Option<usize> }, TakeRandomPeer { height: Option<usize> },
/// Gets the specified number of white peers, or less if we don't have enough. /// Gets the specified number of white peers, or less if we don't have enough.
GetWhitePeers(usize), GetWhitePeers(usize),
/// Get the amount of white & grey peers.
PeerlistSize,
/// Get the amount of incoming & outgoing connections.
ConnectionCount,
/// (Un)ban a peer.
SetBan(SetBan<Z::Addr>),
/// Checks if the given peer is banned. /// Checks if the given peer is banned.
IsPeerBanned(Z::Addr), GetBan(Z::Addr),
/// Get the state of all bans.
GetBans,
} }
/// A response from the address book service. /// A response from the address book service.
pub enum AddressBookResponse<Z: NetworkZone> { pub enum AddressBookResponse<Z: NetworkZone> {
/// Generic OK response.
///
/// Response to:
/// - [`AddressBookRequest::NewConnection`]
/// - [`AddressBookRequest::IncomingPeerList`]
Ok, Ok,
/// Response to:
/// - [`AddressBookRequest::TakeRandomWhitePeer`]
/// - [`AddressBookRequest::TakeRandomGrayPeer`]
/// - [`AddressBookRequest::TakeRandomPeer`]
Peer(ZoneSpecificPeerListEntryBase<Z::Addr>), Peer(ZoneSpecificPeerListEntryBase<Z::Addr>),
/// Response to [`AddressBookRequest::GetWhitePeers`].
Peers(Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>), Peers(Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>),
/// Contains `true` if the peer is banned.
IsPeerBanned(bool), /// Response to [`AddressBookRequest::PeerlistSize`].
PeerlistSize { white: usize, grey: usize },
/// Response to [`AddressBookRequest::ConnectionCount`].
ConnectionCount { incoming: usize, outgoing: usize },
/// Response to [`AddressBookRequest::GetBan`].
///
/// This returns [`None`] if the peer is not banned,
/// else it returns how long the peer is banned for.
GetBan { unban_instant: Option<Instant> },
/// Response to [`AddressBookRequest::GetBans`].
GetBans(Vec<BanState<Z::Addr>>),
} }

View file

@ -79,16 +79,16 @@ where
// If peer is banned, drop connection // If peer is banned, drop connection
if let Some(addr) = &addr { if let Some(addr) = &addr {
let AddressBookResponse::IsPeerBanned(banned) = address_book let AddressBookResponse::GetBan { unban_instant } = address_book
.ready() .ready()
.await? .await?
.call(AddressBookRequest::IsPeerBanned(*addr)) .call(AddressBookRequest::GetBan(*addr))
.await? .await?
else { else {
panic!("Address book returned incorrect response!"); panic!("Address book returned incorrect response!");
}; };
if banned { if unban_instant.is_some() {
continue; continue;
} }
} }

View file

@ -21,8 +21,8 @@
//! //!
//! The 2nd allows any caller to send [`WriteRequest`][req_w]s. //! The 2nd allows any caller to send [`WriteRequest`][req_w]s.
//! //!
//! The `DatabaseReadHandle` can be shared as it is cheaply [`Clone`]able, however, //! The [`BlockchainReadHandle`] can be shared as it is cheaply [`Clone`]able, however,
//! the `DatabaseWriteHandle` cannot be cloned. There is only 1 place in Cuprate that //! the [`BlockchainWriteHandle`] cannot be cloned. There is only 1 place in Cuprate that
//! writes, so it is passed there and used. //! writes, so it is passed there and used.
//! //!
//! ## Initialization //! ## Initialization

View file

@ -1,5 +1,13 @@
//! Database reader thread-pool definitions and logic. //! Database reader thread-pool definitions and logic.
#![expect(
unreachable_code,
unused_variables,
clippy::unnecessary_wraps,
clippy::needless_pass_by_value,
reason = "TODO: finish implementing the signatures from <https://github.com/Cuprate/cuprate/pull/297>"
)]
//---------------------------------------------------------------------------------------------------- Import //---------------------------------------------------------------------------------------------------- Import
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
@ -18,7 +26,7 @@ use cuprate_database_service::{init_thread_pool, DatabaseReadService, ReaderThre
use cuprate_helper::map::combine_low_high_bits_to_u128; use cuprate_helper::map::combine_low_high_bits_to_u128;
use cuprate_types::{ use cuprate_types::{
blockchain::{BlockchainReadRequest, BlockchainResponse}, blockchain::{BlockchainReadRequest, BlockchainResponse},
Chain, ChainId, ExtendedBlockHeader, OutputOnChain, Chain, ChainId, ExtendedBlockHeader, OutputHistogramInput, OutputOnChain,
}; };
use crate::{ use crate::{
@ -107,6 +115,12 @@ fn map_request(
R::CompactChainHistory => compact_chain_history(env), R::CompactChainHistory => compact_chain_history(env),
R::FindFirstUnknown(block_ids) => find_first_unknown(env, &block_ids), R::FindFirstUnknown(block_ids) => find_first_unknown(env, &block_ids),
R::AltBlocksInChain(chain_id) => alt_blocks_in_chain(env, chain_id), R::AltBlocksInChain(chain_id) => alt_blocks_in_chain(env, chain_id),
R::Block { height } => block(env, height),
R::BlockByHash(hash) => block_by_hash(env, hash),
R::TotalTxCount => total_tx_count(env),
R::DatabaseSize => database_size(env),
R::OutputHistogram(input) => output_histogram(env, input),
R::CoinbaseTxSum { height, count } => coinbase_tx_sum(env, height, count),
} }
/* SOMEDAY: post-request handling, run some code for each request? */ /* SOMEDAY: post-request handling, run some code for each request? */
@ -601,3 +615,36 @@ fn alt_blocks_in_chain(env: &ConcreteEnv, chain_id: ChainId) -> ResponseResult {
Ok(BlockchainResponse::AltBlocksInChain(blocks)) Ok(BlockchainResponse::AltBlocksInChain(blocks))
} }
/// [`BlockchainReadRequest::Block`]
fn block(env: &ConcreteEnv, block_height: BlockHeight) -> ResponseResult {
Ok(BlockchainResponse::Block(todo!()))
}
/// [`BlockchainReadRequest::BlockByHash`]
fn block_by_hash(env: &ConcreteEnv, block_hash: BlockHash) -> ResponseResult {
Ok(BlockchainResponse::Block(todo!()))
}
/// [`BlockchainReadRequest::TotalTxCount`]
fn total_tx_count(env: &ConcreteEnv) -> ResponseResult {
Ok(BlockchainResponse::TotalTxCount(todo!()))
}
/// [`BlockchainReadRequest::DatabaseSize`]
fn database_size(env: &ConcreteEnv) -> ResponseResult {
Ok(BlockchainResponse::DatabaseSize {
database_size: todo!(),
free_space: todo!(),
})
}
/// [`BlockchainReadRequest::OutputHistogram`]
fn output_histogram(env: &ConcreteEnv, input: OutputHistogramInput) -> ResponseResult {
Ok(BlockchainResponse::OutputHistogram(todo!()))
}
/// [`BlockchainReadRequest::CoinbaseTxSum`]
fn coinbase_tx_sum(env: &ConcreteEnv, height: usize, count: u64) -> ResponseResult {
Ok(BlockchainResponse::CoinbaseTxSum(todo!()))
}

View file

@ -10,10 +10,12 @@ pub mod ops;
#[cfg(feature = "service")] #[cfg(feature = "service")]
pub mod service; pub mod service;
pub mod tables; pub mod tables;
mod tx;
pub mod types; pub mod types;
pub use config::Config; pub use config::Config;
pub use free::open; pub use free::open;
pub use tx::TxEntry;
//re-exports //re-exports
pub use cuprate_database; pub use cuprate_database;

View file

@ -21,9 +21,7 @@
//! //!
//! The 2nd allows any caller to send [`WriteRequest`][req_w]s. //! The 2nd allows any caller to send [`WriteRequest`][req_w]s.
//! //!
//! The `DatabaseReadHandle` can be shared as it is cheaply [`Clone`]able, however, //! Both the handles are cheaply [`Clone`]able.
//! the `DatabaseWriteHandle` cannot be cloned. There is only 1 place in Cuprate that
//! writes, so it is passed there and used.
//! //!
//! ## Initialization //! ## Initialization
//! The database & thread-pool system can be initialized with [`init()`]. //! The database & thread-pool system can be initialized with [`init()`].

View file

@ -5,30 +5,53 @@ use std::sync::Arc;
use cuprate_types::TransactionVerificationData; use cuprate_types::TransactionVerificationData;
use crate::types::TransactionHash; use crate::{tx::TxEntry, types::TransactionHash};
//---------------------------------------------------------------------------------------------------- TxpoolReadRequest //---------------------------------------------------------------------------------------------------- TxpoolReadRequest
/// The transaction pool [`tower::Service`] read request type. /// The transaction pool [`tower::Service`] read request type.
pub enum TxpoolReadRequest { pub enum TxpoolReadRequest {
/// A request for the blob (raw bytes) of a transaction with the given hash. /// A request for the blob (raw bytes) of a transaction with the given hash.
TxBlob(TransactionHash), TxBlob(TransactionHash),
/// A request for the [`TransactionVerificationData`] of a transaction in the tx pool. /// A request for the [`TransactionVerificationData`] of a transaction in the tx pool.
TxVerificationData(TransactionHash), TxVerificationData(TransactionHash),
/// Get information on all transactions in the pool.
Backlog,
/// Get the number of transactions in the pool.
Size,
} }
//---------------------------------------------------------------------------------------------------- TxpoolReadResponse //---------------------------------------------------------------------------------------------------- TxpoolReadResponse
/// The transaction pool [`tower::Service`] read response type. /// The transaction pool [`tower::Service`] read response type.
#[expect(clippy::large_enum_variant)] #[expect(clippy::large_enum_variant)]
pub enum TxpoolReadResponse { pub enum TxpoolReadResponse {
/// A response containing the raw bytes of a transaction. /// Response to [`TxpoolReadRequest::TxBlob`].
///
/// The inner value is the raw bytes of a transaction.
// TODO: use bytes::Bytes. // TODO: use bytes::Bytes.
TxBlob(Vec<u8>), TxBlob(Vec<u8>),
/// A response of [`TransactionVerificationData`].
/// Response to [`TxpoolReadRequest::TxVerificationData`].
TxVerificationData(TransactionVerificationData), TxVerificationData(TransactionVerificationData),
/// Response to [`TxpoolReadRequest::Backlog`].
///
/// The inner `Vec` contains information on all
/// the transactions currently in the pool.
Backlog(Vec<TxEntry>),
/// Response to [`TxpoolReadRequest::Size`].
///
/// The inner value is the amount of
/// transactions currently in the pool.
Size(usize),
} }
//---------------------------------------------------------------------------------------------------- TxpoolWriteRequest //---------------------------------------------------------------------------------------------------- TxpoolWriteRequest
/// The transaction pool [`tower::Service`] write request type. /// The transaction pool [`tower::Service`] write request type.
#[derive(Clone)]
pub enum TxpoolWriteRequest { pub enum TxpoolWriteRequest {
/// Add a transaction to the pool. /// Add a transaction to the pool.
/// ///
@ -41,6 +64,7 @@ pub enum TxpoolWriteRequest {
/// [`true`] if this tx is in the stem state. /// [`true`] if this tx is in the stem state.
state_stem: bool, state_stem: bool,
}, },
/// Remove a transaction with the given hash from the pool. /// Remove a transaction with the given hash from the pool.
/// ///
/// Returns [`TxpoolWriteResponse::Ok`]. /// Returns [`TxpoolWriteResponse::Ok`].
@ -49,11 +73,14 @@ pub enum TxpoolWriteRequest {
//---------------------------------------------------------------------------------------------------- TxpoolWriteResponse //---------------------------------------------------------------------------------------------------- TxpoolWriteResponse
/// The transaction pool [`tower::Service`] write response type. /// The transaction pool [`tower::Service`] write response type.
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)] #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
pub enum TxpoolWriteResponse { pub enum TxpoolWriteResponse {
/// A [`TxpoolWriteRequest::AddTransaction`] response. /// Response to:
/// - [`TxpoolWriteRequest::RemoveTransaction`]
Ok,
/// Response to [`TxpoolWriteRequest::AddTransaction`].
/// ///
/// If the inner value is [`Some`] the tx was not added to the pool as it double spends a tx with the given hash. /// If the inner value is [`Some`] the tx was not added to the pool as it double spends a tx with the given hash.
AddTransaction(Option<TransactionHash>), AddTransaction(Option<TransactionHash>),
Ok,
} }

View file

@ -1,3 +1,10 @@
#![expect(
unreachable_code,
unused_variables,
clippy::unnecessary_wraps,
reason = "TODO: finish implementing the signatures from <https://github.com/Cuprate/cuprate/pull/297>"
)]
use std::sync::Arc; use std::sync::Arc;
use rayon::ThreadPool; use rayon::ThreadPool;
@ -58,6 +65,8 @@ fn map_request(
match request { match request {
TxpoolReadRequest::TxBlob(tx_hash) => tx_blob(env, &tx_hash), TxpoolReadRequest::TxBlob(tx_hash) => tx_blob(env, &tx_hash),
TxpoolReadRequest::TxVerificationData(tx_hash) => tx_verification_data(env, &tx_hash), TxpoolReadRequest::TxVerificationData(tx_hash) => tx_verification_data(env, &tx_hash),
TxpoolReadRequest::Backlog => backlog(env),
TxpoolReadRequest::Size => size(env),
} }
} }
@ -101,3 +110,15 @@ fn tx_verification_data(env: &ConcreteEnv, tx_hash: &TransactionHash) -> ReadRes
get_transaction_verification_data(tx_hash, &tables).map(TxpoolReadResponse::TxVerificationData) get_transaction_verification_data(tx_hash, &tables).map(TxpoolReadResponse::TxVerificationData)
} }
/// [`TxpoolReadRequest::Backlog`].
#[inline]
fn backlog(env: &ConcreteEnv) -> ReadResponseResult {
Ok(TxpoolReadResponse::Backlog(todo!()))
}
/// [`TxpoolReadRequest::Size`].
#[inline]
fn size(env: &ConcreteEnv) -> ReadResponseResult {
Ok(TxpoolReadResponse::Size(todo!()))
}

14
storage/txpool/src/tx.rs Normal file
View file

@ -0,0 +1,14 @@
//! Transaction metadata.
/// Data about a transaction in the pool.
///
/// Used in [`TxpoolReadResponse::Backlog`](crate::service::interface::TxpoolReadResponse::Backlog).
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct TxEntry {
/// The transaction's weight.
pub weight: u64,
/// The transaction's fee.
pub fee: u64,
/// How long the transaction has been in the pool.
pub time_in_pool: std::time::Duration,
}

View file

@ -8,9 +8,11 @@ use std::{
ops::Range, ops::Range,
}; };
use monero_serai::block::Block;
use crate::{ use crate::{
types::{Chain, ExtendedBlockHeader, OutputOnChain, VerifiedBlockInformation}, types::{Chain, ExtendedBlockHeader, OutputOnChain, VerifiedBlockInformation},
AltBlockInformation, ChainId, AltBlockInformation, ChainId, CoinbaseTxSum, OutputHistogramEntry, OutputHistogramInput,
}; };
//---------------------------------------------------------------------------------------------------- ReadRequest //---------------------------------------------------------------------------------------------------- ReadRequest
@ -103,6 +105,29 @@ pub enum BlockchainReadRequest {
/// A request for all alt blocks in the chain with the given [`ChainId`]. /// A request for all alt blocks in the chain with the given [`ChainId`].
AltBlocksInChain(ChainId), AltBlocksInChain(ChainId),
/// Get a [`Block`] by its height.
Block { height: usize },
/// Get a [`Block`] by its hash.
BlockByHash([u8; 32]),
/// Get the total amount of non-coinbase transactions in the chain.
TotalTxCount,
/// Get the current size of the database.
DatabaseSize,
/// Get an output histogram.
///
/// TODO: document fields after impl.
OutputHistogram(OutputHistogramInput),
/// Get the coinbase amount and the fees amount for
/// `N` last blocks starting at particular height.
///
/// TODO: document fields after impl.
CoinbaseTxSum { height: usize, count: u64 },
} }
//---------------------------------------------------------------------------------------------------- WriteRequest //---------------------------------------------------------------------------------------------------- WriteRequest
@ -147,6 +172,7 @@ pub enum BlockchainWriteRequest {
/// This pairs with [`BlockchainReadRequest`] and [`BlockchainWriteRequest`], /// This pairs with [`BlockchainReadRequest`] and [`BlockchainWriteRequest`],
/// see those two for more info. /// see those two for more info.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[expect(clippy::large_enum_variant)]
pub enum BlockchainResponse { pub enum BlockchainResponse {
//------------------------------------------------------ Reads //------------------------------------------------------ Reads
/// Response to [`BlockchainReadRequest::BlockExtendedHeader`]. /// Response to [`BlockchainReadRequest::BlockExtendedHeader`].
@ -215,18 +241,41 @@ pub enum BlockchainResponse {
cumulative_difficulty: u128, cumulative_difficulty: u128,
}, },
/// The response for [`BlockchainReadRequest::FindFirstUnknown`]. /// Response to [`BlockchainReadRequest::FindFirstUnknown`].
/// ///
/// Contains the index of the first unknown block and its expected height. /// Contains the index of the first unknown block and its expected height.
/// ///
/// This will be [`None`] if all blocks were known. /// This will be [`None`] if all blocks were known.
FindFirstUnknown(Option<(usize, usize)>), FindFirstUnknown(Option<(usize, usize)>),
/// The response for [`BlockchainReadRequest::AltBlocksInChain`]. /// Response to [`BlockchainReadRequest::AltBlocksInChain`].
/// ///
/// Contains all the alt blocks in the alt-chain in chronological order. /// Contains all the alt blocks in the alt-chain in chronological order.
AltBlocksInChain(Vec<AltBlockInformation>), AltBlocksInChain(Vec<AltBlockInformation>),
/// Response to:
/// - [`BlockchainReadRequest::Block`].
/// - [`BlockchainReadRequest::BlockByHash`].
Block(Block),
/// Response to [`BlockchainReadRequest::TotalTxCount`].
TotalTxCount(usize),
/// Response to [`BlockchainReadRequest::DatabaseSize`].
DatabaseSize {
/// The size of the database file in bytes.
database_size: u64,
/// The amount of free bytes there are
/// the disk where the database is located.
free_space: u64,
},
/// Response to [`BlockchainReadRequest::OutputHistogram`].
OutputHistogram(Vec<OutputHistogramEntry>),
/// Response to [`BlockchainReadRequest::CoinbaseTxSum`].
CoinbaseTxSum(CoinbaseTxSum),
//------------------------------------------------------ Writes //------------------------------------------------------ Writes
/// A generic Ok response to indicate a request was successfully handled. /// A generic Ok response to indicate a request was successfully handled.
/// ///
@ -236,7 +285,8 @@ pub enum BlockchainResponse {
/// - [`BlockchainWriteRequest::ReverseReorg`] /// - [`BlockchainWriteRequest::ReverseReorg`]
/// - [`BlockchainWriteRequest::FlushAltBlocks`] /// - [`BlockchainWriteRequest::FlushAltBlocks`]
Ok, Ok,
/// The response for [`BlockchainWriteRequest::PopBlocks`].
/// Response to [`BlockchainWriteRequest::PopBlocks`].
/// ///
/// The inner value is the alt-chain ID for the old main chain blocks. /// The inner value is the alt-chain ID for the old main chain blocks.
PopBlocks(ChainId), PopBlocks(ChainId),

View file

@ -20,8 +20,9 @@ pub use transaction_verification_data::{
CachedVerificationState, TransactionVerificationData, TxVersion, CachedVerificationState, TransactionVerificationData, TxVersion,
}; };
pub use types::{ pub use types::{
AltBlockInformation, Chain, ChainId, ExtendedBlockHeader, OutputOnChain, AltBlockInformation, Chain, ChainId, ChainInfo, CoinbaseTxSum, ExtendedBlockHeader,
VerifiedBlockInformation, VerifiedTransactionInformation, FeeEstimate, HardForkInfo, MinerData, MinerDataTxBacklogEntry, OutputHistogramEntry,
OutputHistogramInput, OutputOnChain, VerifiedBlockInformation, VerifiedTransactionInformation,
}; };
//---------------------------------------------------------------------------------------------------- Feature-gated //---------------------------------------------------------------------------------------------------- Feature-gated

View file

@ -1,6 +1,5 @@
//! Various shared data types in Cuprate. //! Various shared data types in Cuprate.
//---------------------------------------------------------------------------------------------------- Import
use std::num::NonZero; use std::num::NonZero;
use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::edwards::EdwardsPoint;
@ -11,7 +10,6 @@ use monero_serai::{
use crate::HardFork; use crate::HardFork;
//---------------------------------------------------------------------------------------------------- ExtendedBlockHeader
/// Extended header data of a block. /// Extended header data of a block.
/// ///
/// This contains various metadata of a block, but not the block blob itself. /// This contains various metadata of a block, but not the block blob itself.
@ -37,7 +35,6 @@ pub struct ExtendedBlockHeader {
pub long_term_weight: usize, pub long_term_weight: usize,
} }
//---------------------------------------------------------------------------------------------------- VerifiedTransactionInformation
/// Verified information of a transaction. /// Verified information of a transaction.
/// ///
/// This represents a valid transaction /// This represents a valid transaction
@ -61,7 +58,6 @@ pub struct VerifiedTransactionInformation {
pub tx_hash: [u8; 32], pub tx_hash: [u8; 32],
} }
//---------------------------------------------------------------------------------------------------- VerifiedBlockInformation
/// Verified information of a block. /// Verified information of a block.
/// ///
/// This represents a block that has already been verified to be correct. /// This represents a block that has already been verified to be correct.
@ -94,14 +90,12 @@ pub struct VerifiedBlockInformation {
pub cumulative_difficulty: u128, pub cumulative_difficulty: u128,
} }
//---------------------------------------------------------------------------------------------------- ChainID
/// A unique ID for an alt chain. /// A unique ID for an alt chain.
/// ///
/// The inner value is meaningless. /// The inner value is meaningless.
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct ChainId(pub NonZero<u64>); pub struct ChainId(pub NonZero<u64>);
//---------------------------------------------------------------------------------------------------- Chain
/// An identifier for a chain. /// An identifier for a chain.
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum Chain { pub enum Chain {
@ -111,7 +105,6 @@ pub enum Chain {
Alt(ChainId), Alt(ChainId),
} }
//---------------------------------------------------------------------------------------------------- AltBlockInformation
/// A block on an alternative chain. /// A block on an alternative chain.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct AltBlockInformation { pub struct AltBlockInformation {
@ -141,7 +134,6 @@ pub struct AltBlockInformation {
pub chain_id: ChainId, pub chain_id: ChainId,
} }
//---------------------------------------------------------------------------------------------------- OutputOnChain
/// An already existing transaction output. /// An already existing transaction output.
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct OutputOnChain { pub struct OutputOnChain {
@ -155,6 +147,104 @@ pub struct OutputOnChain {
pub commitment: EdwardsPoint, pub commitment: EdwardsPoint,
} }
/// Input required to generate an output histogram.
///
/// Used in RPC's `get_output_histogram`.
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OutputHistogramInput {
pub amounts: Vec<u64>,
pub min_count: u64,
pub max_count: u64,
pub unlocked: bool,
pub recent_cutoff: u64,
}
/// A single entry in an output histogram.
///
/// Used in RPC's `get_output_histogram`.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OutputHistogramEntry {
pub amount: u64,
pub total_instances: u64,
pub unlocked_instances: u64,
pub recent_instances: u64,
}
/// Data of summed coinbase transactions.
///
/// Used in RPC's `get_coinbase_tx_sum`.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CoinbaseTxSum {
pub emission_amount: u128,
pub fee_amount: u128,
pub wide_emission_amount: u128,
pub wide_fee_amount: u128,
}
/// Data to create a custom block template.
///
/// Used in RPC's `get_miner_data`.
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MinerData {
pub major_version: u8,
pub height: u64,
pub prev_id: [u8; 32],
pub seed_hash: [u8; 32],
pub difficulty: u128,
pub median_weight: u64,
pub already_generated_coins: u64,
pub tx_backlog: Vec<MinerDataTxBacklogEntry>,
}
/// A transaction in the txpool.
///
/// Used in [`MinerData::tx_backlog`].
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MinerDataTxBacklogEntry {
pub id: [u8; 32],
pub weight: u64,
pub fee: u64,
}
/// Information on a [`HardFork`].
///
/// Used in RPC's `hard_fork_info`.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct HardForkInfo {
pub earliest_height: u64,
pub enabled: bool,
pub state: u32,
pub threshold: u32,
pub version: u8,
pub votes: u32,
pub voting: u8,
pub window: u32,
}
/// Estimated fee data.
///
/// Used in RPC's `get_fee_estimate`.
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FeeEstimate {
pub fee: u64,
pub fees: Vec<u64>,
pub quantization_mask: u64,
}
/// Information on a (maybe alternate) chain.
///
/// Used in RPC's `get_alternate_chains`.
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChainInfo {
pub block_hash: [u8; 32],
pub block_hashes: Vec<[u8; 32]>,
pub difficulty: u128,
pub height: u64,
pub length: u64,
pub main_chain_parent_block: [u8; 32],
pub wide_difficulty: u128,
}
//---------------------------------------------------------------------------------------------------- Tests //---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)] #[cfg(test)]
mod test { mod test {