参考:https://developers.libra.org/docs/welcome-to-libra
Libra协议
Libra协议实现了一个加密认证的数据库来记录帐户及其余额。数据库存储可编程资源的分类帐,如Libra币。
Libra区块链使用一种新的智能合约语言Move,它是专门为Libra网络开发的。为了灵活地满足新需求,我们选择在Move中实现尽可能多的Libra协议,从而实现快速、简单和安全的开发。
数据库是由遵循LibraBFT共识协议的分布式验证节点网络来维护的。该协议可以容忍三分之一的验证器节点被破坏,并且仍然保证处理Libra币传输的一致性。作为LibraBFT协议的一部分,验证节点生成加密签名,以证明Libra区块链的状态。Libra区块链使用Merkle树数据结构允许任何用户,在世界任何地方,把验证节点的加密签名与一小块的数据,称为“证据”结合在一起,得到一个经过验证的Libra区块链上的任何交易的记录,知道交易永远不会被改变或逆转。
Libra协议:关键概念
交易和状态
Libra协议的核心是两个基本概念——交易和状态。在任何时间点,区块链都有一个“状态”。状态(或分类账状态)表示链上数据的当前快照。执行交易会改变区块链的状态。
图1.1 交易更改状态交易
Libra区块链的客户端提交交易以请求对分类账状态的更新。在区块链上签名的交易包含:
-
发送方地址 - 交易发送方的账户地址
-
发送方公钥 - 用于签名交易的私钥对应的公钥
-
程序 - 程序由以下几个部分组成
-
一个Move字节码交易脚本。
-
脚本输入的可选列表。对于点对点交易,输入包含关于接收者的信息和传输给接收者的金额。
-
要发布的Move字节码模块的可选列表。
-
-
Gas价格(以指定货币/gas单位计算) - 发送人愿意为每单位的gas支付的金额以执行交易。Gas是计算和存储的一种支付方式。Gas单元是一种抽象的计算度量,没有内在的真实值。
-
最大gas数量 - 交易允许消耗的最大gas单位。
-
序列号 - 一个无符号整数,必须等于存储在发送者帐户下的序列号。
-
超时时间 - 交易停止有效的时间。
-
签名 - 发送方的数字签名。
交易脚本是一个任意程序,它对交易的逻辑进行编码,并与发布在Libra区块链分布式数据库中的资源进行交互。
账本状态
Libra区块链的总帐状态或全局状态由区块链中所有帐户的状态组成。要执行交易,每个验证器必须知道最新版本的区块链分布式数据库的全局状态。
版本数据库
Libra区块链中的所有数据都持久化在单一版本的分布式数据库中。版本号是一个无符号64位整数,对应于系统已执行的交易数。
版本化的数据库允许验证器:
-
根据最新版本的分类账状态执行交易。
-
响应客户关于当前版本和以前版本的账本历史记录的查询。
账户
Libra帐户是Move模块和Move资源的容器。它由一个帐户地址标识。这主要意味着每个帐户的状态由代码和数据组成:
-
Move模块包含代码(类型和过程声明),但不包含数据。模块的程序对更新区块链的全局状态的规则进行编码。
-
Move资源包含数据但不包含代码。每个资源值都有一个类型,该类型在区块链的分布式数据库中发布的模块中声明。
一个帐户可以包含任意数量的Move资源和Move模块。
账户地址
Libra帐户的地址是一个16字节的值。用户可以使用数字签名来声明地址。帐户地址来自与签名方案标识符字节连接的用户的公共验证密钥的加密哈希。Libra支持两种签名方案:Ed25519和MultiEd25519(用于多签名交易)。要签署从其帐户地址发送的交易,用户(或代表该用户的托管客户端)必须使用与该帐户对应的私钥。
证明
Libra区块链中的所有数据都存储在单一版本的分布式数据库中。存储用于持久化已确认的交易块及其执行结果。区块链表示为交易不断增长的Merkle树。对于在区块链上执行的每个交易,树中附加一个“叶子”。
-
证明是一种验证Libra区块链数据真实性的方法。
-
存储在区块链上的每个操作都可以通过加密方式进行验证,结果还证明没有漏掉任何数据。例如,如果客户端从一个帐户查询最新的n个交易,该证明将验证查询响应中没有遗漏任何交易。
在区块链中,客户端不需要信任接收数据的实体。客户端可以查询帐户的状态,询问是否处理了特定的交易,等等。与其他Merkle树一样,分类帐历史记录可以为特定的交易对象提供O(logn)大小的证明,其中n是已处理的交易总数。
验证器节点(验证器)
Libra区块链的客户端创建交易并将其提交到验证器节点。验证器节点运行共识协议(与其他验证器节点一起),执行交易,并将交易和执行结果存储在区块链中。验证器节点决定将哪些交易以及以何种顺序添加到区块链。
图1.2 验证器的逻辑组件验证器节点包含以下逻辑组件:
许可控制(AC)
-
许可控制是验证器节点的唯一外部接口。客户端向验证器节点发出的任何请求都将首先发送给AC。
-
AC对请求执行初始检查,以保护验证器节点的其他部分不受损坏或大容量输入的影响。
内存池(Mempool)
-
Mempool是一个保存“等待”执行的交易的缓冲区。
-
当一个新的交易被添加到一个验证器节点的内存池时,这个验证器节点的内存池与系统中其他验证器的内存池共享这个交易。
共识
- 共识组件负责订购交易块,并通过与网络中的其他验证器节点参与共识协议来同意执行的结果。
执行
-
执行组件利用虚拟机(VM)执行交易。
-
执行的工作是协调交易块的执行,并维护可根据一致意见进行投票的瞬态状态。
-
执行维护执行结果在内存中的表示,直到一致意见将块提交给分布式数据库为止。
虚拟机(VM)
-
AC和Mempool使用VM组件对交易执行验证检查。
-
VM用于运行交易中包含的程序并确定结果。
存储
存储组件用于持久化已商定的交易块及其执行结果。
交易的生命周期
为了更深入地理解Libra交易的生命周期,我们将跟踪一个交易从提交到Libra验证器到提交到Libra区块链的过程。然后,我们将“放大”验证器的每个逻辑组件,并查看它与其他组件的交互。
客户端提交一个交易
一个Libra客户端构造一个原始交易(我们称之为T5raw),将10 LBR从Alice的帐户转移到Bob的帐户。原始交易包括以下字段。
-
Alice的账户地址。
-
指示要代表Alice执行操作的程序。它包含:
-
一个点对点交易脚本的Move字节码
-
脚本的输入列表(例如,Bob的账户地址和支付的数量)
-
-
Gas价格(是microlibra/gas单位)- 为完成交易,Alice愿意为每单位gas支付的金额。gas是计算和存储的一种支付方式。gas单元是一种抽象的计算度量,没有内在的真实值。
-
Alice愿意支付给这笔交易的最大gas数量。
-
交易的超时时间
-
序列号 - 5
- 序列号为5的交易只能应用于序列号为5的帐户。
客户端使用Alice的私钥签署事务T5raw。已签署的交易T5包括以下内容:
-
原始交易
-
Alice的公钥
-
Alice的签名
假设
为了描述交易T5的生命周期,我们假设:
-
Alice和Bob在Libra区块链上有账户。
-
Alice的帐户有110 LBR。
-
Alice帐户的当前序列号是5(这表示已经从Alice的帐户发送了5个交易)。
-
网络上总共有100个验证器—从V1到V100。
-
客户端向验证器 V1提交交易T5
-
验证器 V1是当前一轮的提案者/领导者。
交易的生命周期
在本节中,我们将描述交易T5的生命周期,从由客户端提交到提交到Libra区块链。
在相关的地方,按照生命周期中的编号步骤,我们提供了到验证器节点的相应组件间交互的链接。在您熟悉交易生命周期中的所有步骤之后,您可能需要参考关于每个步骤对应的组件间交互的信息。
图1.3 交易的生命周期接受这笔交易
1 -- 客户端向验证器 V1提交交易T5,后者的许可控制(AC)组件将接收该交易。(客户端→AC AC.1)
2 -- AC将使用虚拟机(VM)组件执行验证检查,如签名验证、检查Alice的帐户是否有足够的余额、检查交易T5是否被重放等(AC→VM AC.2, VM.1)
3 -- 当T5通过验证检查时,AC将T5发送到V1的内存池。(AC→Mempool AC.3, MP.1)
与其他验证器分享交易
4 -- 内存池将T5保存在内存中的缓冲区中。内存池可能已经包含了多个从Alice的地址发送的交易。
5 -- 使用共享内存池协议,V1将与其他验证器(V2到V100)共享其内存池中的交易(包括T5),并将从其他验证器接收到的交易放置到自己的内存池中。(Mempool→Other Validators MP.2)
提出区块
6 -- 由于验证器 V1是一个提议者/领导者,它将从它的内存池中提取一个交易块,并通过它的共识组件将这个块作为建议复制给其他验证器。(Consensus→Mempool MP.3, CO.1)
7 -- V1的共识组件负责协调提议块中所有验证器之间关于交易顺序的协议。(Consensus→Other Validators CO.2)。有关我们提出的共识LibraBFT的细节,请参考我们的技术论文Libra区块链中的状态机复制。
执行区块和达成共识
8 -- 作为达成协议的一部分,交易块(包含T5)被传递给执行组件。(Consensus → Execution CO.3,EX.1)
9 -- 执行组件管理虚拟机(VM)中交易的执行。注意,这个执行是在块中的交易被同意之前发生的。(Execution→VM EX.2, VM.3)
10 -- 执行块中的交易后,执行组件将块中的交易(包括T5)追加到Merkle累加器(分类帐历史)。这是一个内存/ Merkle累加器的临时版本。执行这些交易的(建议的/推测的)结果返回到共识组件。(Consensus→ExecutionCO.3, EX.1)。从“consensus”到“execution”的箭头表示执行交易的请求是由共识组件发出的。(为了在整个文档中一致地使用箭头,我们不使用箭头来表示数据流)。
11 -- V1 (共识领导者)尝试与其他参与共识的验证器就块的执行结果达成一致。(Consensus→Other Validators CO.3)
提交区块
12 -- 如果块的执行结果得到了一组拥有绝大多数投票的验证器的同意和签名,那么验证器 V1的执行组件将从推测的执行缓存中读取块执行的结果,并将块中的所有交易提交到持久存储中。(Consensus→Execution CO.4, EX.3),(Execution→Storage EX.4, ST.3)
13 -- Alice的帐户现在将有100 LBR,其序列号将为6。如果Bob重放T5,它将被拒绝,因为Alice的帐户序列号(6)大于重放交易的序列号(5)。
验证器组件交互
在上一节中,我们描述了示例交易从提交到提交到区块链的分布式数据库的典型生命周期。现在,让我们更深入地研究验证器在处理交易和响应查询时的组件间交互。这些信息对下列人员最有用:
-
想了解一下这个系统在幕后是如何工作的。
-
有兴趣最终为Libra的核心软件做出贡献。
在本文中,我们假设客户端向验证器VX提交了一个交易TN。对于每个验证器组件,我们将在各自组件部分下的子节中描述其每个组件间的交互。请注意,描述组件间交互的子节并没有严格按照它们的执行顺序列出。大多数交互都与交易的处理有关,还有一些与客户端的读取查询(查询关于区块链的现有信息)有关。
让我们看看验证器节点的核心逻辑组件:
-
许可控制(Admission Control)
-
内存池(Mempool)
-
共识(Consensus)
-
执行(Execution)
-
虚拟机(Virtual Machine)
-
存储(Storage)
许可控制(AC)
[图片上传失败...(image-5bac96-1605151035607)]
图1.4 许可控制许可控制是验证器的唯一外部接口。客户端对验证器发出的任何请求都将首先发送给AC。
Client → AC (AC.1)
客户端向验证器 的许可控制提交交易。这是通过:AC::SubmitTransaction()
完成的。
AC → VM (AC.2)
许可控制访问验证器的虚拟机(VM)来对交易执行初步检查,以便尽早拒绝格式错误的交易。这是通过:VM::ValidateTransaction()
完成的。
AC → Mempool (AC.3)
一旦VM::ValidateTransaction()
返回无错误,AC通过mempool::AddTransactionWithValidation()
将交易转发到验证器VX的mempool。验证器VX的内存池只有在的序列号是大于或等于当前发送方账户的序列号(注意,交易将不会通过共识,直到下一个序列号)时,才接受发送自AC的交易
AC → Storage (AC.4)
当客户端对Libra区块链执行读取查询(例如,获取Alice的帐户余额)时,AC直接与存储组件交互以获取所请求的信息。
虚拟机(VM)
图1.5 虚拟机Move虚拟机(VM)验证和执行用Move字节码编写的交易脚本。
AC → VM (VM.1)
当验证器的许可控制接收到来自客户端的交易时,它在VM上调用VM::ValidateTransaction()
来验证交易。
VM → Storage (VM.2)
当AC或内存池通过VM::ValidateTransaction()
请求VM验证一个交易时,VM从存储中加载交易发送者的帐户,并执行以下验证:
-
检查已签名交易上的输入签名是否正确(以拒绝未正确签名的交易)。
-
检查发送方的帐户身份验证密钥是否与公钥(对应于用于签署交易的私钥)的哈希值相同。
-
验证交易的序列号不小于发送者帐户的当前序列号。这样做可以防止对发送者的帐户重放相同的交易。
-
验证已签名交易中的程序没有格式错误,因为格式错误的程序不能由VM执行。
-
验证发送方的帐户中是否有足够的余额来支持交易中指定的最大gas量,从而确保交易能够支付所使用的资源。
Execution → VM (VM.3)
执行组件利用VM通过VM::ExecuteTransaction()
执行交易。
重要的是要理解执行交易与更新分类帐的状态和在存储中持久化结果是不同的。在共识期间,首先执行交易,作为试图就块达成一致的一部分。如果与其他验证器就交易的顺序及其执行结果达成一致,则结果将持久化到存储中,并更新分类账的状态。
Mempool → VM (VM.4)
当内存池通过共享的内存池接收到来自其他验证器的交易时,内存池在VM上调用VM::ValidateTransaction()
来验证交易。
内存池
图1.6 内存池内存池是一个共享缓冲区,用于保存“等待”执行的交易。当一个新的交易被添加到内存池中时,内存池与系统中的其他验证器共享这个交易。为了减少“共享内存池”中的网络消耗,每个验证器负责将自己的交易传递给其他验证器。当一个验证器从另一个验证器的内存池接收到一个交易时,该交易被添加到接收方验证器的内存池中。
AC → Mempool (MP.1)
-
执行初始验证检查之后,验证器的AC将交易发送到验证器的内存池。
-
仅当的序列号大于或等于发送者帐户的当前序列号时,验证器的内存池才接受发送者帐户的交易。
Mempool → Other Validators (MP.2)
-
验证器的内存池与同一网络上的其他验证器共享交易。
-
其他验证器将它们的内存池中的交易共享给的内存池。
Consensus → Mempool (MP.3)
-
当验证器成为领导者时,它的共识组件将从它的内存池中提取一个交易块,并将该块复制到其他验证器。它这样做是为了对交易的顺序和块中交易的执行结果达成一致意见。
-
注意,仅仅因为交易包含在共识块中,并不能保证最终将持久化到分布式数据库区块链中。
Mempool → VM (MP.4)
当内存池收到来自其他验证器的交易时,内存池在VM上调用VM::ValidateTransaction()
来验证交易。
共识
图1.7 共识共识组件负责排序交易块,并通过与网络中的其他验证器一起参与共识协议来同意执行的结果。
Consensus → Mempool (CO.1)
当验证器是领导者/提议者时,的共识组件会通过:mempool::GetBlock()
从其内存池中提取一个交易块,并形成一个议案。
Consensus → Other Validators (CO.2)
如果验证器是一个领导者/提议者时,它会将提议的交易块复制到其他验证器。
Consensus → Execution, Consensus → Other Validators (CO.3)
-
为了执行交易块,共识组件与执行组件进行交互。共识通过执行组件执行一个交易块:
ExecuteBlock()
(参考Consensus→Execution) -
在执行块中的交易之后,执行响应与执行这些交易的结果一致。
-
共识签署执行结果,并尝试与参与共识的其他验证器就该结果达成一致。
Consensus → Execution (CO.4)
如果有足够多的验证器投票支持相同的执行结果,的共识组件会通过execution::CommitBlock()
通知执行组件该块已经准备好提交了。
执行组件
图1.8 执行组件执行组件的工作是协调交易块的执行,并维护可根据一致意见进行投票的瞬态状态。
Consensus → Execution (EX.1)
-
共识请求执行组件通过:
execution::ExecuteBlock()
来执行一个交易块。 -
执行组件维护一个“暂存板”,它保存Merkle累加器相关部分的内存副本。此信息用于计算区块链当前状态的根哈希。
-
当前状态的根哈希与块中有关交易的信息相结合,以确定累加器的新根哈希。此操作在持久化任何数据之前完成,并确保在验证器的仲裁达成一致之前不会存储状态或交易。
-
执行组件计算推测的根哈希,然后的共识组件对这个根哈希进行签名,并尝试与其他验证器就这个根哈希达成一致。
Execution → VM (EX.2)
当共识组件请求执行组件通过execution::ExecuteBlock()
执行一个交易块时,执行组件使用VM来确定执行该交易块的结果。
Consensus → Execution (EX.3)
如果有法定个数的验证器同意块执行结果,那么每个验证器的一致意见都会通过execution::CommitBlock()
通知其执行组件该块准备提交。对执行组件的调用将包括同意验证器的签名,以提供它们的一致性的证明。
Execution → Storage (EX.4)
执行组件从它的“暂存板”中获取值,并通过storage::SaveTransactions()
将它们发送到存储中进行持久存储。然后执行组件删除不再需要的“暂存板”中的旧值(例如,无法提交的并行块)。
存储
图1.9 存储存储组件持久存储一致同意的交易块及其执行结果。一个块/一组交易(包括交易)将通过存储保存:
-
超过2f+1个确认者对以下所有事项达成一致意见:
-
要包含在块中的交易。
-
交易的顺序。
-
要包含在块中的交易的执行结果。
-
VM → Storage (ST.1)
当AC或内存池调用VM::ValidateTransaction()
来验证一个交易时,VM::ValidateTransaction()
从存储中加载发送方的帐户,并对交易执行只读有效性检查。
Execution → Storage (ST.2)
当共识组件调用Execution::ExecuteBlock()
时,执行组件从存储中结合内存中的“暂存”数据读取当前状态,以确定执行结果。
Execution → Storage (ST.3)
-
一旦对一个交易块达成一致,执行组件就通过
Storage::SaveTransactions()
调用存储来保存交易块并永久记录它们。这还将存储在此交易块上达成一致的验证器节点的签名。 -
此块的“暂存板”中的内存数据被传递到更新的存储并持久化交易。
-
当更新存储时,每个交易修改的所有资源的序列号将相应地更新。
-
注意:对于源自该帐户的每个提交交易,Libra区块链上的帐户的序列号递增1。
AC → Storage (ST.4)
对于从区块链读取信息的客户端查询,AC直接与存储交互以读取所请求的信息。
网友评论