rpc: feature flags, macro changes, misc setup (#218)

* `serde/epee` feature flags

* modify type generator macros

* add `defaults.rs`

* add `free.rs`

* add `misc` module

* modify `base.rs`, `contants.rs`

* remove `binary_string.rs`, `status.rs`

* fix macro usage

* base: re-add `AccessRequestBase`

* fix default functions

* tx_entry: fix link
This commit is contained in:
hinto-janai 2024-07-09 17:58:02 -04:00 committed by GitHub
parent a82c08cc80
commit 136abf7edd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 1259 additions and 364 deletions

View file

@ -9,14 +9,16 @@ repository = "https://github.com/Cuprate/cuprate/tree/main/rpc/types"
keywords = ["cuprate", "rpc", "types", "monero"]
[features]
default = []
default = ["serde", "epee"]
serde = ["dep:serde"]
epee = ["dep:cuprate-epee-encoding"]
[dependencies]
cuprate-epee-encoding = { path = "../../net/epee-encoding" }
cuprate-epee-encoding = { path = "../../net/epee-encoding", optional = true }
monero-serai = { workspace = true }
paste = { workspace = true }
serde = { workspace = true }
serde = { workspace = true, optional = true }
[dev-dependencies]
serde_json = { workspace = true }

View file

@ -10,13 +10,14 @@ 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 4 modules:
- The root module; `cuprate_rpc_types`
- [`json`] module; JSON types from the `/json_rpc` endpoint
- [`bin`] module; Binary types from the binary endpoints
- [`other`] module; Misc JSON types from other endpoints
Miscellaneous types are found in the root module, e.g. [`crate::Status`].
| 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).
@ -30,23 +31,21 @@ However, each type will document:
# Naming
The naming for types within `{json,bin,other}` follow the following scheme:
- Convert the endpoint or method name into `UpperCamelCase`
- Remove any suffix extension
1. Convert the endpoint or method name into `UpperCamelCase`
1. Remove any suffix extension
1. Add `Request/Response` suffix
For example:
| Endpoint/method | Crate location and name |
|-----------------|-------------------------|
| [`get_block_count`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_block_count) | [`json::GetBlockCountRequest`] & [`json::GetBlockCountResponse`]
| [`/get_blocks.bin`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_blockbin) | `bin::GetBlocksRequest` & `bin::GetBlocksResponse`
| [`/get_height`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_height) | `other::GetHeightRequest` & `other::GetHeightResponse`
TODO: fix doc links when types are ready.
| [`/get_blocks.bin`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_blockbin) | [`bin::GetBlocksRequest`] & [`bin::GetBlocksResponse`]
| [`/get_height`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_height) | [`other::GetHeightRequest`] & [`other::GetHeightResponse`]
# 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
{
@ -57,6 +56,20 @@ values inside JSON strings, for example:
}
```
`binary` here is (de)serialized as a normal [`String`]. In order to be clear on which fields contain binary data, the struct fields that have them will use [`crate::BinaryString`] instead of [`String`].
`binary` here is (de)serialized as a normal [`String`]. In order to be clear on which fields contain binary data, the struct fields that have them will use [`crate::misc::BinaryString`] instead of [`String`].
TODO: list the specific types.
These mixed types are:
- [`crate::json::GetTransactionPoolBacklogResponse`]
- [`crate::json::GetOutputDistributionResponse`]
TODO: we need to figure out a type that (de)serializes correctly, `String` errors with `serde_json`
# Feature flags
List of feature flags for `cuprate-rpc-types`.
All are enabled by default.
| Feature flag | Does what |
|--------------|-----------|
| `serde` | Implements `serde` on all types
| `epee` | Implements `cuprate_epee_encoding` on all types

View file

@ -10,76 +10,44 @@
//! - <https://github.com/monero-project/monero/commit/2899379791b7542e4eb920b5d9d58cf232806937>
//! - <https://github.com/monero-project/monero/issues/8722>
//! - <https://github.com/monero-project/monero/pull/8843>
//!
//! Note that this library doesn't use [`AccessRequestBase`](https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L114-L122) found in `monerod`
//! as the type is practically deprecated.
//!
//! Although, [`AccessResponseBase`] still exists as to allow
//! outputting the same JSON fields as `monerod` (even if deprecated).
//---------------------------------------------------------------------------------------------------- Import
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::epee_object;
use crate::Status;
//---------------------------------------------------------------------------------------------------- Macro
/// Link the original `monerod` definition for RPC base types.
macro_rules! monero_rpc_base_link {
($start:literal..=$end:literal) => {
concat!(
"[Definition](https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L",
stringify!($start),
"-L",
stringify!($end),
")."
)
};
}
use crate::{macros::monero_definition_link, misc::Status};
//---------------------------------------------------------------------------------------------------- Requests
/// The most common base for responses (nothing).
///
#[doc = monero_rpc_base_link!(95..=99)]
#[derive(
Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
pub struct EmptyRequestBase;
cuprate_epee_encoding::epee_object! {
EmptyRequestBase,
}
/// A base for RPC request types that support RPC payment.
///
#[doc = monero_rpc_base_link!(114..=122)]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "rpc/core_rpc_server_commands_defs.h", 114..=122)]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct AccessRequestBase {
/// The RPC payment client.
pub client: String,
}
cuprate_epee_encoding::epee_object! {
#[cfg(feature = "epee")]
epee_object! {
AccessRequestBase,
client: String,
}
//---------------------------------------------------------------------------------------------------- Responses
/// An empty response base.
///
/// This is for response types that do not contain
/// any extra fields, e.g. TODO.
// [`CalcPowResponse`](crate::json::CalcPowResponse).
#[derive(
Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
pub struct EmptyResponseBase;
cuprate_epee_encoding::epee_object! {
EmptyResponseBase,
}
#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "rpc/core_rpc_server_commands_defs.h", 101..=112)]
/// The most common base for responses.
///
#[doc = monero_rpc_base_link!(101..=112)]
#[derive(
Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ResponseBase {
/// General RPC error code. [`Status::Ok`] means everything looks good.
pub status: Status,
@ -89,19 +57,20 @@ pub struct ResponseBase {
pub untrusted: bool,
}
#[cfg(feature = "epee")]
epee_object! {
ResponseBase,
status: Status,
untrusted: bool,
}
#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "rpc/core_rpc_server_commands_defs.h", 124..=136)]
/// A base for RPC response types that support RPC payment.
///
#[doc = monero_rpc_base_link!(124..=136)]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct AccessResponseBase {
/// A flattened [`ResponseBase`].
#[serde(flatten)]
#[cfg_attr(feature = "serde", serde(flatten))]
pub response_base: ResponseBase,
/// If payment for RPC is enabled, the number of credits
/// available to the requesting client. Otherwise, `0`.
@ -111,6 +80,7 @@ pub struct AccessResponseBase {
pub top_hash: String,
}
#[cfg(feature = "epee")]
epee_object! {
AccessResponseBase,
credits: u64,

View file

@ -15,6 +15,7 @@
// What this means for Cuprate: just follow `monerod`.
//---------------------------------------------------------------------------------------------------- Import
use crate::macros::monero_definition_link;
//---------------------------------------------------------------------------------------------------- Status
// Common RPC status strings:
@ -23,39 +24,32 @@
// Note that these are _distinct_ from the ones in ZMQ:
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/message.cpp#L40-L44>.
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L78>
#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "/rpc/core_rpc_server_commands_defs.h", 78)]
pub const CORE_RPC_STATUS_OK: &str = "OK";
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L79>
#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "/rpc/core_rpc_server_commands_defs.h", 79)]
pub const CORE_RPC_STATUS_BUSY: &str = "BUSY";
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L80>
#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "/rpc/core_rpc_server_commands_defs.h", 80)]
pub const CORE_RPC_STATUS_NOT_MINING: &str = "NOT MINING";
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L81>
#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "/rpc/core_rpc_server_commands_defs.h", 81)]
pub const CORE_RPC_STATUS_PAYMENT_REQUIRED: &str = "PAYMENT REQUIRED";
/// Custom `CORE_RPC_STATUS` for usage in Cuprate.
pub const CORE_RPC_STATUS_UNKNOWN: &str = "UNKNOWN";
//---------------------------------------------------------------------------------------------------- Versions
#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "/rpc/core_rpc_server_commands_defs.h", 90)]
/// RPC major version.
///
/// See: <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L90>.
pub const CORE_RPC_VERSION_MAJOR: u32 = 3;
#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "/rpc/core_rpc_server_commands_defs.h", 91)]
/// RPC miror version.
///
/// See: <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L91>.
pub const CORE_RPC_VERSION_MINOR: u32 = 14;
#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "/rpc/core_rpc_server_commands_defs.h", 92..=93)]
/// RPC version.
///
/// See: <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L92-L93>.
///
/// ```rust
/// assert_eq!(cuprate_rpc_types::CORE_RPC_VERSION, 196_622);
/// ```
pub const CORE_RPC_VERSION: u32 = (CORE_RPC_VERSION_MAJOR << 16) | CORE_RPC_VERSION_MINOR;
//---------------------------------------------------------------------------------------------------- Tests

70
rpc/types/src/defaults.rs Normal file
View file

@ -0,0 +1,70 @@
//! These functions define the default values
//! of optional fields in request/response types.
//!
//! For example, [`crate::json::GetBlockRequest`]
//! has a [`crate::json::GetBlockRequest::height`]
//! field and a [`crate::json::GetBlockRequest::hash`]
//! field, when the RPC interface reads JSON without
//! `height`, it will use [`default_height`] to fill that in.
//---------------------------------------------------------------------------------------------------- Import
use std::borrow::Cow;
//---------------------------------------------------------------------------------------------------- TODO
/// Default [`bool`] type used in request/response types, `false`.
#[inline]
pub(crate) const fn default_false() -> bool {
false
}
/// Default [`bool`] type used in _some_ request/response types, `true`.
#[inline]
pub(crate) const fn default_true() -> bool {
true
}
/// Default `Cow<'static, str` type used in request/response types.
#[inline]
pub(crate) const fn default_cow_str() -> Cow<'static, str> {
Cow::Borrowed("")
}
/// Default [`String`] type used in request/response types.
#[inline]
pub(crate) const fn default_string() -> String {
String::new()
}
/// Default block height used in request/response types.
#[inline]
pub(crate) const fn default_height() -> u64 {
0
}
/// Default [`Vec`] used in request/response types.
#[inline]
pub(crate) const fn default_vec<T>() -> Vec<T> {
Vec::new()
}
/// Default `0` value used in request/response types.
#[inline]
pub(crate) fn default_zero<T: From<u8>>() -> T {
T::from(0)
}
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]
mod test {
use super::*;
/// Tests that [`default_zero`] returns `0` on all unsigned numbers.
#[test]
fn zero() {
assert_eq!(default_zero::<usize>(), 0);
assert_eq!(default_zero::<u64>(), 0);
assert_eq!(default_zero::<u32>(), 0);
assert_eq!(default_zero::<u16>(), 0);
assert_eq!(default_zero::<u8>(), 0);
}
}

18
rpc/types/src/free.rs Normal file
View file

@ -0,0 +1,18 @@
//! Free functions.
//---------------------------------------------------------------------------------------------------- Serde
// These are functions used for conditionally (de)serialization.
/// Returns `true` if the input `u` is equal to `0`.
#[inline]
#[allow(clippy::trivially_copy_pass_by_ref)] // serde needs `&`
pub(crate) const fn is_zero(u: &u64) -> bool {
*u == 0
}
/// Returns `true` the input `u` is equal to `1`.
#[inline]
#[allow(clippy::trivially_copy_pass_by_ref)] // serde needs `&`
pub(crate) const fn is_one(u: &u64) -> bool {
*u == 1
}

View file

@ -3,10 +3,7 @@
//! <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/daemon_messages.h>.
//---------------------------------------------------------------------------------------------------- Import
use crate::{
base::{EmptyRequestBase, EmptyResponseBase, ResponseBase},
macros::define_request_and_response,
};
use crate::{base::ResponseBase, macros::define_request_and_response};
//---------------------------------------------------------------------------------------------------- Struct definitions
// This generates 2 structs:
@ -26,38 +23,43 @@ define_request_and_response! {
// The base type name.
GetBlockTemplate,
// The base request type.
// The request type.
//
// This must be a type found in [`crate::base`].
// It acts as a "base" that gets flattened into
// the actually request type.
// If `Request {/* fields */}` is provided, a struct is generate as-is.
//
// "Flatten" means the field(s) of a struct gets inlined
// directly into the struct during (de)serialization, see:
// <https://serde.rs/field-attrs.html#flatten>.
//
// For example here, we're using [`crate::base::EmptyRequestBase`],
// which means that there is no extra fields flattened.
//
// If a request is not specified here, it will create a `type alias YOUR_REQUEST_TYPE = ()`
// If `Request {}` is specified here, it will create a `pub type YOUR_REQUEST_TYPE = ()`
// instead of a `struct`, see below in other macro definitions for an example.
EmptyRequestBase {
reserve_size: u64,
wallet_address: String,
prev_block: String,
extra_nonce: String,
},
// The base response type.
//
// This is the same as the request base type,
// it must be a type found in [`crate::base`].
//
// If there are any additional attributes (`/// docs` or `#[derive]`s)
// for the struct, they go here, e.g.:
// #[derive(Copy)]
Request {
// Within the `{}` is an infinite matching pattern of:
// ```
// $ATTRIBUTES
// $FIELD_NAME: $FIELD_TYPE,
// ```
// The struct generated and all fields are `pub`.
extra_nonce: String,
prev_block: String,
reserve_size: u64,
wallet_address: String,
},
// The response type.
//
// If `Response {/* fields */}` is used,
// this will generate a struct as-is.
//
// If a type found in [`crate::base`] is used,
// It acts as a "base" that gets flattened into
// the actual request type.
//
// "Flatten" means the field(s) of a struct gets inlined
// directly into the struct during (de)serialization, see:
// <https://serde.rs/field-attrs.html#flatten>.
ResponseBase {
// This is using `crate::base::ResponseBase`,
// This is using [`crate::base::ResponseBase`],
// so the type we generate will contain this field:
// ```
// base: crate::base::ResponseBase,
@ -69,56 +71,18 @@ define_request_and_response! {
// status: crate::Status,
// untrusted: bool,
// ```
// Within the `{}` is an infinite matching pattern of:
// ```
// $ATTRIBUTES
// $FIELD_NAME: $FIELD_TYPE,
// ```
// The struct generated and all fields are `pub`.
difficulty: u64,
wide_difficulty: String,
difficulty_top64: u64,
height: u64,
reserved_offset: u64,
expected_reward: u64,
prev_hash: String,
seed_height: u64,
seed_hash: String,
next_seed_hash: String,
blocktemplate_blob: String,
blockhashing_blob: String,
}
}
define_request_and_response! {
get_block_count,
cc73fe71162d564ffda8e549b79a350bca53c454 =>
core_rpc_server_commands_defs.h => 919..=933,
GetBlockCount,
// There is no request type specified,
// this will cause the macro to generate a
// type alias to `()` instead of a `struct`.
ResponseBase {
count: u64,
}
}
define_request_and_response! {
on_get_block_hash,
cc73fe71162d564ffda8e549b79a350bca53c454 =>
core_rpc_server_commands_defs.h => 935..=939,
OnGetBlockHash,
#[derive(Copy)]
EmptyRequestBase {
#[serde(flatten)]
block_height: u64,
},
EmptyResponseBase {
#[serde(flatten)]
block_hash: String,
blocktemplate_blob: String,
difficulty_top64: u64,
difficulty: u64,
expected_reward: u64,
height: u64,
next_seed_hash: String,
prev_hash: String,
reserved_offset: u64,
seed_hash: String,
seed_height: u64,
wide_difficulty: String,
}
}

View file

@ -1,4 +1,5 @@
#![doc = include_str!("../README.md")]
#![cfg_attr(docsrs, feature(doc_cfg))]
//---------------------------------------------------------------------------------------------------- Lints
// Forbid lints.
// Our code, and code generated (e.g macros) cannot overrule these.
@ -13,7 +14,6 @@
unused_allocation,
coherence_leak_check,
while_true,
clippy::missing_docs_in_private_items,
// Maybe can be put into `#[deny]`.
unconditional_recursion,
@ -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,
@ -94,23 +102,25 @@
)
)]
// TODO: remove me after finishing impl
#![allow(dead_code)]
#![allow(
dead_code,
rustdoc::broken_intra_doc_links // TODO: remove after `{bin,json,other}.rs` gets merged
)]
//---------------------------------------------------------------------------------------------------- Use
mod binary_string;
//---------------------------------------------------------------------------------------------------- Mod
mod constants;
mod defaults;
mod free;
mod macros;
mod status;
pub use binary_string::BinaryString;
pub mod base;
pub mod bin;
pub mod json;
pub mod misc;
pub mod other;
pub use constants::{
CORE_RPC_STATUS_BUSY, CORE_RPC_STATUS_NOT_MINING, CORE_RPC_STATUS_OK,
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;
pub mod bin;
pub mod json;
pub mod other;

View file

@ -1,14 +1,12 @@
//! Macros.
//---------------------------------------------------------------------------------------------------- Struct definition
/// A template for generating 2 `struct`s with a bunch of information filled out.
///
/// These are the RPC request and response `struct`s.
//---------------------------------------------------------------------------------------------------- define_request_and_response
/// A template for generating the RPC request and response `struct`s.
///
/// These `struct`s automatically implement:
/// - `Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash`
/// - `serde::{Serialize, Deserialize}`
/// - `epee_encoding::EpeeObject`
/// - `cuprate_epee_encoding::EpeeObject`
///
/// It's best to see the output of this macro via the documentation
/// of the generated structs via `cargo doc`s to see which parts
@ -17,110 +15,35 @@
/// See the [`crate::json`] module for example usage.
///
/// # Macro internals
/// This macro has 2 branches with almost the same output:
/// 1. An empty `Request` type
/// 2. An `Request` type with fields
/// This macro uses:
/// - [`__define_request`]
/// - [`__define_response`]
/// - [`__define_request_and_response_doc`]
///
/// The first branch is the same as the second with the exception
/// that if the caller of this macro provides no fields, it will
/// generate:
/// # `__define_request`
/// This macro has 2 branches. If the caller provides
/// `Request {}`, i.e. no fields, it will generate:
/// ```
/// pub type Request = ();
/// ```
/// instead of:
/// If they _did_ specify fields, it will generate:
/// ```
/// pub struct Request {/* fields */}
/// ```
///
/// This is because having a bunch of types that are all empty structs
/// means they are not compatible and it makes it cumbersome for end-users.
/// Really, they semantically are empty types, so `()` is used.
///
/// Again, other than this, the 2 branches do (should) not differ.
/// # `__define_response`
/// This macro has 2 branches. If the caller provides `Response`
/// it will generate a normal struct with no additional fields.
///
/// FIXME: there's probably a less painful way to branch here on input
/// without having to duplicate 80% of the macro. Sub-macros were attempted
/// but they ended up unreadable. So for now, make sure to fix the other
/// branch as well when making changes. The only de-duplicated part is
/// the doc generation with [`define_request_and_response_doc`].
/// If the caller provides a base type from [`crate::base`], it will
/// flatten that into the request type automatically.
///
/// E.g. `Response {/*...*/}` and `ResponseBase {/*...*/}`
/// would trigger the different branches.
macro_rules! define_request_and_response {
//------------------------------------------------------------------------------
// This version of the macro expects a `Request` type with no fields, i.e. `Request {}`.
(
// The markdown tag for Monero RPC documentation. Not necessarily the endpoint.
$monero_daemon_rpc_doc_link:ident,
// The commit hash and `$file.$extension` in which this type is defined in
// the Monero codebase in the `rpc/` directory, followed by the specific lines.
$monero_code_commit:ident =>
$monero_code_filename:ident.
$monero_code_filename_extension:ident =>
$monero_code_line_start:literal..=
$monero_code_line_end:literal,
// The base `struct` name.
$type_name:ident,
// The response type (and any doc comments, derives, etc).
$( #[$response_type_attr:meta] )*
$response_base_type:ty {
// And any fields.
$(
$( #[$response_field_attr:meta] )*
$response_field:ident: $response_field_type:ty,
)*
}
) => { paste::paste! {
#[doc = $crate::macros::define_request_and_response_doc!(
"response",
$monero_daemon_rpc_doc_link,
$monero_code_commit,
$monero_code_filename,
$monero_code_filename_extension,
$monero_code_line_start,
$monero_code_line_end,
[<$type_name Request>],
)]
///
/// This request has no inputs.
pub type [<$type_name Request>] = ();
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
$( #[$response_type_attr] )*
#[doc = $crate::macros::define_request_and_response_doc!(
"request",
$monero_daemon_rpc_doc_link,
$monero_code_commit,
$monero_code_filename,
$monero_code_filename_extension,
$monero_code_line_start,
$monero_code_line_end,
[<$type_name Response>],
)]
pub struct [<$type_name Response>] {
#[serde(flatten)]
pub base: $response_base_type,
$(
$( #[$response_field_attr] )*
pub $response_field: $response_field_type,
)*
}
::cuprate_epee_encoding::epee_object! {
[<$type_name Response>],
$(
$response_field: $response_field_type,
)*
!flatten: base: $response_base_type,
}
}};
//------------------------------------------------------------------------------
// This version of the macro expects a `Request` type with fields.
(
// The markdown tag for Monero RPC documentation. Not necessarily the endpoint.
$monero_daemon_rpc_doc_link:ident,
@ -134,15 +57,18 @@ macro_rules! define_request_and_response {
$monero_code_line_end:literal,
// The base `struct` name.
// Attributes added here will apply to _both_
// request and response types.
$( #[$type_attr:meta] )*
$type_name:ident,
// The request type (and any doc comments, derives, etc).
$( #[$request_type_attr:meta] )*
$request_base_type:ty {
Request {
// And any fields.
$(
$( #[$request_field_attr:meta] )*
$request_field:ident: $request_field_type:ty,
$request_field:ident: $request_field_type:ty $(= $request_field_type_default:expr)?,
)*
},
@ -152,84 +78,213 @@ macro_rules! define_request_and_response {
// And any fields.
$(
$( #[$response_field_attr:meta] )*
$response_field:ident: $response_field_type:ty,
$response_field:ident: $response_field_type:ty $(= $response_field_type_default:expr)?,
)*
}
) => { paste::paste! {
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
$( #[$request_type_attr] )*
#[doc = $crate::macros::define_request_and_response_doc!(
"response",
$monero_daemon_rpc_doc_link,
$monero_code_commit,
$monero_code_filename,
$monero_code_filename_extension,
$monero_code_line_start,
$monero_code_line_end,
[<$type_name Request>],
)]
pub struct [<$type_name Request>] {
#[serde(flatten)]
pub base: $request_base_type,
$(
$( #[$request_field_attr] )*
pub $request_field: $request_field_type,
)*
$crate::macros::__define_request! {
#[doc = $crate::macros::__define_request_and_response_doc!(
"response" => [<$type_name Response>],
$monero_daemon_rpc_doc_link,
$monero_code_commit,
$monero_code_filename,
$monero_code_filename_extension,
$monero_code_line_start,
$monero_code_line_end,
)]
///
$( #[$type_attr] )*
///
$( #[$request_type_attr] )*
[<$type_name Request>] {
$(
$( #[$request_field_attr] )*
$request_field: $request_field_type $(= $request_field_type_default)?,
)*
}
}
::cuprate_epee_encoding::epee_object! {
[<$type_name Request>],
$(
$request_field: $request_field_type,
)*
!flatten: base: $request_base_type,
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
$( #[$response_type_attr] )*
#[doc = $crate::macros::define_request_and_response_doc!(
"request",
$monero_daemon_rpc_doc_link,
$monero_code_commit,
$monero_code_filename,
$monero_code_filename_extension,
$monero_code_line_start,
$monero_code_line_end,
[<$type_name Response>],
)]
pub struct [<$type_name Response>] {
#[serde(flatten)]
pub base: $response_base_type,
$(
$( #[$response_field_attr] )*
pub $response_field: $response_field_type,
)*
}
::cuprate_epee_encoding::epee_object! {
[<$type_name Response>],
$(
$response_field: $response_field_type,
)*
!flatten: base: $response_base_type,
$crate::macros::__define_response! {
#[allow(dead_code)]
#[allow(missing_docs)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[doc = $crate::macros::__define_request_and_response_doc!(
"request" => [<$type_name Request>],
$monero_daemon_rpc_doc_link,
$monero_code_commit,
$monero_code_filename,
$monero_code_filename_extension,
$monero_code_line_start,
$monero_code_line_end,
)]
///
$( #[$type_attr] )*
///
$( #[$response_type_attr] )*
$response_base_type => [<$type_name Response>] {
$(
$( #[$response_field_attr] )*
$response_field: $response_field_type $(= $response_field_type_default)?,
)*
}
}
}};
}
pub(crate) use define_request_and_response;
//---------------------------------------------------------------------------------------------------- define_request
/// Define a request type.
///
/// This is only used in [`define_request_and_response`], see it for docs.
///
/// `__` is used to notate that this shouldn't be called directly.
macro_rules! __define_request {
//------------------------------------------------------------------------------
// This branch will generate a type alias to `()` if only given `{}` as input.
(
// Any doc comments, derives, etc.
$( #[$attr:meta] )*
// The response type.
$t:ident {}
) => {
$( #[$attr] )*
///
/// This request has no inputs.
pub type $t = ();
};
//------------------------------------------------------------------------------
// This branch of the macro expects fields within the `{}`,
// and will generate a `struct`
(
// Any doc comments, derives, etc.
$( #[$attr:meta] )*
// The response type.
$t:ident {
// And any fields.
$(
$( #[$field_attr:meta] )* // field attributes
// field_name: FieldType
$field:ident: $field_type:ty $(= $field_default:expr)?,
// The $field_default is an optional extra token that represents
// a default value to pass to [`cuprate_epee_encoding::epee_object`],
// see it for usage.
)*
}
) => {
#[allow(dead_code, missing_docs)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
$( #[$attr] )*
pub struct $t {
$(
$( #[$field_attr] )*
pub $field: $field_type,
)*
}
#[cfg(feature = "epee")]
::cuprate_epee_encoding::epee_object! {
$t,
$(
$field: $field_type $(= $field_default)?,
)*
}
};
}
pub(crate) use __define_request;
//---------------------------------------------------------------------------------------------------- define_response
/// Define a response type.
///
/// This is only used in [`define_request_and_response`], see it for docs.
///
/// `__` is used to notate that this shouldn't be called directly.
macro_rules! __define_response {
//------------------------------------------------------------------------------
// This version of the macro expects the literal ident
// `Response` => $response_type_name.
//
// It will create a `struct` that _doesn't_ use a base from [`crate::base`],
// for example, [`crate::json::BannedResponse`] doesn't use a base, so it
// uses this branch.
(
// Any doc comments, derives, etc.
$( #[$attr:meta] )*
// The response type.
Response => $t:ident {
// And any fields.
// See [`__define_request`] for docs, this does the same thing.
$(
$( #[$field_attr:meta] )*
$field:ident: $field_type:ty $(= $field_default:expr)?,
)*
}
) => {
$( #[$attr] )*
pub struct $t {
$(
$( #[$field_attr] )*
pub $field: $field_type,
)*
}
#[cfg(feature = "epee")]
::cuprate_epee_encoding::epee_object! {
$t,
$(
$field: $field_type $($field_default)?,
)*
}
};
//------------------------------------------------------------------------------
// This version of the macro expects a `Request` base type from [`crate::bases`].
(
// Any doc comments, derives, etc.
$( #[$attr:meta] )*
// The response base type => actual name of the struct
$base:ty => $t:ident {
// And any fields.
// See [`__define_request`] for docs, this does the same thing.
$(
$( #[$field_attr:meta] )*
$field:ident: $field_type:ty $(= $field_default:expr)?,
)*
}
) => {
$( #[$attr] )*
pub struct $t {
#[cfg_attr(feature = "serde", serde(flatten))]
pub base: $base,
$(
$( #[$field_attr] )*
pub $field: $field_type,
)*
}
#[cfg(feature = "epee")]
::cuprate_epee_encoding::epee_object! {
$t,
$(
$field: $field_type $(= $field_default)?,
)*
!flatten: base: $base,
}
};
}
pub(crate) use __define_response;
//---------------------------------------------------------------------------------------------------- define_request_and_response_doc
/// Generate documentation for the types generated
/// by the [`define_request_and_response`] macro.
/// by the [`__define_request_and_response`] macro.
///
/// See it for more info on inputs.
macro_rules! define_request_and_response_doc {
///
/// `__` is used to notate that this shouldn't be called directly.
macro_rules! __define_request_and_response_doc {
(
// This labels the last `[request]` or `[response]`
// hyperlink in documentation. Input is either:
@ -239,7 +294,7 @@ macro_rules! define_request_and_response_doc {
// Remember this is linking to the _other_ type,
// so if defining a `Request` type, input should
// be "response".
$request_or_response:literal,
$request_or_response:literal => $request_or_response_type:ident,
$monero_daemon_rpc_doc_link:ident,
$monero_code_commit:ident,
@ -247,7 +302,6 @@ macro_rules! define_request_and_response_doc {
$monero_code_filename_extension:ident,
$monero_code_line_start:literal,
$monero_code_line_end:literal,
$type_name:ident,
) => {
concat!(
"",
@ -269,9 +323,34 @@ macro_rules! define_request_and_response_doc {
"), [",
$request_or_response,
"](",
stringify!($type_name),
stringify!($request_or_response_type),
")."
)
};
}
pub(crate) use define_request_and_response_doc;
pub(crate) use __define_request_and_response_doc;
//---------------------------------------------------------------------------------------------------- Macro
/// Output a string link to `monerod` source code.
macro_rules! monero_definition_link {
(
$commit:ident, // Git commit hash
$file_path:literal, // File path within `monerod`'s `src/`, e.g. `rpc/core_rpc_server_commands_defs.h`
$start:literal$(..=$end:literal)? // File lines, e.g. `0..=123` or `0`
) => {
concat!(
"[Definition](https://github.com/monero-project/monero/blob/",
stringify!($commit),
"/src/",
$file_path,
"#L",
stringify!($start),
$(
"-L",
stringify!($end),
)?
")."
)
};
}
pub(crate) use monero_definition_link;

View file

@ -1,14 +1,14 @@
//! TODO
//! JSON string containing binary data.
//---------------------------------------------------------------------------------------------------- Import
//---------------------------------------------------------------------------------------------------- BinaryString
/// TODO
/// TODO: we need to figure out a type that (de)serializes correctly, `String` errors with `serde_json`
///
/// ```rust
/// use serde::Deserialize;
/// use serde_json::from_str;
/// use cuprate_rpc_types::BinaryString;
/// use cuprate_rpc_types::misc::BinaryString;
///
/// #[derive(Deserialize)]
/// struct Key {

View file

@ -0,0 +1,37 @@
//! TODO
//---------------------------------------------------------------------------------------------------- Use
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::epee_object;
use crate::misc::TxBlobEntry;
//---------------------------------------------------------------------------------------------------- BlockCompleteEntry
#[doc = crate::macros::monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
210..=221
)]
/// Used in [`crate::bin::GetBlocksResponse`].
#[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>,
}

View file

@ -0,0 +1,48 @@
//! TODO
//---------------------------------------------------------------------------------------------------- Use
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::{
macros::bytes::{Buf, BufMut},
EpeeValue, Marker,
};
//---------------------------------------------------------------------------------------------------- KeyImageSpentStatus
#[doc = crate::macros::monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
456..=460
)]
/// Used in [`crate::other::IsKeyImageSpentResponse`].
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum KeyImageSpentStatus {
Unspent = 0,
SpentInBlockchain = 1,
SpentInPool = 2,
}
#[cfg(feature = "epee")]
impl EpeeValue for KeyImageSpentStatus {
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!()
}
}

539
rpc/types/src/misc/misc.rs Normal file
View file

@ -0,0 +1,539 @@
//! Miscellaneous types.
//!
//! These are `struct`s that appear in request/response types.
//! For example, [`crate::json::GetConnectionsResponse`] contains
//! the [`crate::misc::ConnectionInfo`] struct defined here.
//---------------------------------------------------------------------------------------------------- Import
use std::fmt::Display;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::{
epee_object,
macros::bytes::{Buf, BufMut},
EpeeValue, Marker,
};
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,
},
defaults::default_zero,
macros::monero_definition_link,
};
//---------------------------------------------------------------------------------------------------- Macros
/// This macro (local to this file) defines all the misc types.
///
/// This macro:
/// 1. Defines a `pub struct` with all `pub` fields
/// 2. Implements `serde` on the struct
/// 3. Implements `epee` on the struct
///
/// When using, consider documenting:
/// - The original Monero definition site with [`monero_definition_link`]
/// - The request/responses where the `struct` is used
macro_rules! define_struct_and_impl_epee {
(
// Optional `struct` attributes.
$( #[$struct_attr:meta] )*
// The `struct`'s name.
$struct_name:ident {
// And any fields.
$(
$( #[$field_attr:meta] )* // Field attributes
// Field name => the type => optional `epee_object` default value.
$field_name:ident: $field_type:ty $(= $field_default:expr)?,
)*
}
) => {
$( #[$struct_attr] )*
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct $struct_name {
$(
$( #[$field_attr] )*
pub $field_name: $field_type,
)*
}
#[cfg(feature = "epee")]
epee_object! {
$struct_name,
$(
$field_name: $field_type $(= $field_default)?,
)*
}
};
}
//---------------------------------------------------------------------------------------------------- Type Definitions
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
1163..=1212
)]
///
/// Used in:
/// - [`crate::json::GetLastBlockHeaderResponse`]
/// - [`crate::json::GetBlockHeaderByHashResponse`]
/// - [`crate::json::GetBlockHeaderByHeightResponse`]
/// - [`crate::json::GetBlockHeadersRangeResponse`]
/// - [`crate::json::GetBlockResponse`]
BlockHeader {
block_size: u64,
block_weight: u64,
cumulative_difficulty_top64: u64,
cumulative_difficulty: u64,
depth: u64,
difficulty_top64: u64,
difficulty: u64,
hash: String,
height: u64,
long_term_weight: u64,
major_version: u8,
miner_tx_hash: String,
minor_version: u8,
nonce: u32,
num_txes: u64,
orphan_status: bool,
pow_hash: String,
prev_hash: String,
reward: u64,
timestamp: u64,
wide_cumulative_difficulty: String,
wide_difficulty: String,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"cryptonote_protocol/cryptonote_protocol_defs.h",
47..=116
)]
/// Used in [`crate::json::GetConnectionsResponse`].
ConnectionInfo {
address: String,
address_type: u8,
avg_download: u64,
avg_upload: u64,
connection_id: String,
current_download: u64,
current_upload: u64,
height: u64,
host: String,
incoming: bool,
ip: String,
live_time: u64,
localhost: bool,
local_ip: bool,
peer_id: String,
port: String,
pruning_seed: u32,
recv_count: u64,
recv_idle_time: u64,
rpc_credits_per_hash: u32,
rpc_port: u16,
send_count: u64,
send_idle_time: u64,
ssl: bool,
state: String,
support_flags: u32,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
2034..=2047
)]
/// Used in [`crate::json::SetBansRequest`].
SetBan {
host: String,
ip: u32,
ban: bool,
seconds: u32,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
1999..=2010
)]
/// Used in [`crate::json::GetBansResponse`].
GetBan {
host: String,
ip: u32,
seconds: u32,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
2139..=2156
)]
#[derive(Copy)]
/// Used in [`crate::json::GetOutputHistogramResponse`].
HistogramEntry {
amount: u64,
total_instances: u64,
unlocked_instances: u64,
recent_instances: u64,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
2180..=2191
)]
#[derive(Copy)]
/// Used in [`crate::json::GetVersionResponse`].
HardforkEntry {
height: u64,
hf_version: u8,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
2289..=2310
)]
/// Used in [`crate::json::GetAlternateChainsResponse`].
ChainInfo {
block_hash: String,
block_hashes: Vec<String>,
difficulty: u64,
difficulty_top64: u64,
height: u64,
length: u64,
main_chain_parent_block: String,
wide_difficulty: String,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
2393..=2400
)]
/// Used in [`crate::json::SyncInfoResponse`].
SyncInfoPeer {
info: ConnectionInfo,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
2402..=2421
)]
/// Used in [`crate::json::SyncInfoResponse`].
Span {
connection_id: String,
nblocks: u64,
rate: u32,
remote_address: String,
size: u64,
speed: u32,
start_block_height: u64,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
1637..=1642
)]
#[derive(Copy)]
/// Used in [`crate::json::GetTransactionPoolBacklogResponse`].
TxBacklogEntry {
weight: u64,
fee: u64,
time_in_pool: u64,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/rpc_handler.h",
45..=50
)]
/// Used in [`crate::json::GetOutputDistributionResponse`].
OutputDistributionData {
distribution: Vec<u64>,
start_height: u64,
base: u64,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
1016..=1027
)]
/// Used in [`crate::json::GetMinerDataResponse`].
///
/// Note that this is different than [`crate::misc::TxBacklogEntry`].
GetMinerDataTxBacklogEntry {
id: String,
weight: u64,
fee: u64,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
1070..=1079
)]
/// Used in [`crate::json::AddAuxPowRequest`].
AuxPow {
id: String,
hash: String,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
192..=199
)]
/// Used in [`crate::bin::GetBlocksResponse`].
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::GetBlocksResponse`].
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::GetBlocksResponse`].
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::GetBlocksResponse`].
TxBlobEntry {
blob: String,
prunable_hash: [u8; 32],
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
512..=521
)]
#[derive(Copy)]
///
/// Used in:
/// - [`crate::bin::GetOutsRequest`]
/// - [`crate::other::GetOutsRequest`]
GetOutputsOut {
amount: u64,
index: u64,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
538..=553
)]
#[derive(Copy)]
/// Used in [`crate::bin::GetOutsRequest`].
OutKeyBin {
key: [u8; 32],
mask: [u8; 32],
unlocked: bool,
height: u64,
txid: [u8; 32],
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
1335..=1367
)]
/// Used in [`crate::other::GetPeerListResponse`].
Peer {
id: u64,
host: String,
ip: u32,
port: u16,
#[cfg_attr(feature = "serde", serde(default = "default_zero"))]
rpc_port: u16 = default_zero::<u16>(),
#[cfg_attr(feature = "serde", serde(default = "default_zero"))]
rpc_credits_per_hash: u32 = default_zero::<u32>(),
last_seen: u64,
#[cfg_attr(feature = "serde", serde(default = "default_zero"))]
pruning_seed: u32 = default_zero::<u32>(),
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
1398..=1417
)]
///
/// Used in:
/// - [`crate::other::GetPeerListResponse`]
/// - [`crate::other::GetPublicNodesResponse`]
PublicNode {
host: String,
last_seen: u64,
rpc_port: u16,
rpc_credits_per_hash: u32,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
1519..=1556
)]
/// Used in [`crate::other::GetTransactionPoolResponse`].
TxInfo {
blob_size: u64,
do_not_relay: bool,
double_spend_seen: bool,
fee: u64,
id_hash: String,
kept_by_block: bool,
last_failed_height: u64,
last_failed_id_hash: String,
last_relayed_time: u64,
max_used_block_height: u64,
max_used_block_id_hash: String,
receive_time: u64,
relayed: bool,
tx_blob: String,
tx_json: String, // TODO: this should be another struct
#[cfg_attr(feature = "serde", serde(default = "default_zero"))]
weight: u64 = default_zero::<u64>(),
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
1558..=1567
)]
/// Used in [`crate::other::GetTransactionPoolResponse`].
SpentKeyImageInfo {
id_hash: String,
txs_hashes: Vec<String>,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
1666..=1675
)]
#[derive(Copy)]
/// Used in [`crate::other::GetTransactionPoolStatsResponse`].
TxpoolHisto {
txs: u32,
bytes: u64,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
1677..=1710
)]
/// Used in [`crate::other::GetTransactionPoolStatsResponse`].
TxpoolStats {
bytes_max: u32,
bytes_med: u32,
bytes_min: u32,
bytes_total: u64,
fee_total: u64,
histo_98pc: u64,
histo: Vec<TxpoolHisto>,
num_10m: u32,
num_double_spends: u32,
num_failing: u32,
num_not_relayed: u32,
oldest: u64,
txs_total: u32,
}
}
define_struct_and_impl_epee! {
#[doc = monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
582..=597
)]
/// Used in [`crate::other::GetOutsResponse`].
OutKey {
key: String,
mask: String,
unlocked: bool,
height: u64,
txid: String,
}
}
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]
mod test {}

34
rpc/types/src/misc/mod.rs Normal file
View file

@ -0,0 +1,34 @@
//! Miscellaneous types.
//!
//! These are data types that appear in request/response types.
//!
//! For example, [`crate::json::GetConnectionsResponse`] contains
//! the [`crate::misc::ConnectionInfo`] struct defined here.
//---------------------------------------------------------------------------------------------------- Lints
#![allow(
missing_docs, // Docs are at: <https://www.getmonero.org/resources/developer-guides/daemon-rpc.html>
clippy::struct_excessive_bools, // hey man, tell that to the people who wrote `monerod`
)]
//---------------------------------------------------------------------------------------------------- Mod
mod binary_string;
mod block_complete_entry;
mod key_image_spent_status;
mod misc;
mod pool_info_extent;
mod status;
mod tx_entry;
pub use binary_string::BinaryString;
pub use block_complete_entry::BlockCompleteEntry;
pub use key_image_spent_status::KeyImageSpentStatus;
pub use misc::{
AuxPow, BlockHeader, BlockOutputIndices, ChainInfo, ConnectionInfo, GetBan,
GetMinerDataTxBacklogEntry, GetOutputsOut, HardforkEntry, HistogramEntry, OutKey, OutKeyBin,
OutputDistributionData, Peer, PoolTxInfo, PublicNode, SetBan, Span, SpentKeyImageInfo,
SyncInfoPeer, TxBacklogEntry, TxBlobEntry, TxInfo, TxOutputIndices, TxpoolHisto, TxpoolStats,
};
pub use pool_info_extent::PoolInfoExtent;
pub use status::Status;
pub use tx_entry::TxEntry;

View file

@ -0,0 +1,49 @@
//! TODO
//---------------------------------------------------------------------------------------------------- Use
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::{
macros::bytes::{Buf, BufMut},
EpeeValue, Marker,
};
//---------------------------------------------------------------------------------------------------- PoolInfoExtent
#[doc = crate::macros::monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
223..=228
)]
/// Used in [`crate::bin::GetBlocksResponse`].
#[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!()
}
}

View file

@ -3,8 +3,10 @@
//---------------------------------------------------------------------------------------------------- Import
use std::fmt::Display;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::{
macros::bytes::{Buf, BufMut},
EpeeValue, Marker,
@ -16,18 +18,20 @@ use crate::constants::{
};
//---------------------------------------------------------------------------------------------------- Status
// TODO: this type needs to expand more.
// There are a lot of RPC calls that will return a random
// string inside, which isn't compatible with [`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::{
/// Status,
/// misc::Status,
/// CORE_RPC_STATUS_BUSY, CORE_RPC_STATUS_NOT_MINING, CORE_RPC_STATUS_OK,
/// CORE_RPC_STATUS_PAYMENT_REQUIRED, CORE_RPC_STATUS_UNKNOWN
/// };
@ -59,28 +63,27 @@ use crate::constants::{
/// assert_eq!(format!("{:?}", Status::PaymentRequired), "PaymentRequired");
/// assert_eq!(format!("{:?}", unknown), "Unknown");
/// ```
#[derive(
Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
#[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`].
#[serde(rename = "OK")]
#[cfg_attr(feature = "serde", serde(rename = "OK"))]
#[default]
Ok,
/// The daemon is busy, try later; [`CORE_RPC_STATUS_BUSY`].
#[serde(rename = "BUSY")]
#[cfg_attr(feature = "serde", serde(rename = "BUSY"))]
Busy,
/// The daemon is not mining; [`CORE_RPC_STATUS_NOT_MINING`].
#[serde(rename = "NOT MINING")]
#[cfg_attr(feature = "serde", serde(rename = "NOT MINING"))]
NotMining,
/// Payment is required for RPC; [`CORE_RPC_STATUS_PAYMENT_REQUIRED`].
#[serde(rename = "PAYMENT REQUIRED")]
#[cfg_attr(feature = "serde", serde(rename = "PAYMENT REQUIRED"))]
PaymentRequired,
/// Some unknown other string; [`CORE_RPC_STATUS_UNKNOWN`].
@ -91,8 +94,8 @@ pub enum Status {
/// The reason this isn't `Unknown(String)` is because that
/// disallows [`Status`] to be [`Copy`], and thus other types
/// that contain it.
#[serde(other)]
#[serde(rename = "UNKNOWN")]
#[cfg_attr(feature = "serde", serde(other))]
#[cfg_attr(feature = "serde", serde(rename = "UNKNOWN"))]
Unknown,
}
@ -132,6 +135,7 @@ impl Display for Status {
//
// 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;
@ -161,6 +165,7 @@ mod test {
// Test epee (de)serialization works.
#[test]
#[cfg(feature = "epee")]
fn epee() {
for status in [
Status::Ok,

View file

@ -0,0 +1,59 @@
//! TODO
//---------------------------------------------------------------------------------------------------- Use
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::{
epee_object,
macros::bytes::{Buf, BufMut},
EpeeValue, Marker,
};
//---------------------------------------------------------------------------------------------------- TxEntry
#[doc = crate::macros::monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
389..=428
)]
/// Used in [`crate::other::GetTransactionsResponse`].
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TxEntry {
pub as_hex: String,
pub as_json: String,
pub block_height: u64,
pub block_timestamp: u64,
pub confirmations: u64,
pub double_spend_seen: bool,
pub in_pool: bool,
pub output_indices: Vec<u64>,
pub prunable_as_hex: String,
pub prunable_hash: String,
pub pruned_as_hex: String,
pub received_timestamp: u64,
pub relayed: bool,
pub tx_hash: String,
}
// TODO: custom epee
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L406-L427>
#[cfg(feature = "epee")]
epee_object! {
TxEntry,
as_hex: String,
as_json: String, // TODO: should be its own struct
block_height: u64,
block_timestamp: u64,
confirmations: u64,
double_spend_seen: bool,
in_pool: bool,
output_indices: Vec<u64>,
prunable_as_hex: String,
prunable_hash: String,
pruned_as_hex: String,
received_timestamp: u64,
relayed: bool,
tx_hash: String,
}

View file

@ -7,11 +7,15 @@ use crate::{base::ResponseBase, macros::define_request_and_response};
//---------------------------------------------------------------------------------------------------- TODO
define_request_and_response! {
save_bc,
get_height,
cc73fe71162d564ffda8e549b79a350bca53c454 =>
core_rpc_server_commands_defs.h => 898..=916,
SaveBc,
ResponseBase {}
core_rpc_server_commands_defs.h => 138..=160,
GetHeight,
Request {},
ResponseBase {
hash: String,
height: u64,
}
}
//---------------------------------------------------------------------------------------------------- Tests