architecture-book: fill RPC section (#243)

* books: add `rpc` skeleton

* json-rpc

* types section

* differences

* interface

* typos

* differences: add `json-formatting.md`

* rpc: small fixes

* appendix: add `cuprate-rpc-handler` to crate list

* differences: remove extra fields section, add more info

* differences: add `id:0` section
This commit is contained in:
hinto-janai 2024-08-07 19:15:22 -04:00 committed by GitHub
parent eb65efa7fb
commit fafa20c20f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 650 additions and 19 deletions

View file

@ -35,15 +35,27 @@
---
- [🔴 RPC](rpc/intro.md)
- [⚪️ Types](rpc/types/intro.md)
- [⚪️ JSON](rpc/types/json.md)
- [⚪️ Binary](rpc/types/binary.md)
- [⚪️ Other](rpc/types/other.md)
- [⚪️ Interface](rpc/interface.md)
- [⚪️ Router](rpc/router.md)
- [⚪️ Handler](rpc/handler.md)
- [⚪️ Methods](rpc/methods/intro.md)
- [🟢 RPC](rpc/intro.md)
- [🟡 JSON-RPC 2.0](rpc/json-rpc.md)
- [🟢 The types](rpc/types/intro.md)
- [🟢 Misc types](rpc/types/misc-types.md)
- [🟢 Base RPC types](rpc/types/base-types.md)
- [🟢 The type generator macro](rpc/types/macro.md)
- [🟢 Metadata](rpc/types/metadata.md)
- [🟡 (De)serialization](rpc/types/deserialization.md)
- [🟢 The interface](rpc/interface.md)
- [🔴 The handler](rpc/handler/intro.md)
- [🔴 The server](rpc/server/intro.md)
- [🟢 Differences with `monerod`](rpc/differences/intro.md)
- [🟢 JSON field ordering](rpc/differences/json-field-ordering.md)
- [🟢 JSON formatting](rpc/differences/json-formatting.md)
- [🟢 JSON strictness](rpc/differences/json-strictness.md)
- [🟡 JSON-RPC strictness](rpc/differences/json-rpc-strictness.md)
- [🟡 HTTP methods](rpc/differences/http-methods.md)
- [🟡 RPC payment](rpc/differences/rpc-payment.md)
- [🟢 Custom strings](rpc/differences/custom-strings.md)
- [🔴 Unsupported RPC calls](rpc/differences/unsupported-rpc-calls.md)
- [🔴 RPC calls with different behavior](rpc/differences/rpc-calls-with-different-behavior.md)
---

View file

@ -50,6 +50,7 @@ cargo doc --open --package cuprate-blockchain
| [`cuprate-json-rpc`](https://doc.cuprate.org/cuprate_json_rpc) | [`rpc/json-rpc/`](https://github.com/Cuprate/cuprate/tree/main/rpc/json-rpc) | JSON-RPC 2.0 implementation
| [`cuprate-rpc-types`](https://doc.cuprate.org/cuprate_rpc_types) | [`rpc/types/`](https://github.com/Cuprate/cuprate/tree/main/rpc/types) | Monero RPC types and traits
| [`cuprate-rpc-interface`](https://doc.cuprate.org/cuprate_rpc_interface) | [`rpc/interface/`](https://github.com/Cuprate/cuprate/tree/main/rpc/interface) | RPC interface & routing
| [`cuprate-rpc-handler`](https://doc.cuprate.org/cuprate_rpc_handler) | [`rpc/handler/`](https://github.com/Cuprate/cuprate/tree/main/rpc/handler) | RPC inner handlers
## 1-off crates
| Crate | In-tree path | Purpose |

View file

@ -0,0 +1,7 @@
# Custom strings
Many JSON response fields contain strings with custom messages.
This may be error messages, status, etc.
Although the field + string type will be followed, Cuprate will not always
have the exact same message, particularly when it comes to error messages.

View file

@ -0,0 +1,17 @@
# HTTP methods
`monerod` endpoints supports multiple [HTTP methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
that do not necessarily make sense.
For example:
```bash
curl \
http://127.0.0.1:18081/get_limit \
-H 'Content-Type: application/json' \
--request DELETE
```
This is sending an HTTP `DELETE` request, which should be a `GET`.
`monerod` will respond to this the same as `GET`, `POST`, `PUT`, and `TRACE`.
## Cuprate's behavior
> TODO: decide allowed HTTP methods for Cuprate <https://github.com/Cuprate/cuprate/pull/233#discussion_r1700934928>.

View file

@ -0,0 +1,9 @@
# Differences with `monerod`
As noted in the [introduction](../intro.md), `monerod`'s RPC behavior cannot always be perfectly followed by Cuprate.
The reasoning for the differences can vary from:
- Technical limitations
- Behavior being `monerod`-specific
- Purposeful decision to not support behavior
This section lays out the details of the differences between `monerod`'s and Cuprate's RPC system.

View file

@ -0,0 +1,51 @@
# JSON field ordering
When serializing JSON, `monerod` has the behavior to order key fields within a scope alphabetically.
For example:
```json
{
"id": "0",
"jsonrpc": "2.0",
"result": {
"blockhashing_blob": "...",
"blocktemplate_blob": "...",
"difficulty": 283305047039,
"difficulty_top64": 0,
"expected_reward": 600000000000,
"height": 3195018,
"next_seed_hash": "",
"prev_hash": "9d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a",
"reserved_offset": 131,
"seed_hash": "e2aa0b7b55042cd48b02e395d78fa66a29815ccc1584e38db2d1f0e8485cd44f",
"seed_height": 3194880,
"status": "OK",
"untrusted": false,
"wide_difficulty": "0x41f64bf3ff"
}
}
```
In the main `{}`, `id` comes before `jsonrpc`, which comes before `result`.
The same alphabetical ordering is applied to the fields within `result`.
Cuprate uses [`serde`](https://docs.rs/serde) for JSON serialization,
which serializes fields based on the _definition_ order, i.e. whatever
order the fields are defined in the code, is the order they will appear
in JSON.
Some `struct` fields within Cuprate's RPC types happen to be alphabetical, but this is not a guarantee.
As these are JSON maps, the ordering of fields should not matter,
although this is something to note as the output will technically differ.
## Example incompatibility
An example of where this leads to incompatibility is if specific
line numbers are depended on to contain specific fields.
For example, this will print the 10th line:
```bash
curl http://127.0.0.1:18081/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"get_block_template","params":{"wallet_address":"44GBHzv6ZyQdJkjqZje6KLZ3xSyN1hBSFAnLP6EAqJtCRVzMzZmeXTC2AHKDS9aEDTRKmo6a6o9r9j86pYfhCWDkKjbtcns","reserve_size":60}' -H 'Content-Type: application/json' | sed -n 10p
```
It will be `"height": 3195018` in `monerod`'s case, but may not necessarily be for Cuprate.
By all means, this should not be relied upon in the first place, although it is shown as an example.

View file

@ -0,0 +1,118 @@
# JSON formatting
In general, Cuprate's JSON formatting is very similar to `monerod`, but there are some differences.
This is a list of those differences.
## Pretty vs compact
> TODO: decide when handlers are created if we should allow custom formatting.
Cuprate's RPC (really, [`serde_json`](https://docs.rs/serde_json)) can be configured to use either:
- [Pretty formatting](https://docs.rs/serde_json/latest/serde_json/ser/struct.PrettyFormatter.html)
- [Compact formatting](https://docs.rs/serde_json/latest/serde_json/ser/struct.CompactFormatter.html)
`monerod` uses something _similar_ to pretty formatting.
As an example, pretty formatting:
```json
{
"number": 1,
"array": [
0,
1
],
"string": "",
"array_of_objects": [
{
"x": 1.0,
"y": -1.0
},
{
"x": 2.0,
"y": -2.0
}
]
}
```
compact formatting:
```json
{"number":1,"array":[0,1],"string":"","array_of_objects":[{"x":1.0,"y":-1.0},{"x":2.0,"y":-2.0}]}
```
## Array of objects
`monerod` will format an array of objects like such:
```json
{
"array_of_objects": [{
"x": 0.0,
"y": 0.0,
},{
"x": 0.0,
"y": 0.0,
},{
"x": 0.0,
"y": 0.0
}]
}
```
Cuprate will format the above like such:
```json
{
"array_of_objects": [
{
"x": 0.0,
"y": 0.0,
},
{
"x": 0.0,
"y": 0.0,
},
{
"x": 0.0,
"y": 0.0
}
]
}
```
## Array of maps containing named objects
An method that contains outputs like this is the `peers` field in the `sync_info` method:
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"sync_info"}' \
-H 'Content-Type: application/json'
```
`monerod` will format an array of maps that contains named objects like such:
```json
{
"array": [{
"named_object": {
"field": ""
}
},{
"named_object": {
"field": ""
}
}]
}
```
Cuprate will format the above like such:
```json
{
"array": [
{
"named_object": {
"field": ""
}
},
{
"named_object": {
"field": ""
}
}
]
}
```

View file

@ -0,0 +1,137 @@
# JSON-RPC strictness
This is a list of behavior that `monerod`'s JSON-RPC implementation allows, that Cuprate's JSON-RPC implementation does not.
In general, `monerod`'s JSON-RPC is quite lenient, going against the specification in many cases.
Cuprate's JSON-RPC implementation is slightly more strict.
Cuprate also makes some decisions that are _different_ than `monerod`, but are not necessarily more or less strict.
## Allowing an incorrect `jsonrpc` field
[The JSON-RPC 2.0 specification states that the `jsonrpc` field must be exactly `"2.0"`](https://www.jsonrpc.org/specification#request_object).
`monerod` allows `jsonrpc` to:
- Be any string
- Be an empty array
- Be `null`
- Not exist at all
Examples:
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsonrpc":"???","method":"get_block_count"}' \
-H 'Content-Type: application/json'
```
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsonrpc":[],"method":"get_block_count"}' \
-H 'Content-Type: application/json'
```
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsonrpc":null,"method":"get_block_count"}' \
-H 'Content-Type: application/json'
```
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"method":"get_block_count"}' \
-H 'Content-Type: application/json'
```
## Allowing `id` to be any type
JSON-RPC 2.0 responses must contain the same `id` as the original request.
However, the [specification states](https://www.jsonrpc.org/specification#request_object):
> An identifier established by the Client that MUST contain a String, Number, or NULL value if included
`monerod` does not check this and allows `id` to be any JSON type, for example, a map:
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsonrpc":"2.0","id":{"THIS":{"IS":"ALLOWED"}},"method":"get_block_count"}' \
-H 'Content-Type: application/json'
```
The response:
```json
{
"id": {
"THIS": {
"IS": "ALLOWED"
}
},
"jsonrpc": "2.0",
"result": {
"count": 3210225,
"status": "OK",
"untrusted": false
}
}
```
## Responding with `id:0` on error
The JSON-RPC [specification states](https://www.jsonrpc.org/specification#response_object):
> If there was an error in detecting the id in the Request object (e.g. Parse error/Invalid Request), it MUST be Null.
Although, `monerod` will respond with `id:0` in these cases.
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsonrpc":"2.0","id":asdf,"method":"get_block_count"}' \
-H 'Content-Type: application/json'
```
Response:
```bash
{
"error": {
"code": -32700,
"message": "Parse error"
},
"id": 0,
"jsonrpc": "2.0"
}
```
## Responding to notifications
> TODO: decide on Cuprate behavior <https://github.com/Cuprate/cuprate/pull/233#discussion_r1704611186>
Requests that have no `id` field are "notifications".
[The JSON-RPC 2.0 specification states that requests without
an `id` field must _not_ be responded to](https://www.jsonrpc.org/specification#notification).
Example:
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsonrpc":"2.0","method":"get_block_count"}' \
-H 'Content-Type: application/json'
```
## Upper/mixed case fields
`monerod` will accept upper/mixed case fields on:
- `jsonrpc`
- `id`
`method` however, is checked.
The JSON-RPC 2.0 specification does not outright state what case to support,
although, Cuprate only supports lowercase as supporting upper/mixed case
is more code to add as `serde` by default is case-sensitive on `struct` fields.
Example:
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsONrPc":"2.0","iD":0,"method":"get_block_count"}' \
-H 'Content-Type: application/json'
```

View file

@ -0,0 +1,49 @@
# JSON strictness
This is a list of behavior that `monerod`'s JSON parser allows, that Cuprate's JSON parser ([`serde_json`](https://docs.rs/serde_json)) does not.
In general, `monerod`'s parser is quite lenient, allowing invalid JSON in many cases.
Cuprate's (really, `serde_json`) JSON parser is quite strict, essentially sticking to
the [JSON specification](https://datatracker.ietf.org/doc/html/rfc8259).
Cuprate also makes some decisions that are _different_ than `monerod`, but are not necessarily more or less strict.
## Missing closing bracket
`monerod` will accept JSON missing a final closing `}`.
Example:
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"get_block_count"' \
-H 'Content-Type: application/json'
```
## Trailing ending comma
`monerod` will accept JSON containing a final trailing `,`.
Example:
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"get_block_count",}' \
-H 'Content-Type: application/json'
```
## Allowing `-` in fields
`monerod` allows `-` as a valid value in certain fields, **not a string `"-"`, but the character `-`**.
The fields where this is allowed seems to be any field `monerod` does not explicitly look for, examples include:
- `jsonrpc`
- `id`
- `params` (where parameters are not expected)
- Any ignored field
The [JSON-RPC 2.0 specification does state that the response `id` should be `null` upon errors in detecting the request `id`](https://wwwjsonrpc.org/specification#response_object), although in this case, this is invalid JSON and should not make it this far. The response will contain the default `id: 0` in this case.
Example:
```bash
curl \
http://127.0.0.1:18081/json_rpc \
-d '{"jsonrpc":-,"id":-,"params":-,"IGNORED_FIELD":-,"method":"get_block_count"}' \
-H 'Content-Type: application/json'
```

View file

@ -0,0 +1,2 @@
# RPC calls with different behavior
> TODO: compile RPC calls with different behavior after handlers are created.

View file

@ -0,0 +1,9 @@
# RPC payment
The RPC payment system in `monerod` is a [pseudo-deprecated](https://github.com/monero-project/monero/issues/8722)
system that allows node operators to be compensated for RPC usage.
Although this system is pseudo-deprecated, `monerod` still generates related fields in responses. [Cuprate follows this behavior](https://doc.cuprate.org/cuprate_rpc_types/base/struct.AccessResponseBase.html).
However, the [associated endpoints](https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.h#L182-L187) and [actual functionality](https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.h#L260-L265) are not supported by Cuprate. The associated endpoints will return an error upon invocation.
> TODO: decide on behavior and document <https://github.com/Cuprate/cuprate/pull/233#discussion_r1700870051>.

View file

@ -0,0 +1,2 @@
# Unsupported RPC calls
> TODO: compile unsupported RPC calls after handlers are created.

View file

@ -1 +0,0 @@
# ⚪️ Handler

View file

@ -0,0 +1,2 @@
# The handler
> TODO: fill after `cuprate-rpc-handler` is created.

View file

@ -1 +1,36 @@
# ⚪️ Interface
# The interface
> This section is short as [`cuprate-rpc-interface`](https://doc.cuprate.org/cuprate_rpc_interface) contains detailed documentation.
The RPC interface, which includes:
- Endpoint routing (`/json_rpc`, `/get_blocks.bin`, etc)
- Route function signatures (`async fn json_rpc(...) -> Response`)
- Type (de)serialization
- Any miscellaneous handling (denying `restricted` RPC calls)
is handled by the [`cuprate-rpc-interface`](https://doc.cuprate.org/cuprate_rpc_interface) crate.
Essentially, this crate provides the API for the RPC.
`cuprate-rpc-interface` is built on-top of [`axum`](https://docs.rs/axum) and [`tower`](https://docs.rs/tower),
which are the crates doing the bulk majority of the work.
## Request -> Response
The functions that map requests to responses are not implemented by `cuprate-rpc-interface` itself, they must be provided by the user, i.e. it can be _customized_.
In Rust terms, this crate provides you with:
```rust
async fn json_rpc(
state: State,
request: Request,
) -> Response {
/* your handler here */
}
```
and you provide the function body.
The main handler crate is [`cuprate-rpc-handler`](https://doc.cuprate.org/cuprate_rpc_handler).
This crate implements the standard RPC behavior, i.e. it mostly mirrors `monerod`.
Although, it's worth noting that other implementations are possible, such as an RPC handler that caches blocks,
or an RPC handler that only accepts certain endpoints, or any combination.

View file

@ -1,3 +1,30 @@
# RPC
- <https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#other-daemon-rpc-calls>
- <https://github.com/monero-project/monero/tree/master/src/rpc>
`monerod`'s daemon RPC has three kinds of RPC calls:
1. [JSON-RPC 2.0](https://www.jsonrpc.org/specification) methods, called at the `/json_rpc` endpoint
1. JSON (but not JSON-RPC 2.0) methods called at their own endpoints, e.g. [`/get_height`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_height)
1. Binary ([epee](../../formats-protocols-types/epee.html)) RPC methods called at their own endpoints ending in `.bin`, e.g. [`/get_blocks.bin`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_blocksbin)
Cuprate's RPC aims to mirror `monerod`'s as much as it practically can.
This includes, but is not limited to:
- Using the same endpoints
- Receiving the same request data
- Sending the same response data
- Responding with the same HTTP status codes
- Following internal behavior (e.g. [`/pop_blocks`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#pop_blocks))
Not all `monerod` behavior can always be followed, however.
Some are not followed on purpose, some cannot be followed due to technical limitations, and some cannot be due to the behavior being `monerod` specific such as the [`/set_log_categories`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#set_log_categories) endpoint which uses `monerod`'s logging categories.
Both subtle and large differences between Cuprate's RPC and `monerod`'s RPC are documented in the [Differences with `monerod`](differences/intro.md) section.
## Main RPC components
The main components that make up Cuprate's RPC are noted below, alongside the equivalent `monerod` code and other notes.
| Cuprate crate | `monerod` (rough) equivalent | Purpose | Notes |
|---------------|------------------------------|---------|-------|
| [`cuprate-json-rpc`](https://doc.cuprate.org/cuprate_json_rpc) | [`jsonrpc_structs.h`](https://github.com/monero-project/monero/blob/caa62bc9ea1c5f2ffe3ffa440ad230e1de509bfd/contrib/epee/include/net/jsonrpc_structs.h), [`http_server_handlers_map2.h`](https://github.com/monero-project/monero/blob/caa62bc9ea1c5f2ffe3ffa440ad230e1de509bfd/contrib/epee/include/net/http_server_handlers_map2.h) | JSON-RPC 2.0 implementation | `monerod`'s JSON-RPC 2.0 handling is spread across a few files. The first defines some data structures, the second contains macros that (essentially) implement JSON-RPC 2.0.
| [`cuprate-rpc-types`](https://doc.cuprate.org/cuprate_rpc_types) | [`core_rpc_server_commands_defs.h`](https://github.com/monero-project/monero/blob/caa62bc9ea1c5f2ffe3ffa440ad230e1de509bfd/src/rpc/core_rpc_server_commands_defs.h) | RPC request/response type definitions and (de)serialization | |
| [`cuprate-rpc-interface`](https://doc.cuprate.org/cuprate_rpc_interface) | [`core_rpc_server.h`](https://github.com/monero-project/monero/blob/caa62bc9ea1c5f2ffe3ffa440ad230e1de509bfd/src/rpc/core_rpc_server.h) | RPC interface, routing, endpoints | |
| [`cuprate-rpc-handler`](https://doc.cuprate.org/cuprate_rpc_handler) | [`core_rpc_server.cpp`](https://github.com/monero-project/monero/blob/caa62bc9ea1c5f2ffe3ffa440ad230e1de509bfd/src/rpc/core_rpc_server.cpp) | RPC request/response handling | These are the "inner handler" functions that turn requests into responses |

View file

@ -0,0 +1,10 @@
# JSON-RPC 2.0
Cuprate has a standalone crate that implements the [JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification, [`cuprate-json-rpc`](https://doc.cuprate.org/cuprate_json_rpc). The RPC methods at the `/json_rpc` endpoint use this crate's types, functions, and (de)serialization.
There is nothing too special about Cuprate's implementation.
Any small notes and differences are noted in the crate documentation.
As such, there is not much to document here, instead, consider reading the very
brief JSON-RPC 2.0 specification, and the `cuprate-json-rpc` crate documentation.
> TODO: document `method/params` vs flattened `base` when figured out.

View file

@ -1 +0,0 @@
# ⚪️ Methods

View file

@ -1 +0,0 @@
# ⚪️ Router

View file

@ -0,0 +1,2 @@
# 🔴 The server
> TODO: fill after `cuprate-rpc-server` or binary impl is created.

View file

@ -0,0 +1,39 @@
# Base RPC types
There exists a few "base" types that many types are built on-top of in `monerod`.
These are also implemented in [`cuprate-rpc-types`](https://doc.cuprate.org/cuprate_rpc_types/base/index.html).
For example, many requests include these 2 fields:
```json
{
"status": "OK",
"untrusted": false,
}
```
This is [`rpc_response_base`](https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server_commands_defs.h#L101-L112) in `monerod`, and [`ResponseBase`](https://doc.cuprate.org/cuprate_rpc_types/base/struct.ResponseBase.html) in Cuprate.
These types are [flattened](https://serde.rs/field-attrs.html#flatten) into other types, i.e. the fields
from these base types are injected into the given type. For example, [`get_block_count`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_block_count)'s response type is defined [like such in Cuprate](https://doc.cuprate.org/cuprate_rpc_types/json/struct.GetBlockCountResponse.html):
```rust
struct GetBlockCountResponse {
// The fields of this `base` type are directly
// injected into `GetBlockCountResponse` during
// (de)serialization.
//
// I.e. it is as if this `base` field were actually these 2 fields:
// status: Status,
// untrusted: bool,
base: ResponseBase,
count: u64,
}
```
The JSON output of this type would look something like:
```json
{
"status": "OK",
"untrusted": "false",
"count": 993163
}
```
## RPC payment
`monerod` also contains RPC base types for the [RPC payment](https://doc.cuprate.org/cuprate_rpc_types/base/struct.AccessResponseBase.html) system. Although the RPC payment system [is](https://github.com/monero-project/monero/issues/8722) [pseudo](https://github.com/monero-project/monero/pull/8724) [deprecated](https://github.com/monero-project/monero/pull/8843), `monerod` still generates these fields in responses, and thus, [so does Cuprate](https://doc.cuprate.org/cuprate_rpc_types/base/struct.AccessResponseBase.html).

View file

@ -1 +0,0 @@
# ⚪️ Binary

View file

@ -0,0 +1,38 @@
# (De)serialization
A crucial responsibility of [`cuprate-rpc-types`](https://doc.cuprate.org/cuprate_rpc_types)
is to provide the _correct_ (de)serialization of types.
The input/output of Cuprate's RPC should match `monerod` (as much as practically possible).
A simple example of this is that [`/get_height`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_height)
should respond with the exact same data for both `monerod` and Cuprate:
```json
{
"hash": "7e23a28cfa6df925d5b63940baf60b83c0cbb65da95f49b19e7cf0ce7dd709ce",
"height": 2287217,
"status": "OK",
"untrusted": false
}
```
Behavior would be considered incompatible if any of the following were true:
- Fields are missing
- Extra fields exist
- Field types are incorrect (`string` instead of `number`, etc)
## JSON
(De)serialization for JSON is implemented using [`serde`](https://docs.rs/serde) and [`serde_json`](https://docs.rs/serde_json).
[`cuprate-rpc-interface`](https://doc.cuprate.org/cuprate_rpc_interface) (the main crate responsible
for the actual output) uses `serde_json` for JSON formatting. It is _mostly_ the same formatting as `monerod`, [although there are slight differences](../differences/json-formatting.md).
Technically, the formatting of the JSON output is not handled by `cuprate-rpc-types`, users are free to choose whatever formatting they desire.
## Epee
(De)serialization for the [epee binary format](../../formats-protocols-types/epee.md) is
handled by Cuprate's in-house [cuprate-epee-encoding](https://doc.cuprate.org/cuprate_epee_encoding) library.
## Bitcasted `struct`s
> TODO: <https://github.com/monero-project/monero/issues/9422>
## Compressed data
> TODO: <https://github.com/monero-project/monero/issues/9422>

View file

@ -1 +1,31 @@
# ⚪️ Types
# The types
Cuprate has a crate that defines all the types related to RPC: [`cuprate-rpc-types`](https://doc.cuprate.org/cuprate_rpc_types).
The main purpose of this crate is to port the types used in `monerod`'s RPC and to re-implement
(de)serialization for those types, whether that be JSON, `epee`, or a custom mix.
The bulk majority of these types are [request & response types](macro.md), i.e. the inputs
Cuprate's RPC is expecting from users, and the output it will respond with.
## Example
To showcase an example of the kinds of types defined in this crate, here is a request type:
```rust
#[serde(transparent)]
#[repr(transparent)]
struct OnGetBlockHashRequest {
block_height: [u64; 1],
}
```
This is the input (`params`) expected in the [`on_get_block_hash`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#on_get_block_hash) method.
As seen above, the type itself encodes some properties, such as being (de)serialized [transparently](https://serde.rs/container-attrs.html#transparent), and the input being an array with 1 length, rather than a single `u64`. [This is to match the behavior of `monerod`](https://github.com/monero-project/monero/blob/caa62bc9ea1c5f2ffe3ffa440ad230e1de509bfd/src/rpc/core_rpc_server.cpp#L1826).
An example JSON form of this type would be:
```json
{
"jsonrpc": "2.0",
"id": "0",
"method": "on_get_block_hash",
"params": [912345] // <- This can (de)serialize as a `OnGetBlockHashRequest`
}
```

View file

@ -1 +0,0 @@
# ⚪️ JSON

View file

@ -0,0 +1,16 @@
# The type generator macro
Request and response types make up the majority of [`cuprate-rpc-types`](https://doc.cuprate.org/cuprate_rpc_types).
- Request types are the inputs expected _from_ users
- Response types are what will be outputted _to_ users
Regardless of being meant for JSON-RPC, binary, or a standalone JSON endpoint,
all request/response types are defined using the ["type generator macro"](https://github.com/Cuprate/cuprate/blob/bd375eae40acfad7c8d0205bb10afd0b78e424d2/rpc/types/src/macros.rs#L46). This macro is important because it defines _all_ request/response types.
This macro:
- Defines a matching pair of request & response types
- Implements many `derive` traits, e.g. `Clone` on those types
- Implements both `serde` and `epee` on those types
- Automates documentation, tests, etc.
See [here](https://github.com/Cuprate/cuprate/blob/bd375eae40acfad7c8d0205bb10afd0b78e424d2/rpc/types/src/macros.rs#L46) for example usage of this macro.

View file

@ -0,0 +1,13 @@
# Metadata
[`cuprate-rpc-types`](https://doc.cuprate.org/cuprate_rpc_types) also provides
some `trait`s to access some metadata surrounding RPC data types.
For example, [`trait RpcCall`](https://doc.cuprate.org/cuprate_rpc_types/trait.RpcCall.html)
allows accessing whether an RPC request is [`restricted`](https://doc.cuprate.org/cuprate_rpc_types/trait.RpcCall.html#associatedconstant.IS_RESTRICTED) or not.
`monerod` has a boolean permission system. RPC calls can be restricted or not.
If an RPC call is restricted, it will only be allowed on un-restricted RPC servers (`18081`).
If an RPC call is _not_ restricted, it will be allowed on all RPC server types (`18081` & `18089`).
This metadata is used in crates that build upon `cuprate-rpc-types`, e.g.
to know if an RPC call should be allowed through or not.

View file

@ -0,0 +1,11 @@
# Misc types
Other than the main request/response types, this crate is also responsible
for any [miscellaneous types](https://doc.cuprate.org/cuprate_rpc_types/misc) used within `monerod`'s RPC.
For example, the `status` field within many RPC responses is defined within
[`cuprate-rpc-types`](https://doc.cuprate.org/cuprate_rpc_types/misc/enum.Status.html).
Types that aren't requests/responses but exist _within_ request/response
types are also defined in this crate, such as the
[`Distribution`](https://doc.cuprate.org/cuprate_rpc_types/misc/enum.Distribution.html)
structure returned from the [`get_output_distribution`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_output_distribution) method.

View file

@ -1 +0,0 @@
# ⚪️ Other