EIP-1767: GraphQL interface to Ethereum node data
Abstract
This EIP specifies a GraphQL schema for accessing data stored on an Ethereum node. It aims to provide a complete replacement to the read-only information exposed via the present JSON-RPC interface, while improving on usability, consistency, efficiency, and future-proofing.
Motivation
The current JSON-RPC interface for Ethereum nodes has a number of shortcomings. It's informally and incompletely specified in areas, which has led to incompatibilities around issues such as representation of empty byte strings ("" vs "0x" vs "0x0"), and it has to make educated guesses about the data a user will request, which often leads to unnecessary work.
For example, the totalDifficulty
field is stored separately from the block header in common Ethereum node implementations, and many callers do not require this field. However, every call to eth_getBlock
still retrieves this field, requiring a separate disk read, because the RPC server has no way of knowing if the user requires this field or not.
Similarly, transaction receipts in go-ethereum are stored on disk as a single binary blob for each block. Fetching a receipt for a single transaction requires fetching and deserializing this blob, then finding the relevant entry and returning it; this is accomplished by the eth_getTransactionReceipt
API call. A common task for API consumers is to fetch all the receipts in a block; as a result, node implementations end up fetching and deserializing the same data repeatedly, leading to O(n^2)
effort to fetch all transaction receipts from a block instead of O(n)
.
Some of these issues could be fixed with changes to the existing JSON-RPC interface, at the cost of complicating the interface somewhat. Instead, we propose adopting a standard query language, GraphQL, which facilitates more efficient API implementations, while also increasing flexibility.
Prior Art
Nick Johnson and EthQL independently developed a GraphQL schema for node data. Once the parties were made aware of the shared effort, they made efforts to bring their schemas into alignment. The current schema proposed in this EIP is derived primarily from the EthQL schema.
Specification
Node API
Compatible nodes MUST provide a GraphQL endpoint available over HTTP. This SHOULD be offered on port 8547 by default. The path to the GraphQL endpoint SHOULD be '/graphql'.
Compatible nodes MAY offer a GraphiQL interactive query explorer on the root path ('/').
Schema
The GraphQL schema for this service is defined as follows:
Nodes MAY offer a superset of this schema, by adding new fields or types. Experimental or client-specific fields MUST be prefixed with 'client' (eg, 'geth' or 'parity'). Unprefixed fields MUST be specified in a new EIP that extends this one.
Rationale
Ethereum nodes have been moving away from providing read-write functionality such as transaction and message signing, and from other services such as code compilation, in favor of a more 'unix-like' approach where each task is performed by a dedicated process. We have thus specified a core set of types and fields that reflects this trend, leaving out functionality that is presently, or intended to be, deprecated:
eth_compile*
calls are deprecated, and hence not provided here.eth_accounts
,eth_sign
, andeth_sendTransaction
are considered by many to be deprecated, and are not provided here; callers should use local accounts or a separate signing daemon instead.
Further, two areas of the current API interface have been omitted for simplicity in this initial standard, with the intention that they will be defined in a later EIP:
- Filters will require use of GraphQL subscriptions, and require careful consideration around the desire for nodes without local per-caller state.
- Mining functionality is less-used and benefits less from reimplementation in GraphQL, and should be specified in a separate EIP.
Backwards Compatibility
This schema implements the bulk of the current read-only functionality provided by the JSON-RPC node interface. Existing RPC calls can be mapped to GraphQL queries as follows:
RPC | Status | Description |
---|---|---|
eth_blockNumber | IMPLEMENTED | { block { number } } |
eth_call | IMPLEMENTED | { call(data: { to: "0x...", data: "0x..." }) { data status gasUsed } } |
eth_estimateGas | IMPLEMENTED | { estimateGas(data: { to: "0x...", data: "0x..." }) } |
eth_gasPrice | IMPLEMENTED | { gasPrice } |
eth_getBalance | IMPLEMENTED | { account(address: "0x...") { balance } } |
eth_getBlockByHash | IMPLEMENTED | { block(hash: "0x...") { ... } } |
eth_getBlockByNumber | IMPLEMENTED | { block(number: 123) { ... } } |
eth_getBlockTransactionCountByHash | IMPLEMENTED | { block(hash: "0x...") { transactionCount } } |
eth_getBlockTransactionCountByNumber | IMPLEMENTED | { block(number: x) { transactionCounnt } } |
eth_getCode | IMPLEMENTED | { account(address: "0x...") { code } } |
eth_getLogs | IMPLEMENTED | { logs(filter: { ... }) { ... } } or { block(...) { logs(filter: { ... }) { ... } } } |
eth_getStorageAt | IMPLEMENTED | { account(address: "0x...") { storage(slot: "0x...") } } |
eth_getTransactionByBlockHashAndIndex | IMPLEMENTED | { block(hash: "0x...") { transactionAt(index: x) { ... } } } |
eth_getTransactionByBlockNumberAndIndex | IMPLEMENTED | { block(number: n) { transactionAt(index: x) { ... } } } |
eth_getTransactionByHash | IMPLEMENTED | { transaction(hash: "0x...") { ... } } |
eth_getTransactionCount | IMPLEMENTED | { account(address: "0x...") { transactionCount } } |
eth_getTransactionReceipt | IMPLEMENTED | { transaction(hash: "0x...") { ... } } |
eth_getUncleByBlockHashAndIndex | IMPLEMENTED | { block(hash: "0x...") { ommerAt(index: x) { ... } } } |
eth_getUncleByBlockNumberAndIndex | IMPLEMENTED | { block(number: n) { ommerAt(index: x) { ... } } } |
eth_getUncleCountByBlockHash | IMPLEMENTED | { block(hash: "0x...") { ommerCount } } |
eth_getUncleCountByBlockNumber | IMPLEMENTED | { block(number: x) { ommerCount } } |
eth_protocolVersion | IMPLEMENTED | { protocolVersion } |
eth_sendRawTransaction | IMPLEMENTED | mutation { sendRawTransaction(data: data) } |
eth_syncing | IMPLEMENTED | { syncing { ... } } |
eth_getCompilers | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. |
eth_compileLLL | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. |
eth_compileSolidity | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. |
eth_compileSerpent | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. |
eth_newFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
eth_newBlockFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
eth_newPendingTransactionFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
eth_uninstallFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
eth_getFilterChanges | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
eth_getFilterLogs | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. |
eth_accounts | NOT IMPLEMENTED | Accounts functionality is not part of the core node API. |
eth_sign | NOT IMPLEMENTED | Accounts functionality is not part of the core node API. |
eth_sendTransaction | NOT IMPLEMENTED | Accounts functionality is not part of the core node API. |
eth_coinbase | NOT IMPLEMENTED | Mining functionality to be defined separately. |
eth_getWork | NOT IMPLEMENTED | Mining functionality to be defined separately. |
eth_hashRate | NOT IMPLEMENTED | Mining functionality to be defined separately. |
eth_mining | NOT IMPLEMENTED | Mining functionality to be defined separately. |
eth_submitHashrate | NOT IMPLEMENTED | Mining functionality to be defined separately. |
eth_submitWork | NOT IMPLEMENTED | Mining functionality to be defined separately. |
For specific reasoning behind omitted functionality, see the Rationale section.
Test Cases
TBD.
Implementation
- Implemented and released in Go-ethereum 1.9.0
- Implemented and released in Pantheon 1.1.1
- Work in progress in Trinity
- Work in progress in Parity
Copyright
Copyright and related rights waived via CC0.