EIP: Remote procedure call specification

I think adding status to the top-level result is a little too far outside the bounds of the JSONRPC 2.0 spec:

https://www.jsonrpc.org/specification#response_object

While the spec doesn’t expressly forbid adding new top-level fields, it doesn’t allow it either, and most JSONRPC parsers would at best ignore the status field and at possibly throw an error.

So, I think any solution to the problem needs to be JSONRPC 2.0 compliant. Parity’s “reverted” format is in-spec, but could be tweaked slightly to make it easier to parse:

{
  "jsonrpc": "2.0",
  "id": 16,
  "error": {
    "code": -32015,
    "data": {
       "result": "0x",  // is the 0x08c379a... data useful? if so include it
       "status": "reverted",
    },
    "message": "VM execution error: transaction reverted"
  }
}

Alternatively, as you said, if reverting isn’t an error, the only real option is to make the eth_call result an object instead of a single string, but that will be a breaking change for many web3 libraries.

In hindsight, the result field for all RPCs should always be a complex object, so that fields can be added easily in the future. Perhaps that should be an EIP requirement for new methods going forward, but I think is too onerous to back port to the existing methods.

1 Like

copying from the PR description:

Note: There doesn’t appear to be any RPC-friendly API documentation standard, otherwise I’d be open to using that over markdown. Still, this EIP is meant to provide a human-readable RPC specification and isn’t necessarily meant to be program-readable or to drive other documentation tooling (though the markdown itself could drive tooling if desired).

My expectation is that if the RPC specification is only human readable, then it will quickly become outdated just like the current wiki. A human-readable spec relies on volunteers (client developers and users) to update the documentation, which is a laborious burden that people tend to grow tired of.

As a solution, I proposed a machine-readable spec (https://github.com/ethereum/EIPs/issues/217), and kickstarted the effort with a multi-client testrunner and proof-of-concept compatibility table: http://cdetrio.github.io/eth-compat-table

It was recently dusted off and run again on the the latest clients: https://github.com/karalabe/hive/issues/119

Here’s a screenshot of the table:

It only has the JSON schema specs for a handful of rpc methods, so the main remaining todo is to add the rest. Additionally, I was planning to the description field in the json schema to auto-generate the wiki documentation. This way we would not be relying on volunteers to keep the documentation up to date. Rather, the testrunner automatically checks which clients are compatible with the spec, and the human-readable documentation is generated from the spec.

7 Likes

I totally support the idea that the spec should be machine readable. The human readable spec should be an output of the machine readable spec. The test results could be added to the human-readable machine-generated documentation.

I think this is a fine suggestion. Backporting or supporting older callers is possible but likely to be an extreme pain and disruption.

Here is a real example of where the inconsistencies causes errors in projects like Metamask. Inconsistencies in these error cases cause wild and unexpected behaviours.

"status": "reverted" I don’t particularly want to bikeshed on this but usually this is a hex value no?

eth_call is a simple way to validate a transaction has a chance of success before sending. So defining the failure case and standardising will help projects a lot.

Any thoughts on what to do about things in the ecosystem which hijack certain JSONRPC requests. For example, Metamask handles eth_sign but forwards all data fetching, though the responses can be different when going through Metamask versus a client directly.

Is it easy to add additional less conventional “clients” to this test suite?

As I have argued in the past, signers and clients should be separated! There is “the thing that signs stuff” and there is "the thing that sends/receives data from the blockchain. It is most unfortunate that the early Ethereum clients combined these two functionalities into the same API rather than keeping them as separate APIs.

I would love it if we could split the current API into two separate APIs, one for signing and one for fetching/submitting data from/to the blockchain. Some tools would fulfill both APIs, but having them separate would allow you to mix and match as appropriate.

Agree and we can definitely see the carving up of responsibilities, its just at the library level right now. We do this in 0x.js and we encourage all developers to do this (via our developer docs and samples). Mix and match Ledger/Trezor/MM/Generic with a general JSONRPC data provider.

At the very least I think we can section them off and call it out in the JSONRPC spec/wiki. Do you have thoughts on what this would ultimately look like? I imagine their specs should follow similar behaviour (in terms of errors and layout of results).

I haven’t thought super deep on the implementation details. In general, anything that requires a private key to complete should be part of the signer API and antsything that requires chain interaction would be part of the other API.

This does get murky when you want to do things like verifiable signing UIs, because the signer needs chain access. In such cases I would argue that should be part of the signing API, as the signer can gracefully degrade if it doesn’t have chain access.

we have been working on a solution that is now at 1.0.0, it is akin to openapi but specifically designed for JSON-RPC.

here is the EIP PR

love to get some feedback and see how we can work to standardize JSON RPC descriptions.

3 Likes

@bitpshr How would one go about updating this specification? E.g. https://github.com/ethereum/EIPs/pull/1898. Just submit a PR modifying eip-1474.md?

@charles-cooper: That works for me. If you tag me in a PR, I’ll be sure to review it. I’m also open to adding an additional EIP maintainer to 1474 so I’m not the sole reviewer and don’t be come bottleneck.

I posted something similar to this in the EIP PR for discussion on OpenRPC, but can these OpenRPC documents be composed? i.e. if we had a standard set of documents “these OpenRPC files represent the standard eth_* RPCs for 1.0” can I then publish a document on my node that includes the standard RPCs and includes my server specific endpoint name?

My reason for asking is that a spec for this should not consist of “please use OpenRPC” but instead it should be “here are the standard OpenRPC mappings for EIP X, EIP Y, and EIP Z, they live at URLs A, B, and C, and here is a sample of MultiGeth composing those into one endpoint.” Otherwise this EIP is noting more than “OpenRPC is cool, please use it.”

1 Like

Yes! Excellently phrased. Same goes for GraphQL and anything else.

@bitpshr want to take another crack at making a separate JSON-RPC repo? I don’t have time to lead this process, but much like devp2p now has a separate repo to gather interested parties I think this would be valuable.

This one is basically empty and can be ready to go: https://github.com/spadebuilders/ethereum-json-rpc-spec

But obviously any home base repo for the spec & related standards/implementations would work.

@shemnon I’ve added the entire openrpc.json for #1474 + #1436 and eth_getRawTransaciton* methods to the Pull Request here: https://raw.githubusercontent.com/ethereum/EIPs/dbf64faff4dfe2f832d752292a39b8d7b9b46d2a/assets/eip-1901/openrpc.json

And to answer the question around composition, yes its possible, having relative paths is a bit of an edge case, but see my comment here: https://github.com/ethereum/EIPs/issues/1902#issuecomment-488075648

I think that having 1 canonical EIP that contains ALL the methods will help get everyone on the same page, rather than breaking it out to separate files. The same way the #1474 gets updated. Any client can easily extend it.

1 Like

My concern with one canonical EIP is then clients that do not implement all the endpoints will need to edit the canonical file to remove them, and if clients are chopping up canonical files their value is diminished.

As an example Pantheon does not implement eth_send* and eth_sign* methods because we do not integrate a key management system for wallet keys in the node (this is a deliberate security decision).

2 Likes

I like the idea of just removing eth_send* and eth_sign* (except send raw) from the specification altogether. I’d rather users not be able to keep their funds in clients either.

1 Like

Took the time to put this repo together let me know what you think: https://github.com/etclabscore/ethereum-json-rpc-specification

Hopefully this addresses the comments above.

2 Likes

EIP-1767 (the GraphQL EIP) also didn’t implement the send and sign transactions as a non-essential call for nodes. There appears to be some consensus on that. A second file with those APIs may be useful to clients who do implement it.

2 Likes

eth_signTypedData says that the second parameter’s type is Data but it is not, it is a complex object.

Here is the talk from EDCON 2019 on OpenRPC and how we can level up the ecosystems tooling: