ERC-5139: Remote Procedure Call Provider Lists

Format for lists of RPC providers for Ethereum-like chains.


Metadata
Status: StagnantStandards Track: ERCCreated: 2022-06-06
Authors
Sam Wilson (@SamWilsn)
Requires

Abstract


This proposal specifies a JSON schema for describing lists of remote procedure call (RPC) providers for Ethereum-like chains, including their supported EIP-155 CHAIN_ID.

Motivation


The recent explosion of alternate chains, scaling solutions, and other mostly Ethereum-compatible ledgers has brought with it many risks for users. It has become commonplace to blindly add new RPC providers using EIP-3085 without evaluating their trustworthiness. At best, these RPC providers may be accurate, but track requests; and at worst, they may provide misleading information and frontrun transactions.

If users instead are provided with a comprehensive provider list built directly by their wallet, with the option of switching to whatever list they so choose, the risk of these malicious providers is mitigated significantly, without sacrificing functionality for advanced users.

Specification


The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

List Validation & Schema

List consumers (like wallets) MUST validate lists against the provided schema. List consumers MUST NOT connect to RPC providers present only in an invalid list.

Lists MUST conform to the following JSON Schema:


For illustrative purposes, the following is an example list following the schema:


Versioning

List versioning MUST follow the Semantic Versioning 2.0.0 (SemVer) specification.

The major version MUST be incremented for the following modifications:

  • Removing a provider.
  • Changing a provider's key in the providers object.
  • Removing the last ProviderChain for a chain id.

The major version MAY be incremented for other modifications, as permitted by SemVer.

If the major version is not incremented, the minor version MUST be incremented if any of the following modifications are made:

  • Adding a provider.
  • Adding the first ProviderChain of a chain id.

The minor version MAY be incremented for other modifications, as permitted by SemVer.

If the major and minor versions are unchanged, the patch version MUST be incremented for any change.

Publishing

Provider lists SHOULD be published to an Ethereum Name Service (ENS) name using EIP-1577's contenthash mechanism on mainnet.

Provider lists MAY instead be published using HTTPS. Provider lists published in this way MUST allow reasonable access from other origins (generally by setting the header Access-Control-Allow-Origin: *.)

Priority

Provider entries MAY contain a priority field. A priority value of zero SHALL indicate the highest priority, with increasing priority values indicating decreasing priority. Multiple providers MAY be assigned the same priority. All providers without a priority field SHALL have equal priority. Providers without a priority field SHALL always have a lower priority than any provider with a priority field.

List consumers MAY use priority fields to choose when to connect to a provider, but MAY ignore it entirely. List consumers SHOULD explain to users how their implementation interprets priority.

List Subtypes

Provider lists are subdivided into two categories: root lists, and extension lists. A root list contains a list of providers, while an extension list contains a set of modifications to apply to another list.

Root Lists

A root list has a top-level providers key.

Extension Lists

An extension list has top-level extends and changes keys.

Specifying a Parent (extends)

The uri and ens fields SHALL point to a source for the parent list.

If present, the uri field MUST use a scheme specified in Publishing.

If present, the ens field MUST specify an ENS name to be resolved using EIP-1577.

The version field SHALL specify a range of compatible versions. List consumers MUST reject extension lists specifying an incompatible parent version.

In the event of an incompatible version, list consumers MAY continue to use a previously saved parent list, but list consumers choosing to do so MUST display a prominent warning that the provider list is out of date.

Default Mode

If the mode field is omitted, a parent version SHALL be compatible if and only if the parent's version number matches the left-most non-zero portion in the major, minor, patch grouping.

For example:


Is equivalent to:


And:


Is equivalent to:


Caret Mode (^)

The ^ mode SHALL behave exactly as the default mode above.

Exact Mode (=)

In = mode, a parent version SHALL be compatible if and only if the parent's version number exactly matches the specified version.

Specifying Changes (changes)

The changes field SHALL be a JavaScript Object Notation (JSON) Patch document as specified in RFC 6902.

JSON pointers within the changes field MUST be resolved relative to the providers field of the parent list. For example, see the following lists for a correctly formatted extension.

Root List

Extension List

Applying Extension Lists

List consumers MUST follow this algorithm to apply extension lists:

  1. Is the current list an extension list?
    • Yes:
      1. Ensure that this from has not been seen before.
      2. Retrieve the parent list.
      3. Verify that the parent list is valid according to the JSON schema.
      4. Ensure that the parent list is version compatible.
      5. Set the current list to the parent list and go to step 1.
    • No:
      1. Go to step 2.
  2. Copy the current list into a variable $output.
  3. Does the current list have a child:
    • Yes:
      1. Apply the child's changes to providers in $output.
      2. Verify that $output is valid according to the JSON schema.
      3. Set the current list to the child.
      4. Go to step 3.
    • No:
      1. Replace the current list's providers with providers from $output.
      2. The current list is now the resolved list; return it.

List consumers SHOULD limit the number of extension lists to a reasonable number.

Rationale


This specification has two layers (provider, then chain id) instead of a flatter structure so that wallets can choose to query multiple independent providers for the same query and compare the results.

Each provider may specify multiple endpoints to implement load balancing or redundancy.

List version identifiers conform to SemVer to roughly communicate the kinds of changes that each new version brings. If a new version adds functionality (eg. a new chain id), then users can expect the minor version to be incremented. Similarly, if the major version is not incremented, list subscribers can assume dapps that work in the current version will continue to work in the next one.

Security Considerations


Ultimately it is up to the end user to decide on what list to subscribe to. Most users will not change from the default list maintained by their wallet. Since wallets already have access to private keys, giving them additional control over RPC providers seems like a small increase in risk.

While list maintainers may be incentivized (possibly financially) to include or exclude particular providers, actually doing so may jeopardize the legitimacy of their lists. This standard facilitates swapping lists, so if such manipulation is revealed, users are free to swap to a new list with little effort.

If the list chosen by the user is published using EIP-1577, the list consumer has to have access to ENS in some way. This creates a paradox: how do you query Ethereum without an RPC provider? This paradox creates an attack vector: whatever method the list consumer uses to fetch the list can track the user, and even more seriously, can lie about the contents of the list.

Copyright


Copyright and related rights waived via CC0.