这一章会举个例子,让咱们来看看整个交易的生命周期是怎么运行的。
提要
假如有这样一个场景:
- Alice 和 Bob 是两个用户,他们各自有一个 Aptos 公链账户(account)
- Alice 的账户里有 110 个 Aptos 币
- Alice 要转给 Bob 10 个币
- 目前,Alice 的账户序列号 (sequece nubmer) 是 5(这阐明历史上,从 Alice 的账户中,已经收回过 5 笔交易)
- 以后网络中有 100 个验证器 —— 假如叫 V1…V100
- 某个 Aptos 客户端通过 REST 服务,把 Alice 的交易提交到一个全节点,接着被转发到一个验证全节点,而后再持续转发给验证器 V1
-
验证器 V1,成为本轮提案人(proposer/learder)
客户端提交交易
某 Aptos 客户端创立一条原始交易(比如说叫做 Traw5),阐明 Alice 的账户要给 Bob 的账户转账 10 Aptos 币。该客户端用 Alice 的私钥签名这笔交易,签过的 T5 包含如下内容:
- 原始交易信息
- Alice 的公钥
- Alice 的签名
原始交易中的字段见下表:
字段 | 形容 |
---|---|
Account Address | Alice 的账户地址 |
Move Module | 将以 Alice 身份执行的一段 Move 模块(或程序)。在本例中,包含: |
- 一段点对点 Move 字节码交易脚本
- 脚本须要的一组输出(在本例中,就包含 Bob 的账户,和要领取的金额)
|
| Maximum
gas amount | Alice 违心付的最高 gas 金额。Gas 费为了领取交易过程中,耗费的存储和计算资源。Gas unit 是计算资源的形象掂量指标。|
| Gas price | Alice 违心为每个 gas unit(单元)付出的价格 |
| Expiration time | 本次交易的到期工夫 |
| Sequece number | 一个账户的序列号,示意公链上,已经从这个账户提交并确认的交易数量。在本例中,从 Alice 的账户总体提交过 5 笔交易,包含正在提交的这笔 Traw5。
留神:只有以后账户的序列号是 5,能力确认携带序列号为 5 的交易 |
| Chain ID | 以后 Aptos 网络的 ID 号(避免穿插网络攻击)|
生命周期 5 阶段
本节咱们来看一下 T5 这笔交易,从客户端提交当前,到公链上最终确认的过程。
先来相熟一下每一步对应的组件间的信息交互:
图 1.0 交易生命周期
图中的箭头,示意从一个组件向另一个组件,发动交互 / 动作,不代表数据的流动
交易生命周期蕴含 5 个阶段:
- Accepting:承受交易
- Sharing:向其余验证器共享交易
- Proposing:发动区块提案
- Executing and Conensus:执行区块并达成共识
- Committing:确认区块
下表详细描述了 5 个阶段各自产生了什么,并且附上相干概念链接
承受交易
形容 | 组件交互 |
---|---|
- 客户端 -> REST 服务:客户端通过 REST 服务,向全节点提交交易 T5,全节点通过 REST 服务,将交易转发给本人的 mempool,它再转发给网络中其余节点的 mempool,最终转到某个验证全节点的 mempool 里,再交给验证器(本例中的 V1)
| 1.REST Service |
| - REST 服务 -> Mempool:全节点的 REST 服务,把交易 T5 传递给 验证器
| 2.REST Service,
1.Mempool |
| - Mempool -> Virtual Machine (VM):Mempool 通过 VM 组件执行交易验证,比方 确认签名,确认账户余额,还有用序列号避免反复提交
| 4.Mempool
3.Virtual Machine |
|
|
|
共享交易到其余验证器节点
形容 | 组件交互 |
---|---|
- Mempool:mempool 把交易 T5 记入缓存,此时缓存中有可能还有 Alice 账号发过来的其余交易
| Mempool |
| - Mempool -> 其余验证器:通过缓存共享协定(shared-mempool protocol), V1 跟其余验证器节点共享本人的交易(包含 T5 和其余交易),也接管其余验证器的交易,放在本人的缓存池中
| 2.Mempool |
提案区块
形容 | 组件交互 |
---|---|
- Consensus -> Mempool:因为验证器 V1 是本交易的提案人,它会从缓存池拉出一个区块(block), 复制成一个提案(Proposal),通过共识组件,发给其余验证器节点
| 1.Consensus
3.Mempool |
| - Consensus -> 其余验证器:V1 的共识组件,负责协调其余所有验证器,就这个交易提案块,达成统一
| 2.Consensus |
执行区块并达成共识
形容 | 组件交互 |
---|---|
- Consensus -> Execution:为了达成统一,交易区块(含 T5)会被共享给执行组件
| 3.Consensus
1.Execution |
| - Execution -> Virtual Machine:执行组件负责在虚拟机中执行交易。留神这种执行是在交易达成共识一致性之前,揣测式地实现的。
| 2.Execution
3.Virtual Machine |
| - Consensus -> Execution:交易执行实现后,执行组件会把蕴含交易 T5 的区块,增加到默克尔树累加器(或者叫记账历史)中。这是一个默克尔树的长期版本(在内存中)。此时揣测式执行后果中的必要局部,会被传递给共识组件,冀望达成统一。
| 3.Consensus
1.Execution |
| - Consensus -> Other Validators:V1(共识 leader) 会协调其余参加共识的验证器进行投票,就以后提案区块的执行后果达成统一。
| 3.Consensus |
确认区块
形容 | 组件交互 |
---|---|
- Consensus -> Execution, Execution -> Storage:如果参加投票的验证器中,确认并签名的数量超过了法定个数,V1 验证器就会从预执行缓存中读出整个提案区块的执行后果,提交区块中所有交易,并把它们和执行后果一起写入永恒存储。
| 1.Consensus
3.Mempool |
当初 Alice 的账户只剩 100 个 Aptos 币了,它的序列号(sequence number)也长到了 6。如果 Bob 试图从新执行 T5,就会被零碎回绝,因为 Alice 账户的以后序列号(6)曾经比 T5 的序列号(5)大了。
Aptos 节点组件间交互
在上一节,咱们形容了一笔交易典型的生命周期(从提交到确认)当初咱们来看看区块链在解决交易和响应查问时,Aptos 节点组件间互动的状况。互动的详细信息,对以下这些人尤其有用:
- 想晓得零碎底层是如何工作的
- 想参加 Aptos 公链建设,奉献本人的力量
你们能够在这里学到不同类型的 Aptos 节点:
- 验证器节点(Validator nodes)
- 全节点(Fullnodes)
咱们的讲述构造会是这样的:假如一个客户端向验证器 Vx 提交了交易 Tn。对每一个验证器组件,咱们将会给每个组件设置一个章节,并且在外面的每个大节中,形容它们之间的互动。不过各个大节的程序,不是严格依照它们的执行程序列出的。大部分互动都是和交易解决相干的,一小部分跟客户端查问区块链相干(查问链上曾经存在的信息)
上面是交易生命周期中用到的 Aptos 外围组件:
全节点
- REST 服务
验证器节点
- 缓存池(Mempool)
- 共识(Consensus)
- 执行(Execution)
- 虚拟机(Virtual Machine)
-
存储(Storage)
REST 服务
客户端的任何申请,都是从调用全节点的 REST 服务开始的,之后,交易后被转发给一个验证器全节点,它再传给验证器节点 Vx。
1. 客户端 -> REST 服务
客户端发动 REST 服务调用,提交交易到一个 Aptos 全节点
2. REST 服务 -> 缓存池(Mempool)
REST 服务把交易转发给某个验证器全节点,它再传给验证器节点 Vx 的缓存池。缓存池会验证这个交易 TN,只有在它的序列号,大于等于发送者账户以后序列号的时候,才会承受这笔交易(也就是说,如果交易序列号不满足条件,它就不会被发送给共识组件)。
3. REST 服务 -> 存储
当任意客户端向 Aptos 链发动只读查问时(比方,获取 Alice 账户余额),REST 服务会间接和存储组件交互,获取信息。(注:不是从缓存池中读)
虚拟机(Virtual Machine)
图 1.2 虚拟机
Move 语言虚拟机,负责验证和执行 Move bytecode 格局的交易脚本1. 虚拟机 -> 存储
当缓存池申请虚拟机验证一笔交易的时候,它会调用办法 VM::ValidateTransaction(),虚拟机从存储中加载交易发送人的账户,并执行验证,具体过程如下:(残缺的验证列表,能够从这里看到)
- 查看交易中的输入签名(如果签名不正确,就回绝)
- 查看发送者账户的认证秘钥,与公钥的哈希值是否统一(交易应该是被发送者的私钥签名过的)
- 验证交易序列号大于等于发送者账户以后序列号。做这项查看能够避免同一个交易被反复执行。
- 验证签名交易中的程序没有被篡改,避免虚拟机执行篡改过的程序
-
验证发送者账户的余额,大于等于“交易中设定的最大 gas 费 ✖️ 以后 gas 价格”,保障能够领取将要耗费的资源
2. 执行组件 -> 虚拟机
执行组件通过 VM::ValidateTransaction() 办法,调用虚拟机来执行交易。
咱们须要了解,执行交易不等于更新账本中的状态,并长久化后果到存储中。执行 TN 的交易,是达成区块共识过程的一部分。只有其余验证器,就以后块中一系列交易的程序和执行后果都达成统一,它们才会被写入存储,同时更新状态。3. 缓存池 -> 虚拟机
缓存池有可能从 REST 服务或者其余验证器的共享缓存服务中,获取到交易信息,之后它会调用虚拟机的 VM::ValidateTransaction() 办法,来验证这笔交易。
虚拟机的详细信息能够看这里。缓存池
图 1.3 缓存池
缓存池中保留了“期待”执行的交易。一旦某笔交易被退出缓存池,它立刻就和其余验证器节点分享这条交易。为了缩小网络耗费,每个缓存池只负责提交它本人的交易给其余验证器,并且把其余验证器共享进去的交易增加到本人的池子里。1. REST 服务 -> 缓存池
- 从客户端接管到一笔交易 TN 之后,REST 服务把交易转发给某个验证器全节点,再持续转发到验证器节点 VX 的缓存池中。
-
只有在 TN 的序列号大于等于 交易发送者账户的以后序列号时,VX 的缓存池才会承受这笔交易。
2. 缓存池 -> 其余验证节点
- 验证节点 VX 把交易 TN 分享给同网络中其余验证节点
-
其余验证节点,也把它们各自缓存池中的交易,分享给 VX
3. 共识组件 -> 缓存池
- 当一笔交易被首次增加到某个验证节点,它就成为这笔交易的提案人(proposer / leader),它的共识组件,会从缓存池中,为这条交易拉取一个提案区块,并且把该区块复制给其余验证器;之后,共识组件将试图协调其余验证器,就这个区块中交易的程序和执行后果,达成统一的共识。
-
留神到目前为止,TN 这笔交易仅仅是存在于一个提案区块中的,所以不能保障未来 TN 肯定会被长久化到 Aptos 公链的分布式数据库里。
4. 缓存池 -> 虚拟机
- 缓存池从其余验证节点获取到交易当前,也会针对每一笔交易调用虚拟机的 VM::ValidateTransaction() 办法,来实现验证。
详见 缓存池的 readme 文档。
共识组件
图 1.4 共识组件
共识组件负责给交易排序,并且通过 共识协定 和其余验证器交互,来确认排好的程序和交易的执行后果。
1. 共识组件 -> 缓存池
如果验证器 VX 是提案人,那么 VX 的共识组件,就会通过 Mempool::GetBlock() 办法,从它的缓存池中拉取一个区块,并且构建出一个提案区块,其中蕴含多个交易。
2. 共识组件 -> 其余验证器
如果验证器 VX 是提案人,那么它的共识组件,就会复制提案区块给所有其余验证器
3. 共识组件 -> 执行组件,共识组件 -> 其余验证器
- 共识组件调研执行组件的 Excecution::ExecuteBlock() 办法,来执行整个区块的所有交易。(参见 共识组件 -> 执行组件)
- 实现提案区块中的每一项交易执行后,执行组件向共识组件返回所有执行后果。
-
共识组件为这组后果签名,而后试图与其余验证器达成统一
4. 共识组件 -> 执行组件
- 如果有足够多的验证器投了赞成票,共识组件 VX 就会调用执行组件的 Execution::CommitBlock() 办法,来确认区块。
详见 共识组件 readme。
执行组件
图 1.5 执行组件
执行组件协调一个区块中所有交易的执行,维持它们的临时状态(Transient State),交给共识组件投票。一旦这些交易胜利获得共识,它们就会被记入永恒存储。
1. 共识组件 -> 执行组件
- 共识组件通过调用 Excecution::ExecuteBlock() 办法,申请执行交易
- 执行组件外部维持了一个“寄存器”(scratchpad),它在内存中放弃了一份默克尔累加器(Merkle accumulator)相干局部的正本,以便计算 Aptos 链以后状态的根哈希值。
- 以后状态的根哈希值,和提案区块中的交易信息相结合,就能够确定新的累加器根哈希值。这一步在长久化数据之前实现,就能够保障,只有没有法定数量的验证器投赞成票,就不会有交易或者状态变更被记入永恒存储。
-
执行组件先预计算一个根哈希值,交给 VX 的共识组件签发,而后试图和其余验证器的根哈希值匹配
2. 执行组件 -> 虚拟机
-
当共识组件通过调用 Excecution::ExecuteBlock() 办法,申请执行交易的时候,执行组件通过虚拟机来获取区块中交易的执行后果
3. 共识组件 -> 执行组件
-
如果法定数量的验证器投票赞成了区块执行后果,每个验证器的共识组件都会调用本人执行组件的 Excecution::CommitBlock() 办法来确认区块。调用时,该当传入所有验证器签发的批准共识信息。
4. 执行组件 -> 存储
- 执行组件把确认后的所有交易信息,从本人的“寄存器”中取出,传给存储,并通过调用 Storage::SaveTransactions() 办法来长久化。之后,执行组件立刻“修剪”掉寄存器中没用的分支(比方,那些不是被提交进来,然而未能确认的区块)
详情请见 执行组件 readme
存储
图 1.6 存储
存储组件负责把区块交易及其执行后果长久化到 Aptos 链上。当超过法定数量的验证器(2f+1)投票达成统一之后,整个区块的交易(其中包含 TN)都会通过存储组件保存起来。共识必须蕴含以下内容:
- 区块中的交易
- 交易之间的程序
- 区块内交易的执行后果
要具体理解交易是如何被退出 Aptos 链上数据结构的,参见 默克尔累加器
1. 虚拟机 -> 存储
-
当缓存池调用 VM::ValidateTransaction() 办法验证某个交易时,VM::ValidateTransaction() 办法外部,会通过存储加载发送者账户信息,并执行该交易的只读验证
2. 执行组件 -> 存储
-
当共识组件调用 Excecution::ExecuteBlock() 办法时,执行组件会从存储读取以后状态,联合“寄存器”中的数据,来确认执行后果
3. 执行组件 -> 存储
- 一旦整个区块中交易的共识达成,执行组件就会调用存储的 Storage::SaveTransactions() 办法,永恒保留交易信息。这一步同时会保留所有赞成后果的验证器,签发的投票信息。寄存器中的区块数据,会被传递给存储组件,并永恒保留。存储被更新之后,所有被批改过的相干账户,其序列号都会 +1。
留神:每一笔确认的交易,都会导致其发起者账户的序列号 +1。
4. REST 服务 -> 存储
- 如果客户端要查问区块链上的信息,REST 服务会间接和存储组件交互,来获取须要的信息。
详见 存储 readme
我的语雀原文链接