add misc module, start bin and other

This commit is contained in:
hinto.janai 2024-07-07 16:29:24 -04:00
parent 57e9bd1efa
commit 3557ee63bf
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
8 changed files with 401 additions and 29 deletions

View file

@ -10,17 +10,17 @@ This crate ports the types used in Monero's RPC interface, including:
# Modules
This crate's types are split in the following manner:
This crate has 5 modules:
- The root module - miscellaneous items
- [`json`] - JSON types from the `/json_rpc` endpoint
- [`bin`] - Binary types from the binary endpoints
- [`other`] - Misc JSON types from other endpoints
- [`base`] - Base response types
| Module | Purpose |
|--------|---------|
| The root module | Miscellaneous items, e.g. constants.
| [`json`] | Contains JSON request/response (some mixed with binary) that all share the common `/json_rpc` endpoint. |
| [`bin`] | Contains request/response types that are expected to be fully in binary (`cuprate_epee_encoding`) in `monerod` and `cuprated`'s RPC interface. These are called at a custom endpoint instead of `/json_rpc`, e.g. `/get_blocks.bin`. |
| [`other`] | Contains request/response types that are JSON, but aren't called at `/json_rpc` (e.g. [`crate::other::GetHeightRequest`]). |
| [`misc`] | Contains miscellaneous types, e.g. [`crate::misc::Status`]. Many of types here are found and used in request/response types, for example, [`crate::misc::BlockHeader`] is used in [`crate::json::GetLastBlockHeaderResponse`]. |
| [`base`] | Contains base types flattened into many request/response types.
Each type in `{json,bin,other}` come in pairs and have identical names, but are suffixed with either `Request` or `Response`. e.g. [`GetBlockCountRequest`](crate::json::GetBlockCountRequest) & [`GetBlockCountResponse`](crate::json::GetBlockCountResponse).
Miscellaneous types are found in the root module, e.g. [`crate::Status`]. Many of types here are found and used in request/response types, for example, [`crate::BlockHeader`] is used in [`crate::json::GetLastBlockHeaderResponse`].
# Documentation
The documentation for types within `{json,bin,other}` are omitted, as they can be found in [Monero's RPC documentation](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html).
@ -45,9 +45,8 @@ For example:
TODO: fix doc links when types are ready.
# Mixed types
Note that some types within [`other`] mix JSON & binary together, i.e.,
the message overall is JSON, however some fields contain binary
values inside JSON strings, for example:
Note that some types mix JSON & binary together, i.e., the message overall is JSON,
however some fields contain binary values inside JSON strings, for example:
```json
{

View file

@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::epee_object;
use crate::{macros::monero_definition_link, Status};
use crate::{macros::monero_definition_link, misc::Status};
//---------------------------------------------------------------------------------------------------- Requests
/* no types here... yet */

View file

@ -1,8 +1,71 @@
//! Binary types from [binary](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_blocksbin) endpoints.
//!
//! Most (if not all) of these types are defined here:
//! - <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h>
//---------------------------------------------------------------------------------------------------- Import
use crate::{
base::{AccessResponseBase, ResponseBase},
defaults::{
default_bool, default_height, default_string, default_u64, default_u8, default_vec,
},
free::{is_one, is_zero},
macros::define_request_and_response,
misc::{
AuxPow, BlockCompleteEntry, BlockHeader, BlockOutputIndices, ChainInfo, ConnectionInfo,
GetBan, HardforkEntry, HistogramEntry, OutputDistributionData, Peer, PoolTxInfo, SetBan,
Span, Status, TxBacklogEntry,
},
};
//---------------------------------------------------------------------------------------------------- TODO
define_request_and_response! {
get_blocks_bin,
cc73fe71162d564ffda8e549b79a350bca53c454 =>
core_rpc_server_commands_defs.h => 162..=262,
GetBlocksBin,
Request {
#[cfg_attr(feature = "serde", serde(default = "default_u8"))]
requested_info: u8 = default_u8(),
// TODO: This is a `std::list` in `monerod` because...?
block_ids: Vec<[u8; 32]>,
start_height: u64,
prune: bool,
#[cfg_attr(feature = "serde", serde(default = "default_bool"))]
no_miner_tx: bool = default_bool(),
#[cfg_attr(feature = "serde", serde(default = "default_u64"))]
pool_info_since: u64 = default_u64(),
},
ResponseBase {
blocks: Vec<BlockCompleteEntry>,
start_height: u64,
current_height: u64,
output_indices: Vec<BlockOutputIndices>,
daemon_time: u64,
pool_info_extent: u8,
added_pool_txs: Vec<PoolTxInfo>,
remaining_added_pool_txids: Vec<[u8; 32]>,
removed_pool_txids: Vec<[u8; 32]>,
}
}
define_request_and_response! {
add_aux_pow,
cc73fe71162d564ffda8e549b79a350bca53c454 =>
core_rpc_server_commands_defs.h => 1068..=1112,
AddAuxPow,
Request {
blocktemplate_blob: String,
aux_pow: Vec<AuxPow>,
},
ResponseBase {
blocktemplate_blob: String,
blockhashing_blob: String,
merkle_root: String,
merkle_tree_depth: u64,
aux_pow: Vec<AuxPow>,
}
}
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]

View file

@ -47,6 +47,12 @@ pub(crate) const fn default_u64() -> u64 {
0
}
/// Default [`u8`] used in request/response types.
#[inline]
pub(crate) const fn default_u8() -> u8 {
0
}
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]
mod test {

View file

@ -11,9 +11,8 @@ use crate::{
macros::define_request_and_response,
misc::{
AuxPow, BlockHeader, ChainInfo, ConnectionInfo, GetBan, HardforkEntry, HistogramEntry,
Peer, SetBan, Span, TxBacklogEntry,
OutputDistributionData, Peer, SetBan, Span, Status, TxBacklogEntry,
},
OutputDistributionData, Status,
};
//---------------------------------------------------------------------------------------------------- Struct definitions

View file

@ -82,7 +82,15 @@
clippy::option_if_let_else,
)]
// Allow some lints when running in debug mode.
#![cfg_attr(debug_assertions, allow(clippy::todo, clippy::multiple_crate_versions))]
#![cfg_attr(
debug_assertions,
allow(
clippy::todo,
clippy::multiple_crate_versions,
unused_imports,
unused_variables
)
)]
// Allow some lints in tests.
#![cfg_attr(
test,
@ -102,7 +110,6 @@ mod constants;
mod defaults;
mod free;
mod macros;
mod status;
pub use binary_string::BinaryString;
pub use constants::{
@ -110,7 +117,6 @@ pub use constants::{
CORE_RPC_STATUS_PAYMENT_REQUIRED, CORE_RPC_STATUS_UNKNOWN, CORE_RPC_VERSION,
CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR,
};
pub use status::Status;
pub mod base;
#[cfg(feature = "bin")]
@ -119,12 +125,7 @@ pub mod bin;
#[cfg(feature = "json")]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
pub mod json;
pub mod misc;
#[cfg(feature = "other")]
#[cfg_attr(docsrs, doc(cfg(feature = "other")))]
pub mod other;
mod misc;
pub use misc::{
AuxPow, BlockHeader, ChainInfo, ConnectionInfo, GetBan, GetMinerDataTxBacklogEntry,
HardforkEntry, HistogramEntry, OutputDistributionData, Peer, SetBan, Span, TxBacklogEntry,
};

View file

@ -3,8 +3,6 @@
//! These are `struct`s that appear in request/response types.
//! For example, [`crate::json::GetConnectionsResponse`] contains
//! the [`crate::misc::ConnectionInfo`] struct defined here.
//!
//! These types are re-exported to the root module.
//---------------------------------------------------------------------------------------------------- Lints
#![allow(
@ -13,13 +11,25 @@
)]
//---------------------------------------------------------------------------------------------------- Import
use std::fmt::Display;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::epee_object;
use cuprate_epee_encoding::{
epee_object,
macros::bytes::{Buf, BufMut},
EpeeValue, Marker,
};
use crate::macros::monero_definition_link;
use crate::{
constants::{
CORE_RPC_STATUS_BUSY, CORE_RPC_STATUS_NOT_MINING, CORE_RPC_STATUS_OK,
CORE_RPC_STATUS_PAYMENT_REQUIRED, CORE_RPC_STATUS_UNKNOWN,
},
macros::monero_definition_link,
};
//---------------------------------------------------------------------------------------------------- Macros
/// This macro (local to this file) defines all the misc types.
@ -328,8 +338,289 @@ define_struct_and_impl_epee! {
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
192..=199
)]
/// Used in [`crate::bin::GetBlocksBinResponse`].
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
TxOutputIndices {
indices: Vec<u64>,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
201..=208
)]
/// Used in [`crate::bin::GetBlocksBinResponse`].
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
BlockOutputIndices {
indices: Vec<TxOutputIndices>,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
210..=221
)]
/// Used in [`crate::bin::GetBlocksBinResponse`].
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
PoolTxInfo {
tx_hash: [u8; 32],
tx_blob: String,
double_spend_seen: bool,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"cryptonote_protocol/cryptonote_protocol_defs.h",
121..=131
)]
/// Used in [`crate::bin::GetBlocksBinResponse`].
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
TxBlobEntry {
blob: String,
prunable_hash: [u8; 32],
}
}
//---------------------------------------------------------------------------------------------------- TODO
// TODO - weird types.
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
210..=221
)]
/// Used in [`crate::bin::GetBlocksBinResponse`].
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BlockCompleteEntry {
pub pruned: bool,
pub block: String,
pub block_weight: u64,
pub txs: Vec<TxBlobEntry>,
}
// TODO: custom epee
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/cryptonote_protocol/cryptonote_protocol_defs.h#L138-L163>
#[cfg(feature = "epee")]
epee_object! {
BlockCompleteEntry,
pruned: bool,
block: String,
block_weight: u64,
txs: Vec<TxBlobEntry>,
}
/// Used in [`crate::bin::GetBlocksBinResponse`].
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum PoolInfoExtent {
None = 0,
Incremental = 1,
Full = 2,
}
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/cryptonote_protocol/cryptonote_protocol_defs.h#L138-L163>
#[cfg(feature = "epee")]
impl EpeeValue for PoolInfoExtent {
const MARKER: Marker = <String as EpeeValue>::MARKER;
fn read<B: Buf>(r: &mut B, marker: &Marker) -> cuprate_epee_encoding::Result<Self> {
todo!()
}
fn should_write(&self) -> bool {
todo!()
}
fn epee_default_value() -> Option<Self> {
todo!()
}
fn write<B: BufMut>(self, w: &mut B) -> cuprate_epee_encoding::Result<()> {
todo!()
}
}
//---------------------------------------------------------------------------------------------------- Status
/// RPC response status.
///
/// This type represents `monerod`'s frequently appearing string field, `status`.
///
/// This field appears within RPC [JSON response](crate::json) types.
///
/// Reference: <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L78-L81>.
///
/// ## Serialization and string formatting
/// ```rust
/// use cuprate_rpc_types::{
/// misc::Status,
/// CORE_RPC_STATUS_BUSY, CORE_RPC_STATUS_NOT_MINING, CORE_RPC_STATUS_OK,
/// CORE_RPC_STATUS_PAYMENT_REQUIRED, CORE_RPC_STATUS_UNKNOWN
/// };
/// use serde_json::to_string;
///
/// let unknown = Status::Unknown;
///
/// assert_eq!(to_string(&Status::Ok).unwrap(), r#""OK""#);
/// assert_eq!(to_string(&Status::Busy).unwrap(), r#""BUSY""#);
/// assert_eq!(to_string(&Status::NotMining).unwrap(), r#""NOT MINING""#);
/// assert_eq!(to_string(&Status::PaymentRequired).unwrap(), r#""PAYMENT REQUIRED""#);
/// assert_eq!(to_string(&unknown).unwrap(), r#""UNKNOWN""#);
///
/// assert_eq!(Status::Ok.as_ref(), CORE_RPC_STATUS_OK);
/// assert_eq!(Status::Busy.as_ref(), CORE_RPC_STATUS_BUSY);
/// assert_eq!(Status::NotMining.as_ref(), CORE_RPC_STATUS_NOT_MINING);
/// assert_eq!(Status::PaymentRequired.as_ref(), CORE_RPC_STATUS_PAYMENT_REQUIRED);
/// assert_eq!(unknown.as_ref(), CORE_RPC_STATUS_UNKNOWN);
///
/// assert_eq!(format!("{}", Status::Ok), CORE_RPC_STATUS_OK);
/// assert_eq!(format!("{}", Status::Busy), CORE_RPC_STATUS_BUSY);
/// assert_eq!(format!("{}", Status::NotMining), CORE_RPC_STATUS_NOT_MINING);
/// assert_eq!(format!("{}", Status::PaymentRequired), CORE_RPC_STATUS_PAYMENT_REQUIRED);
/// assert_eq!(format!("{}", unknown), CORE_RPC_STATUS_UNKNOWN);
///
/// assert_eq!(format!("{:?}", Status::Ok), "Ok");
/// assert_eq!(format!("{:?}", Status::Busy), "Busy");
/// assert_eq!(format!("{:?}", Status::NotMining), "NotMining");
/// assert_eq!(format!("{:?}", Status::PaymentRequired), "PaymentRequired");
/// assert_eq!(format!("{:?}", unknown), "Unknown");
/// ```
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Status {
// FIXME:
// `#[serde(rename = "")]` only takes raw string literals?
// We have to re-type the constants here...
/// Successful RPC response, everything is OK; [`CORE_RPC_STATUS_OK`].
#[cfg_attr(feature = "serde", serde(rename = "OK"))]
#[default]
Ok,
/// The daemon is busy, try later; [`CORE_RPC_STATUS_BUSY`].
#[cfg_attr(feature = "serde", serde(rename = "BUSY"))]
Busy,
/// The daemon is not mining; [`CORE_RPC_STATUS_NOT_MINING`].
#[cfg_attr(feature = "serde", serde(rename = "NOT MINING"))]
NotMining,
/// Payment is required for RPC; [`CORE_RPC_STATUS_PAYMENT_REQUIRED`].
#[cfg_attr(feature = "serde", serde(rename = "PAYMENT REQUIRED"))]
PaymentRequired,
/// Some unknown other string; [`CORE_RPC_STATUS_UNKNOWN`].
///
/// This exists to act as a catch-all if `monerod` adds
/// a string and a Cuprate node hasn't updated yet.
///
/// The reason this isn't `Unknown(String)` is because that
/// disallows [`Status`] to be [`Copy`], and thus other types
/// that contain it.
#[cfg_attr(feature = "serde", serde(other))]
#[cfg_attr(feature = "serde", serde(rename = "UNKNOWN"))]
Unknown,
}
impl From<String> for Status {
fn from(s: String) -> Self {
match s.as_str() {
CORE_RPC_STATUS_OK => Self::Ok,
CORE_RPC_STATUS_BUSY => Self::Busy,
CORE_RPC_STATUS_NOT_MINING => Self::NotMining,
CORE_RPC_STATUS_PAYMENT_REQUIRED => Self::PaymentRequired,
_ => Self::Unknown,
}
}
}
impl AsRef<str> for Status {
fn as_ref(&self) -> &str {
match self {
Self::Ok => CORE_RPC_STATUS_OK,
Self::Busy => CORE_RPC_STATUS_BUSY,
Self::NotMining => CORE_RPC_STATUS_NOT_MINING,
Self::PaymentRequired => CORE_RPC_STATUS_PAYMENT_REQUIRED,
Self::Unknown => CORE_RPC_STATUS_UNKNOWN,
}
}
}
impl Display for Status {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_ref())
}
}
// [`Status`] is essentially a [`String`] when it comes to
// (de)serialization, except when writing we usually have
// access to a `&'static str` and don't need to allocate.
//
// See below for more impl info:
// <https://github.com/Cuprate/cuprate/blob/bef2a2cbd4e1194991751d1fbc96603cba8c7a51/net/epee-encoding/src/value.rs#L366-L392>.
#[cfg(feature = "epee")]
impl EpeeValue for Status {
const MARKER: Marker = <String as EpeeValue>::MARKER;
fn read<B: Buf>(r: &mut B, marker: &Marker) -> cuprate_epee_encoding::Result<Self> {
let string = <String as EpeeValue>::read(r, marker)?;
Ok(Self::from(string))
}
fn should_write(&self) -> bool {
true
}
fn epee_default_value() -> Option<Self> {
// <https://github.com/Cuprate/cuprate/pull/147#discussion_r1654992559>
Some(Self::Unknown)
}
fn write<B: BufMut>(self, w: &mut B) -> cuprate_epee_encoding::Result<()> {
cuprate_epee_encoding::write_bytes(self.as_ref(), w)
}
}
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]
mod test {
// use super::*;
use super::*;
// Test epee (de)serialization works.
#[test]
#[cfg(feature = "epee")]
fn epee() {
for status in [
Status::Ok,
Status::Busy,
Status::NotMining,
Status::PaymentRequired,
Status::Unknown,
] {
let mut buf = vec![];
<Status as EpeeValue>::write(status, &mut buf).unwrap();
let status2 =
<Status as EpeeValue>::read(&mut buf.as_slice(), &<Status as EpeeValue>::MARKER)
.unwrap();
assert_eq!(status, status2);
}
}
}

View file

@ -1,11 +1,24 @@
//! JSON types from the [`other`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#other-daemon-rpc-calls) endpoints.
//!
//! <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/daemon_messages.h>.
//! Most (if not all) of these types are defined here:
//! - <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h>
//---------------------------------------------------------------------------------------------------- Import
use crate::{base::ResponseBase, macros::define_request_and_response};
//---------------------------------------------------------------------------------------------------- TODO
define_request_and_response! {
get_height,
cc73fe71162d564ffda8e549b79a350bca53c454 =>
core_rpc_server_commands_defs.h => 138..=160,
GetHeight,
Request {},
ResponseBase {
hash: String,
height: u64,
}
}
define_request_and_response! {
save_bc,
cc73fe71162d564ffda8e549b79a350bca53c454 =>