关于比特币、以太坊、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 和用户发行的代币并不享有一样的安全级别。app
那么,可否不那么走极端,试图去抽象一些比简单数字更复杂的资产类型,而又不追求一应俱全的 “通用性” 呢?这正是 Libra 的出发点。Libra 能够定义相似一篮子货币、金融衍生品等比货币更复杂的资产类型,以及如何对他们进行操做,这种资产被称为 “资源”。Move 经过限制对资源的操做来防止不恰当的修改,从而提升资产的安全性。不管资源的操做逻辑如何,都必须知足两个约束条件:electron
这种资产的存储方式并不是 Libra 首创,在此前的一些公链中已有应用,例如在 Vite 公链中,用户发行的币种余额也是顶级对象。不过 Move 能够支持更为复杂的资产类型,并对其提供额外的保护,这是 Libra 的主要贡献。编程语言
编者组: Vite 是本文做者建立的项目。区块链
咱们再来看看三个项目如何经过编程来实现丰富的扩展性。ui
在比特币中,定义了一种 “比特币脚本”,用来描述花一笔钱的规则。比特币是基于 UTXO 模型的,只有知足了预先定义的脚本规则,才能花费一笔 UTXO。经过比特币脚本,能够实现 “多重签名” 之类的复杂逻辑。比特币脚本是一种很是简单的基于栈的字节码,不支持循环之类的复杂结构,也不是图灵完备的。虽然利用它能够在比特币网络上发行新的货币(Colored Coins),但它的描述能力很是有限,对开发者也不友好,没法应用到更复杂的场景中。
在以太坊中,定义了一种 Solidity 的编程语言,能够用来开发 “智能合约”。智能合约代码能够编译成一种基于栈的字节码 ——EVM Code,在以太坊虚拟机 EVM 中执行。Solidity 是一种高级语言,参考了 C++、Python 和 Javascript 的语法,是一种静态类型、图灵完备的语言,支持继承,容许用户自定义复杂的类型。Solidity 更像是一种通用的编程语言,理论上能够用来开发任何类型的程序,它没有针对货币或者资产类型的数据,在语法和语义上作任何限制和保护。好比用它来开发一个新的代币合约,代币的余额一般声明为 uint 类型,若是编码时对余额增减逻辑的处理不够当心,就会使余额变量发生溢出,形成超额铸币、随意增发、下溢增持等严重错误, 如: BEC 智能合约的漏洞。
再来看 Libra,它定义了一种新的编程语言 Move,这种语言主要面向资产类数据,基于 Libra 所设定的 “顶级资源” 结构,主要设计目标是灵活性、安全性和可验证性。目前,Move 高级语言的语法设计尚未完成,白皮书只给出了 Move 的中间语言(Move IR)和 Move 字节码定义。所以咱们没法评估最终 Move 语言对开发者是否友好,但从 Move IR 的设计中,能够感觉到它在安全性和可验证性方面的特色。
下面咱们来简单介绍一下 Move 的语法。Move 的基本封装单元是 “模块”(Module),模块有点相似于以太坊中的 “智能合约”,或者面向对象语言中的 “类”。模块中能够定义 “资源”(Resource)和 “过程”(Procedure),相似于类中的 “成员”(Member) 和 “方法”(Method)。
全部部署在 Libra 上的模块都是全局的,经过相似于 Java 中的包名 + 类名的方式来引用,例如 0x001.MyModule,0x001 是一个 Libra 地址,MyModule 是一个模块名。模块中的过程有 public 和 private 两种可见性,公有过程能够被其余模块调用,私有过程只能被同模块的过程调用。而模块中的资源都是私有的,只有经过公有过程才能被其余模块访问。并且,外部模块或者过程对本模块资源的修改受到严格的限制,惟一容许的操做就是 “移动”(Move),不能随意对资源赋值。例如,Move 中是不容许出现一个相似于 MyCoin.setBalance() 这样的接口,让其余用户有机会随意修改某个币种余额的。
除了受限的资源类型,Move 模块中也容许定义非受限的成员,被称为非受限类型(Unrestricted Type),包括原生类型(boolean、uint6四、address、bytes)和非资源类的结构体(struct)。这些非受限类型就没有那么严格的访问限制,能够用来描述与资产无关的其余应用类数据。从这个角度来讲,Move 语言理论上应该具备和 Solidity 一样的描述能力,但因为实际的去中心化应用中,总会涉及到资产类的数据,而任何引用了资源类型的结构体也都是受限的,可以真正脱离 Move 语言严格限制的机会并很少。因此在实际使用 Move 语言开发的时候,程序员必定会有一种戴着镣铐跳舞的感受,代码出现编译时和运行时失败的可能也更大。
通俗的说,用 Move 写代码不会让你感受 “很爽”,这就是安全性和可验证性的代价。想一想你用 C 语言本身控制内存的分配和释放时,虽然有一种 “我是上帝” 的感受,但也会时刻忧虑缓冲区溢出、内存泄露等潜在风险;而用 Java 语言开发,虽然你再也不可以随心所欲的控制内存,但也不用担忧这些内存安全性问题了。自由仍是安全,每每是不兼得的。
在一个 Libra 的交易(Transaction)中,也能够嵌入一段 Move 代码,被称为交易脚本(Transaction Script)。这段代码不属于任何模块,是一次性执行的,不能再被其余代码调用。脚本中能够包含多个过程,经过 main 过程做为入口来执行,在其中也能够调用其余模块中的过程。这个设计有点相似比特币,而和以太坊彻底不一样。在以太坊中,一个交易自己是不能包含一段可执行代码的,只能部署新合约或者调用一个已部署的合约。我不太喜欢 Libra 的这个设计,因为任何 Move 代码都必须通过字节码验证器(Bytecode Verifier)的严格检查才能发布到链上,这种一次性代码的边际成本远远高于可复用的模块,会拖慢交易被确认的速度,下降系统的吞吐量。交易脚本并非必须的,大部分现实场景均可以经过模块来覆盖,并且,它的存在还增长了 Libra 钱包的开发和使用难度,有机会的话我会向 Libra 的开发团队提议取消这一设计。
本文内容首发于深刻浅出区块链技术博客,点击解读 Libra Move:一种可编程资源语言看一下白皮书中的示例代码片断,直观感觉Move 语言,进一步了解move虚拟机等。