JSON-RPC

JSON-RPC 规范是一种基于OpenRPC的、使用 JSON 编码的远程过程调用协议。它允许在服务器上远程调用函数,并返回结果。

它是执行 API 规范的一部分,该规范提供了一套与以太坊区块链交互的方法。

更为人所熟知的是,该规范阐述了用户如何通过客户端与网络进行交互,以及共识层(CL)与执行层(EL)如何通过引擎 API 相互作用的方式。

本节将详细介绍 JSON-RPC 方法。

API 规范

JSON-RPC 方法按照指定为方法前缀的命名空间进行分组。尽管它们各有不同的用途,但所有方法都共享一个通用结构,并且在所有实现中必须表现出相同的行为:

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "<prefix_methodName>",
  "params": [...]
}

其中:

  • id: 请求的唯一标识符。
  • jsonrpc: JSON-RPC 协议的版本。
  • method: 将要调用的方法。
  • params: 方法的参数。如果该方法不需要任何参数,它可以是一个空数组。其他参数如果没有提供,可能会有默认值。

命名空间

每个方法由一个命名空间前缀和方法名称组成,二者之间用下划线分隔。

以太坊客户端必须实现规范所要求的基本 RPC 方法集,以便与区块链网络进行交互。此外,还有一些特定于客户端的方法,用于控制节点或实现额外的独特功能。请始终参阅客户端文档,查看可用的方法和命名空间。例如,请注意 GethReth 文档中不同命名空间的区别。

以下是一些常见命名空间的示例:

命名空间描述敏感性
etheth API 允许你与以太坊进行交互。可能
web3web3 API 为 web3 客户端提供实用功能。
netnet API 提供节点网络信息访问能力。
txpooltxpool API 允许你检查交易池。
debugdebug API 提供多种方法来检查以太坊状态,包括 Geth 风格的追踪。
tracetrace API 提供多种方法来检查以太坊状态,包括 Parity 风格的追踪。
adminadmin API 允许你配置自己的节点。
rpcrpc API 提供关于 RPC 服务器及其模块的信息。

“敏感性”意味着接口可以用来设置节点,比如 admin,或访问存储在节点中的账户数据,就像 eth 那样。

现在,让我们来看看一些方法,了解它们是如何构建的以及它们的作用:

Eth

Eth 可能是最常用的命名空间,它提供了对以太坊网络的基本访问,例如,钱包需要使用它来读取余额和创建交易。 这里只列出了一些方法,完整的列表可以在 Ethereum JSON-RPC specification 中找到。

方法参数描述
eth_blockNumber无必须参数returns the number of the most recent block
eth_calltransaction objectexecutes a new message call immediately without creating a transaction on the block chain
eth_chainId无必须参数returns the current chain id
eth_estimateGastransaction objectmakes a call or transaction, which won't be added to the blockchain and returns the used gas, which can be used for estimating the used gas
eth_gasPrice无必须参数returns the current price per gas in wei
eth_getBalanceaddress, block numberreturns the balance of the account of the given address
eth_getBlockByHashblock hash, full txsreturns information about a block by hash
eth_getBlockByNumberblock number, full txsreturns information about a block by block number
eth_getBlockTransactionCountByHashblock hashreturns the number of transactions in a block from a block matching the given block hash
eth_getBlockTransactionCountByNumberblock numberreturns the number of transactions in a block from a block matching the given block number
eth_getCodeaddress, block numberreturns code at a given address in the blockchain
eth_getLogsfilter objectreturns an array of all logs matching a given filter object
eth_getStorageAtaddress, position, block numberreturns the value from a storage position at a given address
方法参数描述
eth_blockNumber无必须参数返回最新区块的编号
eth_calltransaction object立即执行一个新的消息调用,不在区块链上创建交易
eth_chainId无必须参数返回当前链的 ID
eth_estimateGastransaction object执行一个调用或交易,不会添加到区块链上,并返回使用的 gas,可用于估算消耗的 gas
eth_gasPrice无必须参数返回当前每单位 gas 的价格,以 wei 为单位
eth_getBalanceaddress, block number返回给定地址的账户余额
eth_getBlockByHashblock hash, full txs通过区块哈希返回区块信息
eth_getBlockByNumberblock number, full txs通过区块编号返回区块信息
eth_getBlockTransactionCountByHashblock hash通过区块哈希返回指定区块的交易数量
eth_getBlockTransactionCountByNumberblock number通过区块编号返回指定区块的交易数量
eth_getCodeaddress, block number返回区块链中指定地址处的代码
eth_getLogsfilter object返回与给定过滤器对象匹配的所有日志的数组
eth_getStorageAtaddress, position, block number返回指定存储位置的值

Debug

debug 命名空间提供了一些方法来检查以太坊的状态。通过它可以直接访问原始数据,这对于某些用例(如区块浏览器或研究目的)可能是必需的。这些方法中的一些可能需要在节点上进行大量计算,而在非存档节点上请求历史状态通常是不可行的。因此,公共 RPC 的提供者通常会限制这个命名空间或只允许安全的方法。这些方法中有些可能需要在节点上进行大量的计算,而且在非存档节点上查询历史状态多数情况下是不可行的。因此,公共 RPC 的提供者通常对这一命名空间加以限制,或只允许使用安全的方法。

以下是调试方法的基本示例:

方法参数描述
debug_getBadBlocks无必须参数返回客户端最近看到的坏区块的数组
debug_getRawBlockblock_number返回一个 RLP 编码的区块
debug_getRawHeaderblock_number返回一个 RLP 编码的头
debug_getRawReceiptsblock_number返回一个 EIP-2718 二进制编码的收据数组
debug_getRawTransactionstx_hash返回一个 EIP-2718 二进制编码的交易数组

Engine

Engine API 与上述方法不同。客户端在一个不同的、经过认证的端点上提供 Engine API,而不是普通的 http JSON RPC,因为它不是面向用户的 API。它主要用于共识层与执行层客户端之间的连接,基本上是一个内部节点通信过程。客户端之间的通信涉及关于共识、分叉选择、区块验证等信息的交换:

方法参数描述
engine_exchangeTransitionConfigurationV1Consensus client config交换客户端配置
engine_forkchoiceUpdatedV1*forkchoice_state, payload attributes更新分叉选择状态
engine_getPayloadBodiesByHashV1*block_hash (array)给定区块哈希返回对应的执行负载体
engine_getPayloadV1*forkchoice_state, payload attributes从负载构建过程中获取执行负载
debug_newPayloadV1*tx_hash返回执行负载验证

那些标有星号(*)的方法具有多个版本,Ethereum JSON-RPC specification 提供了详细的描述。

编码

JSON-RPC 方法的参数编码遵循十六进制编码的约定。

  • 数量使用 "0x" 前缀表示为十六进制值。
    • 例如,数字 65 表示为 "0x41"。
    • 数字 0 表示为 "0x0"。
    • 一些无效的用法包括 "0x" 和 "ff"。前者没有后续数字,后者没有以 "0x" 前缀。
  • 未格式化的数据,如哈希值、账户地址或字节数组,也使用“0x”前缀进行十六进制编码。
    • 例如:0x400(十进制中为 1014)
    • 一个无效的例子是 0x400,因为不允许前导零。

传输协议无关

值得一提的是,JSON-RPC 是传输协议无关的,这意味着它可以使用任何传输协议,如 HTTP、WebSockets (WSS),甚至进程间通信 (IPC)。传输协议之间的差异总结如下:

  • HTTP 传输提供单向的响应-请求模型,发送响应后连接会被关闭。
  • WSS 是双向协议,这意味着连接会一直保持,直到节点或用户显式关闭。支持基于订阅的模型通信,如事件驱动交互。
  • IPC 传输协议用于同一台机器上运行的进程之间的通信。它比 HTTP 和 WSS 更快,但不适合远程通信,例如,可以通过本地 JS 控制台使用。

工具使用

有多种方法可以使用 JSON-RPC 方法。其中一种是使用 curl 命令。例如,要获取最新的区块编号,可以使用以下命令:

curl <node-endpoint> \
-X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

请注意,params 字段为空,因为方法默认传递 "latest" 作为值。

另一种方法是使用 Javascript/TypeScript 中的 axios 库。例如,要获取地址余额,可以使用以下代码:

import axios from "axios";

const node = "<node-endpoint>";
const address = "<address>";

const response = await axios.post(node, {
  jsonrpc: "2.0",
  method: "eth_getBalance",
  params: [address, "latest"],
  id: 1,
  headers: {
    "Content-Type": "application/json",
  },
});

如你所见,JSON-RPC 方法在 POST 请求中,参数在请求体中传递。 这是客户端和服务器之间使用 OSI 的应用层协议(HTTP 协议)交换数据的一种不同方式。

无论哪种方式,与以太坊网络交互的最常见方法是使用 web3 库,例如 web3py 用于 python 或 web3.js/ethers.js 用于 JS/TS:

web3py

from web3 import Web3

# Set up HTTPProvider
w3 = Web3(Web3.HTTPProvider('http://localhost:8545'))

# API
w3.eth.get_balance('0xaddress')

ethers.js

import { ethers } from "ethers";

const provider = new ethers.providers.JsonRpcProvider("http://localhost:8545");

await provider.getBlockNumber();

通常,所有的 web3 库都会封装 JSON-RPC 方法,提供一种更友好的方式与执行层进行交互。可以根据偏好的编程语言查看相关信息,因为不同语言的语法可能会有所不同。

进一步阅读