mirror of
https://github.com/Cuprate/cuprate.git
synced 2024-12-22 19:49:28 +00:00
architecture-book: fill RPC
section (#243)
Some checks failed
Architecture mdBook / build (push) Has been cancelled
CI / fmt (push) Has been cancelled
CI / typo (push) Has been cancelled
CI / ci (macos-latest, stable, bash) (push) Has been cancelled
Doc / build (push) Has been cancelled
CI / ci (ubuntu-latest, stable, bash) (push) Has been cancelled
CI / ci (windows-latest, stable-x86_64-pc-windows-gnu, msys2 {0}) (push) Has been cancelled
Doc / deploy (push) Has been cancelled
Some checks failed
Architecture mdBook / build (push) Has been cancelled
CI / fmt (push) Has been cancelled
CI / typo (push) Has been cancelled
CI / ci (macos-latest, stable, bash) (push) Has been cancelled
Doc / build (push) Has been cancelled
CI / ci (ubuntu-latest, stable, bash) (push) Has been cancelled
CI / ci (windows-latest, stable-x86_64-pc-windows-gnu, msys2 {0}) (push) Has been cancelled
Doc / deploy (push) Has been cancelled
* 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:
parent
eb65efa7fb
commit
fafa20c20f
29 changed files with 650 additions and 19 deletions
|
@ -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)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -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 |
|
||||
|
|
7
books/architecture/src/rpc/differences/custom-strings.md
Normal file
7
books/architecture/src/rpc/differences/custom-strings.md
Normal 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.
|
17
books/architecture/src/rpc/differences/http-methods.md
Normal file
17
books/architecture/src/rpc/differences/http-methods.md
Normal 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>.
|
9
books/architecture/src/rpc/differences/intro.md
Normal file
9
books/architecture/src/rpc/differences/intro.md
Normal 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.
|
|
@ -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.
|
118
books/architecture/src/rpc/differences/json-formatting.md
Normal file
118
books/architecture/src/rpc/differences/json-formatting.md
Normal 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": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
137
books/architecture/src/rpc/differences/json-rpc-strictness.md
Normal file
137
books/architecture/src/rpc/differences/json-rpc-strictness.md
Normal 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'
|
||||
```
|
49
books/architecture/src/rpc/differences/json-strictness.md
Normal file
49
books/architecture/src/rpc/differences/json-strictness.md
Normal 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'
|
||||
```
|
|
@ -0,0 +1,2 @@
|
|||
# RPC calls with different behavior
|
||||
> TODO: compile RPC calls with different behavior after handlers are created.
|
9
books/architecture/src/rpc/differences/rpc-payment.md
Normal file
9
books/architecture/src/rpc/differences/rpc-payment.md
Normal 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>.
|
|
@ -0,0 +1,2 @@
|
|||
# Unsupported RPC calls
|
||||
> TODO: compile unsupported RPC calls after handlers are created.
|
|
@ -1 +0,0 @@
|
|||
# ⚪️ Handler
|
2
books/architecture/src/rpc/handler/intro.md
Normal file
2
books/architecture/src/rpc/handler/intro.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# The handler
|
||||
> TODO: fill after `cuprate-rpc-handler` is created.
|
|
@ -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.
|
|
@ -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 |
|
10
books/architecture/src/rpc/json-rpc.md
Normal file
10
books/architecture/src/rpc/json-rpc.md
Normal 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.
|
|
@ -1 +0,0 @@
|
|||
# ⚪️ Methods
|
|
@ -1 +0,0 @@
|
|||
# ⚪️ Router
|
2
books/architecture/src/rpc/server/intro.md
Normal file
2
books/architecture/src/rpc/server/intro.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# 🔴 The server
|
||||
> TODO: fill after `cuprate-rpc-server` or binary impl is created.
|
39
books/architecture/src/rpc/types/base-types.md
Normal file
39
books/architecture/src/rpc/types/base-types.md
Normal 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).
|
|
@ -1 +0,0 @@
|
|||
# ⚪️ Binary
|
38
books/architecture/src/rpc/types/deserialization.md
Normal file
38
books/architecture/src/rpc/types/deserialization.md
Normal 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>
|
|
@ -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`
|
||||
}
|
||||
```
|
|
@ -1 +0,0 @@
|
|||
# ⚪️ JSON
|
16
books/architecture/src/rpc/types/macro.md
Normal file
16
books/architecture/src/rpc/types/macro.md
Normal 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.
|
13
books/architecture/src/rpc/types/metadata.md
Normal file
13
books/architecture/src/rpc/types/metadata.md
Normal 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.
|
11
books/architecture/src/rpc/types/misc-types.md
Normal file
11
books/architecture/src/rpc/types/misc-types.md
Normal 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.
|
|
@ -1 +0,0 @@
|
|||
# ⚪️ Other
|
Loading…
Reference in a new issue