Compare commits

...

3 commits

Author SHA1 Message Date
hinto.janai
ce6838bd6f
restricted json-rpc error 2024-12-17 18:39:05 -05:00
hinto.janai
3763dc9693
rpc-interface: add restricted invariant comments 2024-12-17 18:23:09 -05:00
hinto.janai
04cdc72f46
/get_blocks.bin 2024-12-17 18:16:03 -05:00
5 changed files with 101 additions and 54 deletions

View file

@ -1,10 +1,13 @@
//! RPC request handler functions (binary endpoints). //! RPC request handler functions (binary endpoints).
use std::num::NonZero;
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use bytes::Bytes; use bytes::Bytes;
use cuprate_constants::rpc::{RESTRICTED_BLOCK_COUNT, RESTRICTED_TRANSACTIONS_COUNT}; use cuprate_constants::rpc::{RESTRICTED_BLOCK_COUNT, RESTRICTED_TRANSACTIONS_COUNT};
use cuprate_fixed_bytes::ByteArrayVec; use cuprate_fixed_bytes::ByteArrayVec;
use cuprate_helper::cast::{u64_to_usize, usize_to_u64};
use cuprate_rpc_interface::RpcHandler; use cuprate_rpc_interface::RpcHandler;
use cuprate_rpc_types::{ use cuprate_rpc_types::{
base::{AccessResponseBase, ResponseBase}, base::{AccessResponseBase, ResponseBase},
@ -17,7 +20,10 @@ use cuprate_rpc_types::{
json::{GetOutputDistributionRequest, GetOutputDistributionResponse}, json::{GetOutputDistributionRequest, GetOutputDistributionResponse},
misc::RequestedInfo, misc::RequestedInfo,
}; };
use cuprate_types::{rpc::PoolInfoExtent, BlockCompleteEntry}; use cuprate_types::{
rpc::{PoolInfo, PoolInfoExtent},
BlockCompleteEntry,
};
use crate::rpc::{ use crate::rpc::{
helper, helper,
@ -50,7 +56,7 @@ pub(super) async fn map_request(
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L611-L789> /// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L611-L789>
async fn get_blocks( async fn get_blocks(
state: CupratedRpcHandler, mut state: CupratedRpcHandler,
request: GetBlocksRequest, request: GetBlocksRequest,
) -> Result<GetBlocksResponse, Error> { ) -> Result<GetBlocksResponse, Error> {
// Time should be set early: // Time should be set early:
@ -58,7 +64,7 @@ async fn get_blocks(
let daemon_time = cuprate_helper::time::current_unix_timestamp(); let daemon_time = cuprate_helper::time::current_unix_timestamp();
let Some(requested_info) = RequestedInfo::from_u8(request.requested_info) else { let Some(requested_info) = RequestedInfo::from_u8(request.requested_info) else {
return Err(anyhow!("Failed, wrong requested info")); return Err(anyhow!("Wrong requested info"));
}; };
let (get_blocks, get_pool) = match requested_info { let (get_blocks, get_pool) = match requested_info {
@ -69,60 +75,66 @@ async fn get_blocks(
let pool_info_extent = PoolInfoExtent::None; let pool_info_extent = PoolInfoExtent::None;
if get_pool { let pool_info = if get_pool {
let allow_sensitive = !state.is_restricted(); let include_sensitive_txs = !state.is_restricted();
let max_tx_count = if state.is_restricted() { let max_tx_count = if state.is_restricted() {
RESTRICTED_TRANSACTIONS_COUNT RESTRICTED_TRANSACTIONS_COUNT
} else { } else {
usize::MAX usize::MAX
}; };
// bool incremental; txpool::pool_info(
// std::vector<std::pair<crypto::hash, tx_memory_pool::tx_details>> added_pool_txs; &mut state.txpool_read,
// bool success = m_core.get_pool_info((time_t)req.pool_info_since, allow_sensitive, max_tx_count, added_pool_txs, res.remaining_added_pool_txids, res.removed_pool_txids, incremental); include_sensitive_txs,
// if (success) max_tx_count,
// { NonZero::new(u64_to_usize(request.pool_info_since)),
// res.added_pool_txs.clear(); )
// if (m_rpc_payment) .await?
// { } else {
// CHECK_PAYMENT_SAME_TS(req, res, added_pool_txs.size() * COST_PER_TX + (res.remaining_added_pool_txids.size() + res.removed_pool_txids.size()) * COST_PER_POOL_HASH); PoolInfo::None
// } };
// for (const auto &added_pool_tx: added_pool_txs)
// { let resp = GetBlocksResponse {
// COMMAND_RPC_GET_BLOCKS_FAST::pool_tx_info info; base: helper::access_response_base(false),
// info.tx_hash = added_pool_tx.first; blocks: vec![],
// std::stringstream oss; start_height: 0,
// binary_archive<true> ar(oss); current_height: 0,
// bool r = req.prune output_indices: vec![],
// ? const_cast<cryptonote::transaction&>(added_pool_tx.second.tx).serialize_base(ar) daemon_time,
// : ::serialization::serialize(ar, const_cast<cryptonote::transaction&>(added_pool_tx.second.tx)); pool_info,
// if (!r) };
// {
// res.status = "Failed to serialize transaction"; if !get_blocks {
// return true; return Ok(resp);
// }
// info.tx_blob = oss.str();
// info.double_spend_seen = added_pool_tx.second.double_spend_seen;
// res.added_pool_txs.push_back(std::move(info));
// }
} }
if get_blocks { // FIXME: impl `first()`
if !request.block_ids.is_empty() { if !request.block_ids.is_empty() {
todo!(); let block_id = request.block_ids[0];
}
todo!(); let (height, hash) = helper::top_height(&mut state).await?;
if hash == block_id {
return Ok(GetBlocksResponse {
current_height: height + 1,
..resp
});
}
}
let block_hashes: Vec<[u8; 32]> = (&request.block_ids).into();
let (blocks, missing_hashes, blockchain_height) =
blockchain::block_complete_entries(&mut state.blockchain_read, block_hashes).await?;
if !missing_hashes.is_empty() {
return Err(anyhow!("Missing blocks"));
} }
Ok(GetBlocksResponse { Ok(GetBlocksResponse {
base: helper::access_response_base(false), blocks,
blocks: todo!(), current_height: usize_to_u64(blockchain_height),
start_height: todo!(), ..resp
current_height: todo!(),
output_indices: todo!(),
daemon_time: todo!(),
pool_info: todo!(),
}) })
} }

View file

@ -411,6 +411,27 @@ pub(crate) async fn total_rct_outputs(
Ok(n) Ok(n)
} }
/// [`BlockchainReadRequest::BlockCompleteEntries`].
pub(crate) async fn block_complete_entries(
blockchain_read: &mut BlockchainReadHandle,
block_hashes: Vec<[u8; 32]>,
) -> Result<(Vec<BlockCompleteEntry>, Vec<[u8; 32]>, usize), Error> {
let BlockchainResponse::BlockCompleteEntries {
blocks,
missing_hashes,
blockchain_height,
} = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::BlockCompleteEntries(block_hashes))
.await?
else {
unreachable!();
};
Ok((blocks, missing_hashes, blockchain_height))
}
/// [`BlockchainReadRequest::BlockCompleteEntriesByHeight`]. /// [`BlockchainReadRequest::BlockCompleteEntriesByHeight`].
pub(crate) async fn block_complete_entries_by_height( pub(crate) async fn block_complete_entries_by_height(
blockchain_read: &mut BlockchainReadHandle, blockchain_read: &mut BlockchainReadHandle,

View file

@ -72,6 +72,12 @@ macro_rules! generate_endpoints_inner {
paste::paste! { paste::paste! {
{ {
// Check if restricted. // Check if restricted.
//
// INVARIANT:
// The RPC handler functions in `cuprated` depend on this line existing,
// the functions themselves do not check if they are being called
// from an (un)restricted context. This line must be here or all
// methods will be allowed to be called freely.
if [<$variant Request>]::IS_RESTRICTED && $handler.is_restricted() { if [<$variant Request>]::IS_RESTRICTED && $handler.is_restricted() {
// TODO: mimic `monerod` behavior. // TODO: mimic `monerod` behavior.
return Err(StatusCode::FORBIDDEN); return Err(StatusCode::FORBIDDEN);

View file

@ -37,16 +37,18 @@ pub(crate) async fn json_rpc<H: RpcHandler>(
// Return early if this RPC server is restricted and // Return early if this RPC server is restricted and
// the requested method is only for non-restricted RPC. // the requested method is only for non-restricted RPC.
//
// INVARIANT:
// The RPC handler functions in `cuprated` depend on this line existing,
// the functions themselves do not check if they are being called
// from an (un)restricted context. This line must be here or all
// methods will be allowed to be called freely.
if request.body.is_restricted() && handler.is_restricted() { if request.body.is_restricted() && handler.is_restricted() {
let error_object = ErrorObject { // The error when a restricted JSON-RPC method is called as per:
code: ErrorCode::ServerError(-1 /* TODO */), //
message: Cow::Borrowed("Restricted. TODO: mimic monerod message"), // - <https://github.com/monero-project/monero/blob/893916ad091a92e765ce3241b94e706ad012b62a/contrib/epee/include/net/http_server_handlers_map2.h#L244-L252>
data: None, // - <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.h#L188>
}; return Ok(Json(Response::method_not_found(id)));
let response = Response::err(id, error_object);
return Ok(Json(response));
} }
// Send request. // Send request.

View file

@ -75,6 +75,12 @@ macro_rules! generate_endpoints_inner {
paste::paste! { paste::paste! {
{ {
// Check if restricted. // Check if restricted.
//
// INVARIANT:
// The RPC handler functions in `cuprated` depend on this line existing,
// the functions themselves do not check if they are being called
// from an (un)restricted context. This line must be here or all
// methods will be allowed to be called freely.
if [<$variant Request>]::IS_RESTRICTED && $handler.is_restricted() { if [<$variant Request>]::IS_RESTRICTED && $handler.is_restricted() {
// TODO: mimic `monerod` behavior. // TODO: mimic `monerod` behavior.
return Err(StatusCode::FORBIDDEN); return Err(StatusCode::FORBIDDEN);