diff --git a/rpc/types/Cargo.toml b/rpc/types/Cargo.toml index 30e4aa95..c088e4df 100644 --- a/rpc/types/Cargo.toml +++ b/rpc/types/Cargo.toml @@ -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 } diff --git a/rpc/types/README.md b/rpc/types/README.md index 65b6d907..21905fab 100644 --- a/rpc/types/README.md +++ b/rpc/types/README.md @@ -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. \ No newline at end of file +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 \ No newline at end of file diff --git a/rpc/types/src/base.rs b/rpc/types/src/base.rs index 6a293678..f13ac403 100644 --- a/rpc/types/src/base.rs +++ b/rpc/types/src/base.rs @@ -10,76 +10,44 @@ //! - //! - //! - +//! +//! 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, diff --git a/rpc/types/src/constants.rs b/rpc/types/src/constants.rs index 2d5266fd..e5802836 100644 --- a/rpc/types/src/constants.rs +++ b/rpc/types/src/constants.rs @@ -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: // . -/// +#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "/rpc/core_rpc_server_commands_defs.h", 78)] pub const CORE_RPC_STATUS_OK: &str = "OK"; -/// +#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "/rpc/core_rpc_server_commands_defs.h", 79)] pub const CORE_RPC_STATUS_BUSY: &str = "BUSY"; -/// +#[doc = monero_definition_link!(cc73fe71162d564ffda8e549b79a350bca53c454, "/rpc/core_rpc_server_commands_defs.h", 80)] pub const CORE_RPC_STATUS_NOT_MINING: &str = "NOT MINING"; -/// +#[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: . 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: . 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: . -/// -/// ```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 diff --git a/rpc/types/src/defaults.rs b/rpc/types/src/defaults.rs new file mode 100644 index 00000000..9366a266 --- /dev/null +++ b/rpc/types/src/defaults.rs @@ -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() -> Vec { + Vec::new() +} + +/// Default `0` value used in request/response types. +#[inline] +pub(crate) fn default_zero>() -> 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::(), 0); + assert_eq!(default_zero::(), 0); + assert_eq!(default_zero::(), 0); + assert_eq!(default_zero::(), 0); + assert_eq!(default_zero::(), 0); + } +} diff --git a/rpc/types/src/free.rs b/rpc/types/src/free.rs new file mode 100644 index 00000000..043a5209 --- /dev/null +++ b/rpc/types/src/free.rs @@ -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 +} diff --git a/rpc/types/src/json.rs b/rpc/types/src/json.rs index 5f5f8ff7..c258d59e 100644 --- a/rpc/types/src/json.rs +++ b/rpc/types/src/json.rs @@ -3,10 +3,7 @@ //! . //---------------------------------------------------------------------------------------------------- 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: - // . - // - // 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: + // . 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, } } diff --git a/rpc/types/src/lib.rs b/rpc/types/src/lib.rs index 780208bd..45cca69c 100644 --- a/rpc/types/src/lib.rs +++ b/rpc/types/src/lib.rs @@ -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; diff --git a/rpc/types/src/macros.rs b/rpc/types/src/macros.rs index 27288004..31bc6bed 100644 --- a/rpc/types/src/macros.rs +++ b/rpc/types/src/macros.rs @@ -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; diff --git a/rpc/types/src/binary_string.rs b/rpc/types/src/misc/binary_string.rs similarity index 80% rename from rpc/types/src/binary_string.rs rename to rpc/types/src/misc/binary_string.rs index b644ad32..5c3908dd 100644 --- a/rpc/types/src/binary_string.rs +++ b/rpc/types/src/misc/binary_string.rs @@ -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 { diff --git a/rpc/types/src/misc/block_complete_entry.rs b/rpc/types/src/misc/block_complete_entry.rs new file mode 100644 index 00000000..ca791b0a --- /dev/null +++ b/rpc/types/src/misc/block_complete_entry.rs @@ -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, +} + +// TODO: custom epee +// +#[cfg(feature = "epee")] +epee_object! { + BlockCompleteEntry, + pruned: bool, + block: String, + block_weight: u64, + txs: Vec, +} diff --git a/rpc/types/src/misc/key_image_spent_status.rs b/rpc/types/src/misc/key_image_spent_status.rs new file mode 100644 index 00000000..d075e64e --- /dev/null +++ b/rpc/types/src/misc/key_image_spent_status.rs @@ -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 = ::MARKER; + + fn read(r: &mut B, marker: &Marker) -> cuprate_epee_encoding::Result { + todo!() + } + + fn should_write(&self) -> bool { + todo!() + } + + fn epee_default_value() -> Option { + todo!() + } + + fn write(self, w: &mut B) -> cuprate_epee_encoding::Result<()> { + todo!() + } +} diff --git a/rpc/types/src/misc/misc.rs b/rpc/types/src/misc/misc.rs new file mode 100644 index 00000000..31719a34 --- /dev/null +++ b/rpc/types/src/misc/misc.rs @@ -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, + 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, + 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, + } +} + +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, + } +} + +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::(), + #[cfg_attr(feature = "serde", serde(default = "default_zero"))] + rpc_credits_per_hash: u32 = default_zero::(), + last_seen: u64, + #[cfg_attr(feature = "serde", serde(default = "default_zero"))] + pruning_seed: u32 = default_zero::(), + } +} + +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::(), + } +} + +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, + } +} + +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, + 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 {} diff --git a/rpc/types/src/misc/mod.rs b/rpc/types/src/misc/mod.rs new file mode 100644 index 00000000..31dba353 --- /dev/null +++ b/rpc/types/src/misc/mod.rs @@ -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: + 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; diff --git a/rpc/types/src/misc/pool_info_extent.rs b/rpc/types/src/misc/pool_info_extent.rs new file mode 100644 index 00000000..09b6c96f --- /dev/null +++ b/rpc/types/src/misc/pool_info_extent.rs @@ -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, +} + +// +#[cfg(feature = "epee")] +impl EpeeValue for PoolInfoExtent { + const MARKER: Marker = ::MARKER; + + fn read(r: &mut B, marker: &Marker) -> cuprate_epee_encoding::Result { + todo!() + } + + fn should_write(&self) -> bool { + todo!() + } + + fn epee_default_value() -> Option { + todo!() + } + + fn write(self, w: &mut B) -> cuprate_epee_encoding::Result<()> { + todo!() + } +} diff --git a/rpc/types/src/status.rs b/rpc/types/src/misc/status.rs similarity index 88% rename from rpc/types/src/status.rs rename to rpc/types/src/misc/status.rs index e8ac6ce9..f2dff1a8 100644 --- a/rpc/types/src/status.rs +++ b/rpc/types/src/misc/status.rs @@ -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: . /// /// ## 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: // . +#[cfg(feature = "epee")] impl EpeeValue for Status { const MARKER: Marker = ::MARKER; @@ -161,6 +165,7 @@ mod test { // Test epee (de)serialization works. #[test] + #[cfg(feature = "epee")] fn epee() { for status in [ Status::Ok, diff --git a/rpc/types/src/misc/tx_entry.rs b/rpc/types/src/misc/tx_entry.rs new file mode 100644 index 00000000..70fbdff3 --- /dev/null +++ b/rpc/types/src/misc/tx_entry.rs @@ -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, + 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 +// +#[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, + prunable_as_hex: String, + prunable_hash: String, + pruned_as_hex: String, + received_timestamp: u64, + relayed: bool, + tx_hash: String, +} diff --git a/rpc/types/src/other.rs b/rpc/types/src/other.rs index 22547edd..66b7197e 100644 --- a/rpc/types/src/other.rs +++ b/rpc/types/src/other.rs @@ -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