Facebook Libra 内存池组件(Mempool)简介

内存池 Mempool 是位于内存的缓冲区,那些等待执行的交易便保存于此。

概述

准入控制(AC)模块将交易发送到内存池。在共识提交之前,内存池将交易保留一段时间。添加新交易时,内存池会与系统中的其他验证器(验证程序节点)共享此交易。内存池是“共享的”,因为各个内存池之间的交易都与其他验证器共享。这有助于维护伪全局的排序(pseudoglobal ordering)。

当验证器从另一个内存池接收交易的时候会对验证器进行排序,然后加入到接收验证器的有序队列。为了减少共享内存池中的网络消耗,每个验证器负责自己交易的通讯。我们不重播来自对等验证器(Peer Validator)的交易。

我们只广播那些有可能包含在下一个区块中的交易。这意味着交易的序列是发件人帐户的下一个序列,或者是发送方帐户的顺序。例如当前帐户的序列为 2,本地内存池包含序列为 2,3,4,7,8 的交易,则广播交易只是 2,3 和 4。

共识模块从内存池得到交易,但内存池不会把交易推到共识模块。这是为了确保在达成共识之前为交易做好准备:

  • 内存池可以基于气化值继续排序交易,并且
  • 共识允许在内存池中建立交易。

这会把交易分组到一个共识区块中,并按气化值确定优先级。

内存池不跟踪发送到共识模块的那些交易。对于每个 get_block 请求(从内存池提取的一个交易区块),共识模块会发送一组从内存池中提取但未提交的交易。这使得内存池对不同共识的分支保持不可知。

当交易完全执行并写入存储时,共识模块会通知内存池,然后内存池l从其内部状态删除该交易。

实施细节

在内部的内存池被建模为 HashMap<AccountAddress, AccountTransactions>,构建了各种索引。

主索引 - PriorityIndex 是一个有序的交易队列,它已“准备好”包含在下一个块中(即它们具有与该帐户的当前序列号修图的序列号)。这个队列按气化值(Gas)价格排序,这样如果客户愿意为每个执行单位支付更多气化值(比其他客户),那么他们可以提前达成共识。

请注意,全局排序是按照气化值排序的,即使如此,对于单个帐户却是按序号来排序交易的。下一个区块中尚未整合好的所有交易都是单独的 ParkingLotIndex 的一部分。一旦某个事件解除阻塞,它们就会被移动到有序队列中。

举个例子:内存池有一个序列号为 4 的交易,而该帐户的当前序列号是 3。该交易被认为“尚未就绪”。来自共识协议的回调通知交易已提交(例如交易 3 已提交给另一个节点,因此已经算在链上提交了)。此事件则会“解除阻塞”本地交易,并将交易 4 移动到 OrderedQueue。

内存池只持有有限数量的交易,以避免积压系统,和防止滥用和被攻击。内存池中的交易有两种超时(expiration)类型:systemTTL 和客户端指定的超时。当其中任何一个超时内存池会删除那交易。

后台的 SystemTTL 会定期检查,对于每一笔共识提交请求都会检查其超时过期值,该过期值是客户端指定的。我们使用一个单独的 SystemTTL 来确保交易不会永远停留在内存池中,即使共识协议没有取得进展。

文件结构

mempool/src
├── core_mempool             # 核心数据结构
├── proto                    # protobuf 内存池交互的接口
├── lib.rs
├── mempool_service.rs       # gRPC 服务
├── runtime.rs               # 内存池和 gRPC 服务的共享绑定
└── shared_mempool.rs        # 共享内存池

译自:https://developers.libra.org/docs/crates/mempool

展开阅读全文

没有更多推荐了,返回首页