libra的分析解读

一、Libra 区块链简介

Libra 区块链的目标是成为金融服务的基础,包括打造一种新的全球支付系统,满足数十 十亿人的日常金融需求。通过对现有区块链解决方案的评估, Libra 决定基于下列三项要求构 建一个新的区块链:

1、能够扩展到数十亿帐户,这要求区块链具有极高的交易吞吐量和低延迟等特点,并拥 有一个高效且高容量的存储系统。

2、高度安全可靠,可保障资金和金融数据的安全。

3、灵活多变,为未来金融服务创新提供动力。

Libra 区块链就是为了了全面满足这些要求,并从现有项目和研究中获得的经验教训为基础。 Libra 区块链的三项核心决策:

设计和使用 Move 编程语言。

使用拜占庭容错 (BFT) 共识机制。

迭代改善已广泛采用的区块链数据结构

二、设计和使用 Move 编程语言

2.1 move介绍

“Move”是一种新的编程语言, 用于在 Libra 区块链中实现自定义交易逻辑和“智能 合约”。由于 Libra 协会的目标是有朝一日为数十亿人服务,因此 Move 语言的设计首先考虑 到安全性和可靠性。Libra 开发团队从以往区块链平台中发生的与智能合约相关的安全事件 中吸取经验教训, 从而创造的一种新的智能合约编程语言 Move。

Move 从本质上令人更加 轻松地编写符合作者意图的代码,从而降低了出现意外漏洞或安全事件的风险。具体而 言,Move 从设计上可防止数字资产被复制。它使得将数字资产限制为与真实资产具有相同属性的“资源类型”成为现实:每个资源只有唯一的所有者, 资源只能花费一次,并限制创建新资源。

Move 语言还便于自动验证交易是否满足特定属性。例如,仅更改付款人和收款人帐户 余额的付款交易。通过优先实现这些特性,Move 可帮助保持 Libra 区块链的安全性。Move 允许轻松和安全地定义 Libra 网络的核心元素,例如支付传输和验证节点的管理。最后,Move 是将合规机制(例如促进旅行规则合规和协议级制裁筛选的机制)构建到 Libra 网络中的一种 方式。

Libra 协会致力于对智能合约实施适当的审查和风险控制。首先,只有协会批准和发布 的智能合约才能与 Libra 支付系统直接交互。随着时间的推移,协会将探索适当的控制措施, 以允许第三方方发布智能合约。

2.2 move语言最主要的特性:

可编程的Move交易脚本

  • 每一个Libra区块链上交易都包含 Move交易脚本 用来对交易逻辑的编码,同时验证器据此验证客户端的行为(例如,将Libra币从Alice的帐户移动到Bob的帐户)。
  • 交易脚本通过调用一个或者多个Move模块的过程和Libra区块链全局存储中发布的 Move资源 进行交互。
  • 交易脚本不存储在区块链的全局状态中,其他的交易脚本也无法调用它,这是一次性程序。

可组合智能合约的Move模块

Move模块(Modules)定义了更新 Libra 区块链全局状态的规则。 这些模块与其他区块链系统中与智能合约相同。 模块声明可以在用户帐户下发布的 资源 类型。Libra 区块链中的每个帐户都是一个容器,可以容纳任意数量的资源和模块。

模块声明两种结构类型(包括资源,这是一种特殊的结构)和过程。
Move模块的过程定义了创建,访问和销毁它声明的类型的规则。
模块可重复使用。 在一个模块中声明的结构类型可以使用在另一个模块中,并且在一个模块中声明的过程可以在另一个模块中声明的公共过程中调用。 模块可以调用其他Move模块中声明的过程。 交易脚本可以调用已发布模块的任何公共过程。

最终,Libra用户将能够在自己的帐户下发布模块。

Move的一等资源

  • Move的关键功能是能自定义资源类型。 资源类型通过编码具有丰富可编程性和安全性。
  • 资源是语言中的普通类型值。 它们可以存储为数据结构,作为参数传递给过程,从过程返回,等等。
  • Move的系统为资源提供特殊的安全性保证。 Move资源永远不会被复制,重用或丢弃。 资源类型只能由定义类型的模块创建或销毁。 这些保证由Move虚拟机 通过字节码静态验证,Move虚拟机将拒绝运行未通过字节码验证的程序代码。
  • Libra货币实现为名为 LibraCoin.T 的资源类型。 LibraCoin.T 在语言中没有特殊的地位; 每个Move资源都享有相同的保护。

总结

  • Move是一种静态类型语言,也就是强类型语言,在这方面Move与Java和C类似,将问题的出现更多放在编译时暴露,降低了在运行时出现crash的机率。

  • Move虚拟机通过字节码保证其资源保持first-class的地位,move拒绝执行未通过字节码验证的程序。也就是资源只能由定义的模块创建或者销毁。其它模块没有均无权限,这样也就避免了类似于以太坊solid多指针指向同一资源可能带来的安全漏洞和其它问题。

2.3 Move语言的设计

下面我们来简单介绍一下Move的语法。Move的基本封装单元是“模块”(Module),模块有点类似于以太坊中的“智能合约”,或者面向对象语言中的“类”。模块中可以定义“资源”(Resource)和“过程”(Procedure),类似于类中的“成员”(Member)和“方法”(Method)。
所有部署在Libra上的模块都是全局的,通过类似于Java中的包名+类名的方式来引用,例如0x001.MyModule,0x001是一个Libra地址,MyModule是一个模块名。模块中的过程有public和private两种可见性,公有过程可以被其他模块调用,私有过程只能被同模块的过程调用。而模块中的资源都是私有的,只有通过公有过程才能被其他模块访问。而且,外部模块或者过程对本模块资源的修改受到严格的限制,唯一允许的操作就是“移动”(Move),不能随意对资源赋值。例如,Move中是不允许出现一个类似于MyCoin.setBalance()这样的接口,让其他用户有机会随意修改某个币种余额的。

除了受限的资源类型,Move模块中也允许定义非受限的成员,被称为非受限类型(Unrestricted Type),包括原生类型(boolean、uint64、address、bytes)和非资源类的结构体(struct)。这些非受限类型就没有那么严格的访问限制,可以用来描述与资产无关的其他应用类数据。从这个角度来说,Move语言理论上应该具有和Solidity同样的描述能力,但由于实际的去中心化应用中,总会涉及到资产类的数据,而任何引用了资源类型的结构体也都是受限的,能够真正脱离Move语言严格限制的机会并不多。所以在实际使用Move语言开发的时候,程序员一定会有一种戴着镣铐跳舞的感觉,代码出现编译时和运行时失败的可能也更大。
通俗的说,用Move写代码不会让你感觉“很爽”,这就是安全性和可验证性的代价。想想你用C语言自己控制内存的分配和释放时,虽然有一种“我是上帝”的感觉,但也会时刻忧虑缓冲区溢出、内存泄露等潜在风险;而用Java语言开发,虽然你不再能够为所欲为的控制内存,但也不用担心这些内存安全性问题了。自由还是安全,往往是不兼得的。

在一个Libra的交易(Transaction)中,也可以嵌入一段Move代码,被称为交易脚本(Transaction Script)。这段代码不属于任何模块,是一次性执行的,不能再被其他代码调用。脚本中可以包含多个过程,通过main过程作为入口来执行,在其中也可以调用其他模块中的过程。这个设计有点类似比特币,而和以太坊完全不同。在以太坊中,一个交易本身是不能包含一段可执行代码的,只能部署新合约或者调用一个已部署的合约。我不太喜欢Libra的这个设计,由于任何Move代码都必须经过字节码验证器(Bytecode Verifier)的严格检查才能发布到链上,这种一次性代码的边际成本远远高于可复用的模块,会拖慢交易被确认的速度,降低系统的吞吐量。交易脚本并不是必须的,大部分现实场景都可以通过模块来覆盖,而且,它的存在还增加了Libra钱包的开发和使用难度,有机会的话我会向Libra的开发团队提议取消这一设计。

2.4 通过一个交易脚本看Move语言

下面我来看一下白皮书中的示例代码片段,直观感受一下Move语言。请注意,这段代码是Move中间语言的(IR),未来Move高级语言肯定会提供一系列语法糖,使代码更加简洁优雅。

// 两个参数
public main(payee: address, amount: u64) {
    
    
// 从sender余额扣除amount个Coin
 let coin: 0x0.Currency.Coin = 0x0.Currency.withdraw_from_sender(copy(amount)); 
 
// 将coin累加到payee的Coin余额中
 0x0.Currency.deposit(copy(payee), move(coin));
}

这段代码是一个交易脚本,只有一个main过程,实现的是一个叫做Coin的代币转账逻辑,接受一个目标地址和转账金额作为参数,预期执行结果是把amount数量的Coin,从交易发起者的账户转移给address地址。

过程体只有两行,第2行声明了一个coin变量,类型是0x0.Currency.Coin。0x0是部署Currency模块的Libra地址,Coin是一个资源类型,属于Currency模块。这是一个赋值语句,coin的值是调用0x0.Currency模块的withdraw_from_sender()过程获得的。这个过程被执行的时候,会从sender的余额中扣除amount数量的Coin;

第3行调用0x0.Currency模块的另一个过程deposit(),把上面取得的coin这个资源累加到payee地址的余额中。

这段代码的特别之处在于,每个取变量右值的地方都有一个copy()或者move()。这就是Move语言最有特点的地方,它借用了C++ 11和Rust的move语义,要求在读取变量的值时,必须指定取值的方式,要么是copy,要么是move。

两种方式的差别是:用copy的方式取值,相当于把变量克隆出一份,原来的变量值不变,还可以继续使用;而用move的方式取值,原变量的引用,或者说所有权转移给了新的变量,原变量就失效了。

C++中引入move语义的目的,是为了减少不必要的对象拷贝,以及临时变量的构造和析构,提高代码执行效率;而Move语言的目的,是为了通过更严格的语法和语义限制,来提高“资源”变量的安全性。在Move语言中,资源类型只能move,不能copy,而且只能move一次。

假如程序员的咖啡喝完了,状态很差,在写这段代码时出了一个bug,把第3行的move(coin)写成了copy(coin),会发生什么呢?

public main(payee: address, amount: u64) {
    
    
  let coin: 0x0.Currency.Coin = 0x0.Currency.withdraw_from_sender(copy(amount));  
   // move(coin) -> copy(coin) 
  0x0.Currency.deposit(copy(payee), copy(coin));
}

由于coin是资源类型,不允许copy,Move的字节码验证器会在第3行报错。

再假如程序员写代码时,他的猫刚好从键盘上走过,踩到了Command和D键,于是,第3行代码重复出现了两次(第4行),又会发生什么呢?

public main(payee: address, amount: u64) {
    
    
  let coin: 0x0.Currency.Coin = 0x0.Currency.withdraw_from_sender(copy(amount));
  0x0.Currency.deposit(copy(payee), move(coin));
  0x0.Currency.deposit(copy(payee), move(coin)); // 猫干的!
}

这一次bug更严重,会导致来源地址只扣除了一次金额,而目标地址却增加了双倍的金额。在这个场景下Move的静态检查就真正发挥作用了,由于第一次coin变量经过move取值后已经不可用,那么第二次move(coin)就会引起字节码验证器报错。

在以太坊中就没有那么幸运了,比如下面的代码:

pragma solidity >=0.5.0 <0.7.0;
contract Coin {
    
    
   mapping (address => uint) public balances;
   event Sent(address from, address to, uint amount);

   function send(address receiver, uint amount) public {
    
    
       require(amount <= balances[msg.sender], "Insufficient balance.");
       balances[msg.sender] -= amount;
       balances[receiver] += amount;
       balances[receiver] += amount; // 又是猫干的!
       emit Sent(msg.sender, receiver, amount);
    } 
    // ………… 
}

以太坊是无法找到代码中多出来的一行balances[receiver] += amount;的(第11行), 每次send()被调用,Coin这个代币的总量都会凭空多出amount个。

2.5 Move字节码验证器

读到这里,大家应该能够意识到,Move中最核心的组件就是字节码验证器。让我们来看看它是如何对一段Move字节码进行验证的,验证过程通常包括以下步骤:

  • 控制流图构建:这一步会将字节码分解成代码块,并构建它们之间的跳转关系;
  • 栈高度检查:这一步主要是防止栈的越界访问;
  • 类型检查:这一步会通过一个“类型栈”模型来对代码进行类型检查;
  • 资源检查:这一步主要针对资源类型进行安全性检查,防止资源被复制或消毁,并确保-资源变量被后续代码所使用。上文举的例子中的bug,就是在这一步被发现的;
  • 引用检查:这一步参考了Rust的类型系统,对引用进行静态和动态检查。检查是在字节码级别进行的,确保没有悬空的引用(指向未分配内存的引用),以及引用的读写权限是安全的;
  • 全局状态链接:这一步主要检查结构体类型和过程的签名,确保模块的私有过程不会被调用,以及调用的参数列表符合过程的声明。

2.6 Move虚拟机

Move的虚拟机,和EVM相似的地方比较多。它也是一个基于栈的虚拟机。指令集包含6类指令:数据加载和移动、栈操作/代数运算/逻辑运算、模块成员及资源操作、引用相关操作、控制流操作、区块链相关操作。

与EVM类似,每一条指令都会计算一个gas,耗光gas后代码会停机。Move中,一个交易的代码执行符合原子性,要么全部执行成功,要么一条也不执行。有趣的是,虽然Libra是一个标准的区块链账本结构,所有交易都是全局有序的,但Move语言本身支持并行执行,这意味着,也许以后Libra可以改进成类似Vite的DAG账本,提高交易并行处理的效率。

2.7 未来工作

当前Move还处于一个比较早起的开发阶段,后续工作包括:

  • 实现Libra链的基本功能,包括账户、Libra代币、准备金管理、验证节点的加入和移除、交易手续费管理、冷钱包等;
  • 新的语言功能,包括范型、容器、事件、合约升级等;
  • 提高开发者体验,包括设计一个人性化的高级语言等;
  • 形式化建模和验证工具;
  • 支持第三方Move模块。

三、使用拜占庭容错 (BFT) 共识机制

Libra 区块链采用了基于 LibraBFT 共识协议的 BFT 机制,来实现所有验证者节点就将 要执行的交易及其执行的顺序达成一致。这种机制实现了三个重要目标:

  • 首先,它可以在网络中建立信任,因为即使某些验证者节点(最多三分之一的网络)被破 坏或发生故障,BFT 共识协议的设计也能够确保网络正常运行。

  • 第二,与其他一些区块链中使用的“工作量证明”机制相比,这类共识协议还可实现高 交易处理量、低延迟和更高能效的共识方法。

  • 第三,LibraBFT 协议有助于清楚地描述交易的最终性,因此当参与者看到来自足够数量 验证者的交易确认时,他们可以确保交易已经完成。

BFT 的安全性取决于验证者的质量,因此协会将对潜在验证者进行尽职调查。Libra 网络的设 计以安全第一为原则,并考虑到了复杂的网络和关键基础设施攻击。

该网络的结构是为了加 强验者运行软件的保证,包括利用关键代码分离等技术、测试共识算法的创新方法以及对依 赖关系的谨慎管理。最后,Libra 网络将定义在出现严重漏洞或需要升级时重新配置 Libra 区 块链的策略及过程。

除了在这些情况下确保系统的安全恢复之外,这种准备将阻止攻击,因为 攻击者将知道他们的行为可以被反击。

四、迭代改善已广泛采用的区块链数据结构

为了保障所存储的交易数据的安全,Libra 区块链中的数据会受到默克尔树(Merkle tree)的保护,它是一种已在其他区块链中被广泛使用的数据结构,可以侦测到现有数据的任何 变化。与以往将区块链视为交易区块集合的区块链项目不同,Libra 区块链是一种单一的数据结构,其可⻓期记录交易历史和状态。这种实现方式简化了访问区块链的应用程序的工作量, 允许它们从任何时间点读取任何数据,并使用统一框架验证该数据的完整性。

上述设计决策的一个结果是,Libra 区块链将提供公共可验证性,这意味着任何人(验证 者、Libra 网络、虚拟资产服务提供商(VASP)、执法部门或任何第三方)都可以审核所有操作 的准确性。交易将以加密方式签名,以便即使所有验证者都被破坏,也不能接受来自具有安全 签名密钥的伪造交易。该设计与硬件密钥管理和高价值密钥的离线存储兼容。

上述设计决策的另一个结果是,Libra 区块链将支持一种隐私方方法,该方法将考虑网络 上参与者的多样性。协会会监督 Libra 区块链协议和网络的发展,并在考虑适用的监管要求的 同时,不断评估新技术以增强区块链上的隐私合规性。

五、LibraBFT 详解

5.1 概述

Libra 的共识机制采用的是 LibraBFT 共识,是一个为 Libra 设计的健壮、高效的状态 复制系统。它基于一种新型的 BFT 共识算法,HotStuff(BFT Consensus in Lens of Blockchain),在扩展性和一致性上达到了较高的水平。LibraBFT 在 HotStuff 的基础上引 入显示活跃度的机制并提供了具体的延时分析。

LibraBFT 在 3f+1 个验证节点之间收集投票, 这些验证者可能是诚实的节点也可能是拜占庭节点。在网络中有 2f+1 个诚实节点的前提下, Libra 能够抵御 f 个验证节点的双花攻击和分叉攻击。

LibraBFT 在一个有全局统一时间 (GST),并且网络最大延时(ΔT)可控的 Partial Synchrony 的网络中是有效的。并且, LibraBFT 在所有验证节点都重启的情况下,也能够保证网络的一致性。

为了能够更好地理解 LibraBFT,我们回顾一下 PBFT 和 HotStuff 共识协议。

5.2 PBFT

原始的拜占庭容错系统由于需要展示其理论上的可行性而缺乏实用性,另外需要额外 的时钟同步机制支持,算法的复杂度也是随节点增加而指数级增加。Castro and Liskov 在 1999 年提出实用拜占庭容错系统(Practical Byzantine Fault Tolerance,PBFT),降低了 拜占庭协议的运行复杂度,从指数级别降低到多项式级别(Polynomial),使拜占庭协议 在分布式系统中应用成为可能。

PBFT 是一类状态机拜占庭系统,要求整个系统共同维护一个状态,所有节点采取的 行动一致。为此,需要运行三类基本协议,包括一致性协议、检查点协议和视图更换协议。 视图转换协议保证共识协议的活性(liveness)。当主节点出故障时能保证共识能继续进行。PBFT 的视图转换协议是非常复杂的,涉及到很多消息的重传。HotStuff 的最重要的改进, 主要是针对视图更换的协议。

5.3 HotStuff

HotStuff 的基本假设是系统有固定的节点数 n = 3f+1,其中 f 是系统能容忍的最大拜 占庭节点数。系统通信是点对点的认证和可靠通信。网络通信的假设是半同步,也就是说, 网络有一个知道的延迟 D,以及一个不知道的全网稳定时间(Global Stabilization Time, 简称 GST),当 GST 过后,任意两个节点之间的通信都将在 D 时间内完成。HotStuff 能总 保证正确性(safety),在 GST 后的消息时延在一定限度(D)内能保证活性 (liveness)。

HotStuff 采用门限签名机制,门限设置是(k, n)。n 个节点中所有的节点共用一个 公钥,但每一个节点有自己的私钥。每个节点用自己的私钥签名消息 m,叫部分签名消息, 多个节点的部分签名消息可以用来生成一个联合签名消息,当至少有 k = 2f+1 个节点提供部 分签名消息时,其它任何一个节点能用公钥验证该联合签名消息。其中 f 是系统能容忍的拜 占庭节点总数,n = 3f+1。

HotStuff 论文中提出一个“认证复杂度”的概念。认证复杂度简单来说,统计协议交 互时通信的认证消息数,也就是部分签名或联合签名消息的个数。

HotStuff 两个重要的优点

一个是 linearity,指的是通信的复杂程度和节点数成线性关系;

另一个是 responsiveness,指的是当网络通信成为同步的时候,HotStuff 能产生 正确的 Leader 来推动协议在网络延迟的实际值内而非最大值达到共识。

HotStuff 在原先诸多的 BFT 共识协议中提升了效率,降低了复杂度。基于这些特性, HotStuff 适合于构建大规模的状态复制服务。因此,不难看出,Libra 从众多的区块链共识 算法中挑选 HotStuff,看中的是 HotStuff 的效率、线性的扩展性,以及拜占庭容错的安全 性。

这也体现了 Libra 的平衡术 – 在去中心、安全、扩展性这个棘手的区块链三难问题上, 巧妙的选择一个平衡点。

5.4 LibraBFT

严格说来,LibraBFT 是基于 HotStuff 的一个变种,叫链式 HotStuff(Chained HotStuff)。链式 HotStuff 是在基本 HotStuff(Basic HotStuff)上引入流水线概念,进一 步提升效率的一个改进共识协议。libraBFT 最初会选择一些在不同地理上分布的创始成员做共识节点,以后逐渐的,共识节点会对外开放,并基于 libra 稳定币的多少来选择共识节点, 也就是转变成 PoS 机制。

libraBFT 的共识流程是分为不同轮次(rounds),每一轮中一个 Leader 主节点被选 出。主节点会提议一个区块,里面包括多个交易。该区块将广播给其它共识节点。其它共识 节点会验证区块里的交易,并对其投票。主节点收到大多数(超过 2f+1,f 是系统中能容忍 的拜占庭节点数)节点的投票后,主节点把确认消息发给所有共识节点确认。如果主节点没 收到大多数投票,或者主节点出现故障,副本共识节点的定时将超时,副本节点会发起新的 一轮提议。

libraBFT 在 HotStuff 基础上的改进主要在于提供一个详细的参与同步轮次的 Pacemaker 设计和实现。并提供对实际交易确认的活性分析。LibraBFT 提供对共识节点投 票权力的重配置机制。同时它给出了对提议节点和投票节点激励的机制。白皮书给出了如何 检测投票节点破坏正确性的行为,为今后在协议中加入惩罚机制打下基础。同时白皮书也详 细讨论如何做同步,使得投票节点能同步它们的状态。libraBFT 白皮书采用 Rust 语言来描 述协议。

在 LibraBFT 中,为了更好地支持 Libra 生态系统的目标,LibraBFT 以多种方式扩展 和调整了核心 HotStuff 协议和实现。重要的是,LibraBFT 重新定义了安全条件,并提供了 安全、存活度和更高响应度的扩展证明。LibraBFT 还实现了一些附加功能。

首先,通过让 验证器对块的结果状态(而不仅仅是交易序列)进行集体签名,LibraBFT 使协议更能抵抗非确 定性错误。 还允许客户端使用法定人数证书来验证读取的数据库。

其次,LibraBFT 设计了 一个发出明确超时的起搏器,验证器依靠法定人数来进入下一轮 - 不需要同步时钟。

第三, LibraBFT 打算设计一个不可预测的领导者选举机制,其中一轮的领导者由最新提交的块的 提议者使用可验证的随机函数 VRF 确定。 这种机制限制了攻击者可以针对领导者发起有效 拒绝服务攻击的时间窗口。

第四,LibraBFT 使用聚合签名来保留签署仲裁证书的验证者的 身份。 这使我们能够为有助于仲裁证书的验证人提供激励,聚合签名也不需要复杂的 密钥 阈值设置。

5.5 实现细节

LibraBFT 共识组件最主要的是实现了 Actor 程序模型,它使用消息传递在不同的子 组件之间进行通信,其中 tokio 框架用作任务运行时。Actor 模型的主要例外是(因为它是由 几个子组件并行访问的)是共识数据结构 BlockStore,它管理块、执行、仲裁证书和其他共 享数据结构共识组件中的主要子组件是:

TxnManager 是内存池组件的接口,支持拉取交易以及删除已提交的交易。 提议者使 用来自内存池中的按需拉取交易来形成提议块。

StateComputer 是访问执行组件的接口。 它可以执行块,提交块,并可以同步状态。

BlockStore 维护提议块树,块执行,投票,仲裁证书和持久存储。 它负责维护这些 数据结构组合的一致性,并且可以由其他子组件同时访问。

EventProcessor 负责处理各个事件 (例如, process_new_round, process_proposal, process_vote). 它公开每个事件类型的异步处理函数和驱动协议。

Pacemaker 负责共识协议的活跃性。 它由于超时证书或仲裁证书而改变轮次,并在 它是当前轮次的提议者时提出阻止。

SafetyRules 负责共识协议的安全性。 它处理仲裁证书和分类信息以了解新的提交, 并保证遵循两个投票规则 — 即使在重启的情况下(因为所有安全数据都持久保存到 本地存储)。

所有共识消息都由其创建者签名,并由其接收者验证。消息验证发生在离网络层最近的地方, 以避免无效或不必要的数据进入协商一致协议。

六、libra区块链总结

Libra 区块链的架构设计汲取了 Bitcoin 和 Ethereum 的两大区块链技术的精华,使 用了新的智能合约语言。如果把 Bitcoin 的脚本指令比作汇编语言(ASM),那么 Ethereum 的 Solidity 就是类似于 JavaScript 的动态语言, 汇编语言效率最高但难于编写, 动态语言灵活强大但容易产生难于觉察的 bug, 这两种语言用来编写和金融相关的业务都不 是最优的。Move 语言借鉴了 Rust 语言的所有权(ownership)管理机制,在编写智能合 约时既保证了安全性又不失灵活性。

libraBFT 基于链式 HotStuff,其确认规则遵从 3-chain 的确认规则。libra 能在众多 的共识协议中选择 HotStuff,显示了 libra 团队的眼光,以及在区块链三难问题上巧妙的平 衡术。libraBFT 继承了 HotStuff,使得它的共识协议具有正确性(safety),在半同步网络 下的活性(Liveness),最终性(Finality);同时具有通信线性复杂度(linearity)和响 应性(responsiveness)。

Libra 的实现也展示了简易性(simplicity)和模块化 (modularity)的实现。同时也体现了 sustainability(可持续性),不需要工作量证明以 降低能耗。

七、libra白皮书解读,与比特币和以太坊的比较

7.1 可编程货币、可编程应用与可编程资源

其实,单从白皮书的标题,就可以大概看出三个项目在设计目标上的差异。

比特币的目标是——可编程货币(Programmable Money),所以白皮书标题是“Bitcoin: A peer-to-peer electronic cash system”。

以太坊的目标是——可编程的去中心化应用(Programmable dApps),在货币的基础上,扩展到更通用的领域。所以白皮书标题是:“Ethereum: a next generation smart contract and decentralized application platform”,黄皮书标题是:“Ethereum: A secure decentralized generalized transaction ledger”。

而Libra的设计目标恰好介于二者中间——可编程资源(Programmable Resources),或者叫可编程资产。

Facebook的技术路线比较务实,没有尝试更颠覆性的创新,而是把目光聚焦在“货币”和“通用应用”之间的“资产”,围绕解决实际问题,便于工程实现而展开。从这点来看,Libra既不是区块链3.0也不是4.0,而是区块链1.5。但这并不代表Libra的目标没有挑战,事实上,实现一个可以保证资产安全性,又能够提供足够灵活性的系统,比臆想出一个解决“不可能三角”的永动机还要困难。

那么,“可编程货币”、“可编程应用”、“可编程资源”,这三者到底有什么不同呢?

既然都是“可编程XX”句式,他们的主要区别就在于两点:

  • 对什么编程;
  • 如何编程。

对什么编程?

对什么编程,是指系统所描述或者抽象的,到底是现实世界中的什么东西。

比特币对“货币”编程

比特币系统抽象的是“货币”,或者说是“账本”的概念。货币可以用一个数字来描述,也就是某一个账户的“余额”。用户可以通过“交易”,把一部分钱转给别人。当比特币网络接收到一笔交易的时候,每个节点都会检查交易是否合法,比如你花的是不是自己的钱,有没有足够的余额(比特币不允许透支)。当这些检查都成功后,节点会做一个简单的加减计算:在你的账户中扣减转账的数额,并在对方账户中加上同样的数量。因此,比特币唯一的功能就是记账,保证在账户彼此转账的过程中,货币的总量不会莫名其妙的增加或减少(不考虑挖矿奖励和黑洞地址等特例)。

以太坊对“应用”编程

以太坊系统抽象的是“应用”,应用的种类包罗万象,比如游戏、借贷系统、电商系统、交易所等,这些都是应用。理论上讲,任何传统的计算机程序都可以移植到以太坊上。因此,以太坊中记录的是各种应用的内部数据(即“合约状态”),比如一个电商系统的库存、订单、结算信息等。这些信息无法用一个简单的数字来描述,必须允许用户定义非常复杂的数据结构,并且允许用户通过代码(智能合约),来对这些数据进行任意所需的操作。当然,这些应用也包含了“货币账本”。事实上,目前在以太坊上应用最广泛的正是此类应用(称为“ERC20智能合约”)。由于以太坊把这类应用看作是平台所能支持的多种应用中的一种,与其他类型的应用相比,并没有什么特别之处,所以也就没有针对此类应用提供更多的安全保护,只提供了类似ERC20这样的接口规范。一个在以太坊上新发行的“货币”,其转账逻辑的正确性完全由开发者负责。

以太坊账户存储

在以太坊的存储结构中,ERC20代币的账本是“二级对象”,和ETH原生代币余额存储在不同的地方。例如上图所示,0x0,0x1和0x2是三个以太坊地址,其中,0x0和0x2是普通账户地址(External accounts),而0x1是一个合约地址(Contract accounts)。我们可以看到,每个账户都存储了一个ETH的余额,这个数据是顶级对象(First-Class Object)。在合约地址0x1中,还存储了一个智能合约代码MyCoin,它是一个ERC20代币应用。而MyCoin这个代币的整个账本,都存储在0x1的空间中,怎么修改都由0x1中的合约代码说了算。

无论是有意还是无意,ERC20代币非常容易出现安全漏洞。也就是说,在以太坊系统中,原生代币ETH和用户发行的代币并不享有同样的安全级别。

Libra 对“资产”编程

那么,能否不那么走极端,试图去抽象一些比简单数字更复杂的资产类型,而又不追求包罗万象的“通用性”呢?这正是Libra的出发点。Libra可以定义类似一篮子货币、金融衍生品等比货币更复杂的资产类型,以及如何对他们进行操作,这种资产被称为“资源”。Move通过限制对资源的操作来防止不恰当的修改,从而提高资产的安全性。无论资源的操作逻辑如何,都必须满足两个约束条件:

  • 稀缺性。即资产总量必须受控,不允许用户随意复制资源。通俗的说,就是允许银行印钞,但不允许用户用复印机来“制造”新钱;
  • 权限控制。简单的说就是资源的操作必须满足某种预先定义的规则。例如,张三只能花自己的钱,而不允许花李四的钱。
    Move的世界状态

上图是Move的世界状态,与以太坊不同,它把所有资产都当作是“一等公民”(First-Class Resources),无论是Libra的原生代币,还是用户自己发行的资产。任何一个“币种”的余额,都存储在用户地址对应的空间中,对其进行操作受到严格的限制。这种被称为资源(resource)的对象,在交易中只能被移动,而且只能移动一次,既不能被复制,也不能被消毁。甚至严格到在代码中赋值给一个局部变量,而后面没有使用它也不允许。

这种资产的存储方式并非Libra独创,在此前的一些公链中已有应用,例如在Vite公链中,用户发行的币种余额也是顶级对象。不过Move可以支持更为复杂的资产类型,并对其提供额外的保护,这是Libra的主要贡献。

编者组: Vite 是本文作者创建的项目。

7.2 如何编程?

我们再来看看三个项目如何通过编程来实现丰富的扩展性。

比特币脚本

在比特币中,定义了一种“比特币脚本”,用来描述花一笔钱的规则。比特币是基于UTXO模型的,只有满足了预先定义的脚本规则,才能花费一笔UTXO。通过比特币脚本,可以实现“多重签名”之类的复杂逻辑。比特币脚本是一种非常简单的基于栈的字节码,不支持循环之类的复杂结构,也不是图灵完备的。虽然利用它可以在比特币网络上发行新的货币(Colored Coins),但它的描述能力非常有限,对开发者也不友好,无法应用到更复杂的场景中。

以太坊的 Solidity语言

在以太坊中,定义了一种Solidity的编程语言,可以用来开发“智能合约”。智能合约代码可以编译成一种基于栈的字节码——EVM Code,在以太坊虚拟机EVM中执行。Solidity是一种高级语言,参考了C++、Python和Javascript的语法,是一种静态类型、图灵完备的语言,支持继承,允许用户自定义复杂的类型。Solidity更像是一种通用的编程语言,理论上可以用来开发任何类型的程序,它没有针对货币或者资产类型的数据,在语法和语义上做任何限制和保护。比如用它来开发一个新的代币合约,代币的余额通常声明为uint类型,如果编码时对余额增减逻辑的处理不够小心,就会使余额变量发生溢出,造成超额铸币、随意增发、下溢增持等严重错误, 如: BEC 智能合约的漏洞。

Libra的Move语言

再来看Libra,它定义了一种新的编程语言Move,这种语言主要面向资产类数据,基于Libra所设定的“顶级资源”结构,主要设计目标是灵活性、安全性和可验证性。目前,Move高级语言的语法设计还没有完成,白皮书只给出了Move的中间语言(Move IR)和Move字节码定义。因此我们无法评估最终Move语言对开发者是否友好,但从Move IR的设计中,可以感受到它在安全性和可验证性方面的特点。

参夸文献

1.《Libra 白皮书 2.0》
2.《LibraBFT 共识协议》(邹均)
3. 详解Libra区块链及其共识协议
4. Libra的Move语言初探,10行代码实现你第一个智能合约
5. 解读Libra Move:一种可编程资源语言

猜你喜欢

转载自blog.csdn.net/qq_40713201/article/details/125114957
今日推荐