mirror of
https://github.com/hinto-janai/cuprate.git
synced 2025-01-22 02:34:29 +00:00
Merge branch 'main' into cuprated-txpool
This commit is contained in:
commit
e199b8c26d
43 changed files with 1474 additions and 190 deletions
23
Cargo.lock
generated
23
Cargo.lock
generated
|
@ -934,6 +934,7 @@ dependencies = [
|
|||
"proptest-derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
@ -2675,6 +2676,28 @@ dependencies = [
|
|||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
|
|
|
@ -79,6 +79,7 @@ serde_bytes = { version = "0.11.15", default-features = false }
|
|||
serde_json = { version = "1.0.128", default-features = false }
|
||||
serde = { version = "1.0.210", default-features = false }
|
||||
sha3 = { version = "0.10.8", default-features = false }
|
||||
strum = { version = "0.26.3", default-features = false }
|
||||
thiserror = { version = "1.0.63", default-features = false }
|
||||
thread_local = { version = "1.1.8", default-features = false }
|
||||
tokio-util = { version = "0.7.12", default-features = false }
|
||||
|
|
|
@ -71,7 +71,7 @@ pub async fn init_blockchain_manager(
|
|||
.ready()
|
||||
.await
|
||||
.expect(PANIC_CRITICAL_SERVICE_ERROR)
|
||||
.call(BlockChainContextRequest::GetContext)
|
||||
.call(BlockChainContextRequest::Context)
|
||||
.await
|
||||
.expect(PANIC_CRITICAL_SERVICE_ERROR)
|
||||
else {
|
||||
|
|
|
@ -479,7 +479,7 @@ impl super::BlockchainManager {
|
|||
.ready()
|
||||
.await
|
||||
.expect(PANIC_CRITICAL_SERVICE_ERROR)
|
||||
.call(BlockChainContextRequest::GetContext)
|
||||
.call(BlockChainContextRequest::Context)
|
||||
.await
|
||||
.expect(PANIC_CRITICAL_SERVICE_ERROR)
|
||||
else {
|
||||
|
|
|
@ -62,7 +62,7 @@ where
|
|||
let BlockChainContextResponse::Context(mut blockchain_ctx) = context_svc
|
||||
.ready()
|
||||
.await?
|
||||
.call(BlockChainContextRequest::GetContext)
|
||||
.call(BlockChainContextRequest::Context)
|
||||
.await?
|
||||
else {
|
||||
unreachable!();
|
||||
|
@ -131,7 +131,7 @@ where
|
|||
}
|
||||
|
||||
let BlockChainContextResponse::Context(ctx) = context_svc
|
||||
.oneshot(BlockChainContextRequest::GetContext)
|
||||
.oneshot(BlockChainContextRequest::Context)
|
||||
.await?
|
||||
else {
|
||||
unreachable!();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#![allow(
|
||||
unused_imports,
|
||||
unreachable_pub,
|
||||
unreachable_code,
|
||||
unused_crate_dependencies,
|
||||
dead_code,
|
||||
unused_variables,
|
||||
|
|
|
@ -6,5 +6,6 @@ mod bin;
|
|||
mod handler;
|
||||
mod json;
|
||||
mod other;
|
||||
mod request;
|
||||
|
||||
pub use handler::{CupratedRpcHandler, CupratedRpcHandlerState};
|
||||
pub use handler::CupratedRpcHandler;
|
||||
|
|
|
@ -10,11 +10,11 @@ use cuprate_rpc_types::{
|
|||
json::{GetOutputDistributionRequest, GetOutputDistributionResponse},
|
||||
};
|
||||
|
||||
use crate::rpc::CupratedRpcHandlerState;
|
||||
use crate::rpc::CupratedRpcHandler;
|
||||
|
||||
/// Map a [`BinRequest`] to the function that will lead to a [`BinResponse`].
|
||||
pub(super) async fn map_request(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: BinRequest,
|
||||
) -> Result<BinResponse, Error> {
|
||||
use BinRequest as Req;
|
||||
|
@ -36,49 +36,49 @@ pub(super) async fn map_request(
|
|||
}
|
||||
|
||||
async fn get_blocks(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetBlocksRequest,
|
||||
) -> Result<GetBlocksResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_blocks_by_height(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetBlocksByHeightRequest,
|
||||
) -> Result<GetBlocksByHeightResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_hashes(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetHashesRequest,
|
||||
) -> Result<GetHashesResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_output_indexes(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetOutputIndexesRequest,
|
||||
) -> Result<GetOutputIndexesResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_outs(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetOutsRequest,
|
||||
) -> Result<GetOutsResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_transaction_pool_hashes(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetTransactionPoolHashesRequest,
|
||||
) -> Result<GetTransactionPoolHashesResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_output_distribution(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetOutputDistributionRequest,
|
||||
) -> Result<GetOutputDistributionResponse, Error> {
|
||||
todo!()
|
||||
|
|
|
@ -3,51 +3,131 @@
|
|||
use std::task::{Context, Poll};
|
||||
|
||||
use anyhow::Error;
|
||||
use futures::{channel::oneshot::channel, future::BoxFuture};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use futures::future::BoxFuture;
|
||||
use monero_serai::block::Block;
|
||||
use tower::Service;
|
||||
|
||||
use cuprate_blockchain::service::BlockchainReadHandle;
|
||||
use cuprate_helper::asynch::InfallibleOneshotReceiver;
|
||||
use cuprate_json_rpc::Id;
|
||||
use cuprate_blockchain::service::{BlockchainReadHandle, BlockchainWriteHandle};
|
||||
use cuprate_rpc_interface::RpcHandler;
|
||||
use cuprate_rpc_types::{
|
||||
bin::{BinRequest, BinResponse},
|
||||
json::{JsonRpcRequest, JsonRpcResponse},
|
||||
other::{OtherRequest, OtherResponse},
|
||||
};
|
||||
use cuprate_txpool::service::TxpoolReadHandle;
|
||||
use cuprate_txpool::service::{TxpoolReadHandle, TxpoolWriteHandle};
|
||||
|
||||
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
|
||||
#[derive(Clone)]
|
||||
pub struct CupratedRpcHandler {
|
||||
/// Should this RPC server be [restricted](RpcHandler::restricted)?
|
||||
//
|
||||
// INVARIANT:
|
||||
// We don't need to include this in `state` and check for
|
||||
// `self.is_restricted()` because `cuprate-rpc-interface` handles that.
|
||||
pub restricted: bool,
|
||||
///
|
||||
/// This is not `pub` on purpose, as it should not be mutated after [`Self::new`].
|
||||
restricted: bool,
|
||||
|
||||
/// State needed for request -> response mapping.
|
||||
pub state: CupratedRpcHandlerState,
|
||||
}
|
||||
|
||||
/// TODO
|
||||
#[derive(Clone)]
|
||||
pub struct CupratedRpcHandlerState {
|
||||
/// 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.
|
||||
pub txpool: TxpoolReadHandle,
|
||||
pub txpool_read: TxpoolReadHandle,
|
||||
|
||||
/// TODO: handle to txpool service.
|
||||
pub txpool_manager: std::convert::Infallible,
|
||||
}
|
||||
|
||||
impl CupratedRpcHandler {
|
||||
/// TODO
|
||||
pub fn init() {
|
||||
todo!()
|
||||
/// Create a new [`Self`].
|
||||
pub const fn new(
|
||||
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 {
|
||||
let state = CupratedRpcHandlerState::clone(&self.state);
|
||||
let state = self.clone();
|
||||
Box::pin(json::map_request(state, request))
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +162,7 @@ impl Service<BinRequest> for CupratedRpcHandler {
|
|||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +177,7 @@ impl Service<OtherRequest> for CupratedRpcHandler {
|
|||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ use cuprate_rpc_types::json::{
|
|||
SyncInfoRequest, SyncInfoResponse,
|
||||
};
|
||||
|
||||
use crate::rpc::CupratedRpcHandlerState;
|
||||
use crate::rpc::CupratedRpcHandler;
|
||||
|
||||
/// Map a [`JsonRpcRequest`] to the function that will lead to a [`JsonRpcResponse`].
|
||||
pub(super) async fn map_request(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: JsonRpcRequest,
|
||||
) -> Result<JsonRpcResponse, Error> {
|
||||
use JsonRpcRequest as Req;
|
||||
|
@ -84,210 +84,210 @@ pub(super) async fn map_request(
|
|||
}
|
||||
|
||||
async fn get_block_count(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetBlockCountRequest,
|
||||
) -> Result<GetBlockCountResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn on_get_block_hash(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: OnGetBlockHashRequest,
|
||||
) -> Result<OnGetBlockHashResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn submit_block(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: SubmitBlockRequest,
|
||||
) -> Result<SubmitBlockResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn generate_blocks(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GenerateBlocksRequest,
|
||||
) -> Result<GenerateBlocksResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_last_block_header(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetLastBlockHeaderRequest,
|
||||
) -> Result<GetLastBlockHeaderResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_block_header_by_hash(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetBlockHeaderByHashRequest,
|
||||
) -> Result<GetBlockHeaderByHashResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_block_header_by_height(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetBlockHeaderByHeightRequest,
|
||||
) -> Result<GetBlockHeaderByHeightResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_block_headers_range(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetBlockHeadersRangeRequest,
|
||||
) -> Result<GetBlockHeadersRangeResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_block(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetBlockRequest,
|
||||
) -> Result<GetBlockResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_connections(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetConnectionsRequest,
|
||||
) -> Result<GetConnectionsResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_info(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetInfoRequest,
|
||||
) -> Result<GetInfoResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn hard_fork_info(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: HardForkInfoRequest,
|
||||
) -> Result<HardForkInfoResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn set_bans(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: SetBansRequest,
|
||||
) -> Result<SetBansResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_bans(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetBansRequest,
|
||||
) -> Result<GetBansResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn banned(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: BannedRequest,
|
||||
) -> Result<BannedResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn flush_transaction_pool(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: FlushTransactionPoolRequest,
|
||||
) -> Result<FlushTransactionPoolResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_output_histogram(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetOutputHistogramRequest,
|
||||
) -> Result<GetOutputHistogramResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_coinbase_tx_sum(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetCoinbaseTxSumRequest,
|
||||
) -> Result<GetCoinbaseTxSumResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_version(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetVersionRequest,
|
||||
) -> Result<GetVersionResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_fee_estimate(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetFeeEstimateRequest,
|
||||
) -> Result<GetFeeEstimateResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_alternate_chains(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetAlternateChainsRequest,
|
||||
) -> Result<GetAlternateChainsResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn relay_tx(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: RelayTxRequest,
|
||||
) -> Result<RelayTxResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn sync_info(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: SyncInfoRequest,
|
||||
) -> Result<SyncInfoResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_transaction_pool_backlog(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetTransactionPoolBacklogRequest,
|
||||
) -> Result<GetTransactionPoolBacklogResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_miner_data(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetMinerDataRequest,
|
||||
) -> Result<GetMinerDataResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn prune_blockchain(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: PruneBlockchainRequest,
|
||||
) -> Result<PruneBlockchainResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn calc_pow(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: CalcPowRequest,
|
||||
) -> Result<CalcPowResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn flush_cache(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: FlushCacheRequest,
|
||||
) -> Result<FlushCacheResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn add_aux_pow(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: AddAuxPowRequest,
|
||||
) -> Result<AddAuxPowResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_tx_ids_loose(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetTxIdsLooseRequest,
|
||||
) -> Result<GetTxIdsLooseResponse, Error> {
|
||||
todo!()
|
||||
|
|
|
@ -17,11 +17,11 @@ use cuprate_rpc_types::other::{
|
|||
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`].
|
||||
pub(super) async fn map_request(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: OtherRequest,
|
||||
) -> Result<OtherResponse, Error> {
|
||||
use OtherRequest as Req;
|
||||
|
@ -71,189 +71,189 @@ pub(super) async fn map_request(
|
|||
}
|
||||
|
||||
async fn get_height(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetHeightRequest,
|
||||
) -> Result<GetHeightResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_transactions(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetTransactionsRequest,
|
||||
) -> Result<GetTransactionsResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_alt_blocks_hashes(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetAltBlocksHashesRequest,
|
||||
) -> Result<GetAltBlocksHashesResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn is_key_image_spent(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: IsKeyImageSpentRequest,
|
||||
) -> Result<IsKeyImageSpentResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn send_raw_transaction(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: SendRawTransactionRequest,
|
||||
) -> Result<SendRawTransactionResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn start_mining(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: StartMiningRequest,
|
||||
) -> Result<StartMiningResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn stop_mining(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: StopMiningRequest,
|
||||
) -> Result<StopMiningResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn mining_status(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: MiningStatusRequest,
|
||||
) -> Result<MiningStatusResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn save_bc(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: SaveBcRequest,
|
||||
) -> Result<SaveBcResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_peer_list(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetPeerListRequest,
|
||||
) -> Result<GetPeerListResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn set_log_hash_rate(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: SetLogHashRateRequest,
|
||||
) -> Result<SetLogHashRateResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn set_log_level(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: SetLogLevelRequest,
|
||||
) -> Result<SetLogLevelResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn set_log_categories(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: SetLogCategoriesRequest,
|
||||
) -> Result<SetLogCategoriesResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn set_bootstrap_daemon(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: SetBootstrapDaemonRequest,
|
||||
) -> Result<SetBootstrapDaemonResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_transaction_pool(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetTransactionPoolRequest,
|
||||
) -> Result<GetTransactionPoolResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_transaction_pool_stats(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetTransactionPoolStatsRequest,
|
||||
) -> Result<GetTransactionPoolStatsResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn stop_daemon(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: StopDaemonRequest,
|
||||
) -> Result<StopDaemonResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_limit(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetLimitRequest,
|
||||
) -> Result<GetLimitResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn set_limit(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: SetLimitRequest,
|
||||
) -> Result<SetLimitResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn out_peers(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: OutPeersRequest,
|
||||
) -> Result<OutPeersResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn in_peers(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: InPeersRequest,
|
||||
) -> Result<InPeersResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_net_stats(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetNetStatsRequest,
|
||||
) -> Result<GetNetStatsResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_outs(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetOutsRequest,
|
||||
) -> Result<GetOutsResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn update(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: UpdateRequest,
|
||||
) -> Result<UpdateResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn pop_blocks(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: PopBlocksRequest,
|
||||
) -> Result<PopBlocksResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_transaction_pool_hashes(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetTransactionPoolHashesRequest,
|
||||
) -> Result<GetTransactionPoolHashesResponse, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_public_nodes(
|
||||
state: CupratedRpcHandlerState,
|
||||
state: CupratedRpcHandler,
|
||||
request: GetPublicNodesRequest,
|
||||
) -> Result<GetPublicNodesResponse, Error> {
|
||||
todo!()
|
||||
|
|
19
binaries/cuprated/src/rpc/request.rs
Normal file
19
binaries/cuprated/src/rpc/request.rs
Normal 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;
|
104
binaries/cuprated/src/rpc/request/address_book.rs
Normal file
104
binaries/cuprated/src/rpc/request/address_book.rs
Normal 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!())
|
||||
}
|
308
binaries/cuprated/src/rpc/request/blockchain.rs
Normal file
308
binaries/cuprated/src/rpc/request/blockchain.rs
Normal 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)
|
||||
}
|
69
binaries/cuprated/src/rpc/request/blockchain_context.rs
Normal file
69
binaries/cuprated/src/rpc/request/blockchain_context.rs
Normal 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)
|
||||
}
|
141
binaries/cuprated/src/rpc/request/blockchain_manager.rs
Normal file
141
binaries/cuprated/src/rpc/request/blockchain_manager.rs
Normal 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))
|
||||
}
|
57
binaries/cuprated/src/rpc/request/txpool.rs
Normal file
57
binaries/cuprated/src/rpc/request/txpool.rs
Normal 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(())
|
||||
}
|
|
@ -230,7 +230,7 @@ where
|
|||
let BlockChainContextResponse::Context(checked_context) = context_svc
|
||||
.ready()
|
||||
.await?
|
||||
.call(BlockChainContextRequest::GetContext)
|
||||
.call(BlockChainContextRequest::Context)
|
||||
.await?
|
||||
else {
|
||||
panic!("Context service returned wrong response!");
|
||||
|
|
|
@ -351,7 +351,7 @@ where
|
|||
let BlockChainContextResponse::Context(checked_context) = context_svc
|
||||
.ready()
|
||||
.await?
|
||||
.call(BlockChainContextRequest::GetContext)
|
||||
.call(BlockChainContextRequest::Context)
|
||||
.await?
|
||||
else {
|
||||
panic!("Context service returned wrong response!");
|
||||
|
@ -374,7 +374,7 @@ where
|
|||
let BlockChainContextResponse::RxVms(rx_vms) = context_svc
|
||||
.ready()
|
||||
.await?
|
||||
.call(BlockChainContextRequest::GetCurrentRxVm)
|
||||
.call(BlockChainContextRequest::CurrentRxVms)
|
||||
.await?
|
||||
else {
|
||||
panic!("Blockchain context service returned wrong response!");
|
||||
|
@ -433,7 +433,7 @@ where
|
|||
context
|
||||
} else {
|
||||
let BlockChainContextResponse::Context(checked_context) = context_svc
|
||||
.oneshot(BlockChainContextRequest::GetContext)
|
||||
.oneshot(BlockChainContextRequest::Context)
|
||||
.await?
|
||||
else {
|
||||
panic!("Context service returned wrong response!");
|
||||
|
|
|
@ -93,7 +93,7 @@ where
|
|||
let BlockChainContextResponse::Context(checked_context) = context_svc
|
||||
.ready()
|
||||
.await?
|
||||
.call(BlockChainContextRequest::GetContext)
|
||||
.call(BlockChainContextRequest::Context)
|
||||
.await?
|
||||
else {
|
||||
panic!("Context service returned wrong response!");
|
||||
|
@ -136,7 +136,7 @@ where
|
|||
let BlockChainContextResponse::RxVms(rx_vms) = context_svc
|
||||
.ready()
|
||||
.await?
|
||||
.call(BlockChainContextRequest::GetCurrentRxVm)
|
||||
.call(BlockChainContextRequest::CurrentRxVms)
|
||||
.await?
|
||||
else {
|
||||
panic!("Blockchain context service returned wrong response!");
|
||||
|
|
|
@ -31,7 +31,7 @@ mod alt_chains;
|
|||
mod task;
|
||||
mod tokens;
|
||||
|
||||
use cuprate_types::Chain;
|
||||
use cuprate_types::{Chain, ChainInfo, FeeEstimate, HardForkInfo};
|
||||
use difficulty::DifficultyCache;
|
||||
use rx_vms::RandomXVm;
|
||||
use weight::BlockWeightsCache;
|
||||
|
@ -221,15 +221,18 @@ pub struct NewBlockData {
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum BlockChainContextRequest {
|
||||
/// Get the current blockchain context.
|
||||
GetContext,
|
||||
/// Gets the current `RandomX` VM.
|
||||
GetCurrentRxVm,
|
||||
Context,
|
||||
|
||||
/// Gets all the current `RandomX` VMs.
|
||||
CurrentRxVms,
|
||||
|
||||
/// Get the next difficulties for these blocks.
|
||||
///
|
||||
/// Inputs: a list of block timestamps and hfs
|
||||
///
|
||||
/// The number of difficulties returned will be one more than the number of timestamps/ hfs.
|
||||
BatchGetDifficulties(Vec<(u64, HardFork)>),
|
||||
|
||||
/// 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,
|
||||
/// 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.
|
||||
NewRXVM(([u8; 32], Arc<RandomXVm>)),
|
||||
|
||||
/// A request to add a new block to the cache.
|
||||
Update(NewBlockData),
|
||||
|
||||
/// Pop blocks from the cache to the specified height.
|
||||
PopBlocks {
|
||||
/// 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.
|
||||
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.
|
||||
ClearAltCache,
|
||||
|
||||
/// Get information on all the current alternate chains.
|
||||
AltChains,
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------- AltChainRequests
|
||||
/// 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.
|
||||
_token: AltChainRequestToken,
|
||||
},
|
||||
|
||||
/// 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
|
||||
|
@ -271,6 +291,7 @@ pub enum BlockChainContextRequest {
|
|||
/// An internal token to prevent external crates calling this request.
|
||||
_token: AltChainRequestToken,
|
||||
},
|
||||
|
||||
/// 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
|
||||
|
@ -281,6 +302,7 @@ pub enum BlockChainContextRequest {
|
|||
/// An internal token to prevent external crates calling this request.
|
||||
_token: AltChainRequestToken,
|
||||
},
|
||||
|
||||
/// A request for a RX VM for an alternative chin.
|
||||
///
|
||||
/// Response variant: [`BlockChainContextResponse::AltChainRxVM`].
|
||||
|
@ -295,6 +317,7 @@ pub enum BlockChainContextRequest {
|
|||
/// An internal token to prevent external crates calling this request.
|
||||
_token: AltChainRequestToken,
|
||||
},
|
||||
|
||||
/// 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
|
||||
|
@ -310,22 +333,49 @@ pub enum BlockChainContextRequest {
|
|||
}
|
||||
|
||||
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),
|
||||
|
||||
/// Response to [`BlockChainContextRequest::CurrentRxVms`]
|
||||
///
|
||||
/// A map of seed height to `RandomX` VMs.
|
||||
RxVms(HashMap<usize, Arc<RandomXVm>>),
|
||||
|
||||
/// A list of difficulties.
|
||||
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.
|
||||
AltChainContextCache(Box<AltChainContextCache>),
|
||||
|
||||
/// A difficulty cache for an alt chain.
|
||||
AltChainDifficultyCache(DifficultyCache),
|
||||
|
||||
/// A randomX VM for an alt chain.
|
||||
AltChainRxVM(Arc<RandomXVm>),
|
||||
|
||||
/// A weight cache for an alt chain
|
||||
AltChainWeightCache(BlockWeightsCache),
|
||||
/// A generic Ok response.
|
||||
Ok,
|
||||
}
|
||||
|
||||
/// The blockchain context service.
|
||||
|
|
|
@ -153,7 +153,7 @@ impl<D: Database + Clone + Send + 'static> ContextTask<D> {
|
|||
req: BlockChainContextRequest,
|
||||
) -> Result<BlockChainContextResponse, tower::BoxError> {
|
||||
Ok(match req {
|
||||
BlockChainContextRequest::GetContext => {
|
||||
BlockChainContextRequest::Context => {
|
||||
tracing::debug!("Getting blockchain context");
|
||||
|
||||
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)
|
||||
}
|
||||
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);
|
||||
BlockChainContextResponse::Ok
|
||||
}
|
||||
BlockChainContextRequest::HardForkInfo(_)
|
||||
| BlockChainContextRequest::FeeEstimate { .. }
|
||||
| BlockChainContextRequest::AltChains => {
|
||||
todo!("finish https://github.com/Cuprate/cuprate/pull/297")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ async fn context_invalidated_on_new_block() -> Result<(), tower::BoxError> {
|
|||
|
||||
let BlockChainContextResponse::Context(context) = ctx_svc
|
||||
.clone()
|
||||
.oneshot(BlockChainContextRequest::GetContext)
|
||||
.oneshot(BlockChainContextRequest::Context)
|
||||
.await?
|
||||
else {
|
||||
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 BlockChainContextResponse::Context(context) = ctx_svc
|
||||
.oneshot(BlockChainContextRequest::GetContext)
|
||||
.await?
|
||||
let BlockChainContextResponse::Context(context) =
|
||||
ctx_svc.oneshot(BlockChainContextRequest::Context).await?
|
||||
else {
|
||||
panic!("context service returned incorrect response!")
|
||||
};
|
||||
|
|
|
@ -229,6 +229,15 @@ impl<Z: BorshNetworkZone> AddressBook<Z> {
|
|||
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(
|
||||
&mut self,
|
||||
mut peer_list: Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>,
|
||||
|
@ -408,9 +417,15 @@ impl<Z: BorshNetworkZone> Service<AddressBookRequest<Z>> for AddressBook<Z> {
|
|||
AddressBookRequest::GetWhitePeers(len) => {
|
||||
Ok(AddressBookResponse::Peers(self.get_white_peers(len)))
|
||||
}
|
||||
AddressBookRequest::IsPeerBanned(addr) => Ok(AddressBookResponse::IsPeerBanned(
|
||||
self.is_peer_banned(&addr),
|
||||
)),
|
||||
AddressBookRequest::GetBan(addr) => Ok(AddressBookResponse::GetBan {
|
||||
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)
|
||||
|
|
23
p2p/p2p-core/src/ban.rs
Normal file
23
p2p/p2p-core/src/ban.rs
Normal 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>,
|
||||
}
|
|
@ -105,7 +105,15 @@ impl<N: NetworkZone> Service<AddressBookRequest<N>> for DummyAddressBook {
|
|||
AddressBookRequest::NewConnection { .. } | AddressBookRequest::IncomingPeerList(_) => {
|
||||
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")
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ use cuprate_wire::{
|
|||
NetworkAddress,
|
||||
};
|
||||
|
||||
pub mod ban;
|
||||
pub mod client;
|
||||
mod constants;
|
||||
pub mod error;
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
use std::time::Instant;
|
||||
|
||||
use cuprate_pruning::{PruningError, PruningSeed};
|
||||
use cuprate_wire::{CoreSyncData, PeerListEntryBase};
|
||||
|
||||
use crate::{
|
||||
client::InternalPeerID, handles::ConnectionHandle, NetZoneAddress, NetworkAddressIncorrectZone,
|
||||
NetworkZone,
|
||||
ban::{BanState, SetBan},
|
||||
client::InternalPeerID,
|
||||
handles::ConnectionHandle,
|
||||
NetZoneAddress, NetworkAddressIncorrectZone, NetworkZone,
|
||||
};
|
||||
|
||||
/// 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
|
||||
rpc_credits_per_hash: u32,
|
||||
},
|
||||
|
||||
/// Tells the address book about a peer list received from a peer.
|
||||
IncomingPeerList(Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>),
|
||||
|
||||
/// 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
|
||||
/// block at that height according to it's pruning seed
|
||||
TakeRandomWhitePeer { height: Option<usize> },
|
||||
|
||||
/// 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
|
||||
/// block at that height according to it's pruning seed
|
||||
TakeRandomGrayPeer { height: Option<usize> },
|
||||
|
||||
/// 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
|
||||
/// 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
|
||||
/// one if no peer is found.
|
||||
TakeRandomPeer { height: Option<usize> },
|
||||
|
||||
/// Gets the specified number of white peers, or less if we don't have enough.
|
||||
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.
|
||||
IsPeerBanned(Z::Addr),
|
||||
GetBan(Z::Addr),
|
||||
|
||||
/// Get the state of all bans.
|
||||
GetBans,
|
||||
}
|
||||
|
||||
/// A response from the address book service.
|
||||
pub enum AddressBookResponse<Z: NetworkZone> {
|
||||
/// Generic OK response.
|
||||
///
|
||||
/// Response to:
|
||||
/// - [`AddressBookRequest::NewConnection`]
|
||||
/// - [`AddressBookRequest::IncomingPeerList`]
|
||||
Ok,
|
||||
|
||||
/// Response to:
|
||||
/// - [`AddressBookRequest::TakeRandomWhitePeer`]
|
||||
/// - [`AddressBookRequest::TakeRandomGrayPeer`]
|
||||
/// - [`AddressBookRequest::TakeRandomPeer`]
|
||||
Peer(ZoneSpecificPeerListEntryBase<Z::Addr>),
|
||||
|
||||
/// Response to [`AddressBookRequest::GetWhitePeers`].
|
||||
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>>),
|
||||
}
|
||||
|
|
|
@ -79,16 +79,16 @@ where
|
|||
|
||||
// If peer is banned, drop connection
|
||||
if let Some(addr) = &addr {
|
||||
let AddressBookResponse::IsPeerBanned(banned) = address_book
|
||||
let AddressBookResponse::GetBan { unban_instant } = address_book
|
||||
.ready()
|
||||
.await?
|
||||
.call(AddressBookRequest::IsPeerBanned(*addr))
|
||||
.call(AddressBookRequest::GetBan(*addr))
|
||||
.await?
|
||||
else {
|
||||
panic!("Address book returned incorrect response!");
|
||||
};
|
||||
|
||||
if banned {
|
||||
if unban_instant.is_some() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -817,8 +817,17 @@ define_request_and_response! {
|
|||
hard_fork_info,
|
||||
cc73fe71162d564ffda8e549b79a350bca53c454 =>
|
||||
core_rpc_server_commands_defs.h => 1958..=1995,
|
||||
HardForkInfo (empty),
|
||||
Request {},
|
||||
HardForkInfo,
|
||||
|
||||
#[doc = serde_doc_test!(
|
||||
HARD_FORK_INFO_REQUEST => HardForkInfoRequest {
|
||||
version: 16,
|
||||
}
|
||||
)]
|
||||
#[derive(Copy)]
|
||||
Request {
|
||||
version: u8,
|
||||
},
|
||||
|
||||
#[doc = serde_doc_test!(
|
||||
HARD_FORK_INFO_RESPONSE => HardForkInfoResponse {
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
//!
|
||||
//! The 2nd allows any caller to send [`WriteRequest`][req_w]s.
|
||||
//!
|
||||
//! The `DatabaseReadHandle` can be shared as it is cheaply [`Clone`]able, however,
|
||||
//! the `DatabaseWriteHandle` cannot be cloned. There is only 1 place in Cuprate that
|
||||
//! The [`BlockchainReadHandle`] can be shared as it is cheaply [`Clone`]able, however,
|
||||
//! the [`BlockchainWriteHandle`] cannot be cloned. There is only 1 place in Cuprate that
|
||||
//! writes, so it is passed there and used.
|
||||
//!
|
||||
//! ## Initialization
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
//! 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
|
||||
use std::{
|
||||
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_types::{
|
||||
blockchain::{BlockchainReadRequest, BlockchainResponse},
|
||||
Chain, ChainId, ExtendedBlockHeader, OutputOnChain,
|
||||
Chain, ChainId, ExtendedBlockHeader, OutputHistogramInput, OutputOnChain,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -107,6 +115,12 @@ fn map_request(
|
|||
R::CompactChainHistory => compact_chain_history(env),
|
||||
R::FindFirstUnknown(block_ids) => find_first_unknown(env, &block_ids),
|
||||
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? */
|
||||
|
@ -601,3 +615,36 @@ fn alt_blocks_in_chain(env: &ConcreteEnv, chain_id: ChainId) -> ResponseResult {
|
|||
|
||||
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!()))
|
||||
}
|
||||
|
|
|
@ -10,10 +10,12 @@ pub mod ops;
|
|||
#[cfg(feature = "service")]
|
||||
pub mod service;
|
||||
pub mod tables;
|
||||
mod tx;
|
||||
pub mod types;
|
||||
|
||||
pub use config::Config;
|
||||
pub use free::{open, transaction_blob_hash};
|
||||
pub use tx::TxEntry;
|
||||
|
||||
//re-exports
|
||||
pub use cuprate_database;
|
||||
|
|
|
@ -21,9 +21,7 @@
|
|||
//!
|
||||
//! The 2nd allows any caller to send [`WriteRequest`][req_w]s.
|
||||
//!
|
||||
//! The `DatabaseReadHandle` can be shared as it is cheaply [`Clone`]able, however,
|
||||
//! the `DatabaseWriteHandle` cannot be cloned. There is only 1 place in Cuprate that
|
||||
//! writes, so it is passed there and used.
|
||||
//! Both the handles are cheaply [`Clone`]able.
|
||||
//!
|
||||
//! ## Initialization
|
||||
//! The database & thread-pool system can be initialized with [`init()`].
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
|||
|
||||
use cuprate_types::TransactionVerificationData;
|
||||
|
||||
use crate::types::{KeyImage, TransactionBlobHash, TransactionHash};
|
||||
use crate::{tx::TxEntry, types::{KeyImage, TransactionBlobHash, TransactionHash}};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- TxpoolReadRequest
|
||||
/// The transaction pool [`tower::Service`] read request type.
|
||||
|
@ -16,14 +16,23 @@ use crate::types::{KeyImage, TransactionBlobHash, TransactionHash};
|
|||
pub enum TxpoolReadRequest {
|
||||
/// A request for the blob (raw bytes) of a transaction with the given hash.
|
||||
TxBlob(TransactionHash),
|
||||
|
||||
/// A request for the [`TransactionVerificationData`] of a transaction in the tx pool.
|
||||
TxVerificationData(TransactionHash),
|
||||
|
||||
/// A request to filter (remove) all **known** transactions from the set.
|
||||
///
|
||||
/// The hash is **not** the transaction hash, it is the hash of the serialized tx-blob.
|
||||
FilterKnownTxBlobHashes(HashSet<TransactionBlobHash>),
|
||||
|
||||
/// A request to pull some transactions for an incoming block.
|
||||
TxsForBlock(Vec<TransactionHash>),
|
||||
|
||||
/// Get information on all transactions in the pool.
|
||||
Backlog,
|
||||
|
||||
/// Get the number of transactions in the pool.
|
||||
Size,
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- TxpoolReadResponse
|
||||
|
@ -32,8 +41,10 @@ pub enum TxpoolReadRequest {
|
|||
pub enum TxpoolReadResponse {
|
||||
/// A response containing the raw bytes of a transaction.
|
||||
TxBlob { tx_blob: Vec<u8>, state_stem: bool },
|
||||
|
||||
/// A response of [`TransactionVerificationData`].
|
||||
TxVerificationData(TransactionVerificationData),
|
||||
|
||||
/// The response for [`TxpoolReadRequest::FilterKnownTxBlobHashes`].
|
||||
FilterKnownTxBlobHashes {
|
||||
/// The blob hashes that are unknown.
|
||||
|
@ -41,6 +52,7 @@ pub enum TxpoolReadResponse {
|
|||
/// The tx hashes of the blob hashes that were known but were in the stem pool.
|
||||
stem_pool_hashes: Vec<TransactionHash>,
|
||||
},
|
||||
|
||||
/// The response for [`TxpoolReadRequest::TxsForBlock`].
|
||||
TxsForBlock {
|
||||
/// The txs we had in the txpool.
|
||||
|
@ -48,6 +60,18 @@ pub enum TxpoolReadResponse {
|
|||
/// The indexes of the missing txs.
|
||||
missing: Vec<usize>,
|
||||
},
|
||||
|
||||
/// 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
|
||||
|
@ -65,15 +89,18 @@ pub enum TxpoolWriteRequest {
|
|||
/// [`true`] if this tx is in the stem state.
|
||||
state_stem: bool,
|
||||
},
|
||||
|
||||
/// Remove a transaction with the given hash from the pool.
|
||||
///
|
||||
/// Returns [`TxpoolWriteResponse::Ok`].
|
||||
RemoveTransaction(TransactionHash),
|
||||
|
||||
/// Promote a transaction from the stem pool to the fluff pool.
|
||||
/// If the tx is already in the fluff pool this does nothing.
|
||||
///
|
||||
/// Returns [`TxpoolWriteResponse::Ok`].
|
||||
Promote(TransactionHash),
|
||||
|
||||
/// Tell the tx-pool about a new block.
|
||||
NewBlock {
|
||||
/// The new blockchain height.
|
||||
|
@ -85,11 +112,14 @@ pub enum TxpoolWriteRequest {
|
|||
|
||||
//---------------------------------------------------------------------------------------------------- TxpoolWriteResponse
|
||||
/// The transaction pool [`tower::Service`] write response type.
|
||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
|
||||
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.
|
||||
AddTransaction(Option<TransactionHash>),
|
||||
Ok,
|
||||
}
|
||||
|
|
|
@ -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::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
|
@ -64,6 +71,8 @@ fn map_request(
|
|||
filter_known_tx_blob_hashes(env, blob_hashes)
|
||||
}
|
||||
TxpoolReadRequest::TxsForBlock(txs_needed) => txs_for_block(env, txs_needed),
|
||||
TxpoolReadRequest::Backlog => backlog(env),
|
||||
TxpoolReadRequest::Size => size(env),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,3 +194,15 @@ fn txs_for_block(env: &ConcreteEnv, txs: Vec<TransactionHash>) -> ReadResponseRe
|
|||
missing: missing_tx_indexes,
|
||||
})
|
||||
}
|
||||
|
||||
/// [`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
14
storage/txpool/src/tx.rs
Normal 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,
|
||||
}
|
|
@ -608,7 +608,10 @@ define_request_and_response! {
|
|||
r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "0",
|
||||
"method": "hard_fork_info"
|
||||
"method": "hard_fork_info",
|
||||
"params": {
|
||||
"version": 16
|
||||
}
|
||||
}"#;
|
||||
Response =
|
||||
r#"{
|
||||
|
|
|
@ -27,6 +27,7 @@ curve25519-dalek = { workspace = true }
|
|||
monero-serai = { workspace = true }
|
||||
hex = { workspace = true, features = ["serde", "alloc"], optional = true }
|
||||
serde = { workspace = true, features = ["derive"], optional = true }
|
||||
strum = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
proptest = { workspace = true, optional = true }
|
||||
|
|
|
@ -8,9 +8,11 @@ use std::{
|
|||
ops::Range,
|
||||
};
|
||||
|
||||
use monero_serai::block::Block;
|
||||
|
||||
use crate::{
|
||||
types::{Chain, ExtendedBlockHeader, OutputOnChain, VerifiedBlockInformation},
|
||||
AltBlockInformation, ChainId,
|
||||
AltBlockInformation, ChainId, CoinbaseTxSum, OutputHistogramEntry, OutputHistogramInput,
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- ReadRequest
|
||||
|
@ -103,6 +105,29 @@ pub enum BlockchainReadRequest {
|
|||
|
||||
/// A request for all alt blocks in the chain with the given [`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
|
||||
|
@ -147,6 +172,7 @@ pub enum BlockchainWriteRequest {
|
|||
/// This pairs with [`BlockchainReadRequest`] and [`BlockchainWriteRequest`],
|
||||
/// see those two for more info.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[expect(clippy::large_enum_variant)]
|
||||
pub enum BlockchainResponse {
|
||||
//------------------------------------------------------ Reads
|
||||
/// Response to [`BlockchainReadRequest::BlockExtendedHeader`].
|
||||
|
@ -215,18 +241,41 @@ pub enum BlockchainResponse {
|
|||
cumulative_difficulty: u128,
|
||||
},
|
||||
|
||||
/// The response for [`BlockchainReadRequest::FindFirstUnknown`].
|
||||
/// Response to [`BlockchainReadRequest::FindFirstUnknown`].
|
||||
///
|
||||
/// Contains the index of the first unknown block and its expected height.
|
||||
///
|
||||
/// This will be [`None`] if all blocks were known.
|
||||
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.
|
||||
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
|
||||
/// A generic Ok response to indicate a request was successfully handled.
|
||||
///
|
||||
|
@ -236,7 +285,8 @@ pub enum BlockchainResponse {
|
|||
/// - [`BlockchainWriteRequest::ReverseReorg`]
|
||||
/// - [`BlockchainWriteRequest::FlushAltBlocks`]
|
||||
Ok,
|
||||
/// The response for [`BlockchainWriteRequest::PopBlocks`].
|
||||
|
||||
/// Response to [`BlockchainWriteRequest::PopBlocks`].
|
||||
///
|
||||
/// The inner value is the alt-chain ID for the old main chain blocks.
|
||||
PopBlocks(ChainId),
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
//! The [`HardFork`] type.
|
||||
use std::time::Duration;
|
||||
|
||||
use strum::{
|
||||
AsRefStr, Display, EnumCount, EnumIs, EnumString, FromRepr, IntoStaticStr, VariantArray,
|
||||
};
|
||||
|
||||
use monero_serai::block::BlockHeader;
|
||||
|
||||
/// Target block time for hf 1.
|
||||
|
@ -27,7 +31,25 @@ pub enum HardForkError {
|
|||
}
|
||||
|
||||
/// An identifier for every hard-fork Monero has had.
|
||||
#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)]
|
||||
#[derive(
|
||||
Default,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Copy,
|
||||
Clone,
|
||||
Hash,
|
||||
EnumCount,
|
||||
Display,
|
||||
AsRefStr,
|
||||
EnumIs,
|
||||
EnumString,
|
||||
FromRepr,
|
||||
IntoStaticStr,
|
||||
VariantArray,
|
||||
)]
|
||||
#[cfg_attr(any(feature = "proptest"), derive(proptest_derive::Arbitrary))]
|
||||
#[repr(u8)]
|
||||
pub enum HardFork {
|
||||
|
@ -47,58 +69,75 @@ pub enum HardFork {
|
|||
V13,
|
||||
V14,
|
||||
V15,
|
||||
// remember to update from_vote!
|
||||
V16,
|
||||
}
|
||||
|
||||
impl HardFork {
|
||||
/// The latest [`HardFork`].
|
||||
///
|
||||
/// ```rust
|
||||
/// # use cuprate_types::HardFork;
|
||||
/// assert_eq!(HardFork::LATEST, HardFork::V16);
|
||||
/// ```
|
||||
pub const LATEST: Self = Self::VARIANTS[Self::COUNT - 1];
|
||||
|
||||
/// Returns the hard-fork for a blocks [`BlockHeader::hardfork_version`] field.
|
||||
///
|
||||
/// ref: <https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote>
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Will return [`Err`] if the version is not a valid [`HardFork`].
|
||||
///
|
||||
/// ```rust
|
||||
/// # use cuprate_types::{HardFork, HardForkError};
|
||||
/// # use strum::VariantArray;
|
||||
/// assert_eq!(HardFork::from_version(0), Err(HardForkError::HardForkUnknown));
|
||||
/// assert_eq!(HardFork::from_version(17), Err(HardForkError::HardForkUnknown));
|
||||
///
|
||||
/// for (version, hf) in HardFork::VARIANTS.iter().enumerate() {
|
||||
/// // +1 because enumerate starts at 0, hf starts at 1.
|
||||
/// assert_eq!(*hf, HardFork::from_version(version as u8 + 1).unwrap());
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub const fn from_version(version: u8) -> Result<Self, HardForkError> {
|
||||
Ok(match version {
|
||||
1 => Self::V1,
|
||||
2 => Self::V2,
|
||||
3 => Self::V3,
|
||||
4 => Self::V4,
|
||||
5 => Self::V5,
|
||||
6 => Self::V6,
|
||||
7 => Self::V7,
|
||||
8 => Self::V8,
|
||||
9 => Self::V9,
|
||||
10 => Self::V10,
|
||||
11 => Self::V11,
|
||||
12 => Self::V12,
|
||||
13 => Self::V13,
|
||||
14 => Self::V14,
|
||||
15 => Self::V15,
|
||||
16 => Self::V16,
|
||||
_ => return Err(HardForkError::HardForkUnknown),
|
||||
})
|
||||
match Self::from_repr(version) {
|
||||
Some(this) => Ok(this),
|
||||
None => Err(HardForkError::HardForkUnknown),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the hard-fork for a blocks [`BlockHeader::hardfork_signal`] (vote) field.
|
||||
///
|
||||
/// <https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote>
|
||||
///
|
||||
/// ```rust
|
||||
/// # use cuprate_types::{HardFork, HardForkError};
|
||||
/// # use strum::VariantArray;
|
||||
/// // 0 is interpreted as 1.
|
||||
/// assert_eq!(HardFork::from_vote(0), HardFork::V1);
|
||||
/// // Unknown defaults to `LATEST`.
|
||||
/// assert_eq!(HardFork::from_vote(17), HardFork::V16);
|
||||
///
|
||||
/// for (vote, hf) in HardFork::VARIANTS.iter().enumerate() {
|
||||
/// // +1 because enumerate starts at 0, hf starts at 1.
|
||||
/// assert_eq!(*hf, HardFork::from_vote(vote as u8 + 1));
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn from_vote(vote: u8) -> Self {
|
||||
if vote == 0 {
|
||||
// A vote of 0 is interpreted as 1 as that's what Monero used to default to.
|
||||
return Self::V1;
|
||||
Self::V1
|
||||
} else {
|
||||
// This must default to the latest hard-fork!
|
||||
Self::from_version(vote).unwrap_or(Self::LATEST)
|
||||
}
|
||||
// This must default to the latest hard-fork!
|
||||
Self::from_version(vote).unwrap_or(Self::V16)
|
||||
}
|
||||
|
||||
/// Returns the [`HardFork`] version and vote from this block header.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Will return [`Err`] if the [`BlockHeader::hardfork_version`] is not a valid [`HardFork`].
|
||||
#[inline]
|
||||
pub fn from_block_header(header: &BlockHeader) -> Result<(Self, Self), HardForkError> {
|
||||
|
@ -109,22 +148,49 @@ impl HardFork {
|
|||
}
|
||||
|
||||
/// Returns the raw hard-fork value, as it would appear in [`BlockHeader::hardfork_version`].
|
||||
pub const fn as_u8(&self) -> u8 {
|
||||
*self as u8
|
||||
///
|
||||
/// ```rust
|
||||
/// # use cuprate_types::{HardFork, HardForkError};
|
||||
/// # use strum::VariantArray;
|
||||
/// for (i, hf) in HardFork::VARIANTS.iter().enumerate() {
|
||||
/// // +1 because enumerate starts at 0, hf starts at 1.
|
||||
/// assert_eq!(hf.as_u8(), i as u8 + 1);
|
||||
/// }
|
||||
/// ```
|
||||
pub const fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
|
||||
/// Returns the next hard-fork.
|
||||
pub fn next_fork(&self) -> Option<Self> {
|
||||
Self::from_version(*self as u8 + 1).ok()
|
||||
pub fn next_fork(self) -> Option<Self> {
|
||||
Self::from_version(self as u8 + 1).ok()
|
||||
}
|
||||
|
||||
/// Returns the target block time for this hardfork.
|
||||
///
|
||||
/// ref: <https://monero-book.cuprate.org/consensus_rules/blocks/difficulty.html#target-seconds>
|
||||
pub const fn block_time(&self) -> Duration {
|
||||
pub const fn block_time(self) -> Duration {
|
||||
match self {
|
||||
Self::V1 => BLOCK_TIME_V1,
|
||||
_ => BLOCK_TIME_V2,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` is [`Self::LATEST`].
|
||||
///
|
||||
/// ```rust
|
||||
/// # use cuprate_types::HardFork;
|
||||
/// # use strum::VariantArray;
|
||||
///
|
||||
/// for hf in HardFork::VARIANTS.iter() {
|
||||
/// if *hf == HardFork::LATEST {
|
||||
/// assert!(hf.is_latest());
|
||||
/// } else {
|
||||
/// assert!(!hf.is_latest());
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub const fn is_latest(self) -> bool {
|
||||
matches!(self, Self::LATEST)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,9 @@ pub use transaction_verification_data::{
|
|||
CachedVerificationState, TransactionVerificationData, TxVersion,
|
||||
};
|
||||
pub use types::{
|
||||
AltBlockInformation, Chain, ChainId, ExtendedBlockHeader, OutputOnChain,
|
||||
VerifiedBlockInformation, VerifiedTransactionInformation,
|
||||
AltBlockInformation, Chain, ChainId, ChainInfo, CoinbaseTxSum, ExtendedBlockHeader,
|
||||
FeeEstimate, HardForkInfo, MinerData, MinerDataTxBacklogEntry, OutputHistogramEntry,
|
||||
OutputHistogramInput, OutputOnChain, VerifiedBlockInformation, VerifiedTransactionInformation,
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Feature-gated
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//! Various shared data types in Cuprate.
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use std::num::NonZero;
|
||||
|
||||
use curve25519_dalek::edwards::EdwardsPoint;
|
||||
|
@ -11,7 +10,6 @@ use monero_serai::{
|
|||
|
||||
use crate::HardFork;
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- ExtendedBlockHeader
|
||||
/// Extended header data of a block.
|
||||
///
|
||||
/// 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,
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- VerifiedTransactionInformation
|
||||
/// Verified information of a transaction.
|
||||
///
|
||||
/// This represents a valid transaction
|
||||
|
@ -61,7 +58,6 @@ pub struct VerifiedTransactionInformation {
|
|||
pub tx_hash: [u8; 32],
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- VerifiedBlockInformation
|
||||
/// Verified information of a block.
|
||||
///
|
||||
/// This represents a block that has already been verified to be correct.
|
||||
|
@ -94,14 +90,12 @@ pub struct VerifiedBlockInformation {
|
|||
pub cumulative_difficulty: u128,
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- ChainID
|
||||
/// A unique ID for an alt chain.
|
||||
///
|
||||
/// The inner value is meaningless.
|
||||
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
||||
pub struct ChainId(pub NonZero<u64>);
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Chain
|
||||
/// An identifier for a chain.
|
||||
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
||||
pub enum Chain {
|
||||
|
@ -111,7 +105,6 @@ pub enum Chain {
|
|||
Alt(ChainId),
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- AltBlockInformation
|
||||
/// A block on an alternative chain.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct AltBlockInformation {
|
||||
|
@ -141,7 +134,6 @@ pub struct AltBlockInformation {
|
|||
pub chain_id: ChainId,
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- OutputOnChain
|
||||
/// An already existing transaction output.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct OutputOnChain {
|
||||
|
@ -155,6 +147,104 @@ pub struct OutputOnChain {
|
|||
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
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
|
Loading…
Reference in a new issue