Compare commits

...

3 commits

Author SHA1 Message Date
hinto.janai
bf07f2c84c
BlockchainManagerRequest docs 2024-10-16 20:47:39 -04:00
hinto.janai
bd3a844cc5
get_miner_data 2024-10-16 16:57:48 -04:00
hinto.janai
4b1d7bc897
sync_info 2024-10-16 16:46:13 -04:00
14 changed files with 264 additions and 46 deletions

View file

@ -69,25 +69,48 @@ pub enum BlockchainManagerRequest {
seed_hash: [u8; 32], seed_hash: [u8; 32],
}, },
/// TODO /// Add auxirilly proof-of-work to a block.
///
/// From the RPC `add_aux_pow` usecase's documentation:
/// ````
/// This enables merge mining with Monero without requiring
/// software that manually alters the extra field in the coinbase
/// tx to include the merkle root of the aux blocks.
/// ````
AddAuxPow { AddAuxPow {
/// TODO /// The block template to add to.
blocktemplate_blob: Vec<u8>, block_template: Block,
/// TODO /// The auxirilly proof-of-work to add.
aux_pow: Vec<AuxPow>, aux_pow: Vec<AuxPow>,
}, },
/// TODO /// Generate new blocks.
///
/// This request is only for regtest, see RPC's `generateblocks`.
GenerateBlocks { GenerateBlocks {
/// TODO /// Number of the blocks to be generated.
amount_of_blocks: u64, amount_of_blocks: u64,
/// TODO /// The previous block's hash.
prev_block: [u8; 32], prev_block: [u8; 32],
/// TODO /// The starting value for the nonce.
starting_nonce: u32, starting_nonce: u32,
/// TODO /// The address that will receive the coinbase reward.
wallet_address: String, wallet_address: String,
}, },
/// Get a visual [`String`] overview of blockchain progress.
///
/// This is a highly implementation specific format used by
/// `monerod` in the `sync_info` RPC call's `overview` field;
/// it is essentially an ASCII visual of blocks.
///
/// See also:
/// - <https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#sync_info>
/// - <https://github.com/monero-project/monero/blob/master/src/cryptonote_protocol/block_queue.cpp#L178>
Overview {
/// TODO: the current blockchain height? do we need to pass this?
height: usize,
},
} }
/// TODO: use real type when public. /// TODO: use real type when public.
@ -129,11 +152,14 @@ pub enum BlockchainManagerResponse {
/// Response to [`BlockchainManagerRequest::GenerateBlocks`] /// Response to [`BlockchainManagerRequest::GenerateBlocks`]
GenerateBlocks { GenerateBlocks {
/// TODO /// Hashes of the blocks generated.
blocks: Vec<[u8; 32]>, blocks: Vec<[u8; 32]>,
/// TODO /// The new top height. (TODO: is this correct?)
height: usize, height: usize,
}, },
/// Response to [`BlockchainManagerRequest::Overview`]
Overview(String),
} }
/// TODO: use real type when public. /// TODO: use real type when public.

View file

@ -41,8 +41,8 @@ use cuprate_rpc_types::{
SyncInfoResponse, SyncInfoResponse,
}, },
misc::{ misc::{
AuxPow, BlockHeader, ChainInfo, GetBan, HardforkEntry, HistogramEntry, Status, AuxPow, BlockHeader, ChainInfo, GetBan, GetMinerDataTxBacklogEntry, HardforkEntry,
TxBacklogEntry, HistogramEntry, Status, SyncInfoPeer, TxBacklogEntry,
}, },
CORE_RPC_VERSION, CORE_RPC_VERSION,
}; };
@ -758,17 +758,39 @@ async fn relay_tx(
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3306-L3330> /// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3306-L3330>
async fn sync_info( async fn sync_info(
state: CupratedRpcHandler, mut state: CupratedRpcHandler,
request: SyncInfoRequest, request: SyncInfoRequest,
) -> Result<SyncInfoResponse, Error> { ) -> Result<SyncInfoResponse, Error> {
let height = usize_to_u64(
blockchain_context::context(&mut state.blockchain_context)
.await?
.unchecked_blockchain_context()
.chain_height,
);
let target_height = blockchain_manager::target_height(&mut state.blockchain_manager).await?;
let peers = address_book::connection_info::<ClearNet>(&mut DummyAddressBook)
.await?
.into_iter()
.map(|info| SyncInfoPeer { info })
.collect();
let next_needed_pruning_seed =
address_book::next_needed_pruning_seed::<ClearNet>(&mut DummyAddressBook)
.await?
.compress();
let overview = blockchain_manager::overview(&mut state.blockchain_manager, height).await?;
let spans = address_book::spans::<ClearNet>(&mut DummyAddressBook).await?;
Ok(SyncInfoResponse { Ok(SyncInfoResponse {
base: AccessResponseBase::OK, base: AccessResponseBase::OK,
height: todo!(), height,
next_needed_pruning_seed: todo!(), next_needed_pruning_seed,
overview: todo!(), overview,
peers: todo!(), peers,
spans: todo!(), spans,
target_height: todo!(), target_height,
}) })
} }
@ -795,19 +817,38 @@ async fn get_transaction_pool_backlog(
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L1998-L2033> /// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L1998-L2033>
async fn get_miner_data( async fn get_miner_data(
state: CupratedRpcHandler, mut state: CupratedRpcHandler,
request: GetMinerDataRequest, request: GetMinerDataRequest,
) -> Result<GetMinerDataResponse, Error> { ) -> Result<GetMinerDataResponse, Error> {
let context = blockchain_context::context(&mut state.blockchain_context).await?;
let context = context.unchecked_blockchain_context();
let major_version = context.current_hf.as_u8();
let height = usize_to_u64(context.chain_height);
let prev_id = hex::encode(context.top_hash);
let seed_hash = todo!();
let difficulty = format!("{:#x}", context.next_difficulty);
let median_weight = usize_to_u64(context.median_weight_for_block_reward);
let already_generated_coins = context.already_generated_coins;
let tx_backlog = txpool::block_template_backlog(&mut state.txpool_read)
.await?
.into_iter()
.map(|entry| GetMinerDataTxBacklogEntry {
id: hex::encode(entry.id),
weight: entry.weight,
fee: entry.fee,
})
.collect();
Ok(GetMinerDataResponse { Ok(GetMinerDataResponse {
base: ResponseBase::OK, base: ResponseBase::OK,
major_version: todo!(), major_version,
height: todo!(), height,
prev_id: todo!(), prev_id,
seed_hash: todo!(), seed_hash,
difficulty: todo!(), difficulty,
median_weight: todo!(), median_weight,
already_generated_coins: todo!(), already_generated_coins,
tx_backlog: todo!(), tx_backlog,
}) })
} }
@ -869,7 +910,9 @@ async fn add_aux_pow(
mut state: CupratedRpcHandler, mut state: CupratedRpcHandler,
request: AddAuxPowRequest, request: AddAuxPowRequest,
) -> Result<AddAuxPowResponse, Error> { ) -> Result<AddAuxPowResponse, Error> {
let blocktemplate_blob = hex::decode(request.blocktemplate_blob)?; let hex = hex::decode(request.blocktemplate_blob)?;
let block_template = Block::read(&mut hex.as_slice())?;
let aux_pow = request let aux_pow = request
.aux_pow .aux_pow
.into_iter() .into_iter()
@ -881,7 +924,7 @@ async fn add_aux_pow(
.collect::<Result<Vec<_>, Error>>()?; .collect::<Result<Vec<_>, Error>>()?;
let resp = let resp =
blockchain_manager::add_aux_pow(&mut state.blockchain_manager, blocktemplate_blob, aux_pow) blockchain_manager::add_aux_pow(&mut state.blockchain_manager, block_template, aux_pow)
.await?; .await?;
let blocktemplate_blob = hex::encode(resp.blocktemplate_blob); let blocktemplate_blob = hex::encode(resp.blocktemplate_blob);

View file

@ -3,7 +3,8 @@
use std::convert::Infallible; use std::convert::Infallible;
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use cuprate_rpc_types::misc::ConnectionInfo; use cuprate_pruning::PruningSeed;
use cuprate_rpc_types::misc::{ConnectionInfo, Span};
use tower::ServiceExt; use tower::ServiceExt;
use cuprate_helper::cast::usize_to_u64; use cuprate_helper::cast::usize_to_u64;
@ -156,3 +157,53 @@ pub(crate) async fn get_bans<Z: NetworkZone>(
Ok(bans) Ok(bans)
} }
/// [`AddressBookRequest::Spans`]
pub(crate) async fn spans<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>,
) -> Result<Vec<Span>, Error> {
let AddressBookResponse::Spans(vec) = address_book
.ready()
.await
.map_err(|e| anyhow!(e))?
.call(AddressBookRequest::Spans)
.await
.map_err(|e| anyhow!(e))?
else {
unreachable!();
};
// FIXME: impl this map somewhere instead of inline.
let vec = vec
.into_iter()
.map(|span| Span {
connection_id: span.connection_id,
nblocks: span.nblocks,
rate: span.rate,
remote_address: span.remote_address,
size: span.size,
speed: span.speed,
start_block_height: span.start_block_height,
})
.collect();
Ok(vec)
}
/// [`AddressBookRequest::NextNeededPruningSeed`]
pub(crate) async fn next_needed_pruning_seed<Z: NetworkZone>(
address_book: &mut impl AddressBook<Z>,
) -> Result<PruningSeed, Error> {
let AddressBookResponse::NextNeededPruningSeed(seed) = address_book
.ready()
.await
.map_err(|e| anyhow!(e))?
.call(AddressBookRequest::NextNeededPruningSeed)
.await
.map_err(|e| anyhow!(e))?
else {
unreachable!();
};
Ok(seed)
}

View file

@ -15,9 +15,9 @@ use cuprate_types::{FeeEstimate, HardFork, HardForkInfo};
/// [`BlockChainContextRequest::Context`]. /// [`BlockChainContextRequest::Context`].
pub(crate) async fn context( pub(crate) async fn context(
service: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
) -> Result<BlockChainContext, Error> { ) -> Result<BlockChainContext, Error> {
let BlockChainContextResponse::Context(context) = service let BlockChainContextResponse::Context(context) = blockchain_context
.ready() .ready()
.await .await
.map_err(|e| anyhow!(e))? .map_err(|e| anyhow!(e))?
@ -33,10 +33,10 @@ pub(crate) async fn context(
/// [`BlockChainContextRequest::HardForkInfo`]. /// [`BlockChainContextRequest::HardForkInfo`].
pub(crate) async fn hard_fork_info( pub(crate) async fn hard_fork_info(
service: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
hard_fork: HardFork, hard_fork: HardFork,
) -> Result<HardForkInfo, Error> { ) -> Result<HardForkInfo, Error> {
let BlockChainContextResponse::HardForkInfo(hf_info) = service let BlockChainContextResponse::HardForkInfo(hf_info) = blockchain_context
.ready() .ready()
.await .await
.map_err(|e| anyhow!(e))? .map_err(|e| anyhow!(e))?
@ -52,10 +52,10 @@ pub(crate) async fn hard_fork_info(
/// [`BlockChainContextRequest::FeeEstimate`]. /// [`BlockChainContextRequest::FeeEstimate`].
pub(crate) async fn fee_estimate( pub(crate) async fn fee_estimate(
service: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
grace_blocks: u64, grace_blocks: u64,
) -> Result<FeeEstimate, Error> { ) -> Result<FeeEstimate, Error> {
let BlockChainContextResponse::FeeEstimate(fee) = service let BlockChainContextResponse::FeeEstimate(fee) = blockchain_context
.ready() .ready()
.await .await
.map_err(|e| anyhow!(e))? .map_err(|e| anyhow!(e))?

View file

@ -172,14 +172,14 @@ pub(crate) async fn calculate_pow(
/// [`BlockchainManagerRequest::AddAuxPow`] /// [`BlockchainManagerRequest::AddAuxPow`]
pub(crate) async fn add_aux_pow( pub(crate) async fn add_aux_pow(
blockchain_manager: &mut BlockchainManagerHandle, blockchain_manager: &mut BlockchainManagerHandle,
blocktemplate_blob: Vec<u8>, block_template: Block,
aux_pow: Vec<AuxPow>, aux_pow: Vec<AuxPow>,
) -> Result<AddAuxPow, Error> { ) -> Result<AddAuxPow, Error> {
let BlockchainManagerResponse::AddAuxPow(response) = blockchain_manager let BlockchainManagerResponse::AddAuxPow(response) = blockchain_manager
.ready() .ready()
.await? .await?
.call(BlockchainManagerRequest::AddAuxPow { .call(BlockchainManagerRequest::AddAuxPow {
blocktemplate_blob, block_template,
aux_pow, aux_pow,
}) })
.await? .await?
@ -214,3 +214,22 @@ pub(crate) async fn generate_blocks(
Ok((blocks, usize_to_u64(height))) Ok((blocks, usize_to_u64(height)))
} }
/// [`BlockchainManagerRequest::Overview`]
pub(crate) async fn overview(
blockchain_manager: &mut BlockchainManagerHandle,
height: u64,
) -> Result<String, Error> {
let BlockchainManagerResponse::Overview(overview) = blockchain_manager
.ready()
.await?
.call(BlockchainManagerRequest::Overview {
height: u64_to_usize(height),
})
.await?
else {
unreachable!();
};
Ok(overview)
}

View file

@ -11,7 +11,7 @@ use cuprate_txpool::{
interface::{TxpoolReadRequest, TxpoolReadResponse}, interface::{TxpoolReadRequest, TxpoolReadResponse},
TxpoolReadHandle, TxpoolReadHandle,
}, },
TxEntry, BlockTemplateTxEntry, TxEntry,
}; };
// FIXME: use `anyhow::Error` over `tower::BoxError` in txpool. // FIXME: use `anyhow::Error` over `tower::BoxError` in txpool.
@ -32,6 +32,24 @@ pub(crate) async fn backlog(txpool_read: &mut TxpoolReadHandle) -> Result<Vec<Tx
Ok(tx_entries) Ok(tx_entries)
} }
/// [`TxpoolReadRequest::BlockTemplateBacklog`]
pub(crate) async fn block_template_backlog(
txpool_read: &mut TxpoolReadHandle,
) -> Result<Vec<BlockTemplateTxEntry>, Error> {
let TxpoolReadResponse::BlockTemplateBacklog(tx_entries) = txpool_read
.ready()
.await
.map_err(|e| anyhow!(e))?
.call(TxpoolReadRequest::BlockTemplateBacklog)
.await
.map_err(|e| anyhow!(e))?
else {
unreachable!();
};
Ok(tx_entries)
}
/// [`TxpoolReadRequest::Size`] /// [`TxpoolReadRequest::Size`]
pub(crate) async fn size( pub(crate) async fn size(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,

View file

@ -424,7 +424,9 @@ impl<Z: BorshNetworkZone> Service<AddressBookRequest<Z>> for AddressBook<Z> {
| AddressBookRequest::ConnectionCount | AddressBookRequest::ConnectionCount
| AddressBookRequest::SetBan(_) | AddressBookRequest::SetBan(_)
| AddressBookRequest::GetBans | AddressBookRequest::GetBans
| AddressBookRequest::ConnectionInfo => { | AddressBookRequest::ConnectionInfo
| AddressBookRequest::NextNeededPruningSeed
| AddressBookRequest::Spans => {
todo!("finish https://github.com/Cuprate/cuprate/pull/297") todo!("finish https://github.com/Cuprate/cuprate/pull/297")
} }
}; };

View file

@ -112,7 +112,9 @@ impl<N: NetworkZone> Service<AddressBookRequest<N>> for DummyAddressBook {
| AddressBookRequest::ConnectionCount | AddressBookRequest::ConnectionCount
| AddressBookRequest::SetBan(_) | AddressBookRequest::SetBan(_)
| AddressBookRequest::GetBans | AddressBookRequest::GetBans
| AddressBookRequest::ConnectionInfo => { | AddressBookRequest::ConnectionInfo
| AddressBookRequest::NextNeededPruningSeed
| AddressBookRequest::Spans => {
todo!("finish https://github.com/Cuprate/cuprate/pull/297") todo!("finish https://github.com/Cuprate/cuprate/pull/297")
} }
})) }))

View file

@ -6,7 +6,7 @@ use cuprate_wire::{CoreSyncData, PeerListEntryBase};
use crate::{ use crate::{
client::InternalPeerID, client::InternalPeerID,
handles::ConnectionHandle, handles::ConnectionHandle,
types::{BanState, ConnectionInfo, SetBan}, types::{BanState, ConnectionInfo, SetBan, Span},
NetZoneAddress, NetworkAddressIncorrectZone, NetworkZone, NetZoneAddress, NetworkAddressIncorrectZone, NetworkZone,
}; };
@ -132,6 +132,12 @@ pub enum AddressBookRequest<Z: NetworkZone> {
/// Get the state of all bans. /// Get the state of all bans.
GetBans, GetBans,
/// TODO
Spans,
/// TODO
NextNeededPruningSeed,
} }
/// A response from the address book service. /// A response from the address book service.
@ -169,4 +175,10 @@ pub enum AddressBookResponse<Z: NetworkZone> {
/// Response to [`AddressBookRequest::GetBans`]. /// Response to [`AddressBookRequest::GetBans`].
GetBans(Vec<BanState<Z::Addr>>), GetBans(Vec<BanState<Z::Addr>>),
/// Response to [`AddressBookRequest::Spans`].
Spans(Vec<Span>),
/// Response to [`AddressBookRequest::NextNeededPruningSeed`].
NextNeededPruningSeed(PruningSeed),
} }

View file

@ -52,3 +52,17 @@ pub struct ConnectionInfo<A: NetZoneAddress> {
pub state: String, pub state: String,
pub support_flags: u32, pub support_flags: u32,
} }
/// Used in RPC's `sync_info`.
///
/// Data within [`crate::services::AddressBookResponse::Spans`].
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Span {
pub connection_id: String,
pub nblocks: u64,
pub rate: u32,
pub remote_address: String,
pub size: u64,
pub speed: u32,
pub start_block_height: u64,
}

View file

@ -15,7 +15,7 @@ pub mod types;
pub use config::Config; pub use config::Config;
pub use free::open; pub use free::open;
pub use tx::TxEntry; pub use tx::{BlockTemplateTxEntry, TxEntry};
//re-exports //re-exports
pub use cuprate_database; pub use cuprate_database;

View file

@ -5,7 +5,10 @@ use std::sync::Arc;
use cuprate_types::TransactionVerificationData; use cuprate_types::TransactionVerificationData;
use crate::{tx::TxEntry, types::TransactionHash}; use crate::{
tx::{BlockTemplateTxEntry, TxEntry},
types::TransactionHash,
};
//---------------------------------------------------------------------------------------------------- TxpoolReadRequest //---------------------------------------------------------------------------------------------------- TxpoolReadRequest
/// The transaction pool [`tower::Service`] read request type. /// The transaction pool [`tower::Service`] read request type.
@ -19,6 +22,9 @@ pub enum TxpoolReadRequest {
/// Get information on all transactions in the pool. /// Get information on all transactions in the pool.
Backlog, Backlog,
/// TODO
BlockTemplateBacklog,
/// Get the number of transactions in the pool. /// Get the number of transactions in the pool.
Size { Size {
/// TODO /// TODO
@ -45,6 +51,11 @@ pub enum TxpoolReadResponse {
/// the transactions currently in the pool. /// the transactions currently in the pool.
Backlog(Vec<TxEntry>), Backlog(Vec<TxEntry>),
/// Response to [`TxpoolReadRequest::BlockTemplateBacklog`].
///
/// TODO
BlockTemplateBacklog(Vec<BlockTemplateTxEntry>),
/// Response to [`TxpoolReadRequest::Size`]. /// Response to [`TxpoolReadRequest::Size`].
/// ///
/// The inner value is the amount of /// The inner value is the amount of

View file

@ -66,6 +66,7 @@ fn map_request(
TxpoolReadRequest::TxBlob(tx_hash) => tx_blob(env, &tx_hash), TxpoolReadRequest::TxBlob(tx_hash) => tx_blob(env, &tx_hash),
TxpoolReadRequest::TxVerificationData(tx_hash) => tx_verification_data(env, &tx_hash), TxpoolReadRequest::TxVerificationData(tx_hash) => tx_verification_data(env, &tx_hash),
TxpoolReadRequest::Backlog => backlog(env), TxpoolReadRequest::Backlog => backlog(env),
TxpoolReadRequest::BlockTemplateBacklog => block_template_backlog(env),
TxpoolReadRequest::Size { TxpoolReadRequest::Size {
include_sensitive_txs, include_sensitive_txs,
} => size(env, include_sensitive_txs), } => size(env, include_sensitive_txs),
@ -119,6 +120,12 @@ fn backlog(env: &ConcreteEnv) -> ReadResponseResult {
Ok(TxpoolReadResponse::Backlog(todo!())) Ok(TxpoolReadResponse::Backlog(todo!()))
} }
/// [`TxpoolReadRequest::BlockTemplateBacklog`].
#[inline]
fn block_template_backlog(env: &ConcreteEnv) -> ReadResponseResult {
Ok(TxpoolReadResponse::BlockTemplateBacklog(todo!()))
}
/// [`TxpoolReadRequest::Size`]. /// [`TxpoolReadRequest::Size`].
#[inline] #[inline]
fn size(env: &ConcreteEnv, include_sensitive_txs: bool) -> ReadResponseResult { fn size(env: &ConcreteEnv, include_sensitive_txs: bool) -> ReadResponseResult {

View file

@ -12,3 +12,16 @@ pub struct TxEntry {
/// How long the transaction has been in the pool. /// How long the transaction has been in the pool.
pub time_in_pool: std::time::Duration, pub time_in_pool: std::time::Duration,
} }
/// TODO
///
/// Used in [`TxpoolReadResponse::BlockTemplateBacklog`](crate::service::interface::TxpoolReadResponse::BlockTemplateBacklog).
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct BlockTemplateTxEntry {
/// TODO
pub id: [u8; 32],
/// TODO
pub weight: u64,
/// TODO
pub fee: u64,
}