MOVE VS Solidity :两个值得注意的区别点

MoveChina热度: 18468

事务脚本是原子的——要么完全执行,要么完全不执行。

原文作者:MoveChina

原文来源:Aptos World

如果你对 Aptos 感兴趣的话,那你应该对编程语言 MOVE 有更多的了解。这篇文章主要探讨 Move 语言的主要特征,以及它与另一种流行的智能合约编程语言——Solidity(在以太坊平台上)的主要区别是什么。

Move 是一种可执行的字节码语言,用于执行用户交易和智能合约。

有两点需要注意

1)Move 是一种可以直接在 Move 虚拟机上执行的字节码语言,而 Solidity(以太坊上的智能合约语言)是一种高级语言,它首先编译成字节码,然后在 EVM(以太坊虚拟机)上执行。

2)Move 不仅可以用于实现智能合约,还可以用于用户交易(稍后会详细介绍),而 Solidity 是一种仅用于智能合约的语言。Move 的一个关键特性是能够使用基于线性逻辑的语义自定义资源类型:资源类型:资源永远不能被复制或隐式删除,只能移动。在功能上,这类似于 Rust 语言的特性。Rust 中的值一次只能分配给一个名称,将值分配给另一个名称将使其无法在以前的名称下进行访问。

Solidity开放系统中数字资产的表示

实物资产中有两个属性难以用数字表示

1)稀缺性。必须控制系统中资产(发行)的数量。必须禁止复制现有资产,而创建新资产是一项特权操作。

2)访问控制。系统参与者必须能够使用访问控制策略保护资产。

这两个特性对于物理资产来说是很自然的,如果我们想将数字对象视为资产,也必须为数字对象实现这两个特性。例如,稀有金属具有天然稀缺性,只有您可以获取它(例如,将其握在手中),出售或消费它。为了说明我们是如何实现这两个属性的,让我们从以下句子开始:

建议#1:没有稀缺性和访问控制的最简单规则

Solidity

  • G[K]:=n 表示用新值 n 更新区块链全局状态中键 K 可用的数字。
  • 交易⟨Alice,100⟩表示将Alice的账户余额设置为100。上述解决方案中有几个主要问题:
  • Alice 只需发送交易 ⟨Alice, 100⟩ 即可接收无限数量的代币。
  • 爱丽丝发送给鲍勃的代币毫无价值,因为鲍勃可以使用相同的技术向自己发送无限数量的代币。

建议#2:核算赤字

现在我们监控情况,让 Ka 账户中代币的数量在转账交易之前至少等于 n。然而,虽然这解决了稀缺性问题,但没有规定谁可以发送代币给Alice(目前,任何人都可以这样做,只要你不违反数量限制规则)。

建议#3:结合稀缺性和访问控制

Solidity

我们通过在检查余额之前使用 verify_sig 数字签名机制来解决这个问题,这意味着 Alice 使用她的私钥签署交易并确认她是其代币的持有者。

区块链编程语言

现有的区块链语言面临以下问题(所有这些问题都在 Move 中得到了解决(注:不幸的是,文章作者在他的比较中只提到了以太坊,所以你应该只在这种情况下考虑它们。例如,EOS也解决了以下问题中的大部分)):

  • 资产的间接代表。资产使用整数编码,但整数值与资产不同。事实上,没有代表*比特币/以太/*的类型或值,使得编写使用资产的程序变得困难且容易出错。例如向/从过程传递资产或将资产存储在结构中等模式需要语言的特殊支持。
  • 赤字不可扩大。语言只代表一种稀缺资产。此外,对稀缺性的防御直接与语言本身的语义紧密相连。开发人员如果想要创建自定义资产,他必须自己仔细控制资源的各个方面。这些正是以太坊智能合约的问题。用户发行他们的资产,ERC-20 标准代币,使用整数来确定价值和总供应量。每当创建新代币时,智能合约代码必须独立检查该代币是否满足发行规则。此外,资产的间接表示在某些情况下会导致严重的错误——重复、双花,甚至资产的完全损失。
  • 缺乏灵活的访问控制。当前唯一的访问控制策略是使用非对称加密的签名方案。与稀缺保护一样,访问控制策略深深嵌入语言的语义中。但是如何扩展语言以允许程序员定义自己的访问控制策略通常是一项非常重要的任务。


对于以太坊来说也是如此,智能合约不支持用于访问控制的加密技术。开发人员必须手动编写访问控制,例如,使用 onlyOwner 修饰符。尽管我是以太坊的忠实粉丝,但出于安全目的,我认为资产属性应该由语言原生支持。特别是,将以太币传递到智能合约中可以实现动态调度,但这引入了一类新的漏洞,称为重入漏洞。这里的动态调度意味着代码执行逻辑将在运行时(动态)而不是在编译时(静态)确定。因此,在 Solidity 中,当合约 A 调用合约 B 的函数时,合约 B 可以运行合约 A 的开发者不打算执行的代码,这可能导致重入漏洞(合约 A 意外执行合约 B 的功能,在实际扣除账户余额之前提取资金)。

move语言设计基础

一级资源

在高层次上,Move 语言中的模块/资源/程序(procedures)之间的交互与 OOP 语言中的类/对象和方法之间的关系非常相似。Move 中的模块(modules)类似于其他区块链中的智能合约。该模块声明资源类型和程序,这些类型和程序定义了创建、销毁和更新已声明资源的规则。但这一切都只是 Move 中的惯例。稍后我们将说明这一点。

灵活性

Move 通过脚本增加了 Libra 的灵活性。Libra 中的每个事务都包含一个脚本,这实际上是事务的主要过程。该脚本可以执行一项指定的操作,例如,向指定的收款人列表付款,也可以重用其他资源,比如,通过调用定义公共逻辑的过程。这就是为什么 Move 事务脚本提供了很大的灵活性。一个脚本可以同时使用一次性行为和循环行为,而以太坊只能执行循环脚本(调用单个智能合约方法)。之所以称为“重复”,是因为智能合约功能可以多次执行。(注意:这里是非常微妙的。一方面,伪字节码形式的交易脚本也在比特币中。另一方面,据我所知,move将这种语言拓展到了成熟的智能合约语言水平)

安全性

Move 可执行格式是字节码,一方面,它是一种比汇编程序更高级的语言,但比源代码低级。字节码在运行时(链上)使用字节码验证器检查资源、类型和内存安全,然后由解释器执行。这种方法允许 Move 提供源代码的安全性,但无需编译过程,也无需向系统添加编译器。让 Move 成为字节码语言是一个非常好的主意。它不需要像 Solidity 那样从源代码编译,无需担心编译器基础设施可能出现的故障或攻击。

可验证性

我们的目标是使检查尽可能轻巧,因为它们都是链上链下静态验证工具。虽然这更可取,但验证工具(作为单独的工具包)的开发已被推迟到未来,目前仅支持运行时(链上)的动态验证。

模块化

move模块提供数据抽象和本地化关键资源操作。模块提供的封装与 Move 类型系统提供的保护相结合,确保模块类型上设置的属性不会被模块外的代码违反。这是一个经过深思熟虑的抽象设计,意味着合约内部的数据只能在合约执行的框架内更改,而不能从外部更改。

move 概览

示例事务脚本演示了模块外程序员的恶意或粗心行为不会危及模块资源的安全性。接下来,我们将看看如何使用模块、资源和程序(procedures)来对 Libra 区块链进行编程的示例。

Solidity

给出的代币数量将从发送者的余额转移到接收者。这里有几个新的注意点(以红色高亮显示):0x0:存放模块的账户地址Currency:模块名称Coin : 资源类型,程序返回的coin值是类型为0x0.Currency.Coin的资源值move() : 值(value)不能再次使用copy(): 值(value)可以稍后使用

让我们来分解代码:

在第一步中,发送者从存储在 0x0.Currency 的模块中调用一个名为withdraw_from_sender 的程序。第二步,发送方通过将coin资源的值转移到 0x0.Currency 模块的存款程序中,将资金转移给接收方。

以下是三个将被检查拒绝的错误示例代码:

通过将 move(coin) 调用更改为 copy(coin) 来复制资金。资源只能移动。尝试复制资源的数量(例如,通过在上面的示例中调用 copy(coin))将在字节码验证期间导致错误。通过指定 move(coin) 两次来重复使用资金。将0x0.Currency.deposit(copy(some_other_payee), move(coin)) 行添加到上面的示例中,将允许发送人两次“花费”代币 - 一次给收款人,一次给 some_other_payee。这是物理资产不可能发生的不良行为。幸运的是,Move 会拒绝这个程序。由于拒绝 move(coin)而造成的资金损失。如果资源未移动(例如,通过删除包含 move(coin) 的行),则会引发字节码验证错误。这可以保护 Move 程序员免受意外或恶意的资金损失。

Currency 模块

每个帐户可以包含 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 引用两个资源。

Coin资源声明

Solidity名为 Currency 的模块和名为 Coin 的资源类型一些关键点:

  • Coin 是 u64 类型的单字段结构(64 位无符号整数)
  • 只有 Currency 模块中的过程可以创建或销毁 Coin 类型的值。
  • 其他模块和脚本只能通过模块提供的公共过程写入或引用值字段。
实现存款

Solidity此过程将 Coin 资源作为输入,并将其与接收者帐户中持有的 Coin 资源连接起来:

  • 销毁输入资源 Coin 并写入其值。
  • 获取存储在收款人帐户中的唯一 Coin 资源的链接。
  • 调用程序时通过参数中传递的值更改Coin数量。

一些关键点:

  • Unpack, BorrowGlobal - 内置程序
  • Unpack是删除 T 类型资源的唯一方法。该过程将资源作为输入,销毁它,并返回与资源字段关联的值。
  • BorrowGlobal 将地址作为输入并返回对该地址发布(拥有)的唯一 T 实例的引用
&mut Coin 是指向Coin 资源的链接

实现 withdraw_from_sender

Solidity此过程:

  • 获取链接到发件人帐户的唯一 Coin 资源的链接
  • 通过引用将 Coin 资源的值减少指定数量
  • 创建并返回具有更新余额的新 Coin 资源。

一些关键点:

1、任何人都可以调用存款,但withdraw_from_sender 只能访问调用帐户的代币

2、GetTxnSenderAddress 类似于Solidity 中的msg.sender

3、RejectUnless 类似于Solidity 中的require。如果此检查失败,则事务的执行将停止并且所有更改都将回滚

4、Pack 也是一个内置过程,它创建一个类型为 T 的新资源

5、就像 Unpack 一样,Pack 只能在声明资源 T 的模块内调用。

声明:本文为入驻“MarsBit 专栏”作者作品,不代表MarsBit官方立场。
转载请联系网页底部:内容合作栏目,邮件进行授权。授权后转载时请注明出处、作者和本文链接。未经许可擅自转载本站文章,将追究相关法律责任,侵权必究。
提示:投资有风险,入市须谨慎,本资讯不作为投资理财建议。
免责声明:本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况,及遵守所在国家和地区的相关法律法规。