接下来,我们将详细研究Move语言的主要特征及其与另一种已经流行的智能合约语言-Solidity(在以太坊平台上)的主要区别是什么。 该材料基于对可用的在线26页白皮书的研究。
引言
Move是一种可执行的字节码语言,用于执行用户交易和智能合约。 注意两点:
- 尽管Move是可以直接在Move虚拟机上执行的字节码语言,但是Solidity(以太坊中的智能合约语言)是一种高级语言,在EVM(以太坊虚拟机)中执行之前,它首先被编译为字节码。 )
- 移动不仅可以用于智能合约的实现,还可以用于用户交易(稍后会详细介绍),而Solidity是仅用于智能合约的语言。
由INDEX协议项目团队进行的翻译。 我们之前翻译了很多描述Libra项目的材料 ,现在轮到更深入地了解Move语言了。 翻译是与coolsiu一起完成的Move的一个关键功能是能够使用线性逻辑语义定义自定义资源类型:永远不能复制或隐式删除资源,只能移动资源。 从功能上讲,这类似于Rust语言的功能。 Rust中的值一次只能分配给一个名称。 将值分配给另一个名称将使其无法使用以前的名称进行访问。

例如,以下代码片段将引发错误:
使用移动值'x'。 这是因为Rust中没有垃圾回收。 当变量超出范围时,它们所引用的内存也会被释放。 简而言之,数据只能有一个“所有者”。 在此示例中,
x是原始所有者,然后
y成为新所有者。
在此处阅读有关此行为的更多信息 。
开放系统中数字资产的表示
有形资产的两个属性很难用数字表示:
- 稀有度 (稀缺性,原为-稀缺性)。 系统中的资产(发行)数量应受到控制。 必须禁止现有资产的重复,并且创建新资产是一项特权操作。
- 访问控制 。 系统参与者必须能够使用访问控制策略保护资产。
如果我们想将数字资产视为资产,则对数字对象必须实现这两个对于自然资产而言很自然的特性。 例如,一种稀有金属-具有天然赤字,只有您有权使用(例如,掌握在手中),您才能出售或花费它。
为了说明我们如何达到这两个属性,让我们从以下句子开始:
命题1:没有稀缺性和访问控制的最简单规则

- G [K]:= n表示用新值n更新在区块链全局状态下密钥K可访问的数字。
- 交易“爱丽丝,100”表示将爱丽丝的帐户余额设置为100。
上面的解决方案有几个严重的问题:
- 通过发送交易⟨Alice,100⟩, Alice可以接收无限数量的硬币。
- 爱丽丝发送给鲍勃的硬币是没有用的,因为鲍勃可以使用相同的技术向自己发送无限数量的硬币。
提案2:考虑到赤字

现在,我们正在监视这种情况,以便在转账交易之前,
Ka硬币的数量至少为
n 。 尽管如此,尽管这解决了短缺问题,但是却没有关于谁可以发送爱丽丝硬币的信息(到目前为止,每个人都可以这样做,主要是不违反数量限制规则)。
命题3:结合缺陷和访问控制

我们在检查余额之前使用
verify_sig数字签名
机制解决了这个问题,这意味着Alice使用她的私钥对交易进行签名并确认她拥有自己的硬币。
区块链编程语言
现有的区块链语言面临以下问题(所有问题均在Move中解决(注意:
不幸的是,本文的作者仅在比较中吸引了以太坊,因此您仅应在这种情况下使用它们。例如,以下大多数情况也已在EOS中解决) )):
资产的间接表示 。 资产使用整数进行编码,但整数值与资产不同。 实际上,没有代表比特币/以太币/ <任何硬币>的类型或值! 这使得编写使用资产的程序变得困难且容易出错。 诸如将资产转移到过程或从过程转移资产或将资产存储在结构中的模式需要特殊的语言支持。
赤字是不可扩大的 。 语言仅代表一种稀缺资产。 此外,针对赤字的补救措施直接硬连接到语言本身的语义中。 开发人员如果要创建用户资产,必须自己仔细监视资源的各个方面。 这些只是以太坊智能合约的问题。
用户使用整数确定其成本和总发行量来发行资产(ERC-20标准令牌)。 每当创建新令牌时,智能合约代码都必须独立验证是否符合排放规则。 另外,资产的间接表示在某些情况下会导致严重的错误-重复,重复支出甚至完全损失资产。
缺乏灵活的访问控制 。 当前唯一使用的访问控制策略是使用非对称密码的签名方案。 与缺陷保护一样,访问控制策略也深深地嵌入到语言的语义中。 但是如何扩展语言以允许程序员定义自己的访问控制策略通常是一项非常艰巨的任务。
以太坊也是如此,因为智能合约没有访问控制的本地加密支持。 开发人员必须手动规定访问控制,例如,使用onlyOwner修饰符。
尽管我是以太坊的忠实拥护者,但出于安全原因,我认为资产属性应由该语言本地支持。 特别是,将以太币转移到智能合约涉及动态调度,这导致出现了称为重新进入漏洞的新型错误。 这里的动态分派意味着代码执行的逻辑将在运行时(动态)而不是编译时(静态)确定。
因此,在Solidity中,当合同A调用合同B的功能时,合同B可以运行未由合同A的开发人员提供的代码,这可能导致
重新输入漏洞 (合同A意外执行合同B的功能以在实际扣除之前扣除资金)帐户余额)。
移动语言设计基础
一阶资源
在更高层次上讲,Move语言中的模块/资源/过程之间的交互与OOP语言中的类/对象与方法之间的关系非常相似。
Move中的模块类似于其他区块链中的智能合约。 该模块声明资源类型和过程,以设置用于创建,销毁和更新声明的资源的规则。 但这只是Move中的约定(“
行话 ”)。 稍后,我们将说明这一点。
柔韧性
Move通过脚本编写增加了Libra的灵活性。 Libra中的每个事务都包含一个脚本,该脚本实际上是主要的事务过程。 该脚本可以执行一个指定的操作,例如,根据指定的收件人列表进行付款,或重用其他资源-例如,通过调用在其中指定了通用逻辑的过程。 这就是移动事务脚本提供更大灵活性的原因。 该脚本可以使用一次性行为和重复行为,而以太坊只能执行重复脚本(通过调用一种方法来调用智能合约方法)。 之所以称为“多个”,是因为智能合约的功能可以多次执行。 (请注意:
此刻的情况非常微妙。一方面,伪字节码形式的交易脚本也采用比特币。另一方面,据我了解,Move将该语言实际上扩展到了成熟的智能合约语言的水平 )。
安全性
Move可执行文件格式是字节码,一方面,它是比汇编程序更高级别但比源代码更低级别的语言。 使用字节码验证程序在链上检查字节码的资源,类型和内存安全性的可用性,然后由解释器执行。 这种方法允许Move提供特定于源代码的安全性,但无需编译过程,也无需向系统添加编译器。 使移动字节码语言是一个非常好的解决方案。 无需像Solidity一样从源代码进行编译,也不必担心编译器基础结构可能发生的崩溃或攻击。
可验证性
我们的目标是执行尽可能简单的检查,因为所有这些操作都是在链上进行的(注意:
在每笔交易的过程中都是在线的,因此任何延迟都会导致整个网络的速度下降 ),但是,语言设计最初已准备就绪,可以使用和链下静态验证方法。 尽管这是更可取的,但到目前为止,验证工具(作为单独的工具包)的开发已推迟到将来,现在仅支持运行时(链上)的动态验证。
模块化
移动模块提供数据抽象,并在资源上本地化关键操作。 模块提供的封装与Move类型系统提供的保护相结合,确保模块外部的代码不会违反为模块类型设置的属性。 这是一种经过深思熟虑的抽象设计,这意味着合同内部的数据只能作为合同执行的一部分进行更改,而不能从外部进行更改。

移动评论
示例事务脚本演示了模块外部程序员的恶意或鲁re行为不会违反模块资源的安全性。 接下来,我们将看一下如何使用模块,资源和过程对Libra区块链进行编程的示例。
点对点付款

金额中指定的硬币金额将从发件人的余额转移到收件人。
有几个新点(以红色突出显示):
- 0x0 :存储模块的帐户地址
- 货币 :模块名称
- 硬币 :资源类型
- 该过程返回的硬币值是类型为0x0.Currency.Coin的资源值。
- move() :值不能再次使用
- copy() :值可以在以后使用
我们解析代码:第一步,发送者从存储在
0x0.Currency中的模块调用一个名为
withdraw_from_sender的过程。 在第二阶段,发送者将资金转移到接收者,将硬币资源的值移到模块
0x0.Currency的存款过程中。
这是三个将被检查拒绝的代码错误的示例:
通过更改移动(硬币)到复制(硬币)的呼叫来重复资金 。 资源只能移动。 尝试复制资源量(例如,在上面的示例中,通过调用
copy(硬币) )将在检查字节码时导致错误。
通过两次指定移动(硬币)来重复使用资金 。 在上面的示例中,添加行
0x0.Currency.deposit(复制(some_other_payee),移动(硬币)) ,将允许发送方“花费”两次硬币-第一次与收款人,第二次与
some_other_payee 。 这是不良行为,对于有形资产是不可能的。 幸运的是,Move将拒绝该程序。
由于移动失败(硬币)而导致资金损失 。 如果您不移动资源(例如,通过删除包含
move(coin)的行 ),则通过检查字节码将产生错误。 这样可以保护Move程序员免受意外或恶意的资金损失。
货币模块

每个帐户可以包含0个或多个模块(以矩形表示)和一个或多个资源值(以圆柱体表示)。 例如,位于
0x0的帐户包含一个
0x0.Currency模块和一个类型为
0x0.Currency.Coin的资源值。
0x1的帐户有两个资源和一个模块。
0x2的帐户具有两个模块和一个资源值。
一些要点:
- 事务脚本是原子的-要么完全执行,要么根本不执行。
- 模块是全球可用的长期代码段。
- 全局状态被构造为哈希表,其中的键将是帐户地址
- 帐户最多只能包含一个这种类型的资源值,并且不能包含一个具有给定名称的模块( 0x0帐户不能包含其他资源0x0.Currency.Coin或另一个名为Currency的模块)
- 声明的模块的地址是该类型的一部分( 0x0.Currency.Coin和0x1.Currency.Coin是单独的类型,不能互换使用)
- 程序员可以通过定义其自定义资源-( 资源TwoCoins {c1:0x0.Currency.Coin,c2:0x0.Currency.Coin} )在帐户中存储此类资源的多个实例。
- 您可以按名称无冲突地引用资源,例如,可以使用TwoCoins.c1和TwoCoins.c2引用两个资源。
硬币资源广告

名为
Currency的模块和名为
Coin的资源类型
一些要点:
- 硬币是u64类型的单字段结构(64位无符号整数)
- 只有货币模块过程可以创建或销毁硬币值。
- 其他模块和脚本只能通过模块提供的开放过程来写入或引用值字段。
存款执行

此过程将
Coin资源作为输入,并将其与存储在收件人帐户中的
Coin资源进行组合:
- 销毁硬币输入资源并记录其价值。
- 获取指向收件人帐户中存储的唯一硬币资源的链接。
- 通过调用该过程时在参数中传递的值来更改硬币金额的值。
一些要点:
- 解压,BorrowGlobal-内置程序
- Unpack <T>是删除类型T的资源的唯一方法。该过程将资源带到输入中,销毁它并返回与资源字段关联的值。
- BorrowGlobal <T>接受地址作为输入,并返回到该地址发布(拥有的)T的唯一实例的链接
- &mut Coin是Coin资源的链接
实现withdraw_from_sender

此过程:
- 获取指向链接到发件人帐户的唯一硬币资源的链接
- 通过参考指定数量减少硬币资源的价值
- 创建并返回具有更新余额的新硬币资源。
一些要点:
- 任何人都可以调用存款 ,但是withdraw_from_sender只能访问主叫账户的硬币
- GetTxnSenderAddress与Solidity中的msg.sender相似
- RejectUnless与Solidity中的要求相似。 如果此检查失败,则事务将停止并且所有更改都将回滚。
- Pack <T>也是一个内置过程,可创建类型为T的新资源。
- 像Unpack <T>一样 , Pack <T>只能在描述资源T的模块内部调用
结论
我们研究了Move语言的主要特征,将其与以太坊进行了比较,并熟悉了脚本的基本语法。 总之,我强烈建议您仔细阅读
原始白皮书 。 它包括有关编程语言设计原理的许多详细信息,以及许多有用的链接。