Transaction的生命周期
本文会以一个提交到Libra validator的transaction为例,来讲解Transaction和其他组件的交互,和具体的状态变化过程。
提交一个Transaction
这里我们举个例子,还是上篇文章的例子,A拥有110LBR,B拥有52LBR。接下来会构建一个原始交易Tn,将A拥有的10LBR转给B。
这个原始交易将包含如下字段:
-
A的帐户地址。
-
一个要代表A执行的动作的程序。它包含:
一个Move字节码表示的peer-to-peer交易脚本。
一个该脚本的输入列表(例如,B的帐户地址和付款金额)。
-
Gas价格 -A愿意为执行交易而为每单位Gas支付的金额。Gas是一种支付计算和存储费用的方式。Gas单位是对计算的抽象度量,没有固有的实际值。
-
A愿意为此交易支付的最大Gas金额。
-
交易的到期时间。
-
序列号
每个账号的交易都有一个唯一的序列号,用来标记这个账号发出的交易。
有了这个原始交易之后,我们会使用A的私钥对这个原始交易进行签名,签名后的交易包含如下内容:
- 原始交易
- A的公钥
- A的签名
我们假设这个Libra区块链上面有100个validators, 我们用V1到V100来表示。客户将这个Transaction提交到了V1。V1是这一轮共识的发起者。
交易入链的详细过程
我们先用一张图来表示这个Transaction入链的过程:
Transaction的入链过程可以分为五大步:
- 接收Transaction
- 和其他Validators共享这个Transaction
- 区块Proposing
- 执行区块并达成共识
- 提交区块
接收Transaction
-
客户端将transaction提交给V1,V1的admission Control(AC)模块将会接收这个transaction。
AC是验证器的唯一外部接口。 客户端对验证器的任何请求都将首先转到AC。
-
AC调用虚拟机(VM)的接口来验证该交易的正确性,包括:签名认证,判断账户是否有足够的金额,Tn不是一个重放交易等等信息。用以防止恶意节点。
这里虚拟机是用来执行Move脚本,也是Libra业务逻辑运行的地方。
-
如果Tn通过了VM的验证,那么进入下一步,AC将会把Transaction送到MemPool中。
Mempool是一个共享缓冲区,用于保存“等待”执行的事务。 将新事务添加到内存池后,内存池将与系统中的其他验证程序共享此事务。 为了减少“共享内存池”中的网络消耗,每个验证器负责将自己的事务传递给其他验证器。 当验证者从另一个验证者的内存池接收到事务时,该事务将添加到接收者验证者的内存池中。
和其他Validators共享这个Transaction
- Mempool将会把接收到的Transaction缓存起来,用于和其他验证器共享。
- 通过共享Mempool的协议,V1将会把自己mempool的交易和其他验证节点共享,并将从其他验证节点收到的交易放到自己的mempool中。
区块Proposing
-
我们假设V1是Proposing节点,那么它会将自己mempool的交易打包成一个Block,然后通过共识模块向其他验证节点提交一个Proposal。
共识模块负责通过与网络中的其他验证者一起参与共识协议来对交易块进行排序并就执行结果达成一致。
-
V1的共识模块负责协调所有验证者之间对拟议区块中交易顺序的协议。
执行区块并达成共识
-
为了达成共识,在第六步生成的Block会被传递到执行模块。执行的工作是协调一组事务的执行,并保持一个可以通过共识投票的临时状态。
-
执行模块管理虚拟机(VM)中事务的执行。 请注意,这里的执行是在区块中的交易达成一致之前进行的推测性执行。
-
将Block中的Transaction执行完成后,执行模块将Block中的Transaction追加到Libra区块链的Merkle累加器。 这是Merkle累加器的内存/临时版本。 执行这些事务的(提议/推测)结果将返回到共识组件。从“共识”到“执行”的箭头表示执行交易的请求是由共识组件发出的。
-
V1(共识领导者)试图与参与该共识的其他验证者就块的执行结果达成共识。
提交区块
-
如果区块的执行结果由一组具有多数表决权的验证器达成一致并签名,则验证器V1的执行模块从推测执行缓存中读取区块执行的结果,并提交区块中的所有事务并永久存储。
-
A的帐户现在将具有100LBR,其序列号将为n+1。如果Tn被B重放,则它将被拒绝,因为A的帐户的序列号n+1大于重放的事务的序列号n。