Merge branch 'main' into p2p-protocol
Some checks failed
Audit / audit (push) Has been cancelled
Deny / audit (push) Has been cancelled

This commit is contained in:
Boog900 2024-07-10 02:42:10 +01:00
commit a8ca3990c0
No known key found for this signature in database
GPG key ID: 42AB1287CB0041C2
26 changed files with 1522 additions and 433 deletions

8
Cargo.lock generated
View file

@ -3233,9 +3233,9 @@ dependencies = [
[[package]]
name = "zerovec"
version = "0.10.2"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c"
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
dependencies = [
"yoke",
"zerofrom",
@ -3244,9 +3244,9 @@ dependencies = [
[[package]]
name = "zerovec-derive"
version = "0.10.2"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7"
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",

View file

@ -101,7 +101,203 @@ tokio-test = { version = "0.4.4" }
# regex = { version = "1.10.2" } # Regular expressions | https://github.com/rust-lang/regex
# ryu = { version = "1.0.15" } # Fast float to string formatting | https://github.com/dtolnay/ryu
# Maybe one day.
# disk = { version = "*" } # (De)serialization to/from disk with various file formats | https://github.com/hinto-janai/disk
# readable = { version = "*" } # Stack-based string formatting utilities | https://github.com/hinto-janai/readable
# json-rpc = { git = "https://github.com/hinto-janai/json-rpc" } # JSON-RPC 2.0 types
# Lints: cold, warm, hot: <https://github.com/Cuprate/cuprate/issues/131>
[workspace.lints.clippy]
# Cold
borrow_as_ptr = "deny"
case_sensitive_file_extension_comparisons = "deny"
cast_lossless = "deny"
cast_ptr_alignment = "deny"
checked_conversions = "deny"
cloned_instead_of_copied = "deny"
doc_link_with_quotes = "deny"
empty_enum = "deny"
enum_glob_use = "deny"
expl_impl_clone_on_copy = "deny"
explicit_into_iter_loop = "deny"
filter_map_next = "deny"
flat_map_option = "deny"
from_iter_instead_of_collect = "deny"
if_not_else = "deny"
ignored_unit_patterns = "deny"
inconsistent_struct_constructor = "deny"
index_refutable_slice = "deny"
inefficient_to_string = "deny"
invalid_upcast_comparisons = "deny"
iter_filter_is_ok = "deny"
iter_filter_is_some = "deny"
implicit_clone = "deny"
manual_c_str_literals = "deny"
manual_instant_elapsed = "deny"
manual_is_variant_and = "deny"
manual_let_else = "deny"
manual_ok_or = "deny"
manual_string_new = "deny"
map_unwrap_or = "deny"
match_bool = "deny"
match_same_arms = "deny"
match_wildcard_for_single_variants = "deny"
mismatching_type_param_order = "deny"
mut_mut = "deny"
needless_bitwise_bool = "deny"
needless_continue = "deny"
needless_for_each = "deny"
needless_raw_string_hashes = "deny"
no_effect_underscore_binding = "deny"
no_mangle_with_rust_abi = "deny"
option_as_ref_cloned = "deny"
option_option = "deny"
ptr_as_ptr = "deny"
ptr_cast_constness = "deny"
pub_underscore_fields = "deny"
redundant_closure_for_method_calls = "deny"
ref_as_ptr = "deny"
ref_option_ref = "deny"
same_functions_in_if_condition = "deny"
semicolon_if_nothing_returned = "deny"
trivially_copy_pass_by_ref = "deny"
uninlined_format_args = "deny"
unnecessary_join = "deny"
unnested_or_patterns = "deny"
unused_async = "deny"
unused_self = "deny"
used_underscore_binding = "deny"
zero_sized_map_values = "deny"
as_ptr_cast_mut = "deny"
clear_with_drain = "deny"
collection_is_never_read = "deny"
debug_assert_with_mut_call = "deny"
derive_partial_eq_without_eq = "deny"
empty_line_after_doc_comments = "deny"
empty_line_after_outer_attr = "deny"
equatable_if_let = "deny"
iter_on_empty_collections = "deny"
iter_on_single_items = "deny"
iter_with_drain = "deny"
needless_collect = "deny"
needless_pass_by_ref_mut = "deny"
negative_feature_names = "deny"
non_send_fields_in_send_ty = "deny"
nonstandard_macro_braces = "deny"
path_buf_push_overwrite = "deny"
read_zero_byte_vec = "deny"
redundant_clone = "deny"
redundant_feature_names = "deny"
trailing_empty_array = "deny"
trait_duplication_in_bounds = "deny"
type_repetition_in_bounds = "deny"
uninhabited_references = "deny"
unnecessary_struct_initialization = "deny"
unused_peekable = "deny"
unused_rounding = "deny"
use_self = "deny"
useless_let_if_seq = "deny"
wildcard_dependencies = "deny"
unseparated_literal_suffix = "deny"
unnecessary_safety_doc = "deny"
unnecessary_safety_comment = "deny"
unnecessary_self_imports = "deny"
tests_outside_test_module = "deny"
string_to_string = "deny"
rest_pat_in_fully_bound_structs = "deny"
redundant_type_annotations = "deny"
infinite_loop = "deny"
# Warm
cast_possible_truncation = "deny"
cast_possible_wrap = "deny"
cast_precision_loss = "deny"
cast_sign_loss = "deny"
copy_iterator = "deny"
doc_markdown = "deny"
explicit_deref_methods = "deny"
explicit_iter_loop = "deny"
float_cmp = "deny"
fn_params_excessive_bools = "deny"
into_iter_without_iter = "deny"
iter_without_into_iter = "deny"
iter_not_returning_iterator = "deny"
large_digit_groups = "deny"
large_types_passed_by_value = "deny"
manual_assert = "deny"
maybe_infinite_iter = "deny"
missing_fields_in_debug = "deny"
needless_pass_by_value = "deny"
range_minus_one = "deny"
range_plus_one = "deny"
redundant_else = "deny"
ref_binding_to_reference = "deny"
return_self_not_must_use = "deny"
single_match_else = "deny"
string_add_assign = "deny"
transmute_ptr_to_ptr = "deny"
unchecked_duration_subtraction = "deny"
unnecessary_box_returns = "deny"
unnecessary_wraps = "deny"
branches_sharing_code = "deny"
fallible_impl_from = "deny"
missing_const_for_fn = "deny"
significant_drop_in_scrutinee = "deny"
significant_drop_tightening = "deny"
try_err = "deny"
lossy_float_literal = "deny"
let_underscore_must_use = "deny"
iter_over_hash_type = "deny"
impl_trait_in_params = "deny"
get_unwrap = "deny"
error_impl_error = "deny"
empty_structs_with_brackets = "deny"
empty_enum_variants_with_brackets = "deny"
empty_drop = "deny"
clone_on_ref_ptr = "deny"
# Hot
# inline_always = "deny"
# large_futures = "deny"
# large_stack_arrays = "deny"
# linkedlist = "deny"
# missing_errors_doc = "deny"
# missing_panics_doc = "deny"
# should_panic_without_expect = "deny"
# similar_names = "deny"
# too_many_lines = "deny"
# unreadable_literal = "deny"
# wildcard_imports = "deny"
# allow_attributes_without_reason = "deny"
# missing_assert_message = "deny"
# missing_docs_in_private_items = "deny"
# undocumented_unsafe_blocks = "deny"
# multiple_unsafe_ops_per_block = "deny"
# single_char_lifetime_names = "deny"
# wildcard_enum_match_arm = "deny"
[workspace.lints.rust]
# Cold
absolute_paths_not_starting_with_crate = "deny"
explicit_outlives_requirements = "deny"
keyword_idents = "deny"
missing_abi = "deny"
non_ascii_idents = "deny"
non_local_definitions = "deny"
single_use_lifetimes = "deny"
trivial_casts = "deny"
trivial_numeric_casts = "deny"
unsafe_op_in_unsafe_fn = "deny"
unused_crate_dependencies = "deny"
unused_import_braces = "deny"
unused_lifetimes = "deny"
unused_macro_rules = "deny"
ambiguous_glob_imports = "deny"
unused_unsafe = "deny"
# Warm
let_underscore_drop = "deny"
unreachable_pub = "deny"
unused_qualifications = "deny"
variant_size_differences = "deny"
# Hot
# unused_results = "deny"
# non_exhaustive_omitted_patterns = "deny"
# missing_docs = "deny"
# missing_copy_implementations = "deny"

View file

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

View file

@ -10,13 +10,14 @@ This crate ports the types used in Monero's RPC interface, including:
# Modules
This crate's types are split in the following manner:
This crate has 4 modules:
- The root module; `cuprate_rpc_types`
- [`json`] module; JSON types from the `/json_rpc` endpoint
- [`bin`] module; Binary types from the binary endpoints
- [`other`] module; Misc JSON types from other endpoints
Miscellaneous types are found in the root module, e.g. [`crate::Status`].
| Module | Purpose |
|--------|---------|
| The root module | Miscellaneous items, e.g. constants.
| [`json`] | Contains JSON request/response (some mixed with binary) that all share the common `/json_rpc` endpoint. |
| [`bin`] | Contains request/response types that are expected to be fully in binary (`cuprate_epee_encoding`) in `monerod` and `cuprated`'s RPC interface. These are called at a custom endpoint instead of `/json_rpc`, e.g. `/get_blocks.bin`. |
| [`other`] | Contains request/response types that are JSON, but aren't called at `/json_rpc` (e.g. [`crate::other::GetHeightRequest`]). |
| [`misc`] | Contains miscellaneous types, e.g. [`crate::misc::Status`]. Many of types here are found and used in request/response types, for example, [`crate::misc::BlockHeader`] is used in [`crate::json::GetLastBlockHeaderResponse`]. |
| [`base`] | Contains base types flattened into many request/response types.
Each type in `{json,bin,other}` come in pairs and have identical names, but are suffixed with either `Request` or `Response`. e.g. [`GetBlockCountRequest`](crate::json::GetBlockCountRequest) & [`GetBlockCountResponse`](crate::json::GetBlockCountResponse).
@ -30,23 +31,21 @@ However, each type will document:
# Naming
The naming for types within `{json,bin,other}` follow the following scheme:
- Convert the endpoint or method name into `UpperCamelCase`
- Remove any suffix extension
1. Convert the endpoint or method name into `UpperCamelCase`
1. Remove any suffix extension
1. Add `Request/Response` suffix
For example:
| Endpoint/method | Crate location and name |
|-----------------|-------------------------|
| [`get_block_count`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_block_count) | [`json::GetBlockCountRequest`] & [`json::GetBlockCountResponse`]
| [`/get_blocks.bin`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_blockbin) | `bin::GetBlocksRequest` & `bin::GetBlocksResponse`
| [`/get_height`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_height) | `other::GetHeightRequest` & `other::GetHeightResponse`
TODO: fix doc links when types are ready.
| [`/get_blocks.bin`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_blockbin) | [`bin::GetBlocksRequest`] & [`bin::GetBlocksResponse`]
| [`/get_height`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_height) | [`other::GetHeightRequest`] & [`other::GetHeightResponse`]
# Mixed types
Note that some types within [`other`] mix JSON & binary together, i.e.,
the message overall is JSON, however some fields contain binary
values inside JSON strings, for example:
Note that some types mix JSON & binary together, i.e., the message overall is JSON,
however some fields contain binary values inside JSON strings, for example:
```json
{
@ -57,6 +56,20 @@ values inside JSON strings, for example:
}
```
`binary` here is (de)serialized as a normal [`String`]. In order to be clear on which fields contain binary data, the struct fields that have them will use [`crate::BinaryString`] instead of [`String`].
`binary` here is (de)serialized as a normal [`String`]. In order to be clear on which fields contain binary data, the struct fields that have them will use [`crate::misc::BinaryString`] instead of [`String`].
TODO: list the specific types.
These mixed types are:
- [`crate::json::GetTransactionPoolBacklogResponse`]
- [`crate::json::GetOutputDistributionResponse`]
TODO: we need to figure out a type that (de)serializes correctly, `String` errors with `serde_json`
# Feature flags
List of feature flags for `cuprate-rpc-types`.
All are enabled by default.
| Feature flag | Does what |
|--------------|-----------|
| `serde` | Implements `serde` on all types
| `epee` | Implements `cuprate_epee_encoding` on all types

View file

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

View file

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

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

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

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

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

View file

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

View file

@ -1,4 +1,5 @@
#![doc = include_str!("../README.md")]
#![cfg_attr(docsrs, feature(doc_cfg))]
//---------------------------------------------------------------------------------------------------- Lints
// Forbid lints.
// Our code, and code generated (e.g macros) cannot overrule these.
@ -13,7 +14,6 @@
unused_allocation,
coherence_leak_check,
while_true,
clippy::missing_docs_in_private_items,
// Maybe can be put into `#[deny]`.
unconditional_recursion,
@ -82,7 +82,15 @@
clippy::option_if_let_else,
)]
// Allow some lints when running in debug mode.
#![cfg_attr(debug_assertions, allow(clippy::todo, clippy::multiple_crate_versions))]
#![cfg_attr(
debug_assertions,
allow(
clippy::todo,
clippy::multiple_crate_versions,
unused_imports,
unused_variables
)
)]
// Allow some lints in tests.
#![cfg_attr(
test,
@ -94,23 +102,25 @@
)
)]
// TODO: remove me after finishing impl
#![allow(dead_code)]
#![allow(
dead_code,
rustdoc::broken_intra_doc_links // TODO: remove after `{bin,json,other}.rs` gets merged
)]
//---------------------------------------------------------------------------------------------------- Use
mod binary_string;
//---------------------------------------------------------------------------------------------------- Mod
mod constants;
mod defaults;
mod free;
mod macros;
mod status;
pub use binary_string::BinaryString;
pub mod base;
pub mod bin;
pub mod json;
pub mod misc;
pub mod other;
pub use constants::{
CORE_RPC_STATUS_BUSY, CORE_RPC_STATUS_NOT_MINING, CORE_RPC_STATUS_OK,
CORE_RPC_STATUS_PAYMENT_REQUIRED, CORE_RPC_STATUS_UNKNOWN, CORE_RPC_VERSION,
CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR,
};
pub use status::Status;
pub mod base;
pub mod bin;
pub mod json;
pub mod other;

View file

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

View file

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

View file

@ -0,0 +1,37 @@
//! TODO
//---------------------------------------------------------------------------------------------------- Use
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::epee_object;
use crate::misc::TxBlobEntry;
//---------------------------------------------------------------------------------------------------- BlockCompleteEntry
#[doc = crate::macros::monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
210..=221
)]
/// Used in [`crate::bin::GetBlocksResponse`].
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BlockCompleteEntry {
pub pruned: bool,
pub block: String,
pub block_weight: u64,
pub txs: Vec<TxBlobEntry>,
}
// TODO: custom epee
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/cryptonote_protocol/cryptonote_protocol_defs.h#L138-L163>
#[cfg(feature = "epee")]
epee_object! {
BlockCompleteEntry,
pruned: bool,
block: String,
block_weight: u64,
txs: Vec<TxBlobEntry>,
}

View file

@ -0,0 +1,48 @@
//! TODO
//---------------------------------------------------------------------------------------------------- Use
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::{
macros::bytes::{Buf, BufMut},
EpeeValue, Marker,
};
//---------------------------------------------------------------------------------------------------- KeyImageSpentStatus
#[doc = crate::macros::monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
456..=460
)]
/// Used in [`crate::other::IsKeyImageSpentResponse`].
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum KeyImageSpentStatus {
Unspent = 0,
SpentInBlockchain = 1,
SpentInPool = 2,
}
#[cfg(feature = "epee")]
impl EpeeValue for KeyImageSpentStatus {
const MARKER: Marker = <String as EpeeValue>::MARKER;
fn read<B: Buf>(r: &mut B, marker: &Marker) -> cuprate_epee_encoding::Result<Self> {
todo!()
}
fn should_write(&self) -> bool {
todo!()
}
fn epee_default_value() -> Option<Self> {
todo!()
}
fn write<B: BufMut>(self, w: &mut B) -> cuprate_epee_encoding::Result<()> {
todo!()
}
}

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

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

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

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

View file

@ -0,0 +1,49 @@
//! TODO
//---------------------------------------------------------------------------------------------------- Use
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::{
macros::bytes::{Buf, BufMut},
EpeeValue, Marker,
};
//---------------------------------------------------------------------------------------------------- PoolInfoExtent
#[doc = crate::macros::monero_definition_link!(
cc73fe71162d564ffda8e549b79a350bca53c454,
"rpc/core_rpc_server_commands_defs.h",
223..=228
)]
/// Used in [`crate::bin::GetBlocksResponse`].
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum PoolInfoExtent {
None = 0,
Incremental = 1,
Full = 2,
}
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/cryptonote_protocol/cryptonote_protocol_defs.h#L138-L163>
#[cfg(feature = "epee")]
impl EpeeValue for PoolInfoExtent {
const MARKER: Marker = <String as EpeeValue>::MARKER;
fn read<B: Buf>(r: &mut B, marker: &Marker) -> cuprate_epee_encoding::Result<Self> {
todo!()
}
fn should_write(&self) -> bool {
todo!()
}
fn epee_default_value() -> Option<Self> {
todo!()
}
fn write<B: BufMut>(self, w: &mut B) -> cuprate_epee_encoding::Result<()> {
todo!()
}
}

View file

@ -3,8 +3,10 @@
//---------------------------------------------------------------------------------------------------- Import
use std::fmt::Display;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "epee")]
use cuprate_epee_encoding::{
macros::bytes::{Buf, BufMut},
EpeeValue, Marker,
@ -16,18 +18,20 @@ use crate::constants::{
};
//---------------------------------------------------------------------------------------------------- Status
// TODO: this type needs to expand more.
// There are a lot of RPC calls that will return a random
// string inside, which isn't compatible with [`Status`].
/// RPC response status.
///
/// This type represents `monerod`'s frequently appearing string field, `status`.
///
/// This field appears within RPC [JSON response](crate::json) types.
///
/// Reference: <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L78-L81>.
///
/// ## Serialization and string formatting
/// ```rust
/// use cuprate_rpc_types::{
/// Status,
/// misc::Status,
/// CORE_RPC_STATUS_BUSY, CORE_RPC_STATUS_NOT_MINING, CORE_RPC_STATUS_OK,
/// CORE_RPC_STATUS_PAYMENT_REQUIRED, CORE_RPC_STATUS_UNKNOWN
/// };
@ -59,28 +63,27 @@ use crate::constants::{
/// assert_eq!(format!("{:?}", Status::PaymentRequired), "PaymentRequired");
/// assert_eq!(format!("{:?}", unknown), "Unknown");
/// ```
#[derive(
Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Status {
// FIXME:
// `#[serde(rename = "")]` only takes raw string literals?
// We have to re-type the constants here...
/// Successful RPC response, everything is OK; [`CORE_RPC_STATUS_OK`].
#[serde(rename = "OK")]
#[cfg_attr(feature = "serde", serde(rename = "OK"))]
#[default]
Ok,
/// The daemon is busy, try later; [`CORE_RPC_STATUS_BUSY`].
#[serde(rename = "BUSY")]
#[cfg_attr(feature = "serde", serde(rename = "BUSY"))]
Busy,
/// The daemon is not mining; [`CORE_RPC_STATUS_NOT_MINING`].
#[serde(rename = "NOT MINING")]
#[cfg_attr(feature = "serde", serde(rename = "NOT MINING"))]
NotMining,
/// Payment is required for RPC; [`CORE_RPC_STATUS_PAYMENT_REQUIRED`].
#[serde(rename = "PAYMENT REQUIRED")]
#[cfg_attr(feature = "serde", serde(rename = "PAYMENT REQUIRED"))]
PaymentRequired,
/// Some unknown other string; [`CORE_RPC_STATUS_UNKNOWN`].
@ -91,8 +94,8 @@ pub enum Status {
/// The reason this isn't `Unknown(String)` is because that
/// disallows [`Status`] to be [`Copy`], and thus other types
/// that contain it.
#[serde(other)]
#[serde(rename = "UNKNOWN")]
#[cfg_attr(feature = "serde", serde(other))]
#[cfg_attr(feature = "serde", serde(rename = "UNKNOWN"))]
Unknown,
}
@ -132,6 +135,7 @@ impl Display for Status {
//
// See below for more impl info:
// <https://github.com/Cuprate/cuprate/blob/bef2a2cbd4e1194991751d1fbc96603cba8c7a51/net/epee-encoding/src/value.rs#L366-L392>.
#[cfg(feature = "epee")]
impl EpeeValue for Status {
const MARKER: Marker = <String as EpeeValue>::MARKER;
@ -161,6 +165,7 @@ mod test {
// Test epee (de)serialization works.
#[test]
#[cfg(feature = "epee")]
fn epee() {
for status in [
Status::Ok,

View file

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

View file

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

View file

@ -50,20 +50,12 @@ pub fn open(config: Config) -> Result<ConcreteEnv, InitError> {
// we want since it is agnostic, so we are responsible for this.
{
let env_inner = env.env_inner();
let tx_rw = env_inner.tx_rw();
let tx_rw = match tx_rw {
Ok(tx_rw) => tx_rw,
Err(e) => return Err(runtime_to_init_error(e)),
};
let tx_rw = env_inner.tx_rw().map_err(runtime_to_init_error)?;
// Create all tables.
if let Err(e) = OpenTables::create_tables(&env_inner, &tx_rw) {
return Err(runtime_to_init_error(e));
};
OpenTables::create_tables(&env_inner, &tx_rw).map_err(runtime_to_init_error)?;
if let Err(e) = tx_rw.commit() {
return Err(runtime_to_init_error(e));
}
TxRw::commit(tx_rw).map_err(runtime_to_init_error)?;
}
Ok(env)

View file

@ -1,7 +1,7 @@
//! TODO
//---------------------------------------------------------------------------------------------------- Import
use cuprate_database::{EnvInner, RuntimeError, TxRo, TxRw};
use cuprate_database::{EnvInner, RuntimeError};
use crate::tables::{TablesIter, TablesMut};
@ -84,12 +84,12 @@ pub(crate) use call_fn_on_all_tables_or_early_return;
/// let mut tables = env_inner.open_tables_mut(&tx_rw)?;
/// # Ok(()) }
/// ```
pub trait OpenTables<'env, Ro, Rw>
where
Self: 'env,
Ro: TxRo<'env>,
Rw: TxRw<'env>,
{
pub trait OpenTables<'env> {
/// The read-only transaction type of the backend.
type Ro<'a>;
/// The read-write transaction type of the backend.
type Rw<'a>;
/// Open all tables in read/iter mode.
///
/// This calls [`EnvInner::open_db_ro`] on all database tables
@ -100,7 +100,7 @@ where
///
/// As all tables are created upon [`crate::open`],
/// this function will never error because a table doesn't exist.
fn open_tables(&'env self, tx_ro: &Ro) -> Result<impl TablesIter, RuntimeError>;
fn open_tables(&self, tx_ro: &Self::Ro<'_>) -> Result<impl TablesIter, RuntimeError>;
/// Open all tables in read-write mode.
///
@ -109,7 +109,7 @@ where
///
/// # Errors
/// This will only return [`RuntimeError::Io`] on errors.
fn open_tables_mut(&'env self, tx_rw: &Rw) -> Result<impl TablesMut, RuntimeError>;
fn open_tables_mut(&self, tx_rw: &Self::Rw<'_>) -> Result<impl TablesMut, RuntimeError>;
/// Create all database tables.
///
@ -118,28 +118,29 @@ where
///
/// # Errors
/// This will only return [`RuntimeError::Io`] on errors.
fn create_tables(&'env self, tx_rw: &Rw) -> Result<(), RuntimeError>;
fn create_tables(&self, tx_rw: &Self::Rw<'_>) -> Result<(), RuntimeError>;
}
impl<'env, Ei, Ro, Rw> OpenTables<'env, Ro, Rw> for Ei
impl<'env, Ei> OpenTables<'env> for Ei
where
Ei: EnvInner<'env, Ro, Rw>,
Ro: TxRo<'env>,
Rw: TxRw<'env>,
Ei: EnvInner<'env>,
{
fn open_tables(&'env self, tx_ro: &Ro) -> Result<impl TablesIter, RuntimeError> {
type Ro<'a> = <Ei as EnvInner<'env>>::Ro<'a>;
type Rw<'a> = <Ei as EnvInner<'env>>::Rw<'a>;
fn open_tables(&self, tx_ro: &Self::Ro<'_>) -> Result<impl TablesIter, RuntimeError> {
call_fn_on_all_tables_or_early_return! {
Self::open_db_ro(self, tx_ro)
}
}
fn open_tables_mut(&'env self, tx_rw: &Rw) -> Result<impl TablesMut, RuntimeError> {
fn open_tables_mut(&self, tx_rw: &Self::Rw<'_>) -> Result<impl TablesMut, RuntimeError> {
call_fn_on_all_tables_or_early_return! {
Self::open_db_rw(self, tx_rw)
}
}
fn create_tables(&'env self, tx_rw: &Rw) -> Result<(), RuntimeError> {
fn create_tables(&self, tx_rw: &Self::Rw<'_>) -> Result<(), RuntimeError> {
match call_fn_on_all_tables_or_early_return! {
Self::create_db(self, tx_rw)
} {

View file

@ -9,7 +9,7 @@ repository = "https://github.com/Cuprate/cuprate/tree/main/storage/database"
keywords = ["cuprate", "database"]
[features]
default = ["heed"]
# default = ["heed"]
# default = ["redb"]
# default = ["redb-memory"]
heed = ["dep:heed"]

View file

@ -244,25 +244,28 @@ impl Env for ConcreteEnv {
}
//---------------------------------------------------------------------------------------------------- EnvInner Impl
impl<'env> EnvInner<'env, heed::RoTxn<'env>, RefCell<heed::RwTxn<'env>>>
for RwLockReadGuard<'env, heed::Env>
impl<'env> EnvInner<'env> for RwLockReadGuard<'env, heed::Env>
where
Self: 'env,
{
type Ro<'a> = heed::RoTxn<'a>;
type Rw<'a> = RefCell<heed::RwTxn<'a>>;
#[inline]
fn tx_ro(&'env self) -> Result<heed::RoTxn<'env>, RuntimeError> {
fn tx_ro(&self) -> Result<Self::Ro<'_>, RuntimeError> {
Ok(self.read_txn()?)
}
#[inline]
fn tx_rw(&'env self) -> Result<RefCell<heed::RwTxn<'env>>, RuntimeError> {
fn tx_rw(&self) -> Result<Self::Rw<'_>, RuntimeError> {
Ok(RefCell::new(self.write_txn()?))
}
#[inline]
fn open_db_ro<T: Table>(
&self,
tx_ro: &heed::RoTxn<'env>,
tx_ro: &Self::Ro<'_>,
) -> Result<impl DatabaseRo<T> + DatabaseIter<T>, RuntimeError> {
// Open up a read-only database using our table's const metadata.
//
@ -280,7 +283,7 @@ where
#[inline]
fn open_db_rw<T: Table>(
&self,
tx_rw: &RefCell<heed::RwTxn<'env>>,
tx_rw: &Self::Rw<'_>,
) -> Result<impl DatabaseRw<T>, RuntimeError> {
// Open up a read/write database using our table's const metadata.
//
@ -293,7 +296,7 @@ where
})
}
fn create_db<T: Table>(&self, tx_rw: &RefCell<heed::RwTxn<'env>>) -> Result<(), RuntimeError> {
fn create_db<T: Table>(&self, tx_rw: &Self::Rw<'_>) -> Result<(), RuntimeError> {
// Create a database using our:
// - [`Table`]'s const metadata.
// - (potentially) our [`Key`] comparison function
@ -325,10 +328,7 @@ where
}
#[inline]
fn clear_db<T: Table>(
&self,
tx_rw: &mut RefCell<heed::RwTxn<'env>>,
) -> Result<(), RuntimeError> {
fn clear_db<T: Table>(&self, tx_rw: &mut Self::Rw<'_>) -> Result<(), RuntimeError> {
let tx_rw = tx_rw.get_mut();
// Open the table. We don't care about flags or key

View file

@ -118,18 +118,20 @@ impl Env for ConcreteEnv {
}
//---------------------------------------------------------------------------------------------------- EnvInner Impl
impl<'env> EnvInner<'env, redb::ReadTransaction, redb::WriteTransaction>
for (&'env redb::Database, redb::Durability)
impl<'env> EnvInner<'env> for (&'env redb::Database, redb::Durability)
where
Self: 'env,
{
type Ro<'a> = redb::ReadTransaction;
type Rw<'a> = redb::WriteTransaction;
#[inline]
fn tx_ro(&'env self) -> Result<redb::ReadTransaction, RuntimeError> {
fn tx_ro(&self) -> Result<redb::ReadTransaction, RuntimeError> {
Ok(self.0.begin_read()?)
}
#[inline]
fn tx_rw(&'env self) -> Result<redb::WriteTransaction, RuntimeError> {
fn tx_rw(&self) -> Result<redb::WriteTransaction, RuntimeError> {
// `redb` has sync modes on the TX level, unlike heed,
// which sets it at the Environment level.
//
@ -142,7 +144,7 @@ where
#[inline]
fn open_db_ro<T: Table>(
&self,
tx_ro: &redb::ReadTransaction,
tx_ro: &Self::Ro<'_>,
) -> Result<impl DatabaseRo<T> + DatabaseIter<T>, RuntimeError> {
// Open up a read-only database using our `T: Table`'s const metadata.
let table: redb::TableDefinition<'static, StorableRedb<T::Key>, StorableRedb<T::Value>> =
@ -154,7 +156,7 @@ where
#[inline]
fn open_db_rw<T: Table>(
&self,
tx_rw: &redb::WriteTransaction,
tx_rw: &Self::Rw<'_>,
) -> Result<impl DatabaseRw<T>, RuntimeError> {
// Open up a read/write database using our `T: Table`'s const metadata.
let table: redb::TableDefinition<'static, StorableRedb<T::Key>, StorableRedb<T::Value>> =

View file

@ -62,17 +62,17 @@ pub trait Env: Sized {
// For `heed`, this is just `heed::Env`, for `redb` this is
// `(redb::Database, redb::Durability)` as each transaction
// needs the sync mode set during creation.
type EnvInner<'env>: EnvInner<'env, Self::TxRo<'env>, Self::TxRw<'env>>
type EnvInner<'env>: EnvInner<'env>
where
Self: 'env;
/// The read-only transaction type of the backend.
type TxRo<'env>: TxRo<'env> + 'env
type TxRo<'env>: TxRo<'env>
where
Self: 'env;
/// The read/write transaction type of the backend.
type TxRw<'env>: TxRw<'env> + 'env
type TxRw<'env>: TxRw<'env>
where
Self: 'env;
@ -209,23 +209,23 @@ Subsequent table opens will follow the flags/ordering, but only if
///
/// # Invariant
#[doc = doc_heed_create_db_invariant!()]
pub trait EnvInner<'env, Ro, Rw>
where
Self: 'env,
Ro: TxRo<'env>,
Rw: TxRw<'env>,
{
pub trait EnvInner<'env> {
/// The read-only transaction type of the backend.
type Ro<'a>: TxRo<'a>;
/// The read-write transaction type of the backend.
type Rw<'a>: TxRw<'a>;
/// Create a read-only transaction.
///
/// # Errors
/// This will only return [`RuntimeError::Io`] if it errors.
fn tx_ro(&'env self) -> Result<Ro, RuntimeError>;
fn tx_ro(&self) -> Result<Self::Ro<'_>, RuntimeError>;
/// Create a read/write transaction.
///
/// # Errors
/// This will only return [`RuntimeError::Io`] if it errors.
fn tx_rw(&'env self) -> Result<Rw, RuntimeError>;
fn tx_rw(&self) -> Result<Self::Rw<'_>, RuntimeError>;
/// Open a database in read-only mode.
///
@ -252,7 +252,7 @@ where
#[doc = doc_heed_create_db_invariant!()]
fn open_db_ro<T: Table>(
&self,
tx_ro: &Ro,
tx_ro: &Self::Ro<'_>,
) -> Result<impl DatabaseRo<T> + DatabaseIter<T>, RuntimeError>;
/// Open a database in read/write mode.
@ -271,7 +271,10 @@ where
///
/// # Invariant
#[doc = doc_heed_create_db_invariant!()]
fn open_db_rw<T: Table>(&self, tx_rw: &Rw) -> Result<impl DatabaseRw<T>, RuntimeError>;
fn open_db_rw<T: Table>(
&self,
tx_rw: &Self::Rw<'_>,
) -> Result<impl DatabaseRw<T>, RuntimeError>;
/// Create a database table.
///
@ -282,7 +285,7 @@ where
///
/// # Invariant
#[doc = doc_heed_create_db_invariant!()]
fn create_db<T: Table>(&self, tx_rw: &Rw) -> Result<(), RuntimeError>;
fn create_db<T: Table>(&self, tx_rw: &Self::Rw<'_>) -> Result<(), RuntimeError>;
/// Clear all `(key, value)`'s from a database table.
///
@ -297,5 +300,5 @@ where
///
/// If the specified table is not created upon before this function is called,
/// this will return [`RuntimeError::TableNotFound`].
fn clear_db<T: Table>(&self, tx_rw: &mut Rw) -> Result<(), RuntimeError>;
fn clear_db<T: Table>(&self, tx_rw: &mut Self::Rw<'_>) -> Result<(), RuntimeError>;
}