mirror of
https://github.com/Cuprate/cuprate.git
synced 2024-12-22 11:39:26 +00:00
rpc: start cuprate-rpc-types
(#147)
* rpc: add `monero-rpc-types`
* lib.rs: add lints
* add base files, deps
* fix macro generation, doc test
* add `strum`, add `misc` module
* document struct generation macro
* add `GetHeight`
* lib.rs: create re-export macro
* macro changes, add few more types
* docs
* `monero-rpc-types` -> `cuprate-rpc-types`
* fix modules
* specify commit in macro, add () type aliases
* macro docs, fixes
* add `Status::Other(String)`
* add TODO for `strum`
* Update rpc/types/Cargo.toml
Co-authored-by: Boog900 <boog900@tutanota.com>
* add `BinaryString`
* add `ResponseBase`
* add `CORE_RPC_*` constants
* fix status; use `CORE_RPC_*` constants
* cargo.toml: add `epee_encoding`
* rpc: add epee_encoding impl for `Status`
* macro: add epee_encoding for every type
* remove `strum`
* add response bases
* add `CORE_RPC_STATUS_UNKNOWN`
* add response/request bases for epee
* create `base` module
* use different type for macro example
* move base / root types around
* docs, status serde test
* status: use `Status::Unknown` for `epee_default_value`
* json: add missing fields to `GetBlockTemplateRequest`
not sure I missed these
cc73fe7116/src/rpc/core_rpc_server_commands_defs.h (L947-L950)
---------
Co-authored-by: Boog900 <boog900@tutanota.com>
This commit is contained in:
parent
5c08d1a0e2
commit
e405786a73
16 changed files with 1035 additions and 5 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -745,6 +745,13 @@ version = "0.0.0"
|
|||
[[package]]
|
||||
name = "cuprate-rpc-types"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cuprate-epee-encoding",
|
||||
"monero-serai",
|
||||
"paste",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cuprate-test-utils"
|
||||
|
|
|
@ -23,8 +23,8 @@ members = [
|
|||
"test-utils",
|
||||
"types",
|
||||
"rpc/json-rpc",
|
||||
"rpc/rpc-types",
|
||||
"rpc/rpc-interface",
|
||||
"rpc/types",
|
||||
"rpc/interface",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -5,11 +5,18 @@ edition = "2021"
|
|||
description = "Monero RPC types"
|
||||
license = "MIT"
|
||||
authors = ["hinto-janai"]
|
||||
repository = "https://github.com/Cuprate/cuprate/tree/main/rpc/monero-rpc-types"
|
||||
keywords = ["monero", "rpc", "types"]
|
||||
repository = "https://github.com/Cuprate/cuprate/tree/main/rpc/types"
|
||||
keywords = ["cuprate", "rpc", "types", "monero"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
cuprate-epee-encoding = { path = "../../net/epee-encoding" }
|
||||
|
||||
monero-serai = { workspace = true }
|
||||
paste = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = { workspace = true }
|
62
rpc/types/README.md
Normal file
62
rpc/types/README.md
Normal file
|
@ -0,0 +1,62 @@
|
|||
Monero RPC types.
|
||||
|
||||
# What
|
||||
This crate ports the types used in Monero's RPC interface, including:
|
||||
- JSON types
|
||||
- Binary (epee) types
|
||||
- Mixed types
|
||||
- Other commonly used RPC types
|
||||
|
||||
# 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`].
|
||||
|
||||
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).
|
||||
|
||||
# Documentation
|
||||
The documentation for types within `{json,bin,other}` are omitted, as they can be found in [Monero's RPC documentation](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html).
|
||||
|
||||
However, each type will document:
|
||||
- **Definition**: the exact type definition location in `monerod`
|
||||
- **Documentation**: the Monero RPC documentation link
|
||||
- **Request/response**: the other side of this type, either the request or response
|
||||
|
||||
# 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
|
||||
|
||||
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.
|
||||
|
||||
# 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:
|
||||
|
||||
```json
|
||||
{
|
||||
"string": "",
|
||||
"float": 30.0,
|
||||
"integer": 30,
|
||||
"binary": "<serialized binary>"
|
||||
}
|
||||
```
|
||||
|
||||
`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`].
|
||||
|
||||
TODO: list the specific types.
|
125
rpc/types/src/base.rs
Normal file
125
rpc/types/src/base.rs
Normal file
|
@ -0,0 +1,125 @@
|
|||
//! The base data that appear in many RPC request/responses.
|
||||
//!
|
||||
//! These are the common "headers" or "base" types that are
|
||||
//! [`flattened`](https://serde.rs/field-attrs.html#flatten)
|
||||
//! into many of Monero's RPC types.
|
||||
//!
|
||||
//! The `Access*` structs (e.g. [`AccessResponseBase`]
|
||||
//! are pseudo-deprecated structs for the RPC payment system, see:
|
||||
//!
|
||||
//! - <https://github.com/monero-project/monero/commit/2899379791b7542e4eb920b5d9d58cf232806937>
|
||||
//! - <https://github.com/monero-project/monero/issues/8722>
|
||||
//! - <https://github.com/monero-project/monero/pull/8843>
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
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),
|
||||
")."
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- 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)]
|
||||
pub struct AccessRequestBase {
|
||||
/// The RPC payment client.
|
||||
pub client: String,
|
||||
}
|
||||
|
||||
cuprate_epee_encoding::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,
|
||||
}
|
||||
|
||||
/// 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,
|
||||
)]
|
||||
pub struct ResponseBase {
|
||||
/// General RPC error code. [`Status::Ok`] means everything looks good.
|
||||
pub status: Status,
|
||||
/// States if the result is obtained using the bootstrap mode,
|
||||
/// and is therefore not trusted (`true`), or when the daemon
|
||||
/// is fully synced and thus handles the RPC locally (`false`).
|
||||
pub untrusted: bool,
|
||||
}
|
||||
|
||||
epee_object! {
|
||||
ResponseBase,
|
||||
status: Status,
|
||||
untrusted: bool,
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
pub struct AccessResponseBase {
|
||||
/// A flattened [`ResponseBase`].
|
||||
#[serde(flatten)]
|
||||
pub response_base: ResponseBase,
|
||||
/// If payment for RPC is enabled, the number of credits
|
||||
/// available to the requesting client. Otherwise, `0`.
|
||||
pub credits: u64,
|
||||
/// If payment for RPC is enabled, the hash of the
|
||||
/// highest block in the chain. Otherwise, empty.
|
||||
pub top_hash: String,
|
||||
}
|
||||
|
||||
epee_object! {
|
||||
AccessResponseBase,
|
||||
credits: u64,
|
||||
top_hash: String,
|
||||
!flatten: response_base: ResponseBase,
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Tests
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
// use super::*;
|
||||
}
|
11
rpc/types/src/bin.rs
Normal file
11
rpc/types/src/bin.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
//! Binary types from [binary](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_blocksbin) endpoints.
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- TODO
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Tests
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
// use super::*;
|
||||
}
|
29
rpc/types/src/binary_string.rs
Normal file
29
rpc/types/src/binary_string.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
//! TODO
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- BinaryString
|
||||
/// TODO
|
||||
///
|
||||
/// ```rust
|
||||
/// use serde::Deserialize;
|
||||
/// use serde_json::from_str;
|
||||
/// use cuprate_rpc_types::BinaryString;
|
||||
///
|
||||
/// #[derive(Deserialize)]
|
||||
/// struct Key {
|
||||
/// key: BinaryString,
|
||||
/// }
|
||||
///
|
||||
/// let binary = r"<22>\b<><62><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
|
||||
/// let json = format!("{{\"key\":\"{binary}\"}}");
|
||||
/// let key = from_str::<Key>(&json).unwrap();
|
||||
/// let binary: BinaryString = key.key;
|
||||
/// ```
|
||||
pub type BinaryString = String;
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Tests
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
// use super::*;
|
||||
}
|
65
rpc/types/src/constants.rs
Normal file
65
rpc/types/src/constants.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
//! TODO
|
||||
|
||||
// From: <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L83-L89>
|
||||
//
|
||||
// ```
|
||||
// When making *any* change here, bump minor
|
||||
// If the change is incompatible, then bump major and set minor to 0
|
||||
// This ensures CORE_RPC_VERSION always increases, that every change
|
||||
// has its own version, and that clients can just test major to see
|
||||
// whether they can talk to a given daemon without having to know in
|
||||
// advance which version they will stop working with
|
||||
// Don't go over 32767 for any of these
|
||||
// ```
|
||||
//
|
||||
// What this means for Cuprate: just follow `monerod`.
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Status
|
||||
// Common RPC status strings:
|
||||
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L78-L81>.
|
||||
//
|
||||
// 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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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
|
||||
/// 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;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// 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
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
// use super::*;
|
||||
}
|
129
rpc/types/src/json.rs
Normal file
129
rpc/types/src/json.rs
Normal file
|
@ -0,0 +1,129 @@
|
|||
//! JSON types from the [`/json_rpc`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#json-rpc-methods) endpoint.
|
||||
//!
|
||||
//! <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,
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Struct definitions
|
||||
// This generates 2 structs:
|
||||
//
|
||||
// - `GetBlockTemplateRequest`
|
||||
// - `GetBlockTemplateResponse`
|
||||
//
|
||||
// with some interconnected documentation.
|
||||
define_request_and_response! {
|
||||
// The markdown tag for Monero RPC documentation. Not necessarily the endpoint.
|
||||
get_block_template,
|
||||
|
||||
// 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.
|
||||
cc73fe71162d564ffda8e549b79a350bca53c454 => core_rpc_server_commands_defs.h => 943..=994,
|
||||
|
||||
// The base type name.
|
||||
GetBlockTemplate,
|
||||
|
||||
// The base request type.
|
||||
//
|
||||
// This must be a type found in [`crate::base`].
|
||||
// It acts as a "base" that gets flattened into
|
||||
// the actually 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>.
|
||||
//
|
||||
// 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 = ()`
|
||||
// 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)]
|
||||
ResponseBase {
|
||||
// This is using `crate::base::ResponseBase`,
|
||||
// so the type we generate will contain this field:
|
||||
// ```
|
||||
// base: crate::base::ResponseBase,
|
||||
// ```
|
||||
//
|
||||
// This is flattened with serde and epee, so during
|
||||
// (de)serialization, it will act as if there are 2 extra fields here:
|
||||
// ```
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Tests
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
// use super::*;
|
||||
}
|
116
rpc/types/src/lib.rs
Normal file
116
rpc/types/src/lib.rs
Normal file
|
@ -0,0 +1,116 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
//---------------------------------------------------------------------------------------------------- Lints
|
||||
// Forbid lints.
|
||||
// Our code, and code generated (e.g macros) cannot overrule these.
|
||||
#![forbid(
|
||||
// `unsafe` is allowed but it _must_ be
|
||||
// commented with `SAFETY: reason`.
|
||||
clippy::undocumented_unsafe_blocks,
|
||||
|
||||
// Never.
|
||||
unused_unsafe,
|
||||
redundant_semicolons,
|
||||
unused_allocation,
|
||||
coherence_leak_check,
|
||||
while_true,
|
||||
clippy::missing_docs_in_private_items,
|
||||
|
||||
// Maybe can be put into `#[deny]`.
|
||||
unconditional_recursion,
|
||||
for_loops_over_fallibles,
|
||||
unused_braces,
|
||||
unused_labels,
|
||||
keyword_idents,
|
||||
non_ascii_idents,
|
||||
variant_size_differences,
|
||||
single_use_lifetimes,
|
||||
|
||||
// Probably can be put into `#[deny]`.
|
||||
future_incompatible,
|
||||
let_underscore,
|
||||
break_with_label_and_loop,
|
||||
duplicate_macro_attributes,
|
||||
exported_private_dependencies,
|
||||
large_assignments,
|
||||
overlapping_range_endpoints,
|
||||
semicolon_in_expressions_from_macros,
|
||||
noop_method_call,
|
||||
)]
|
||||
// Deny lints.
|
||||
// Some of these are `#[allow]`'ed on a per-case basis.
|
||||
#![deny(
|
||||
clippy::all,
|
||||
clippy::correctness,
|
||||
clippy::suspicious,
|
||||
clippy::style,
|
||||
clippy::complexity,
|
||||
clippy::perf,
|
||||
clippy::pedantic,
|
||||
clippy::nursery,
|
||||
clippy::cargo,
|
||||
unused_doc_comments,
|
||||
unused_mut,
|
||||
missing_docs,
|
||||
deprecated,
|
||||
unused_comparisons,
|
||||
nonstandard_style,
|
||||
unreachable_pub
|
||||
)]
|
||||
#![allow(
|
||||
// FIXME: this lint affects crates outside of
|
||||
// `database/` for some reason, allow for now.
|
||||
clippy::cargo_common_metadata,
|
||||
|
||||
// FIXME: adding `#[must_use]` onto everything
|
||||
// might just be more annoying than useful...
|
||||
// although it is sometimes nice.
|
||||
clippy::must_use_candidate,
|
||||
|
||||
// FIXME: good lint but too many false positives
|
||||
// with our `Env` + `RwLock` setup.
|
||||
clippy::significant_drop_tightening,
|
||||
|
||||
// FIXME: good lint but is less clear in most cases.
|
||||
clippy::items_after_statements,
|
||||
|
||||
// TODO
|
||||
rustdoc::bare_urls,
|
||||
|
||||
clippy::module_name_repetitions,
|
||||
clippy::module_inception,
|
||||
clippy::redundant_pub_crate,
|
||||
clippy::option_if_let_else,
|
||||
)]
|
||||
// Allow some lints when running in debug mode.
|
||||
#![cfg_attr(debug_assertions, allow(clippy::todo, clippy::multiple_crate_versions))]
|
||||
// Allow some lints in tests.
|
||||
#![cfg_attr(
|
||||
test,
|
||||
allow(
|
||||
clippy::cognitive_complexity,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::too_many_lines
|
||||
)
|
||||
)]
|
||||
// TODO: remove me after finishing impl
|
||||
#![allow(dead_code)]
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Use
|
||||
mod binary_string;
|
||||
mod constants;
|
||||
mod macros;
|
||||
mod status;
|
||||
|
||||
pub use binary_string::BinaryString;
|
||||
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;
|
277
rpc/types/src/macros.rs
Normal file
277
rpc/types/src/macros.rs
Normal file
|
@ -0,0 +1,277 @@
|
|||
//! 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.
|
||||
///
|
||||
/// These `struct`s automatically implement:
|
||||
/// - `Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash`
|
||||
/// - `serde::{Serialize, Deserialize}`
|
||||
/// - `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
|
||||
/// generate which docs.
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
/// 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:
|
||||
/// ```
|
||||
/// pub type Request = ();
|
||||
/// ```
|
||||
/// instead of:
|
||||
/// ```
|
||||
/// 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.
|
||||
///
|
||||
/// 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`].
|
||||
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,
|
||||
|
||||
// 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 request type (and any doc comments, derives, etc).
|
||||
$( #[$request_type_attr:meta] )*
|
||||
$request_base_type:ty {
|
||||
// And any fields.
|
||||
$(
|
||||
$( #[$request_field_attr:meta] )*
|
||||
$request_field:ident: $request_field_type:ty,
|
||||
)*
|
||||
},
|
||||
|
||||
// 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! {
|
||||
#[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,
|
||||
)*
|
||||
}
|
||||
|
||||
::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,
|
||||
}
|
||||
}};
|
||||
}
|
||||
pub(crate) use define_request_and_response;
|
||||
|
||||
/// Generate documentation for the types generated
|
||||
/// by the [`define_request_and_response`] macro.
|
||||
///
|
||||
/// See it for more info on inputs.
|
||||
macro_rules! define_request_and_response_doc {
|
||||
(
|
||||
// This labels the last `[request]` or `[response]`
|
||||
// hyperlink in documentation. Input is either:
|
||||
// - "request"
|
||||
// - "response"
|
||||
//
|
||||
// Remember this is linking to the _other_ type,
|
||||
// so if defining a `Request` type, input should
|
||||
// be "response".
|
||||
$request_or_response:literal,
|
||||
|
||||
$monero_daemon_rpc_doc_link:ident,
|
||||
$monero_code_commit:ident,
|
||||
$monero_code_filename:ident,
|
||||
$monero_code_filename_extension:ident,
|
||||
$monero_code_line_start:literal,
|
||||
$monero_code_line_end:literal,
|
||||
$type_name:ident,
|
||||
) => {
|
||||
concat!(
|
||||
"",
|
||||
"[Definition](",
|
||||
"https://github.com/monero-project/monero/blob/",
|
||||
stringify!($monero_code_commit),
|
||||
"/src/rpc/",
|
||||
stringify!($monero_code_filename),
|
||||
".",
|
||||
stringify!($monero_code_filename_extension),
|
||||
"#L",
|
||||
stringify!($monero_code_line_start),
|
||||
"-L",
|
||||
stringify!($monero_code_line_end),
|
||||
"), [documentation](",
|
||||
"https://www.getmonero.org/resources/developer-guides/daemon-rpc.html",
|
||||
"#",
|
||||
stringify!($monero_daemon_rpc_doc_link),
|
||||
"), [",
|
||||
$request_or_response,
|
||||
"](",
|
||||
stringify!($type_name),
|
||||
")."
|
||||
)
|
||||
};
|
||||
}
|
||||
pub(crate) use define_request_and_response_doc;
|
21
rpc/types/src/other.rs
Normal file
21
rpc/types/src/other.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
//! JSON types from the [`other`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#other-daemon-rpc-calls) endpoints.
|
||||
//!
|
||||
//! <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/daemon_messages.h>.
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use crate::{base::ResponseBase, macros::define_request_and_response};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- TODO
|
||||
define_request_and_response! {
|
||||
save_bc,
|
||||
cc73fe71162d564ffda8e549b79a350bca53c454 =>
|
||||
core_rpc_server_commands_defs.h => 898..=916,
|
||||
SaveBc,
|
||||
ResponseBase {}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Tests
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
// use super::*;
|
||||
}
|
182
rpc/types/src/status.rs
Normal file
182
rpc/types/src/status.rs
Normal file
|
@ -0,0 +1,182 @@
|
|||
//! RPC response status type.
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use std::fmt::Display;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use cuprate_epee_encoding::{
|
||||
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,
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- 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,
|
||||
/// CORE_RPC_STATUS_BUSY, CORE_RPC_STATUS_NOT_MINING, CORE_RPC_STATUS_OK,
|
||||
/// CORE_RPC_STATUS_PAYMENT_REQUIRED, CORE_RPC_STATUS_UNKNOWN
|
||||
/// };
|
||||
/// use serde_json::to_string;
|
||||
///
|
||||
/// let unknown = Status::Unknown;
|
||||
///
|
||||
/// assert_eq!(to_string(&Status::Ok).unwrap(), r#""OK""#);
|
||||
/// assert_eq!(to_string(&Status::Busy).unwrap(), r#""BUSY""#);
|
||||
/// assert_eq!(to_string(&Status::NotMining).unwrap(), r#""NOT MINING""#);
|
||||
/// assert_eq!(to_string(&Status::PaymentRequired).unwrap(), r#""PAYMENT REQUIRED""#);
|
||||
/// assert_eq!(to_string(&unknown).unwrap(), r#""UNKNOWN""#);
|
||||
///
|
||||
/// assert_eq!(Status::Ok.as_ref(), CORE_RPC_STATUS_OK);
|
||||
/// assert_eq!(Status::Busy.as_ref(), CORE_RPC_STATUS_BUSY);
|
||||
/// assert_eq!(Status::NotMining.as_ref(), CORE_RPC_STATUS_NOT_MINING);
|
||||
/// assert_eq!(Status::PaymentRequired.as_ref(), CORE_RPC_STATUS_PAYMENT_REQUIRED);
|
||||
/// assert_eq!(unknown.as_ref(), CORE_RPC_STATUS_UNKNOWN);
|
||||
///
|
||||
/// assert_eq!(format!("{}", Status::Ok), CORE_RPC_STATUS_OK);
|
||||
/// assert_eq!(format!("{}", Status::Busy), CORE_RPC_STATUS_BUSY);
|
||||
/// assert_eq!(format!("{}", Status::NotMining), CORE_RPC_STATUS_NOT_MINING);
|
||||
/// assert_eq!(format!("{}", Status::PaymentRequired), CORE_RPC_STATUS_PAYMENT_REQUIRED);
|
||||
/// assert_eq!(format!("{}", unknown), CORE_RPC_STATUS_UNKNOWN);
|
||||
///
|
||||
/// assert_eq!(format!("{:?}", Status::Ok), "Ok");
|
||||
/// assert_eq!(format!("{:?}", Status::Busy), "Busy");
|
||||
/// assert_eq!(format!("{:?}", Status::NotMining), "NotMining");
|
||||
/// assert_eq!(format!("{:?}", Status::PaymentRequired), "PaymentRequired");
|
||||
/// assert_eq!(format!("{:?}", unknown), "Unknown");
|
||||
/// ```
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, 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")]
|
||||
#[default]
|
||||
Ok,
|
||||
|
||||
/// The daemon is busy, try later; [`CORE_RPC_STATUS_BUSY`].
|
||||
#[serde(rename = "BUSY")]
|
||||
Busy,
|
||||
|
||||
/// The daemon is not mining; [`CORE_RPC_STATUS_NOT_MINING`].
|
||||
#[serde(rename = "NOT MINING")]
|
||||
NotMining,
|
||||
|
||||
/// Payment is required for RPC; [`CORE_RPC_STATUS_PAYMENT_REQUIRED`].
|
||||
#[serde(rename = "PAYMENT REQUIRED")]
|
||||
PaymentRequired,
|
||||
|
||||
/// Some unknown other string; [`CORE_RPC_STATUS_UNKNOWN`].
|
||||
///
|
||||
/// This exists to act as a catch-all if `monerod` adds
|
||||
/// a string and a Cuprate node hasn't updated yet.
|
||||
///
|
||||
/// The reason this isn't `Unknown(String)` is because that
|
||||
/// disallows [`Status`] to be [`Copy`], and thus other types
|
||||
/// that contain it.
|
||||
#[serde(other)]
|
||||
#[serde(rename = "UNKNOWN")]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl From<String> for Status {
|
||||
fn from(s: String) -> Self {
|
||||
match s.as_str() {
|
||||
CORE_RPC_STATUS_OK => Self::Ok,
|
||||
CORE_RPC_STATUS_BUSY => Self::Busy,
|
||||
CORE_RPC_STATUS_NOT_MINING => Self::NotMining,
|
||||
CORE_RPC_STATUS_PAYMENT_REQUIRED => Self::PaymentRequired,
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Status {
|
||||
fn as_ref(&self) -> &str {
|
||||
match self {
|
||||
Self::Ok => CORE_RPC_STATUS_OK,
|
||||
Self::Busy => CORE_RPC_STATUS_BUSY,
|
||||
Self::NotMining => CORE_RPC_STATUS_NOT_MINING,
|
||||
Self::PaymentRequired => CORE_RPC_STATUS_PAYMENT_REQUIRED,
|
||||
Self::Unknown => CORE_RPC_STATUS_UNKNOWN,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Status {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
// [`Status`] is essentially a [`String`] when it comes to
|
||||
// (de)serialization, except when writing we usually have
|
||||
// access to a `&'static str` and don't need to allocate.
|
||||
//
|
||||
// See below for more impl info:
|
||||
// <https://github.com/Cuprate/cuprate/blob/bef2a2cbd4e1194991751d1fbc96603cba8c7a51/net/epee-encoding/src/value.rs#L366-L392>.
|
||||
impl EpeeValue for Status {
|
||||
const MARKER: Marker = <String as EpeeValue>::MARKER;
|
||||
|
||||
fn read<B: Buf>(r: &mut B, marker: &Marker) -> cuprate_epee_encoding::Result<Self> {
|
||||
let string = <String as EpeeValue>::read(r, marker)?;
|
||||
Ok(Self::from(string))
|
||||
}
|
||||
|
||||
fn should_write(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn epee_default_value() -> Option<Self> {
|
||||
// <https://github.com/Cuprate/cuprate/pull/147#discussion_r1654992559>
|
||||
Some(Self::Unknown)
|
||||
}
|
||||
|
||||
fn write<B: BufMut>(self, w: &mut B) -> cuprate_epee_encoding::Result<()> {
|
||||
cuprate_epee_encoding::write_bytes(self.as_ref(), w)
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Tests
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
// Test epee (de)serialization works.
|
||||
#[test]
|
||||
fn epee() {
|
||||
for status in [
|
||||
Status::Ok,
|
||||
Status::Busy,
|
||||
Status::NotMining,
|
||||
Status::PaymentRequired,
|
||||
Status::Unknown,
|
||||
] {
|
||||
let mut buf = vec![];
|
||||
|
||||
<Status as EpeeValue>::write(status, &mut buf).unwrap();
|
||||
let status2 =
|
||||
<Status as EpeeValue>::read(&mut buf.as_slice(), &<Status as EpeeValue>::MARKER)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(status, status2);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue