mirror of
https://github.com/Cuprate/cuprate.git
synced 2024-12-24 04:29:38 +00:00
bin: get_blocks_by_height
, get_hashes
This commit is contained in:
parent
4f738eef38
commit
6dc85c606f
5 changed files with 209 additions and 5 deletions
|
@ -1,4 +1,4 @@
|
||||||
use anyhow::Error;
|
use anyhow::{anyhow, Error};
|
||||||
|
|
||||||
use cuprate_rpc_types::{
|
use cuprate_rpc_types::{
|
||||||
base::{AccessResponseBase, ResponseBase},
|
base::{AccessResponseBase, ResponseBase},
|
||||||
|
@ -9,9 +9,13 @@ use cuprate_rpc_types::{
|
||||||
GetTransactionPoolHashesRequest, GetTransactionPoolHashesResponse,
|
GetTransactionPoolHashesRequest, GetTransactionPoolHashesResponse,
|
||||||
},
|
},
|
||||||
json::{GetOutputDistributionRequest, GetOutputDistributionResponse},
|
json::{GetOutputDistributionRequest, GetOutputDistributionResponse},
|
||||||
|
misc::RequestedInfo,
|
||||||
};
|
};
|
||||||
|
use cuprate_types::BlockCompleteEntry;
|
||||||
|
|
||||||
use crate::rpc::CupratedRpcHandlerState;
|
use crate::rpc::{blockchain, helper, CupratedRpcHandlerState, RESTRICTED_TRANSACTIONS_COUNT};
|
||||||
|
|
||||||
|
use super::RESTRICTED_BLOCK_COUNT;
|
||||||
|
|
||||||
/// Map a [`BinRequest`] to the function that will lead to a [`BinResponse`].
|
/// Map a [`BinRequest`] to the function that will lead to a [`BinResponse`].
|
||||||
pub(super) async fn map_request(
|
pub(super) async fn map_request(
|
||||||
|
@ -41,6 +45,38 @@ async fn get_blocks(
|
||||||
state: CupratedRpcHandlerState,
|
state: CupratedRpcHandlerState,
|
||||||
request: GetBlocksRequest,
|
request: GetBlocksRequest,
|
||||||
) -> Result<GetBlocksResponse, Error> {
|
) -> Result<GetBlocksResponse, Error> {
|
||||||
|
// Time should be set early:
|
||||||
|
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L628-L631>
|
||||||
|
let daemon_time = cuprate_helper::time::current_unix_timestamp();
|
||||||
|
|
||||||
|
let Some(requested_info) = RequestedInfo::from_u8(request.requested_info) else {
|
||||||
|
return Err(anyhow!("Failed, wrong requested info"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let (get_blocks, get_pool) = match requested_info {
|
||||||
|
RequestedInfo::BlocksOnly => (true, false),
|
||||||
|
RequestedInfo::BlocksAndPool => (true, true),
|
||||||
|
RequestedInfo::PoolOnly => (false, true),
|
||||||
|
};
|
||||||
|
|
||||||
|
if get_pool {
|
||||||
|
let max_tx_count = if state.restricted {
|
||||||
|
RESTRICTED_TRANSACTIONS_COUNT
|
||||||
|
} else {
|
||||||
|
usize::MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
if get_blocks {
|
||||||
|
if !request.block_ids.is_empty() {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
// Ok(GetBlocksResponse {
|
// Ok(GetBlocksResponse {
|
||||||
// base: ResponseBase::ok(),
|
// base: ResponseBase::ok(),
|
||||||
// ..todo!()
|
// ..todo!()
|
||||||
|
@ -53,20 +89,55 @@ async fn get_blocks_by_height(
|
||||||
state: CupratedRpcHandlerState,
|
state: CupratedRpcHandlerState,
|
||||||
request: GetBlocksByHeightRequest,
|
request: GetBlocksByHeightRequest,
|
||||||
) -> Result<GetBlocksByHeightResponse, Error> {
|
) -> Result<GetBlocksByHeightResponse, Error> {
|
||||||
|
if state.restricted && request.heights.len() > RESTRICTED_BLOCK_COUNT {
|
||||||
|
return Err(anyhow!("Too many blocks requested in restricted mode"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let blocks = request
|
||||||
|
.heights
|
||||||
|
.into_iter()
|
||||||
|
.map(|height| Ok(todo!()))
|
||||||
|
.collect::<Result<Vec<BlockCompleteEntry>, Error>>()?;
|
||||||
|
|
||||||
Ok(GetBlocksByHeightResponse {
|
Ok(GetBlocksByHeightResponse {
|
||||||
base: AccessResponseBase::ok(),
|
base: AccessResponseBase::ok(),
|
||||||
..todo!()
|
blocks,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L859-L880>
|
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L859-L880>
|
||||||
async fn get_hashes(
|
async fn get_hashes(
|
||||||
state: CupratedRpcHandlerState,
|
mut state: CupratedRpcHandlerState,
|
||||||
request: GetHashesRequest,
|
request: GetHashesRequest,
|
||||||
) -> Result<GetHashesResponse, Error> {
|
) -> Result<GetHashesResponse, Error> {
|
||||||
|
let Some(last) = request.block_ids.last() else {
|
||||||
|
return Err(anyhow!("block_ids empty"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const GENESIS_BLOCK_HASH: [u8; 32] = [0; 32]; // TODO
|
||||||
|
if last != GENESIS_BLOCK_HASH {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"genesis block mismatch, found: {last:?}, expected: {GENESIS_BLOCK_HASH:?}"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bytes = request.block_ids;
|
||||||
|
let hashes: Vec<[u8; 32]> = bytes.clone().into();
|
||||||
|
|
||||||
|
let (current_height, _) = helper::top_height(&mut state).await?;
|
||||||
|
|
||||||
|
let Some((index, start_height)) = blockchain::find_first_unknown(&mut state, hashes).await?
|
||||||
|
else {
|
||||||
|
return Err(anyhow!("Failed"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let m_blocks_ids = bytes.split_off(index);
|
||||||
|
|
||||||
Ok(GetHashesResponse {
|
Ok(GetHashesResponse {
|
||||||
base: AccessResponseBase::ok(),
|
base: AccessResponseBase::ok(),
|
||||||
..todo!()
|
m_blocks_ids,
|
||||||
|
start_height,
|
||||||
|
current_height,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,24 @@ pub(super) async fn pop_blocks(
|
||||||
Ok(usize_to_u64(height))
|
Ok(usize_to_u64(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [`BlockchainResponse::FindFirstUnknown`]
|
||||||
|
pub(super) async fn find_first_unknown(
|
||||||
|
state: &mut CupratedRpcHandlerState,
|
||||||
|
hashes: Vec<[u8; 32]>,
|
||||||
|
) -> Result<Option<(usize, u64)>, Error> {
|
||||||
|
let BlockchainResponse::FindFirstUnknown(resp) = state
|
||||||
|
.blockchain_read
|
||||||
|
.ready()
|
||||||
|
.await?
|
||||||
|
.call(BlockchainReadRequest::FindFirstUnknown(hashes))
|
||||||
|
.await?
|
||||||
|
else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(resp.map(|(index, height)| (index, usize_to_u64(height))))
|
||||||
|
}
|
||||||
|
|
||||||
// FindBlock([u8; 32]),
|
// FindBlock([u8; 32]),
|
||||||
// FilterUnknownHashes(HashSet<[u8; 32]>),
|
// FilterUnknownHashes(HashSet<[u8; 32]>),
|
||||||
// BlockExtendedHeaderInRange(Range<usize>, Chain),
|
// BlockExtendedHeaderInRange(Range<usize>, Chain),
|
||||||
|
|
|
@ -154,6 +154,26 @@ impl<const N: usize> ByteArrayVec<N> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn first(&self) -> Option<[u8; N]> {
|
||||||
|
let len = self.len();
|
||||||
|
|
||||||
|
if len == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(self[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn last(&self) -> Option<[u8; N]> {
|
||||||
|
let len = self.len();
|
||||||
|
|
||||||
|
if len == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(self[len - 1])
|
||||||
|
}
|
||||||
|
|
||||||
/// Splits the byte array vec into two at the given index.
|
/// Splits the byte array vec into two at the given index.
|
||||||
///
|
///
|
||||||
/// Afterwards self contains elements [0, at), and the returned [`ByteArrayVec`] contains elements [at, len).
|
/// Afterwards self contains elements [0, at), and the returned [`ByteArrayVec`] contains elements [at, len).
|
||||||
|
@ -246,6 +266,13 @@ impl<const N: usize> Index<usize> for ByteArrayVec<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> From<ByteArrayVec<N>> for Vec<[u8; N]> {
|
||||||
|
fn from(value: ByteArrayVec<N>) -> Self {
|
||||||
|
let len = value.len();
|
||||||
|
(0..len).map(|i| value[i]).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use serde_json::{from_str, to_string};
|
use serde_json::{from_str, to_string};
|
||||||
|
|
|
@ -18,6 +18,7 @@ mod key_image_spent_status;
|
||||||
#[allow(clippy::module_inception)]
|
#[allow(clippy::module_inception)]
|
||||||
mod misc;
|
mod misc;
|
||||||
mod pool_info_extent;
|
mod pool_info_extent;
|
||||||
|
mod requested_info;
|
||||||
mod status;
|
mod status;
|
||||||
mod tx_entry;
|
mod tx_entry;
|
||||||
|
|
||||||
|
@ -31,5 +32,6 @@ pub use misc::{
|
||||||
SyncInfoPeer, TxBacklogEntry, TxInfo, TxOutputIndices, TxpoolHisto, TxpoolStats,
|
SyncInfoPeer, TxBacklogEntry, TxInfo, TxOutputIndices, TxpoolHisto, TxpoolStats,
|
||||||
};
|
};
|
||||||
pub use pool_info_extent::PoolInfoExtent;
|
pub use pool_info_extent::PoolInfoExtent;
|
||||||
|
pub use requested_info::RequestedInfo;
|
||||||
pub use status::Status;
|
pub use status::Status;
|
||||||
pub use tx_entry::TxEntry;
|
pub use tx_entry::TxEntry;
|
||||||
|
|
86
rpc/types/src/misc/requested_info.rs
Normal file
86
rpc/types/src/misc/requested_info.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
//! TODO
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Use
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[cfg(feature = "epee")]
|
||||||
|
use cuprate_epee_encoding::{
|
||||||
|
error,
|
||||||
|
macros::bytes::{Buf, BufMut},
|
||||||
|
EpeeValue, Marker,
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- RequestedInfo
|
||||||
|
#[doc = crate::macros::monero_definition_link!(
|
||||||
|
cc73fe71162d564ffda8e549b79a350bca53c454,
|
||||||
|
"rpc/core_rpc_server_commands_defs.h",
|
||||||
|
178..=183
|
||||||
|
)]
|
||||||
|
/// Used in [`crate::bin::GetBlocksRequest`].
|
||||||
|
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum RequestedInfo {
|
||||||
|
#[default]
|
||||||
|
BlocksOnly = 0,
|
||||||
|
BlocksAndPool = 1,
|
||||||
|
PoolOnly = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequestedInfo {
|
||||||
|
/// Convert [`Self`] to a [`u8`].
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cuprate_rpc_types::misc::RequestedInfo as R;
|
||||||
|
///
|
||||||
|
/// assert_eq!(R::BlocksOnly.to_u8(), 0);
|
||||||
|
/// assert_eq!(R::BlocksAndPool.to_u8(), 1);
|
||||||
|
/// assert_eq!(R::PoolOnly.to_u8(), 2);
|
||||||
|
/// ```
|
||||||
|
pub const fn to_u8(self) -> u8 {
|
||||||
|
match self {
|
||||||
|
Self::BlocksOnly => 0,
|
||||||
|
Self::BlocksAndPool => 1,
|
||||||
|
Self::PoolOnly => 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a [`u8`] to a [`Self`].
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This returns [`None`] if `u > 2`.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cuprate_rpc_types::misc::RequestedInfo as R;
|
||||||
|
///
|
||||||
|
/// assert_eq!(R::from_u8(0), Some(R::BlocksOnly));
|
||||||
|
/// assert_eq!(R::from_u8(1), Some(R::BlocksAndPool));
|
||||||
|
/// assert_eq!(R::from_u8(2), Some(R::PoolOnly));
|
||||||
|
/// assert_eq!(R::from_u8(3), None);
|
||||||
|
/// ```
|
||||||
|
pub const fn from_u8(u: u8) -> Option<Self> {
|
||||||
|
Some(match u {
|
||||||
|
0 => Self::BlocksOnly,
|
||||||
|
1 => Self::BlocksAndPool,
|
||||||
|
2 => Self::PoolOnly,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "epee")]
|
||||||
|
impl EpeeValue for RequestedInfo {
|
||||||
|
const MARKER: Marker = u8::MARKER;
|
||||||
|
|
||||||
|
fn read<B: Buf>(r: &mut B, marker: &Marker) -> error::Result<Self> {
|
||||||
|
let u = u8::read(r, marker)?;
|
||||||
|
Self::from_u8(u).ok_or(error::Error::Format("u8 was greater than 2"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<B: BufMut>(self, w: &mut B) -> error::Result<()> {
|
||||||
|
let u = self.to_u8();
|
||||||
|
u8::write(u, w)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue