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".

monerod allows jsonrpc to:

  • Be any string
  • Be an empty array
  • Be null
  • Not exist at all

Examples:

curl \
	http://127.0.0.1:18081/json_rpc \
	-d '{"jsonrpc":"???","method":"get_block_count"}' \
	-H 'Content-Type: application/json'
curl \
	http://127.0.0.1:18081/json_rpc \
	-d '{"jsonrpc":[],"method":"get_block_count"}' \
	-H 'Content-Type: application/json'
curl \
	http://127.0.0.1:18081/json_rpc \
	-d '{"jsonrpc":null,"method":"get_block_count"}' \
	-H 'Content-Type: application/json'
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:

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:

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:

{
  "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:

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.

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:

{
  "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.

Example:

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:

curl \
	http://127.0.0.1:18081/json_rpc \
	-d '{"jsONrPc":"2.0","iD":0,"method":"get_block_count"}' \
	-H 'Content-Type: application/json'
Last change: 2024-09-08, commit: 0162553