Alert Source Discuss
🚧 Stagnant Standards Track: Interface

EIP-758: 已完成交易的订阅和过滤器

Authors Jack Peterson <jack@tinybike.net>
Created 2017-11-09
Requires EIP-1474

简单总结

提供一种方式让外部调用者能够收到已完成交易的通知,并访问交易被挖掘时执行的函数的返回数据。

摘要

当一个新的交易成功提交给以太坊节点时,节点会返回交易的哈希值。如果交易涉及到执行一个返回数据的合约函数,那么这些数据会被丢弃。如果返回数据是依赖于状态的(这种情况很常见),那么调用者就没有直接的方法来访问或计算返回数据。本 EIP 提议,调用者应该能够订阅(或轮询)已完成的交易。当交易被确认时,以太坊节点会将返回数据发送给调用者。

动机

如果函数是通过 eth_sendTransactioneth_sendRawTransaction RPC 请求执行的,那么外部调用者目前无法访问来自以太坊的返回数据。在许多情况下,访问函数返回数据是一个理想的功能。使外部调用者能够访问返回数据,也解决了内部调用者(可以在交易上下文中访问返回数据)和外部调用者(不能访问返回数据)之间的不一致性。目前,一种常见的解决方法是记录返回数据,但这有几个缺点:它会导致链的膨胀,给调用者带来额外的 gas 成本,并且如果外部调用的函数涉及到其他(内部)函数调用,这些函数也会记录它们的返回数据,那么可能会导致写入未使用的日志。在实现此 EIP 的原始版本时,决定稍微扩展此功能,以便在没有返回数据的情况下,外部调用者也能收到其已完成交易的通知。这可能是因为调用的方法没有返回值,或者因为交易只是简单的价值转移。

规范

订阅

想要在交易完成时收到通知的调用者,会发送一个 eth_subscribe RPC 请求,其中第一个参数是 "completedTransaction"

{"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["completedTransaction", filter]}

filter 参数是一个字典,包含 3 个可选的命名参数:fromtohasReturnDatafromto 可以是单个地址,也可以是地址列表。它们用于过滤掉任何不是从 from 列表中的地址发送,并且不是发送到 to 列表中的地址的交易。hasReturnData 是一个布尔值——如果指定为 true,则仅接收包含 returnData 的已完成交易的通知。

例如,要将结果限制为源自以下两个地址之一(0x3f7d39bDBf1f5cE649c194571aEd3D2BbB2F85ce 或 0x7097f41F1C1847D52407C629d0E0ae0fDD24fd58)的合约创建:

filter = { "from" : ["0x3f7d39bDBf1f5cE649c194571aEd3D2BbB2F85ce",
                      "0x7097f41F1C1847D52407C629d0E0ae0fDD24fd58"],
           "to" : "0x0" 
         }

要将结果限制为合约地址 0xD9Cb531aB97A652c8fC60dcF6D263fcA2F5764e9 上的方法调用:

filter = { "to" : "0xD9Cb531aB97A652c8fC60dcF6D263fcA2F5764e9", "hasReturnData" : true }

或者,要在 rpc 客户端提交的任何交易完成时收到通知,而不做进一步的限制:

filter = {}

收到请求后,以太坊节点会返回一个订阅 ID:

{"jsonrpc": "2.0", "id": 1, "result": "0x00000000000000000000000000000b0b"}

假设调用者随后通过 eth_sendTransactioneth_sendRawTransaction RPC 请求提交了一个交易,该交易的哈希值为 "0x00000000000000000000000000000000000000000000000000000000deadbeef"。当交易被确认(挖掘)时,以太坊节点会向调用者推送一个通知。如果交易是对合约的方法调用,这将包括被调用函数的返回值(例如 "0x000000000000000000000000000000000000000000000000000000000000002a"):

{
  "jsonrpc": "2.0",
  "method": "eth_subscription",
  "params": {
    "result": {
      "transactionHash": "0x00000000000000000000000000000000000000000000000000000000deadbeef",
      "returnData": "0x000000000000000000000000000000000000000000000000000000000000002a"
    },
    "subscription": "0x00000000000000000000000000000b0b"
  }
}

调用者在两种情况下会收到关于其交易的通知:首先是当交易被确认时,以及如果交易受到链重组的影响时(带有额外的 "removed": true 字段)。对于从客户端提交的,并且在订阅之后被确认的所有交易,都会向客户端发送通知。如果指定了 fromtohasReturnData,那么只有符合筛选标准的交易才会生成通知。与其他订阅一样,调用者可以发送 eth_unsubscribe RPC 请求来停止接收推送通知:

{"jsonrpc": "2.0", "id": 2, "method": "eth_unsubscribe", "params": ["0x00000000000000000000000000000b0b"]}

轮询

推送通知需要全双工连接(即,websocket 或 IPC)。使用 HTTP 的调用者可以发送一个 eth_newCompletedTransactionFilter 请求,而不是订阅:

{"jsonrpc": "2.0", "id": 1, "method": "eth_newCompletedTransactionFilter", "params": [filter] }

以太坊节点会返回一个过滤器 ID:

{"jsonrpc": "2.0", "id": 1, "result": "0x1"}

当一个交易被提交时,以太坊节点会将交易通知(包括返回值)推送到一个队列中,当调用者使用 eth_getFilterChanges 进行轮询时,该队列会被清空:

{"jsonrpc": "2.0", "id": 2, "method": "eth_getFilterChanges", "params": ["0x1"]}

节点会返回一个交易哈希及其对应返回数据组成的数组,按照计算的顺序排列:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": [{
    "transactionHash": "0x00000000000000000000000000000000000000000000000000000000deadbeef",
    "returnData": "0x000000000000000000000000000000000000000000000000000000000000002a"
  }]
}

所有在初始 eth_newCompletedTransactionFilter 请求之后 被确认的交易都包含在这个数组中。同样,如果 filter 参数是一个非空字典(包含 fromtohasReturnData 中的任何一个),那么只有符合筛选标准的交易才会生成通知。请注意,在轮询的情况下,以太坊节点无法确定提交交易的 RPC 客户端与创建过滤器的客户端是否相同,因此没有基于交易提交位置的限制。

原理

EIP-658 最初提议将返回数据添加到交易回执中。然而,返回数据是不收费的(因为它没有存储在区块链上),所以将其添加到交易回执中可能会导致 DoS 和垃圾邮件的机会。相反,一个简单的布尔值 status 字段被添加到交易回执中。这个修改后的 EIP 658 版本包含在拜占庭硬分叉中。虽然 status 字段很有用,但应用程序通常也需要返回数据。

使用此处概述的策略的主要优势是效率:不需要在区块链上存储额外的数据,并且对节点施加的额外计算负载最小。虽然不支持事后查找返回值,但这与返回数据的传统使用方式一致,即只有在函数返回时,调用者才能访问返回数据,并且不会存储以供以后使用。

版权

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

Citation

Please cite this document as:

Jack Peterson <jack@tinybike.net>, "EIP-758: 已完成交易的订阅和过滤器 [DRAFT]," Ethereum Improvement Proposals, no. 758, November 2017. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-758.