Alert Source Discuss
Standards Track: Interface

EIP-1898: 向 defaultBlock 方法添加 `blockHash`

向当前支持 defaultBlock 参数的 JSON-RPC 方法添加 `blockHash` 选项。

Authors Charles Cooper (@charles-cooper)
Created 2019-04-01
Requires EIP-234

摘要

对于当前接受默认区块参数的 JSON-RPC 方法,额外允许该参数为一个区块哈希。

此 EIP 可以被认为是 EIP-234 的泛化。它将使客户端能够明确指定他们想要查询的特定 JSON-RPC 方法的区块,即使该区块不在规范链中。这允许客户端维护他们感兴趣的区块链状态的连贯视图,即使在存在重组的情况下,也无需节点维护与客户端的持久连接或存储任何客户端特定的状态。

规范

以下 JSON-RPC 方法受到影响:

  • eth_getBalance
  • eth_getStorageAt
  • eth_getTransactionCount
  • eth_getCode
  • eth_call
  • eth_getProof

以下选项(引自 Ethereum JSON-RPC 规范)目前可用于 defaultBlock 参数:

  • HEX String - 一个整数区块号
  • String “earliest” - 用于最早/创世区块
  • String “latest” - 用于最新的规范区块
  • String “pending” - 用于待处理状态/交易
  • String “safe” - 用于最新的安全区块
  • String “finalized” - 用于最新的最终确定区块

由于没有办法清楚地区分 DATA 参数和 QUANTITY 参数,因此本 EIP 提出了一种新的区块参数方案。另外允许以下选项:

  • OBJECT
    • blockNumber: QUANTITY - 一个区块号
    • blockHash: DATA - 一个区块哈希

如果未找到该区块,则被调用者应引发 JSON-RPC 错误(建议的错误代码为 -32001: Resource not found)。

如果标签是 blockHash,则可以向区块参数提供一个额外的布尔字段 requireCanonical,其默认为 false,并定义根据被调用者,该区块是否必须是规范区块。如果 requireCanonicalfalse,则仅当未找到该区块时,被调用者才应引发 JSON-RPC 错误(如上所述)。如果 requireCanonicaltrue,则如果该区块不在规范链中,被调用者还应引发 JSON-RPC 错误(建议的错误代码为 -32000: Invalid input,并且在任何情况下都应与未找到区块的情况的错误代码不同,以便调用者可以区分这些情况)。未找到区块的检查应优先于区块是否规范的检查,因此如果未找到区块,则被调用者应引发未找到区块的错误,而不是区块不规范的错误。

为了保持向后兼容性,区块号可以指定为十六进制字符串或使用新的区块参数方案。换句话说,对于默认区块参数,以下是等效的:

  • "earliest"
  • "0x0"
  • { "blockNumber": "0x0" }
  • { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" } (以太坊主链上创世区块的哈希)
  • { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": true }
  • { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": false }

理由

目前,上述状态查询 JSON-RPC 方法没有明确指定要查询哪个区块的状态的选项。这可能会给需要多次调用 RPC 的应用程序带来问题。例如,刚刚执行了转账的钱包可能想要显示发送者和接收者的余额。如果在通过 eth_getBalance 查询发送者的余额和查询接收者的余额之间存在重组,则余额可能无法协调。作为一个稍微复杂一点的例子,去中心化交易所的 UI(在链上托管订单)可以通过为每个订单调用 eth_call 来获取订单数据,从而遍历订单列表。另一种用例是应用程序需要根据多个状态来做出决策,例如基于同时拥有两个 NFT 的支付。

为了确保状态是连贯的(即,对于每次调用,eth_call 都使用完全相同的区块调用),应用程序目前可以使用以下几种策略之一:

  • 决定要使用的区块号(例如,应用程序已知的最新区块号)。在使用该区块号的每个 eth_call 之后,也使用该区块号调用 eth_getBlockByNumber。如果区块哈希与该区块号的已知哈希不匹配,则回滚当前活动并从头开始重试。这增加了 O(n) 次调用作为基线开销,并为每次需要的重试增加了另一次 O(n) 次调用。此外,无法检测到相关区块在 eth_call 之前被重组出去,然后在 eth_getBlockByNumber 之前被重组回来的(不太可能但可能发生的)情况。
  • 依赖于日志,由于 blockHash 参数,日志 可以 被明确查询。但是,这需要智能合约的语义支持;如果智能合约不发出适当的事件,客户端将无法重构其感兴趣的特定状态。
  • 依赖于非标准扩展,如 parity_subscribe。这需要在客户端和节点之间建立持久连接(通过 IPC 或 websockets),增加了客户端和节点之间的耦合,并且无法处理 eth_call 调用之间存在依赖关系的用例,例如,遍历链表。

允许 eth_call 及其友元明确指定要查询的区块,为应用程序开发人员提供了一种强大而直观的方式来解决这些问题。多个连续查询将查询相同的状态,使应用程序开发人员不必担心其区块链状态视图中的不一致性。

向后兼容性

向后兼容。

测试用例

  • eth_getStorageAt [ "0x<address>", { "blockNumber": "0x0" } -> 返回创世区块中给定地址的存储
  • eth_getStorageAt [ "0x<address>", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" } -> 返回创世区块中给定地址的存储
  • eth_getStorageAt [ "0x<address>", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": false } -> 返回创世区块中给定地址的存储
  • eth_getStorageAt [ "0x<address>", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": true } -> 返回创世区块中给定地址的存储
  • eth_getStorageAt [ "0x<address>", { "blockHash": "0x<non-existent-block-hash>" } -> 引发 block-not-found 错误
  • eth_getStorageAt [ "0x<address>", { "blockHash": "0x<non-existent-block-hash>", "requireCanonical": false } -> 引发 block-not-found 错误
  • eth_getStorageAt [ "0x<address>", { "blockHash": "0x<non-existent-block-hash>", "requireCanonical": true } -> 引发 block-not-found 错误
  • eth_getStorageAt [ "0x<address>", { "blockHash": "0x<non-canonical-block-hash>" } -> 返回指定区块中给定地址的存储
  • eth_getStorageAt [ "0x<address>", { "blockHash": "0x<non-canonical-block-hash>", "requireCanonical": false } -> 返回指定区块中给定地址的存储
  • eth_getStorageAt [ "0x<address>", { "blockHash": "0x<non-canonical-block-hash>", "requireCanonical": true } -> 引发 block-not-canonical 错误

安全考虑

版权

通过 CC0 放弃版权及相关权利。

Citation

Please cite this document as:

Charles Cooper (@charles-cooper), "EIP-1898: 向 defaultBlock 方法添加 `blockHash`," Ethereum Improvement Proposals, no. 1898, April 2019. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1898.