rpc: move json-rpc types away from macros
Some checks are pending
Deny / audit (push) Waiting to run

This commit is contained in:
hinto.janai 2024-12-06 11:29:55 -05:00
parent a1903f33b0
commit d1c1025238
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
14 changed files with 1250 additions and 886 deletions

2
Cargo.lock generated
View file

@ -1072,7 +1072,9 @@ dependencies = [
"cuprate-test-utils",
"cuprate-types",
"hex",
"hex-literal",
"paste",
"pretty_assertions",
"serde",
"serde_json",
]

View file

@ -76,7 +76,6 @@ pub(super) async fn block_header(
let (cumulative_difficulty_top64, cumulative_difficulty) =
split_u128_into_low_high_bits(header.cumulative_difficulty);
let (difficulty_top64, difficulty) = split_u128_into_low_high_bits(difficulty);
let wide_difficulty = hex::encode(difficulty.to_ne_bytes());
let reward = block
.miner_transaction

View file

@ -34,24 +34,25 @@ use cuprate_rpc_types::{
GetBlockCountRequest, GetBlockCountResponse, GetBlockHeaderByHashRequest,
GetBlockHeaderByHashResponse, GetBlockHeaderByHeightRequest,
GetBlockHeaderByHeightResponse, GetBlockHeadersRangeRequest, GetBlockHeadersRangeResponse,
GetBlockRequest, GetBlockResponse, GetCoinbaseTxSumRequest, GetCoinbaseTxSumResponse,
GetConnectionsRequest, GetConnectionsResponse, GetFeeEstimateRequest,
GetFeeEstimateResponse, GetInfoRequest, GetInfoResponse, GetLastBlockHeaderRequest,
GetLastBlockHeaderResponse, GetMinerDataRequest, GetMinerDataResponse,
GetOutputDistributionRequest, GetOutputDistributionResponse, GetOutputHistogramRequest,
GetOutputHistogramResponse, GetTransactionPoolBacklogRequest,
GetTransactionPoolBacklogResponse, GetTxIdsLooseRequest, GetTxIdsLooseResponse,
GetVersionRequest, GetVersionResponse, HardForkInfoRequest, HardForkInfoResponse,
JsonRpcRequest, JsonRpcResponse, OnGetBlockHashRequest, OnGetBlockHashResponse,
PruneBlockchainRequest, PruneBlockchainResponse, RelayTxRequest, RelayTxResponse,
SetBansRequest, SetBansResponse, SubmitBlockRequest, SubmitBlockResponse, SyncInfoRequest,
SyncInfoResponse,
GetBlockRequest, GetBlockResponse, GetBlockTemplateRequest, GetBlockTemplateResponse,
GetCoinbaseTxSumRequest, GetCoinbaseTxSumResponse, GetConnectionsRequest,
GetConnectionsResponse, GetFeeEstimateRequest, GetFeeEstimateResponse, GetInfoRequest,
GetInfoResponse, GetLastBlockHeaderRequest, GetLastBlockHeaderResponse,
GetMinerDataRequest, GetMinerDataResponse, GetOutputDistributionRequest,
GetOutputDistributionResponse, GetOutputHistogramRequest, GetOutputHistogramResponse,
GetTransactionPoolBacklogRequest, GetTransactionPoolBacklogResponse, GetTxIdsLooseRequest,
GetTxIdsLooseResponse, GetVersionRequest, GetVersionResponse, HardForkInfoRequest,
HardForkInfoResponse, JsonRpcRequest, JsonRpcResponse, OnGetBlockHashRequest,
OnGetBlockHashResponse, PruneBlockchainRequest, PruneBlockchainResponse, RelayTxRequest,
RelayTxResponse, SetBansRequest, SetBansResponse, SubmitBlockRequest, SubmitBlockResponse,
SyncInfoRequest, SyncInfoResponse,
},
misc::{BlockHeader, ChainInfo, Distribution, GetBan, HistogramEntry, Status, SyncInfoPeer},
CORE_RPC_VERSION,
};
use cuprate_types::{
rpc::{AuxPow, CoinbaseTxSum, GetMinerDataTxBacklogEntry, HardforkEntry, TxBacklogEntry},
hex::Hex,
rpc::{AuxPow, CoinbaseTxSum, GetMinerDataTxBacklogEntry, HardForkEntry, TxBacklogEntry},
HardFork,
};
@ -76,6 +77,7 @@ pub(super) async fn map_request(
use JsonRpcResponse as Resp;
Ok(match request {
Req::GetBlockTemplate(r) => Resp::GetBlockTemplate(get_block_template(state, r).await?),
Req::GetBlockCount(r) => Resp::GetBlockCount(get_block_count(state, r).await?),
Req::OnGetBlockHash(r) => Resp::OnGetBlockHash(on_get_block_hash(state, r).await?),
Req::SubmitBlock(r) => Resp::SubmitBlock(submit_block(state, r).await?),
@ -125,6 +127,101 @@ pub(super) async fn map_request(
})
}
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L1911-L2005>
async fn get_block_template(
mut state: CupratedRpcHandler,
request: GetBlockTemplateRequest,
) -> Result<GetBlockTemplateResponse, Error> {
if request.reserve_size > 255 {
return Err(anyhow!("Too big reserved size, maximum 255"));
}
if request.reserve_size != 0 && !request.extra_nonce.is_empty() {
return Err(anyhow!(
"Cannot specify both a reserve_size and an extra_nonce"
));
}
if request.extra_nonce.len() > 510 {
return Err(anyhow!("Too big extra_nonce size"));
}
// cryptonote::address_parse_info info;
if request.wallet_address.is_empty()
|| todo!(
"!cryptonote::get_account_address_from_str(info, nettype(), request.wallet_address))"
)
{
return Err(anyhow!("Failed to parse wallet address"));
}
if todo!("info.is_subaddress") {
return Err(anyhow!("Mining to subaddress is not supported yet"));
}
// block b;
// cryptonote::blobdata blob_reserve;
// size_t reserved_offset;
// if(!request.extra_nonce.empty())
// {
// if(!string_tools::parse_hexstr_to_binbuff(request.extra_nonce, blob_reserve))
// {
// error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
// error_resp.message = "Parameter extra_nonce should be a hex string";
// return false;
// }
// }
// else
// blob_reserve.resize(request.reserve_size, 0);
// cryptonote::difficulty_type wdiff;
// crypto::hash prev_block;
// if (!request.prev_block.empty())
// {
// if (!epee::string_tools::hex_to_pod(request.prev_block, prev_block))
// {
// error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
// error_resp.message = "Invalid prev_block";
// return false;
// }
// }
// crypto::hash seed_hash, next_seed_hash;
// if (!get_block_template(info.address, request.prev_block.empty() ? NULL : &prev_block, blob_reserve, reserved_offset, wdiff, res.height, res.expected_reward, res.cumulative_weight, b, res.seed_height, seed_hash, next_seed_hash, error_resp))
// return false;
// if (b.major_version >= RX_BLOCK_VERSION)
// {
// res.seed_hash = string_tools::pod_to_hex(seed_hash);
// if (seed_hash != next_seed_hash)
// res.next_seed_hash = string_tools::pod_to_hex(next_seed_hash);
// }
// res.reserved_offset = reserved_offset;
// store_difficulty(wdiff, res.difficulty, res.wide_difficulty, res.difficulty_top64);
// blobdata block_blob = t_serializable_object_to_blob(b);
// blobdata hashing_blob = get_block_hashing_blob(b);
// res.prev_hash = string_tools::pod_to_hex(b.prev_id);
// res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob);
// res.blockhashing_blob = string_tools::buff_to_hex_nodelimer(hashing_blob);
// res.status = CORE_RPC_STATUS_OK;
// return true;
Ok(GetBlockTemplateResponse {
base: ResponseBase::OK,
blockhashing_blob: todo!(),
blocktemplate_blob: todo!(),
difficulty_top64: todo!(),
difficulty: todo!(),
expected_reward: todo!(),
height: todo!(),
next_seed_hash: todo!(),
prev_hash: todo!(),
reserved_offset: todo!(),
seed_hash: todo!(),
seed_height: todo!(),
wide_difficulty: todo!(),
})
}
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L1790-L1804>
async fn get_block_count(
mut state: CupratedRpcHandler,
@ -148,9 +245,10 @@ async fn on_get_block_hash(
todo!("access to `cuprated`'s Chain"),
)
.await?;
let block_hash = hex::encode(hash);
Ok(OnGetBlockHashResponse { block_hash })
Ok(OnGetBlockHashResponse {
block_hash: Hex(hash),
})
}
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L2209-L2266>
@ -232,19 +330,19 @@ async fn get_block_header_by_hash(
async fn get(
state: &mut CupratedRpcHandler,
hex: String,
hash: [u8; 32],
fill_pow_hash: bool,
) -> Result<BlockHeader, Error> {
let hash = helper::hex_to_hash(hex)?;
let block_header = helper::block_header_by_hash(state, hash, fill_pow_hash).await?;
Ok(block_header)
}
let block_header = get(&mut state, request.hash, request.fill_pow_hash).await?;
let block_header = get(&mut state, request.hash.0, request.fill_pow_hash).await?;
// FIXME PERF: could make a `Vec` on await on all tasks at the same time.
let mut block_headers = Vec::with_capacity(request.hashes.len());
for hash in request.hashes {
let hash = helper::hex_to_hash(hash)?;
let hash = get(&mut state, hash, request.fill_pow_hash).await?;
block_headers.push(hash);
}
@ -736,7 +834,7 @@ async fn get_version(
for hf in HardFork::VARIANTS {
if let Ok(hf) = blockchain_context::hard_fork_info(&mut state.blockchain_context, *hf).await
{
let entry = HardforkEntry {
let entry = HardForkEntry {
height: hf.earliest_height,
hf_version: HardFork::from_version(hf.version)
.expect("blockchain context should not be responding with invalid hardforks"),
@ -1196,7 +1294,7 @@ fn add_aux_pow_inner(
let blocktemplate_blob = hex::encode(blocktemplate_blob);
let blockhashing_blob = hex::encode(blockhashing_blob);
let merkle_root = hex::encode(merkle_root);
let merkle_root = Hex(merkle_root);
let aux_pow = aux_pow.into_vec();
Ok(AddAuxPowResponse {

View file

@ -23,7 +23,7 @@ map = ["cast", "dep:monero-serai", "dep:cuprate-constants"]
time = ["dep:chrono", "std"]
thread = ["std", "dep:target_os_lib"]
tx = ["dep:monero-serai"]
fmt = ["map"]
fmt = ["map", "std"]
[dependencies]
cuprate-constants = { workspace = true, optional = true, features = ["block"] }

View file

@ -11,7 +11,7 @@ pub mod atomic;
#[cfg(feature = "cast")]
pub mod cast;
#[cfg(all(feature = "fs", feature = "std"))]
#[cfg(feature = "fs")]
pub mod fs;
pub mod network;

View file

@ -59,6 +59,7 @@ impl Service<JsonRpcRequest> for RpcHandlerDummy {
#[expect(clippy::default_trait_access)]
let resp = match req {
Req::GetBlockTemplate(_) => Resp::GetBlockTemplate(Default::default()),
Req::GetBlockCount(_) => Resp::GetBlockCount(Default::default()),
Req::OnGetBlockHash(_) => Resp::OnGetBlockHash(Default::default()),
Req::SubmitBlock(_) => Resp::SubmitBlock(Default::default()),

View file

@ -16,6 +16,7 @@ from = [
"dep:cuprate-helper",
"cuprate-helper/map",
"cuprate-helper/fmt",
"cuprate-types/rpc",
"dep:cuprate-p2p-core",
"dep:hex"
]
@ -34,8 +35,10 @@ hex = { workspace = true, optional = true }
[dev-dependencies]
cuprate-test-utils = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
hex-literal = { workspace = true }
pretty_assertions = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
[lints]
workspace = true

View file

@ -8,6 +8,7 @@
//! `height`, it will use [`default_height`] to fill that in.
//---------------------------------------------------------------------------------------------------- Import
// use cuprate_types::hex::Hex;
//---------------------------------------------------------------------------------------------------- TODO
/// Default [`bool`] type used in request/response types, `false`.
@ -28,6 +29,12 @@ pub(crate) const fn default_string() -> String {
String::new()
}
// /// Default [`Hex`] type used in request/response types.
// #[inline]
// pub(crate) const fn default_hex<const N: usize>() -> Hex<N> {
// Hex([0; N])
// }
/// Default block height used in request/response types.
#[inline]
pub(crate) const fn default_height() -> u64 {

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,7 @@ json = ["hex", "dep:cuprate-helper"]
# We sadly have no choice but to enable serde here as otherwise we will get warnings from the `hex` dep being unused.
# This isn't too bad as `Hex` only makes sense with serde anyway.
hex = ["serde", "dep:hex"]
rpc = ["hex"]
rpc = ["hex", "json"]
[dependencies]
cuprate-epee-encoding = { workspace = true, optional = true, features = ["std"] }

View file

@ -59,6 +59,7 @@ pub enum HardForkError {
)]
#[cfg_attr(any(feature = "proptest"), derive(proptest_derive::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "u8", into = "u8"))]
#[repr(u8)]
pub enum HardFork {
#[default]
@ -203,6 +204,19 @@ impl HardFork {
}
}
impl TryFrom<u8> for HardFork {
type Error = HardForkError;
fn try_from(version: u8) -> Result<Self, Self::Error> {
Self::from_version(version)
}
}
impl From<HardFork> for u8 {
fn from(value: HardFork) -> Self {
value.as_u8()
}
}
#[cfg(feature = "epee")]
impl EpeeValue for HardFork {
const MARKER: Marker = u8::MARKER;

View file

@ -56,6 +56,37 @@ impl<const N: usize> Default for Hex<N> {
}
}
impl<const N: usize> From<Hex<N>> for [u8; N] {
fn from(hex: Hex<N>) -> Self {
hex.0
}
}
impl<const N: usize> From<[u8; N]> for Hex<N> {
fn from(value: [u8; N]) -> Self {
Self(value)
}
}
impl<const N: usize> TryFrom<String> for Hex<N> {
type Error = hex::FromHexError;
fn try_from(value: String) -> Result<Self, Self::Error> {
let vec = hex::decode(value)?;
match <[u8; N]>::try_from(vec) {
Ok(s) => Ok(Self(s)),
Err(_) => Err(hex::FromHexError::InvalidStringLength),
}
}
}
impl<const N: usize> TryFrom<&str> for Hex<N> {
type Error = hex::FromHexError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let mut bytes = [0; N];
hex::decode_to_slice(value, &mut bytes).map(|()| Self(bytes))
}
}
#[cfg(test)]
mod test {
use super::*;

View file

@ -16,7 +16,7 @@ pub use pool_info::PoolInfo;
pub use pool_info_extent::PoolInfoExtent;
pub use types::{
AddAuxPow, AuxPow, BlockHeader, BlockOutputIndices, ChainInfo, CoinbaseTxSum, ConnectionInfo,
FeeEstimate, GetBan, GetMinerDataTxBacklogEntry, GetOutputsOut, HardForkInfo, HardforkEntry,
FeeEstimate, GetBan, GetMinerDataTxBacklogEntry, GetOutputsOut, HardForkEntry, HardForkInfo,
HistogramEntry, MinerData, MinerDataTxBacklogEntry, OutKey, OutKeyBin, OutputDistributionData,
OutputHistogramEntry, OutputHistogramInput, Peer, PoolInfoFull, PoolInfoIncremental,
PoolTxInfo, PublicNode, SetBan, Span, SpentKeyImageInfo, SyncInfoPeer, TxBacklogEntry, TxInfo,

View file

@ -190,7 +190,7 @@ define_struct_and_impl_epee! {
2180..=2191
)]
#[derive(Copy)]
HardforkEntry {
HardForkEntry {
height: u64,
hf_version: HardFork,
}