EIP-2464: eth/65: 交易公布与检索
引入 `NewPooledTransactionHashes`、`GetPooledTransactions` 和 `PooledTransactions`。
Authors | Péter Szilágyi <peterke@gmail.com>, Péter Szilágyi (@karalabe), Gary Rong <garyrong0905@gmail.com>, Tim Beiko (@timbeiko) |
---|---|
Created | 2020-01-13 |
Requires | EIP-2364 |
摘要
本 EIP 在 eth
协议中引入了三个额外的消息类型(发布一个新版本 eth/65
):NewPooledTransactionHashes (0x08)
用于公布一组交易,但不包含其内容;GetPooledTransactions (0x09)
用于通过已公布的哈希请求一批交易;以及 PooledTransactions (0x0a)
用于回复交易请求。这允许将用于交易传播的带宽从与对等节点的数量成线性复杂度降低到平方根;并且还将初始交易交换从 10s-100s MB 降低到 len(pool) * 32B ~= 128KB
。
动机
eth
网络协议有两种传播新挖出的区块的方式:它可以完整地广播给一个对等节点(通过 eth/64
及之前的 NewBlock (0x07)
),或者可以只进行公布(通过 NewBlockHashes (0x01)
)。这种二元性允许节点对平方根数量的对等节点进行高带宽广播(10s-100s KB);并对剩余的线性数量的对等节点进行低带宽公布(10s-100s B)。平方根广播足以覆盖所有连接良好的节点,但线性公布对于穿透退化的拓扑结构是必要的。这运作良好。
然而,eth
协议没有类似的二元机制来传播交易,因此节点需要依赖广播(通过 Transactions (0x02)
)。为了适应退化的拓扑结构,交易不能以平方根的方式广播,而是需要线性地传输给所有对等节点。对于 N 个对等节点,每个节点会将相同的交易传输 N 次(包括两个方向),而在理想情况下 1 次就足够了。这是一个很大的浪费。
当两个节点之间建立新的网络连接时,也会出现类似的问题,因为它们需要同步它们的交易池,但该池只是一堆悬挂的交易。在没有远程去重交易的方法的情况下,每个节点都被迫天真地将其整个交易列表传输到另一端。由于池中包含数千个交易,因此天真的传输量达到 10s-100s MB,其中大部分是无用的。然而,没有更好的方法。
本 EIP 在 eth
协议中引入了三个额外的消息类型(发布一个新版本,eth/65
):NewPooledTransactionHashes (0x08)
用于公布一组交易,但不包含其内容;GetPooledTransactions (0x09)
用于通过已公布的哈希请求一批交易;以及 PooledTransactions (0x0a)
用于回复交易请求。这允许将用于交易传播的带宽从与对等节点的数量成线性复杂度降低到平方根;并且还将初始交易交换从 10s-100s MB 降低到 len(pool) * 32B ~= 128KB
。
随着以太坊中交易吞吐量(和大小)的增加,交易传播是当前使用的网络资源的主要组成部分。然而,这些资源中的大部分都被浪费了,因为 eth
协议没有一种远程去重交易的机制,因此相同的数据在所有网络连接上被重复传输。
本 EIP 提出了对 eth
协议的一个微小的扩展,该扩展允许节点在进行昂贵的交换之前,就需要在网络连接上传输的交易集合达成一致。这应有助于将以太坊网络的全局(运营)带宽使用量至少减少一个数量级。
规范
向 eth
协议添加三个新的消息类型:
NewPooledTransactionHashes (0x08): [hash_0: B_32, hash_1: B_32, ...]
- 指定一个或多个已出现在网络中且尚未包含在区块中的交易。为了提供最大的帮助,节点应将它们可能不知道的所有交易通知给对等节点。
- 节点可以向远程对等节点公布的哈希数量没有协议违反硬性上限(除了 10MB 的
devp2p
网络数据包限制),但 4096 似乎是一个合理的块大小(128KB),以避免单个数据包占用网络连接。 - 节点应仅公布远程对等节点可能合理地被认为不知道的交易的哈希,但最好是过度热情,而不是在池中出现 nonce 间隙。
GetPooledTransactions (0x09): [hash_0: B_32, hash_1: B_32, ...]
- 指定要从远程对等节点的交易池中检索的一个或多个交易。
- 节点可以从远程对等节点请求的交易数量没有协议违反硬性上限(除了 10MB 的
devp2p
网络数据包限制),但接收者可以对回复强制执行任意上限(大小或服务时间),这不能被视为协议违反。为了减少浪费的带宽(未响应的哈希),256 似乎是一个合理的上限。
PooledTransactions (0x0a): [[nonce: P, receivingAddress: B_20, value: P, ...], ...]
- 指定远程节点通过
GetPooledTransactions (0x09)
消息请求的来自本地交易池的交易。列表中的项目是主要以太坊规范中描述的格式的交易。 - 交易必须与请求中的顺序相同,但可以跳过不可用的交易。这样,如果达到响应大小限制,请求者将知道要再次请求哪些哈希(来自最后一个返回的交易的所有内容),以及假设哪些不可用(最后一个返回的交易之前的所有间隙)。
- 如果没有一个哈希与池中的交易匹配,则对等方可以响应一个空回复 iff。如果一个交易在中间被包含在一个区块中,则允许公布一个稍后将不会被提供的交易。
- 指定远程节点通过
理由
问:为什么限制 GetPooledTransactions (0x09)
仅从池中检索项目?
除了交易池之外,以太坊中的交易总是以数百个为单位捆绑在区块主体中,并且现有的网络检索也遵循这种数据布局。允许直接访问数据库中的单个交易没有可操作的用例,但会将代价高昂的数据库读取暴露到网络中。
对于交易传播的目的,没有理由允许磁盘访问,因为任何最终确定到磁盘的交易都将在区块内广播,因此最坏的情况是当节点获得交易时,会延迟几百毫秒。
仅按需传输包含的交易可能会使区块传播更加优化,但那本身就是一个 EIP,因此最好在所有要求都已知时再放宽协议,而不是提前放宽。可能足以在内存中维护一组包含在最近区块中的交易。
问:NewPooledTransactionHashes (0x08)
应该从磁盘中去重吗?
与 GetPooledTransactions (0x09)
类似,NewPooledTransactionHashes (0x08)
也应该仅在交易池上运行,并且应该完全忽略磁盘。在健康的网络状况下,一个交易的传播速度将比它包含在一个区块中的速度快得多,因此新公布的交易已经存在于磁盘上的情况基本上是不存在的。通过避免磁盘去重,我们可以避免远程交易公布造成的 DoS 攻击。
如果我们想非常正确地避免去重公布时出现哪怕是最轻微的数据竞争,我们可以使用上面讨论的相同的最近包含的交易技巧来丢弃最近已过期的公布。
问:为什么不重用 Transaction (0x02)
而不是新的 PooledTransactions (0x0a)
?
最初,这个 EIP 重用了现有的 Transaction (0x02)
消息作为 GetPooledTransactions (0x09)
请求的回复。这使得客户端代码更加复杂,因为节点不断地将 Transaction (0x02)
消息作为广播相互八卦,因此很难匹配哪个消息是请求的实际回复。
通过保持 Transaction (0x02)
和 PooledTransactions (0x0a)
作为单独的消息,我们还可以使协议在未来优化方面更灵活(例如,添加请求 ID,这对八卦广播没有意义)。
向后兼容性
本 EIP 以向后不兼容的方式扩展了 eth
协议,并且需要推出一个新版本,eth/65
。然而,devp2p
支持并行运行同一线路协议的多个版本,因此推出 eth/65
不需要客户端协调,因为未更新的客户端可以继续使用 eth/64
。
本 EIP 不会更改共识引擎,因此_不_需要硬分叉。
安全考虑
无。
版权
通过 CC0 放弃版权和相关权利。
Citation
Please cite this document as:
Péter Szilágyi <peterke@gmail.com>, Péter Szilágyi (@karalabe), Gary Rong <garyrong0905@gmail.com>, Tim Beiko (@timbeiko), "EIP-2464: eth/65: 交易公布与检索," Ethereum Improvement Proposals, no. 2464, January 2020. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2464.