万字长文解析Libra技术
行文主要参考Libra官方文档《 The Libra Blockchain 》。
目录
一、背景介绍
二、逻辑数据模型
(一)账本状态 Ledger State
(二)交易 Transactions
(三)账本历史 Ledger History
三、执行交易
(一)交易执行的前提 Execution Requirements
(二)交易的结构 Transaction Structure
(三)交易的执行 Executing Transactions
(四)Move语言简介 The Move Programming Language
一、背景介绍
互联网及数字化产品和服务的发展助推了效率的提高,降低了准入的门槛,对于绝大多数产业而言,也降低了成本。对于金融行业,这也进一步助推了越来越多的人参与到生态中来。尽管如此,金融服务对于某些人而言,尽管他们极度渴求,但在成本、可靠性、资产流转便利度等方面,仍存在诸多限制。
Libra协议是Libra生态系统的核心支撑,它为解决当前存在的困难和挑战、拓展资产流转渠道、为革新化金融服务提供平台等方面提供了一揽子解决方案。Libra生态也提出了一种崭新的全球货币,Libra coin,它的价值锚定一篮子货币,由可靠金融机构的银行存款及有价证券作背书。所有背书的货币均有低通胀率,同时由于这些货币所属国家在地理位置上是多元分散的,这也为Libra coin价值的稳定增添了优势(单个或者少数国货币价值的大幅波动对Libra coin的币值影响有限)。Libra生态的目标是为成为全球重要金融基础设施,这需要稳定客观的交易规模、为经济和治理政策提供弹性的实施空间。
在提供金融服务的过程中,保障健康竞争和快速革新迭代的重要先决条件是有能力依赖普通基础设施进行交易、维护账户和保障跨服务、机构间的交互。为降低准入和切换成本的门槛,Libra协议将为所有人提供平等的施展平台,同时从新式商业模型和金融应用进行实验。区块链技术是最佳的实现路径,基于其去中心化、可追溯的特点,它能够保证没有任何人可以对Libra生态实现完全控制。
Libra的区块链是去中心化的,通过验证人(validators)间的共同协作进行开展交易并维护区块链的状态数据,这些验证人同时也是Libra现实组织的成员,他们将为Libra网络和保证金的治理提供框架。目前,Libra现实组织的成员都是地理分散和多元化的,他们都为Libra生态的形成和发展做出了一定的贡献,随着时间的推移,未来Libra现实组织和验证人的门槛将更加开放,并依据其持有Libra coin的数量来行权(最终实现形式类似POS,参照当前IMF依据出资份额获取投票权的治理形式),未来Libra的愿景是实现无许可(permissonless)的成员准入和治理体系。
与现存公链一致,Libra区块链服从Libra协议维护了一个加密的认证数据库,这个数据库存储着记录可编程资源(resources,包括Libra coin)的账本,这些资源(resources)服从特定模型(modules)的规则,这些特定模型(modules)也存储在数据库中。资源是由账户(accounts)拥有的,账户的使用方式仍是参照了非对称加密,公钥代表身份,私钥签名交易,账户(accounts)的持有者可以是个人,也可以是机构。
下图简要展现了客户端(client)和验证人(validator)通过Libra协议进行交互的具体形式:
- 验证人:维护数据库;
- 客户端:向数据库发起查询或者提交交易来更新数据库。
(1)验证人负责维护数据库和处理客户端提交的交易数据,并以此对数据库进行更新。验证人间通过分布式共识协议来进行决策,随着系统的运行,验证人共同接收交易并达成共识,进而更新交易的执行结果,上述分布式共识协议在即使存在少部分作恶节点的情况下依然有效。
(2)验证者轮流担任领导者,作为领导者,既要提交从客户端接收到的交易,同时也要提交从其他验证人那里接收到的交易。交易信息是在验证者之间进行流转的,验证者获取交易的渠道既包括客户端,也包括其他验证者。
(3)所有的验证者执行交易并形成一个认证的数据结构(authenticated data structure),这个数据结构包含新的账本历史数据(ledger history)。这一步仅为各验证者内部进行的操作,不同验证者形成的数据结构不是一致的,细节的数据结构内容会在后文中详细阐述。
(4)所有的验证者通过共识协议投票选出共同认可的数据结构,这个数据结构具备唯一性,这个过程叫做确认(commiting),对于确认交易后的数据库状态,共识协议会对其进行签名。
(5)最终由验证者将依照上述处理结果对客户端进行答复,提供认证的数据库状态信息。
二、逻辑数据模型
Libra区块链上的所有数据都储存在有单一版本号的数据库中,一旦数据库发生任何更新,版本号立即改变。版本号是64位无签名的整数,与系统已经执行过的交易数量有关。
Libra区块链上状态更新逻辑为: Apply(Si-1 ,Ti )→ <Oi ,Si>其中:数据库版本号为i已提交的交易为Ti交易Ti的执行输出结果为Oi账本状态为Si ,上一账本状态为Si-1确定性(deterministic)的执行函数为Apply(所谓确定性是指,开始于相同状态的状态机状态,以相同的顺序接收到相同的输入,将会达到相同状态和产生相同的输出。也就是说,对于相同的账本初始状态,在按相同顺序接受到相同的交易并进行处理后,最终账本的当前状态应该是一致的)。本部分内容首先介绍在单个版本号下的账本状态(Ledger State)的结构,之后介绍关于账本历史(Ledger history)的内容。
(一)账本状态 Ledger State
账本状态代表着Libra生态系统最核心的内容,包括每个账户所包含的Libra coin的数量,每个验证人必须知晓最新的账本状态才能够执行新的交易。类似于以太坊,Libra协议使用了基于账户的数据模型来编码账本状态。账本状态被设计为关键值存储的结构,将账户地址与账户值进行映射关联。在账本状态中,一个账户的值就是资源(resouces,简单可以理解为代币token)和模型(modules,简单可以理解为代币模板)的集合,创世账本状态中记录着最初的账户设定和账户状态。一个账户状态的例子如下图,明确展示了账户状态主要包含的细节:
上图中,椭圆形框起来的代表资源(resources),长方形框起来的代表模型(Modules),箭头代表资源和模型的隶属和服从关系。
账户地址(Account addresses)
一个账户地址256位,想要创建一个新账户,用户必须先生成密钥对,并对公钥进行哈希运算后获得账户地址。新的账户必须通过现存账户发起交易进行开立,这常常发生在一个交易想要把Libra coin发送到一个还未创建的账户地址时。一旦新的账户创立了,用户可以用私钥对该账户发起的交易进行签名,用户还可以在不变更账户地址的前提下,更换签名的私钥来增强账户安全性。与其他公链一样,Libra的账户具有匿名性的特点,任何用户都可以随意创建账户并签名交易,除非通过社会工程学的方式对账户交易明细进行分析,单从账户本身无法将账户与现实个人建立关联。
资源(Resouces)
资源,是特定字段与数据值关联关系的记录,数据值可以是简单的整数,也可以是复杂的值,比如当其他的资源被内嵌在当前资源中时,此时该资源的数据值将复杂。每一种资源都有自己的类型,而这个类型由自己服从的模型进行声明。参考本部分开始时的账本状态图,资源类型可以举例为:资源Currency.T的类型为0x56.Currency.T,其中:0x56为Currency模型储存的地址,Currency是模型的名称,Currency.T是资源的名称。这种设计的初衷是让所有的账户在储存自己的类型为0x56.Currency.T的资源时使用相同的路径 /resources/0x56.Currency.T,这样,每个账户只能最多储存一种给定类型的资源。当然,这种限制并非绝对的,用户可以可以定义一种包含两个资源的资源,类似resource TwoCoin {c1:0x56.Currency.T, c2:0x56.Currency.T}。改变、删除和发布资源的方式全部编码在对应的模型之中,Move语言的安全和验证规则禁止了通过其他方式来改变资源。
模型(Modules)
模型声明了资源的类型和细节,类似于资源的类型,模型本身也识别标志,模型的识别标志为类似0x56.Currency,是模型所在地址与模型名称的组合。在单个账户内,模型的名称必须是唯一的,参考之前的图,0x56地址内不可以再命名一个模型叫Currency,但0x34内可以再命名一个模型叫Currency,此时改模型的标志为0x34.Currency,与0x56.Currency是两个不同的模型,不可混用。在当前的Libra协议中,模型是不可更改的,一旦生成,不可以被调整和删除,除非通过硬分叉的方式。未来Libra基金会将寻求安全实现模型升级的细节方式,并在未来版本中发布。
(二)交易 Transactions
Libra区块链的账本状态(Ledger State)通过客户端提交交易的方式进行更新,从浅层面上来说,一笔交易包含交易脚本(transaction script)和交易参数(arguments,比如收款账户地址)。验证人执行交易的方式是参照前文提到的状态转换逻辑Apply(Si-1 ,Ti )→ <Oi ,Si>,将交易脚本和交易参数作为输入,通过执行确定性的函数来获取交易输出,但是要注意,只有该笔交易产生的输出被共识机制确认以后,账本状态才会发生变化。本文将在第三部分讨论交易执行的具体细节。
交易输出(Transaction output)
通过执行一笔交易Ti我们可以得到新的账本状态Si,以及交易执行状态代码(execution status code)、油费使用量(gas usage)和事件列表(event list),上述信息都囊括在交易输出(Transaction output)中。交易执行状态代码记录了交易的执行结果(成功、错误或者油费不足等),油费使用量记录了交易执行过程中的油费。
事件(Events)
事件(events)是执行交易后产生的“附带效果”,move语言通过事件结构(event structure)来触发事件。每个事件都与单独的密钥关联,密钥代表着事件结构和负载(payload),负载涵盖了要触发事件的细节信息。一旦一笔交易被共识确定,那么该笔交易所产生的事件将被添加到账本历史中(ledger histoy,下一小节介绍),并反馈出交易事件成功执行,即某个特殊效果(例如一笔付款交易触发了一个允许收款方确认付款被收到且付款金额是否正确的事件)成功实现的证据。
事件(event)的引入乍一看似乎很多余,没什么意义,因为可以通过向系统确认该笔交易是否被共识确认来替代想系统确认事件发生的具体信息。但是要注意,交易被共识确认并不意味着交易成功被执行,在一个交易可以执行失败(运行时错误或者油费不足)的系统里,引入事件(event),不仅可以确认交易被成功执行,还可以确认其想实现的“附带效果”是否也实现了。
(三)账本历史 Ledger History
账本历史(Ledger History)按顺序储存着已经被确认和执行的交易以及这些交易所触发的事件。账本历史的作用是记录最新的账本状态(Ledger state)是如何产生的(交易的确认和执行意味着账本状态的改变,因为账本状态记录着各个账户地址的细节信息,而交易的执行意味着部分账户的细节信息发生变化。账本历史记录了历次被纳入区块链的交易,也就记录着账本状态是如何被改变和更新的)。在账本历史中,没有区块(block)的概念,区块概念的存在目的是能够形成共识机制不断将交易确认和执行,但是,在第二部分逻辑数据模型中,只考虑交易依照顺序被记录下来,而不考虑哪些交易被囊括在哪个区块中。
尽快验证人在执行新的交易时并不需要事先知道账本历史(即历史交易明细),但客户端可以向账本历史发起查询请求,以及使用账本历史审计交易的执行情况。
查询请求的回复(Responding to client queries)
验证人可以使用账本历史来回复客户端关于查询历史账本状态、交易和交易输出信息的请求(从第四部分我们会讲到,交易、交易输出、事件、账本状态都储存在账本历史的叶节点中)。
例如:历史客户端可以会询问特定版本号的账本状态信息——在账本状态(版本号30)中地址为X的账户有多少Libra?或者询问特定类型事件的历史记录——地址为Y的账户在过去20分钟里都收到了哪些货币支付?
审计交易的执行(Auditing transaction execution)
客户端可以通过重新执行历史交易Ti,通过对比自己的计算结果和系统中的账本状态Si以及交易输出Oi (核心状态逻辑仍是Apply(Si-1 ,Ti )→ <Oi ,Si>)来验证当前的账本状态Si是否正确。这种机制允许客户端对验证人开展审计,以确保交易被正确无误的执行了。
三、执行交易
在Libra协议中,改变区块链状态的唯一办法就行执行交易。本部分简要介绍了交易执行的前置条件,定义了交易的结构并解释了Move语言虚拟机如何执行执行一笔交易,最后阐述了Move语言的核心概念。
在最初版本的Libra协议中,仅有一部分Move语言的功能可用,玩家无法发布自定义的模型(modules)并声明自己的资源(resources)类型。Move语言在实现全功能可用前,仍有很长的路要走,这在一定程度上限制了实现智能合约中交易的执行及数据的存储。
(一)交易执行的前提 Execution Requirements
了解初始/创世状态(Known initial state)
所有验证人必须首先就最初的,或者说创世的账本状态达成一致。由于Libra区块链的核心组成部件,例如账户逻辑,交易验证,验证人选举和Libra coin都是定义好的Move模型,因此在创世账本状态中,这些都要被声明和创建。在创世账本状态中还必须要有足够的核心组件实例以保障交易可以被顺利执行(例如,至少要有一个账户且拥有足够的资产来支付第一笔交易的油费,要有一组验证人来保证第一笔交易可以被共识机制确认)。
为了简化系统的设计,系统的状态一开始为空,而后通过执行特殊的交易T0(该交易定义了创世状态所需的模型和资源)来创建创世状态,值得注意的是,交易T0的执行不通过正常的流程进行,因为缺乏正常执行交易的条件。客户端和验证人被设置为只接受从特殊交易T0开始的账本历史,这通过其哈希值来保证。
确定性(Deterministic)
交易的执行过程必须具有确定性(前文介绍过确定性的定义)和密封性的特点,这就意味着交易执行的输出结果是完全可预测的,并且只与执行前的账本状态及交易自身相关。交易的执行本身是没有外部效应的(比如在控制台中显示或者进行网络交互),确定性和密封性保证了只要最终的系统状态是由相同交易按相同顺序执行而产生的,即使这些交易是被不同的验证人独立执行的,多个验证人依然能够就最终系统状态达成一致。这也就意味着,如果从创世区块开始,如果按照区块链的历史交易列表同顺序的执行交易,仍然能够得到当前的账本状态。
计算和测量(Metered)
为了有效管理对计算资源的需求,Libra协议收取用Libra coin计量的交易费,这种收费模型与以太坊一致。Libra生态选择有充足计算能力的验证人来满足Libra生态系统对计算资源的需求。收取交易费的唯一目的在系统超过其预定负载的时候适当减少需求(例如遭受了DDOS攻击),在正常状态下,系统收取的交易费是非常低的。Libra的交易费收取模式与现有的很多公链是不同的,现存的很多公链其验证人的计算能力是不足的,因此使用者对计算资源的需求经常超过其正常吞吐能力,在需求过盛的情况下,交易费用会陡升,这对于验证人来说是一项收入,对使用者来说,大大增加了成本。
交易费的大小由两个因素来决定,油费单价(gas price)及油耗(gas cost)。每笔交易都标明了交易发起人愿意付出的油费单价,油耗依据该笔交易所耗费的计算资源自动累计计算。对于验证人而言,他们总是优先选取高油费单价的交易,将低单价的交易排后或者放弃,这种机制在系统高负载的情况下降低了对计算资源的需求。
同时,交易中还包括最大油费数量(maximum gas amount),它定义了交易发起者最大可以承受的费用,在执行过程中,虚拟机会不断跟踪油费的使用量,如果在交易执行成功前,油费使用量已经超过了最大油费数量,虚拟机就会终止交易,因而该笔交易的执行结果以及事件触发都不会被系统确认。值得注意的是,即使交易被终止,该笔交易仍然会出现在历史交易列表中,而且发送者依然会因已经使用了计算资源而被收取交易费用。
Libra区块链的很多核心逻辑都说是通过Move语言实现的,包括交易费的计算。为避免死循环的出现,虚拟机在执行交易的核心环节会停止油费的计算(后面会详细讲到),这些核心环节在创世状态中已经被确定并且使用了保守的代码来防止作恶者发送恶意交易来触发消耗大量计算资源的计算环节,执行这种逻辑所消耗的油费成本已经囊括在了交易费的基本费用中(基本费用类似于出租车的起步价,交易执行的部分环节不收取油费,因为这些费用已被囊括在起步价中)。
资产(Asset semantics)
在账本状态中直接将数字资产(即账户中的资源)与现实世界中的价值进行了关联,正是由于涉及用户的利益,因此交易的执行必须保证资产不存在复制、丢失或者未经同意被转移的可能。Libra协议利用Move虚拟机来安全的执行交易和处置资产。
(二)交易的结构 Transaction Structure
一笔交易就是一笔被签名过的信息,它涵盖了以下信息:
发送人账户地址(Sender address):交易发送者的账户地址。虚拟机从该地址的LibraAccount.T资源中读取顺序号、验证密钥和资源数量信息。
发送人的公钥(Sender public key):公钥与私钥是一对,私钥用来签名交易。公钥的哈希值必须与发送人账户LibraAccount.T资源中的验证密钥相匹配。
程序(Program):即将被执行的交易脚本,用Move语言字节码的方式表示,有一系列脚本输入项和模型可供选择。
油费单价(Gas price):参考了以太坊的交易费用计算模型,油费单价是指交易发送人愿意承受的油费单价,油费单价乘以油(gas)的使用数量即为发送者为该笔交易付出的交易费。
最大油费(Maximum gas amount):该笔交易允许花费的交易费用最大值,超过该最大油费数量,交易即停止。
顺序号(Sequence number):未签名的整数,与账户地址相关,这个整数应当与发送人账户LibraAccount.T资源中的顺序号一致。每当交易执行一笔,该顺序号+1。对于单个顺序号而言,只有一笔交易可以被系统确认并执行,交易是无法被重复确认和执行的。
(三)交易的执行 Executing Transactions
执行一笔交易需要在Move虚拟机中运行六个步骤,交易的执行是独立于账本状态的更新的。首先,一笔交易被共识确认并依照顺序被执行,由于交易执行的过程是封闭的,因此交易的执行并不会引起任何的外部效果。其次,如果交易被确认,该笔交易执行的结果将被写入账本历史。具体的六个步骤具体如下:
1、核验签名(Check signature):交易上的签名必须与交易发送者的公钥和交易数据相匹配。这一步仅围绕交易本身,从交易结构(参考上一小节)即可获得,它不需要从发送者的账户中读取任何信息。
2、运行“前言”程序(Run prologue):LibraAccount模型中的“前言”(prologue)程序对交易发送者进行验证,保证交易发送者有足够的Libra coin来支付最大油费(Maximum gas amount,由交易发送者在构造交易时设定,是交易发送者愿意为本笔交易承受的最大费用支出),同时检查该笔交易是否之前已经被执行过。在执行“前言”程序的过程中,不计算gas的花费(如之前部分介绍的,该费用打包在起步费用中),具体而言,“前言”程序的执行内容如下:
验证交易发送者公钥(在交易结构中)的哈希计算结果与发送者账户中储存的验证密钥是否一致。如果没有这步检查,虚拟机将会错误的接受具备有效数字签名的交易,即使该笔交易与事先约定的交易发送者账户无关。(第一步核验签名仅就交易本身进行自洽性验证,即交易结构中的签名与公钥要匹配,但未验证该笔交易是不是某个既定的账户发送出来的,实际上本环节是在核实交易发起人的身份)。
验证油费单价*最大油耗是否小于等于发送者账户的libra coin余额。如果没有这步验证,虚拟机将会执行那些无法进行到最后的交易,因为他们的libra coin余额不足以支付本笔交易的油费。
确保交易结构中的顺序号(Sequence number)与发送者账户中存储的顺序号一致。如果没有本步验证,作恶者可能会反复执行旧交易来获利(比如反复执行别人给自己付款的交易)。
3、验证交易脚本和模型(Verify transaction script and modules):一旦“前言”程序执行完毕,虚拟机会对交易脚本和模型进行完整性验证(使用Move bytecode verifier,在执行或者发布Move代码前,Move bytecode verifier会验证代码在数据类型、参考实现、资源设计等方面的安全性)。
4、发布模型(Publish modules):通过发送交易发布模型时,每个模型都是发布在交易发送者账户下的。同一账户下,发布同名模型是不可能的。
5、执行交易脚本(Run transaction script):虚拟机将交易中携带的数据与交易脚本中的参数进行匹配并执行交易脚本。如果交易脚本执行成功,脚本的执行结果包括脚本触发的事件都会被全局状态所确认,如果交易脚本执行失败(由于油费不足或运行时错误),关于运行脚本的任何结果都不会被系统确认。
6、运行“结尾”程序(Run epilogue):最后一步,虚拟机会运行“结尾”程序向用户收取所需的油费并增加交易发送者的顺序号(sequence number)。像“前言”(prologue)程序一样,“结尾”程序也是LibraAccount模型的一部分,并且计算过程不收取油费。只要一笔交易的执行过程成功完成第二步(“前沿”程序),即使第三、四、五步都运行失败,本步骤总会执行。“前沿”程序只要成功运行,就确认了交易发送者账户中有足够的libra coin来支付其设定的最大油费,即使因为最大油费不足而导致交易失败,“结尾”程序仍会按最大油费收取本笔交易的交易费。“前沿”程序和“结尾”程序总是成对出现的,他们的存在共同保证了所有交易都会被记录在账本历史中,并且会被收取油费,对于那些并没有成功运行通过“前沿”程序的交易,不会被记录在账本历史中。
(四)Move语言简介 The Move Programming Language
如先前介绍的,交易就是Move语言字节码程序的打包,Move是一种在设计Libra协议过程中创造的新编程语言,其在系统中承担三种重要的角色:
一是通过编写交易脚本来实现各类交易;
二是允许用户自定义代码和数据类型,包括通过模型(modules)实现“智能合约”;
三是支持Libra协议的设置和延展。
Move语言的核心特点是能够自定义资源(resources),资源用来实现可编程资产,它能够被保存在数据结构中或者作为参数被发送到程序中。同时,Move语言还保证了资源的安全性,资源不能够被复制,仅能够被移动。资源由模型(modules)来声明,并且仅能够由该模型来创造和消除。上述这些特性都由Move虚拟机来静态的实现,这也就允许我们将Libra coin作为一种资源来推出。在本节中,仅仅就Move语言在交易执行过程中涉及的核心概念进行介绍。
编写Move程序(Writing Move programs)
一个Move程序可以有三种表达方式,即源码语言(source code/source language)、中间代码IR(intermediate representation)和字节码(bytecode)。目前源代码形式正在开发当中,目标是形成一种易于编写和验证安全代码的人机工程语言。同时,用户可以使用中间代码IR的形式开发模型和交易脚本,IR是一种语义明显、易于阅读的方式,同时也很容易被转化为字节码形式。源代码和IR的方式最终都将被编译成字节码的形式通过Libra协议进行传输。
Libra使用认证的字节码方式作为Move语言的传输和执行形式,主要出于以下两方面的考量:
一是前文提到的Move语言的安全特性是适用于所有Move程序的,这样仅在编译器中确保这些安全特性是不够的,攻击者可以通过恶意代码绕过编译器直接使用字节码(Move语言代码都将通过编译器转化为字节码,如果仅在编译器中保障代码的安全性,则作恶者直接将恶意代码以字节码形式输入,就可以绕过编译器的编译环节,安全特性就形同虚设了)。同时,在交易执行环节运行编译器是非常耗时和复杂的,而且需要验证人完全信任编译器的正确定,因此Libra协议直接对编译器转码后的字节码进行安全性验证(bytecode verification),来保证Move语言的安全特性。
二是Move基于堆栈的字节码相对源码语言(source code/source language)形式而言,指令更少,这些指令的语义更为简单,仅需要简单微小的步骤即可实现。
交易脚本(Transaction scripts)
交易脚本是Libra协议的核心,交易脚本能够实现交易指令因为一个交易脚本其本质就是一个Move字节码程序。一个交易脚本能够通过自定义的逻辑,利用本地计算资源实现多个模型(modules)的发布并在账本状态中确认,例如向特定的收款人进行一次性付款。
Libra希望绝大多数的交易脚本都能够通过执行一次程序调用来实现常用功能。例如对于实现P2P付款的程序LibraAccount.pay_from_sender(recipient_address,amount),一笔涵盖recipient_address和amount参数的交易脚本就会触发上述P2P付款程序来实现类似以太坊上的代币转移。
模型(Modules)
模型是一组发布并记录在账本状态中的代码,模型在声明自身结构类型的同时也声明了程序,模型的结构包含有初始值的数值域,初始值可能是整数或者其他的数据结构值。
每个模型结构要么是资源型(resource),要么是非限制型(unrestricted)。非限制型结构并没有在复制(copy)和毁灭(destruction)方面的限制,但是,非限制型结构不能够包含资源型结构(直接或者间接),并且不能够在某个账户下被声明。
在面向对象的编程中,module/struct/procedure的关系就类似class/object/method(由左至右的包含关系)。但也是有区别的。一个模型可以声明多种结构类型,但在模型外是无法调用模型内数据的(没有声明public的字段)。模型的程序(procedure)是静态方法而非实例方法,在程序中没有self和this的概念。
Move模型与以太坊的智能合约概念相关,但又不同。以太坊上的智能合约既包括代码也包括数据,在Libra中,模型包含代码,资源包含数据。从面向对象的角度,以太坊的智能合约就类似在单个账户下发布一个singleton对象,而模型是创建资源的“菜谱”,它可以创建任意多个资源,并发布在不同的账户地址下。
Move虚拟机(The Move virtual machine)
Move虚拟机内嵌了一个Move字节码的验证器和解释器。开发者通过使用MoveIR编写交易脚本和模型,之后编译为字节码,编译器将结构化的控制流结构转化为无结构的控制流,将复杂的表述转化为简单的字节码数据。Move虚拟机是通过验证和运行字节码来执行一笔交易的。