• 元宇宙:本站分享元宇宙相关资讯,资讯仅代表作者观点与平台立场无关,仅供参考.

Move vs. Rust:深入了解Move编程语言(下)

  • FastDaily
  • 2022年9月27日12时

本文属于老雅痞原创文章,转载规矩不变,给我们打声招呼~

转载请微信联系:yaoyoabigc,更多DAO、Web3、NFT、Metaverse资讯请关注老雅痞

导读


今日FastDaily共推送3篇文章。


Move如何做到在没有账户检查的同时又同样安全?推荐阅读本文。


第一条是我们的原创文章,为你说明白Aave Arc、RWA Markets、Centrifuge 是如何切入现实金融的。


我们说Web3比较吸引人的一点,就是它对创作者的“优待”,具体怎么个“优待”呢,第二条是我们的原创,给你说清楚创作者经济到底是怎么一回儿事。


RR丨编译

信息来源自medium,略有修改,作者Kreimir Klas

上篇我们说到Move如何做到在没有账户检查的同时又同样安全。Move vs. Rust:深入了解Move编程语言(上)


现在让我们仔细看看这些检查的实际作用。下面是mint_to指令所需的账户检查(权限持有人通过调用该指令来铸造代币):



有6项检查(用红色标出):


  1. 检查所提供的lock account是否属于此智能合约并为MintLock类型。

  2. 检查所提供的铸币权限帐户是否属于所提供的lock。

  3. 检查指令调用者是否拥有此权限(签名交易所需的权限)所需的密钥。

  4. 需要传入代币目标帐户,因为代币程序将在CPI调用中对其进行更改(添加余额)。严格地说,这里并不需要mint检查,因为如果传入了错误的账户,CPI调用就会失败,但尽管如此,还是要进行这种检查。

  5. 类似于4。

  6. 检查代币程序帐户是否正确传入。


我们可以看到账户检查(在这个例子中)分为以下五类:


  • 账户所有权检查(1,2,4,5)

  • 帐户类型检查(1,2,4,5)

  • 帐户实例检查(是否传入了某个帐户类型的正确实例)(2,5)

  • 账户签名检查(3)

  • 程序帐户地址检查(6)


注意:这并没有涵盖所有类型的账户检查,但这足以说明问题。


但是在Move中却不需要帐户检查或任何类似的东西。我们只需要函数签名:



mint_balance函数只需要四个参数。在这四个参数中,只有lock和cap表示对象(有点类似于帐户)。


那么,在Solana中,我们需要申报6个账户,并手动对其进行各种检查,而在Move中,我们只需要传入2个对象,且不需要进行明确的检查。这是怎么做到的呢?


在Move中,有些检查是由runtime透明地完成的,有些是由验证器在编译时静态地完成的,而有些则是在构造上根本不需要的。让我们来看看:


  • 帐户所有权检查——由于Move的类型系统设计,没有必要进行帐户所有权检查。Move结构只能通过其模块中定义的函数进行更改,而不能直接进行变动。字节码验证保证了结构实例可以自由地流入不受信任的代码(其他模块),而不会被非法改动。

  • 帐户类型检查——没有必要,因为Move类型存在于整个智能合约中。类型定义被嵌入到模块二进制文件中(模块二进制文件是在区块链上发布并由VM执行的)。在编译/发布期间调用函数时,验证器将检查传递的类型是否正确。

  • 帐户实例检查——在Move中(有时在Solana上也是如此),你将在函数主体中执行此操作。在这个特定的例子中没有必要这样做,因为用于lock和cap参数类型的通用类型参数T强制要求传入的cap (mint能力/权限)对象正确匹配它的lock(每个Coin类型T只能有一个lock)。

  • 帐户签名检查——我们在Sui中不直接处理签名。对象可以由用户拥有。mint权限是由mint能力对象(由管理员创建)的所有权授予的。将这个对象的引用传递给mint_balance函数将允许我们进行铸币。所有对象只能由其所有者在交易中使用。换句话说,对象签名检查是由runtime透明地完成的。


从本质上说,Move利用字节码验证,以便为数字资产编程提供更自然的编程模型。Solana的模型围绕着帐户所有权、签名、CPI调用、PDA等。但是如果我们退一步想一下,我们会发现我们并不是真的想处理这些问题。它们本身与数字资产没有任何关系——相反,我们必须使用它们,因为它允许我们在Solana的编程模型中实现所需的功能。


在Solana上,由于没有字节码验证来保证更细化的类型或资源安全,你不能允许任何程序改变任何帐户,因此引入帐户所有权的概念是必要的。出于类似的原因(没有跨程序调用的类型/资源安全),也没有可以进出程序的用户所有对象的概念,相反,我们用账户签名来证明权限。由于有时程序也需要能够提供帐户签名,所以我们有PDA…


虽然你可以在Solana上拥有与Move中相同的跨程序类型和资源安全,但你必须使用低级构建块(帐户签名、PDA……)手动实现它。最终我们所做的是使用低级原语来构建可编程资源(线性类型)。而这就是账户检查的作用——它们是手动实现类型安全和建模资源所需的开销。


Move会对资源进行原生抽象,这使我们可以直接使用资源,而不需要引入PDA等任何低级构建块。跨智能合约边界的类型和资源安全保证将由验证器来确保,不需要手动实现。


5.3. Solana可组合性的局限性


我想再举一个例子,突出Solana上智能合约可组合性的一些痛点。


我们已经在Mint Authority Lock示例中看到,与Sui相比,我们需要在Solana上申报更多的输入(Solana上有6个帐户,而在Sui上只有2个对象的mint_to调用)。显然,处理6个帐户比处理2个对象要麻烦得多,特别是考虑到我们还需要为帐户实现帐户检查。理论上来说,这仍然是可控的,但当我们开始在单一的调用中把多个不同智能合约组合在一起时会发生什么?


假设我们想要创建一个智能合约,完成以下工作:


  • 它拥有来自Token mint Lock程序(如前一节所述)的某个Token的mint权限

  • 当它被调用时,它将使用其权限铸造户指定数量的代币,使用AMM将其交换为不同的代币,并在同一条指令中将将发送给用户


本例的重点是说明如何将Mint Authority Lock智能合约和AMM智能合约组合在一起。这纯粹是一个假设性的例子,在现实生活中可能没有任何用处,但可以用来说明问题——现实中组成智能合约的例子与此没有太大区别。


帐户检查执行此操作的指令调用可能如下所示:



而在Sui上,一个相当的函数的签名是这样的:



那么为什么我们在Sui上传递的对象与Solana上的账户相比要少得多呢?


从根本上说,这是因为在Move中我们能够嵌入它们。类型系统的安全保证使我们能够做到这一点。


下面是Solana帐户和持有AMM池状态的Sui对象之间的比较:



我们可以看到,在Solana上我们存储了其他帐户的地址(Pubkey),这些地址就像指针一样,并不存储实际数据。为了访问这些账户,它们需要被单独传入,并且我们还需要手动检查是否正确的帐户已经被传入。在Move中,我们能够将结构相互嵌入并直接访问它们的值。我们可以混合和匹配来自任何模块的类型,同时保留它们的资源和类型的安全保证。这都是得益于Move的全局类型系统和字节码验证所支持的资源安全。

但在组合多个智能合约时,必须传递(并因此检查)多个帐户,这导致实施非常复杂,并存在安全隐患。这些账户之间的关系可能相当复杂,在某种程度上,跟踪所有必要的账户检查以及它们是否被正确处理变得相当困难。

事实上,我认为这就是发生在Cashio漏洞(4800万美元)中的情况。以下是导致该漏洞的帐户检查的明细。正如你所看到的,这些帐户检查可能有些复杂。开发人员可能非常希望进行适当的检查,但是在某种程度上,他们的精神压力变得过大,很容易出错。账户越多,出现漏洞的几率就越高。

Move的全局类型系统和更自然的编程模型意味着,我们可以在达到心理压力的极限之前,以更安全的方式进一步推进智能合约组合。

顺便说一下,与Rust/Anchor相比,Move的安全性还有一个值得考虑的问题,这可能不是很明显。Move的TCB(可信计算基础)比Rust/Anchor要小得多。更小的TCB意味着需要信任的智能合约编译和执行的组件更少。这减少了可能影响智能合约的漏洞的大小——TCB之外的漏洞不会影响智能合约的安全性。

Move的设计考虑到了减少TCB——为了尽可能地减少TCB,Move做出了许多决定。字节码验证器将Move编译器执行的许多检查从TCB中移除,而在Rust/Anchor中,有更多的组件需要被信任,因此安全错误的影响范围就越大。

6.Solana上的Move

显然,Move非常棒。我们还知道,Solana被设计成允许使用其他编程语言为其开发智能合约。现在的问题是,我们能否在Solana上拥有Move,以及如何拥有?

6.1. 拥有全局类型安全的Anchor?

在我们开始研究Move on Solana之前,让我们先简单看看Anchor,并做一个小小的思维实验。也许我们可以以某种方式升级Anchor,以提供我们从Move中获得的一些好处?也许我们可以通过程序调用获得对类型安全的原生支持?毕竟,Anchor指令已经类似于Move的入口函数:

// Function signatures of the "mint to" function from the

// "Mint Authority Lock" smart contract from the previous chapter.

// Sui Move

public entry fun mint_balance(

Lock:&mut TreasuryLock,

Cap:&mut MintCap,

Amount:u64,

Ctx:&mut TxContext

) {

// Anchor

pub fn mint_to(ctx:Context, amount:u64) -> Result<()> {

也许如果我们以某种方式扩Anchor,允许在指令参数中直接传递账户:

// Anchor modified

pub fn mint_to(

lock:&mut MintLock,

Authority:&mut MintAuthority,

Amount:u64

) -> Result<()> {

我们可以避免做账户检查吗?

在这种情况下,我们希望类型检查由runtime而不是程序来完成——runtime将读取Anchor的帐户判别器(或等效的东西),并能够检查传入的帐户是否匹配所需的判别器(Anchor帐户的前8个字节)。

但是请记住,Solana并不对同一程序的不同指令调用进行区分,这是由程序手动实现的(在这种情况下,繁重的工作由Anchor完成)。因此,为了做到这一点,runtime必须以某种方式了解不同的指令,它们的签名,并拥有关于类型的信息。

Solana程序编译为SBF (Solana Bytecode Format,eBPF的一种修改版本),并上传到链上。SBF本身不嵌入任何对我们有帮助的类型或函数信息。但是也许我们可以修改SBF,以允许指令和类型信息被嵌入二进制文件中?那么所需的指令和签名信息就可以由runtime从二进制文件中读取。

我们确实可以这么做。这将是一个相当大的工程,特别是如果你考虑到我们需要保持与旧程序的向后兼容性,但以下是我们将得到的好处:

  • 帐户所有权和类型检查由runtime,而不是在程序中完成。

  • 对于在编译时已知地址的帐户(例如程序帐户),我们可以避免从客户端传入,这些账户现在可以由runtime传入。

  • 如果我们还设法将帐户约束嵌入到二进制文件中,我们就可以通过使用runtime动态递归地加载帐户(基于嵌入的约束信息)来进一步减少必须由客户端传入的帐户数量。

我们仍然没有得到以下好处:

  • 嵌入式账户。我们仍然必须使用Pubkey来引用其他帐户,而不是能够直接嵌入他们。这意味着我们无法摆脱5.3节中描述的帐户膨胀问题。

  • 在进行跨程序调用时,帐户类型检查仍然需要在runtime中动态执行,而不是像Move中那样在编译时静态执行

虽然这些好处确实不错,但从智能合约开发的角度来看,它们并没有从根本上改变什么。在runtime而不是在程序中进行类型检查可能会带来一些性能上的好处,并且不必传递在编译时从客户端手动传递地址的帐户,这在一定程度上提高了效率。但是,尽管这些效率和性能改进确实有所帮助,但我们最终还是要处理Solana的编程模型,它本身并没有在处理数字资产上提供多少帮助——我们仍然没有原生的资源安全,我们不能嵌入帐户,所以仍然有帐户膨胀问题,我们仍然要处理帐户签名和PDA……

理想情况下,我们希望所有智能合约都存在于单一类型系统中,并且能够像Move中那样自由地传递对象。但由于其他智能合约不可信,我们无法直接做到这一点。为了解决这个问题,Solana设有程序分离和帐户所有权——每个程序管理自己的帐户,它们通过CPI调用进行交互。这很安全,并且允许充分的可编程性,但由此产生的编程模型并不理想——没有全局类型系统,也就没有真正的资源安全。

我们希望有一个自然的编程模型,但同时我们也在使用不受信任的代码。虽然在Solana上我们可以安全地使用不受信任的代码,但这使得在编程模型上会有所妥协。字节码验证使两者同时存在成为可能。所以如果没有它,我们似乎真的无法大大改进编程模型……

6.2. Solana字节码格式


如前所述,SBF (Solana字节码格式)是Solana智能合约基于eBPF的编译和链上存储格式。在Solana上使用eBPF而不是任何其他字节码格式(如WASM)作为基础的主要动机是,Solana对安全和性能智能合约执行的要求与eBPF设计的内核沙盒程序执行的要求相一致(它也需要安全和高性能)。

理论上,eBPF确实是一个可靠的选择。它的高性能,围绕安全的设计,有限的程序大小和指令数量…看起来很不错!

但让我们看看这在实践中意味着什么。也许我们可以以某种方式利用eBPF验证器来提高我们智能合约的安全性?以下是eBPF验证器所做的一些事情。

  • 不允许无限循环

  • 检查程序是否是DAG

  • 不允许越界跳转

  • 在执行各种helper函数调用时检查参数类型

禁止越界跳转似乎很有用,但其他的就没那么有用了。事实上,强制程序必须是DAG并且没有无限循环是有问题的,因为它极大地限制了可编程性。在eBPF程序中需要这样做的原因是,验证器需要确定程序在一定数量的指令内终止,而gas计量不是一个选项,因为它会大大阻碍性能。

虽然这种权衡对于实现高性能防火墙来说很好,但对于智能合约开发来说就不是那么好了,而且绝大多数eBPF验证器不能用于Solana程序。事实上,Solana甚至根本就没有使用原始的eBPF验证器。它使用了一个(更基本的)自定义验证器,主要检查指令是否正确以及是否有越界跳转。

除了验证器之外,对于编译智能合约来说,还有一些其他的eBPF细节存在一些问题。比如,eBPF被设计为最多允许向一个函数调用传递5个参数。这实际上意味着Rust标准库不能直接编译到eBPF。或者堆栈大小被限制为512字节,这减少了我们可以传递给函数的参数大小。

因此,即使Rust编译到LLVM,有一个用于LLVM的eBPF后端,甚至支持Rust编译器以eBPF为目标,你仍然不能使Solana智能合约按它本身的方式编译到eBPF。这就是为什么Solana团队不得不对Rust代码库和eBPF LLVM后端进行多次更改(例如支持通过堆栈传递参数)。

由于其中一些更改本质上不是上游可用的(无论是Rust还是LLVM),所以Solana团队目前在维护Rust和LLVM的分叉时进行了这些修改。当你执行cargo build-bpf(构建Solana智能合约的规范命令)时,cargo将拉出这个Solana特定版本的rustc来进行智能合约编译。

这就是SBF诞生的原因——Solana需要的一些要求与eBPF不兼容。Solana团队目前正致力于将SBF作为独立的LLVM后端进行升级,并将其添加为Rust目标,以避免不得不维护单独的分叉。

因此,尽管eBPF可以作为智能合约的一种格式,但它并不像理论上看起来那么理想。它需要进行一些修补,而且原来的验证器也用处不大。

在关于Move和Solana/SBF的讨论中,我还看到一个误解,我认为这是非常重要的。有人评论说,Move的主要思想应该适用于SBF,因为它基于eBPF,也许可以利用其验证器做静态的账户改动检查,而不是在runtime中动态地进行。

在我看来,这是一个令人怀疑的说法。即使有可能证明,程序不会在eBPF中改动他们并不拥有的账户,但这肯定不是Move的主要思想。

Move的主要思想是使一个以资源为中心的编程模型能够以一种自然的方式与不受信任的代码交互。

在实践中,这意味着:


  • 全局类型安全

  • 资源安全(key, clone, store, drop)

  • 可嵌入的资源

  • 资源安全地进出不受信任的代码

  • ...

第五章的Flash Lending、Mint Authority Lock、Solana可组合性的局限性说明了这在智能合约安全性、可组合性和人机工程学方面的重要性。其影响远远超出了跳过一些runtime安全检查来提高跨程序调用的性能。这一点不容小觑。


现在,如果你想知道把主要的Move思想带入eBPF/SBF有多困难,答案是非常困难。如果不对eBPF进行重大修改,就不可能强制执行诸如“此不受信任的代码不应能够删除一个T”这样的属性。事实上,这需要大量的修改,以至于最终你将得到一个看起来更像Move而不是eBPF的新字节码。这无疑将是一项繁杂的研究工作。

事实上,一开始Move的诞生也是基于类似的思路。Move团队(当时在Diem)最初考虑从WASM、JVM或CLR等其他格式开始,但事后添加这些实在太难了。因此,Move是从零开始设计的,其理念是通过轻量级验证器通道有效地执行这些检查。

如果你仔细想想,这其实并不奇怪。归根结底,智能合约编程不是系统编程、后端编程或任何其他类型的传统编程。这是一种完全不同的编程类型。

明确一点,我不是在批评索拉纳选择eBPF。事实上,我认为这是一个非常可靠的选择,也是团队考虑到背景的良好判断。事后看来,该团队选择使用WASM而不是eBPF可能是因为WASM在Rust中有一流的支持,因此可以避免前面提到的将智能合约编译成eBPF的问题。但考虑到对性能的强调,团队可能会觉得eBPF是一个更安全的选择。此外,在做出这些设计选择时,Move甚至还没有公布,从头创建一门新语言对初创公司来说肯定不是一个合理的选择。最终,Solana成功地推出了一个高性能L1,这才是最重要的。

6.3. 在Solana上运行Move

扩展eBPF/SBF来支持Move功能似乎很困难,我们可能最终会得到类似于Move字节码的东西。与其试图改进SBF,也许我们应该以某种方式让Move直接在Solana上运行?毕竟,Solana对支持智能合约开发的多种编程语言持开放态度,甚至Anatoly在他的一些推文中也鼓励Move被整合。

似乎有三种方法可以让Move出现在Solana上:


  1. 将Move VM添加为本机加载器(与SBF VM一起)

  2. 将Move VM作为程序运行(如Neon)

  3. 将Move编译为SBF(如Solang)

让我们先讨论(3)。这里的想法是为Move构建一个LLVM前端,以便将其编译为SBF。编译到SBF的移动智能合约可以以与在Rust(或编译到SBF的任何其他语言)中构建的智能合约相同的方式透明地执行,并且runtime不需要对Move有任何区分或了解。从runtime的角度来看,这将是一个非常优雅的解决方案,因为它不需要对其或其安全假设进行任何更改。

但从智能合约的角度来看,这并没有太大的影响。虽然有真正的理由为Move构建一个LLVM前端,例如为了性能或可移植性,但在我看来,使用SBF runtime执行Move智能合约并没有带来太多好处。事实上,我认为以这种方式开发智能合约会比直接使用Anchor更糟。

通过(3)所得到的是Solana编程模型中的Move语法。这意味着在第5章中讨论的Move的所有重要优势(全局类型安全、全局资源安全、可嵌入对象……)将不复存在。相反,我们仍然需要处理帐户检查、CPI调用、PDA等问题,就像在Rust中一样。由于Move不支持宏,因此不可能使用eDSL实现Anchor这样的框架来简化其中的一些操作,所以代码将类似于原始的Rust(但可能更糟)。Rust标准库和生态系统也不可用,所以像帐户序列化和反序列化这样的事情必须在Move中重新实现。

Move不太适合与其他编程模型一起使用。这是因为它被专门设计为能够编译到Move字节码并通过验证器。去掉字节码就放弃了Move的所有主要好处。正如《Resources:A Safe Language Abstraction for Money》一文所述:

Move的显著特征是可执行的字节码表示,为所有程序提供了资源安全保证。考虑到合约的开放部署模型,这一点至关重要——回想一下,任何合约都必须容忍与不可信代码进行任意交互。如果源码级线性可以被可执行级别上不受信任的代码违反,那么其价值就很有限。

虽然Move的类型、资源和内存安全特性将在程序级别上保留,但它们不会被全局保留。程序级别的安全性并没有带来什么新东西——我们在很大程度上已经在Rust中具备了这一点。


Move的智能合约生态系统也不能在Solana上使用——其编程模型非常不同,智能合约的重要部分必须重写。


考虑到所有这些,我预计用(3)实现的Move的方法不会被接受——与Anchor相比,它使用起来太麻烦了。在某些方面,它可能比原始Rust还要麻烦。

至于(1),这里的想法是(与SBF加载器一起)在runtime添加对Move加载器的支持。Move智能合约将被存储为链上的Move字节码,并由Move VM执行(就像在Sui中一样)。这意味着我们将拥有一个SBF智能合约的生态系统和一个Move智能合约的生态系统,前者将在当前的Solana编程模型上运行,而后者将在(可以说是更高级的)Move模型上运行。

通过这种方法,我们可以保持Move智能合约相互交互的所有好处,但这里的一个很大的挑战是使Move智能合约能够与SBF智能合约交互,反之亦然。实现这一点将具有挑战性——你需要一个深刻理解Move和Solana的人。验证器也必须进行调整。

还有一个缺点是需要在运行时维护两个不同的加载器。这会有安全隐患,因为这意味着攻击面会翻倍-任何加载器中的一个bug都可能意味着整个链被利用。顺便提一下,实际上早在2019年,Solana就添加了对Move VM的早期支持,但后来由于安全考虑被删除。

至于(2),其想法是将整个Move VM作为一个Solana程序(智能合约)运行。Move VM是用Rust实现的,所以可以将它编译成SBF(除非它使用线程或其他不支持的API)。尽管这听起来很疯狂,但Neon已经实现了一种类似的方法,将EVM作为Solana程序运行。这种方法的好处是不需要对runtime进行更改,并且可以保持相同的安全假设。

我不熟悉Move VM的技术细节,所以我不能对它的可行性和局限性发表太多评论。我想到的第一件事是,验证器也必须作为一个程序运行。这种方法也会遇到与(1)相同的SBF和Move智能合约之间的互操作性问题的影响。

要将Move的主要功能带到Solana并没有什么简单的方法。虽然可以构建一个LLVM前端并将Mov编译为SBF,但这不会有什么作用,因为编程模型将保持不变。正如第6.1节中的思维实验所说明的那样,在这种情况下,如果不进行某种字节码验证,就无法改进编程模型。更改eBPF/SBF以支持字节码验证将非常困难。似乎唯一合理的选择是让Move VM以某种方式运行起来。但这意味着将会有两个生态系统在不同的编程模型上运行,而让它们正确地互操作是非常具有挑战性的。

6.4. Move的性能


Move字节码不是一种通用的字节码语言。它有一个非常有主见的类型系统,为了允许所有必要的验证,它的水平相当高。这可能意味着与eBPF /SBF等更接近原生代码的其他字节码格式相比,其性能更低,有人可能会说,这对于在高性能的L1中使用是一个问题。

但是智能合约执行目前还没有成为Solana(在撰写本文时,Solana的平均速度是3k TPS)和Sui(基于团队完成的初始端到端基准测试)的瓶颈。提高交易处理性能的主要驱动因素是并行执行。Solana和Sui都要求预先声明依赖关系,并对依赖不同对象/账户集的交易的执行进行并调度,从而实现了这一点。

此外,一旦TX执行出现在关键路径上,没有任何东西可以阻止Move被AOT编译或JIT化以提高其性能。这就是为Move构建LLVM前端的好处所在。此外,由于Move对静态分析的固有适应性,Move可以获得其特有的进一步优化。

考虑到所有这些,我预计Move的性能在可预见的未来不会成为一个重要的障碍。

7. Move的其他特性


在这一章中,我将描述Move的其他一些特性,它们可能不是本文讨论的中心,但仍然相关。

7.1. 验证器

Move为智能合约提供了一个名为Move Prover的正式验证工具。通过这个工具,你能够判断不同的不变量是否适用于智能合约。在幕后,验证条件会被转换为SMT公式,然后使用SMT求解器进行检查。

Move验证器速度非常快,所以它可以像类型检查器或linter一样集成到常规的开发工作流程中。


下面是验证器的一个示例:



7.2. 钱包安全


由于Sui要求交易将访问的所有对象都在函数参数中传递,并且Move函数签名和类型信息都存储在字节码中,因此我们可以让钱包在用户签署交易之前向用户提供关于交易将做什么的更有意义的信息。

例如,如果我们有一个具有以下签名的函数:


public entry fun foo(

asset1:&Asset,

asset2:&mut Asset,

asset3:Asset

)


我们可以从函数签名中得知,这个交易将访问用户的3个资产(资产类型)。不仅如此,根据&和&mut关键字(以及缺少的关键字),我们还可以知道asset1可以被读取,asset2可以被改变(但不能转移或销毁),而asset3有可能被改变、转移或销毁。

钱包可以将这些信息显示给用户,用户可以更有意义地了解交易可能对资产做些什么。如果有些事情看起来不太对,例如来自web3应用程序的交易调用触及了一些它不应该触及的资产或代币,用户可以观察到这一点,并决定不继续进行交易。

此外,钱包还可以模拟交易,这将为用户提供更多关于其影响的信息。Sui以对象为中心的编程模型以及类型信息是runtime原生的这一事实意味着无需对智能合约有任何具体的应用级知识就可以解释对象的更改。

这在Solana上是不可能的,因为从runtime的角度来看,帐户包含任意数据。你将需要帐户(特定于应用程序)的外部描述才能对其进行解释,而智能合约发布者可能提供也可能不提供这些描述。此外,Solana runtime中不存在资产所有权的概念,每个智能合约都需要手动实现这一语义(通常使用帐户签名和PDA),这意味着没有通用方法对此进行追踪。

7.3简单交易与复杂交易

Sui在共识层面上有一个有趣的优化,它允许某些类型的交易放弃完全共识,转而使用基于Byzantine Consistent Broadcast的更简单的算法来提交。这样做的好处是,这些交易可以在共识级别上并行处理,消除了队头阻塞,最终得以近乎即时的提交——这基本上实现了web2的可扩展性。

这是由于Sui对所有和共享对象的区分(见3.1节)。只涉及所有对象的交易(称为简单交易)不需要在Sui上达成完全一致。由于所有对象除了发送方不能在交易中被其他任何人使用,而且发送方一次只能发送一个交易,这本质上意味着这些交易不需要参照其他交易进行排序(总排序与因果排序)——我们知道在交易中引用的对象不会受其他交易的影响,而且这个交易也不会影响其他对象。因此,我们不关心这个交易相对于链上并行发生的其他交易的排序——这实际上是不相关的。Sui利用这一事实,极大地优化了简单交易的处理,得以在几百毫秒内实现最终结果。缺点是发送者一次只允许发送一个交易。另一方面,涉及任意数量的共享对象的交易(称为复杂交易)总是需要充分的共识。

考虑到所有对象的创建、传输和修改可以完全通过简单交易完成,某些类型的应用程序可以很好地利用简单交易。NFT(包括大规模铸币)和web3游戏便是很好的例子。这些用例受益于低延迟最终性和消除队头阻塞,实现了更好的用户体验和可扩展性。

但有些其他类型的应用必须依赖复杂交易。这包括大多数DeFi应用程序。例如,AMM流动性池将需要成为一个共享对象,因为任何类型的交易所订单执行都需要完全的共识和总的排序。因为从根本上说,如果多个订单同时来自不同的用户,我们需要就谁的订单将首先执行达成一致,这将决定每个用户将获得的执行价格。

还有一些应用程序可以混合使用简单和复杂的交易。这些应用需要复杂交易才能实现其所需的功能,但在某些操作上可以利用简单交易来获得更好的效率。例如,价格oracle可以被这样设计:我们可以让多个发布者使用简单交易提交市场价格数据,然后由权威机构使用复交易对价格进行汇总。在某些情况下,不依赖复杂交易是不可能实现价格oracle的,但至少我们可以用简单交易优化发布者的写入。

Sui文档中有关于简单和复杂交易的更多细节:


  • https://docs.sui.io/devnet/learn/sui-compared

  • https://docs.sui.io/devnet/learn/how-sui-works#system-overview

8.结语

本文深入探讨了Solana和Sui的编程模型、它们之间的对比以及Move编程语言。


第2章是对Solana编程模型的总结,而第3章则介绍了Sui Move及其编程模型。第4章接着解释了Move中的类型和资源安全的运作方式。Move的特性对智能合约开发的意义不是很明显,所以在第5章中,我利用实际例子对Solana和Sui Move进行了更彻底的比较。第6章讨论了eBPF/SBF,而第7章触及了其他一些Move特性。

智能合约编程是关于数字资产的编程。可以肯定地说,这是一种新的编程类型,不同于我们迄今为止看到的其他类型的编程(如系统、后端……)。因此,现有的编程语言和编程模型不能很好地适应这个用例也就不足为奇。

问题的关键在于,我们希望有一个编程模型,它既适合处理资源,同时又能与不受信任的代码进行交互。Solana在这里做了一个折衷,它确实使智能合约在一个不受信任的环境中具有必要的可编程性,但它的编程模型不太适合使用资源进行编程。字节码验证使两者都成为可能。在某种程度上,它将不受信任的代码变为了可信代码。

Move是一种用于智能合约开发的新型编程语言。其核心创新之处在于它的字节码被有意设计为便于验证。虽然字节码验证本身并不是一个新奇的概念,但是Move所做验证是新奇的。通过其字节码和验证,Move实现了一种对资源具有一流支持,并可以保证在不受信任的环境中安全编程的智能合约编程模型。

这对智能合约开发的影响乍一看并不明显,但如第5章所述,它们在智能合约人机工程学、可组合性和安全性方面确实非常重要。与Solana基于Rust的编程模型相比,Move进行了重大改进。

因此,我认为Move对于智能合约开发的作用就像React对于前端开发的作用一样,说“你可以用Move做什么,就可以用Rust做什么”就相当于说“你可以用React做什么,你就可以用jQuery做什么”一样。当然,实现一个相当于React的基于jQuery的应用是可能的,但这是不实际的。React引入了虚拟DOM的概念,它对开发人员是完全透明的,但允许更快、可扩展和简单的前端开发。同样,Move的字节码验证是一种同样对开发人员完全透明的底层技术,但它提供了一种更符合人机工程学、更可组合、更安全的智能合约开发。由于其安全性和更直观的编程模型,Move还大大降低了智能合约开发人员的准入门槛。

如果Move成功获得吸引力(早期迹象表明它会),它可能会对Solana构成相当大的威胁。这有两个原因。

首先,Move智能合约的开发时间要快得多。在Move中从零开始开发智能合约的速度似乎比在Rust中快2-5倍。在编写智能合约时尤其如此。正因为如此,Move生态系统的发展速度可能会超过Solana。由于区块链的开放和无许可的性质,流动性可以很容易地移动。Solana开发人员可能会仅仅因为经济原因而被迫采用Move——你要么切换到Move,要么被开发出更安全、更快的智能合约的Move开发人员超越。

第二个原因是Move的准入门槛比Rust或Solidity要低得多。因为Move语法更简单,编程模型更直观,所以有很多开发人员无法在Rust或Solidity中进行智能合约开发,但可以在Move中开发。由于需要学习的概念较少,让非智能合约开发人员学习Move要比让他们学习Rust或Solidit容易得多。即使现有的Solana和Solidity开发者不转向Move,尚未进入该领域的开发者数量也要比该领域现有开发者的数量多出好几个数量级。因为Move的准入门槛更低,开发速度更快,所以它比Rust或Solidity更适合产品市场,可以从市场中分得更大的份额。如果新开发者开始大量涌入,我希望他们从Move,而不是Rust或Solidity开始。这与React在网络行业的情况类似。

正因为如此,我完全期待在中长期内,Solana会对Move进行大力支持。但这并非易事。为了获得Move的主要优势,Move字节码需要得到原生支持。这意味着简单地将Move编译成eBPF/SB并不能解决这个问题(参见6.3节)。为了保持现有的生态系统,两个runtime都需要被支持。主要的技术挑战是如何在runtime之间实现适当的互操作性。这需要对Move和Solana都有深入的了解,所以我认为这需要Solana团队在Move团队的支持下直接对此进行推动。

Move起源于Meta的Diem项目。由Sam Blackshear领导的Move团队的任务是弄清楚如何处理智能合约。在更仔细地研究了这个问题之后,他们发现智能合约编程都是关于数字资产(资源)的编程,但是现有的语言都不支持这个用例。于是他们决定从头开始构建一种新的编程语言。

我想强调的是,创建一门新语言的决定不是能轻易做出的,因为它需要多年的工程努力才能实现,而且在大多数情况下,使用现有的解决方案会更好。Move团队正确地预见到可以构建一种安全的、对资源有一流支持、同时足够灵活的智能合约语言,这本身就显示了其高度的专业性。Meta停止了他们在Diem的努力,最终也没能收获其在Move上的投资成果,但这对更广泛的加密社区来说是一个巨大的贡献。

总而言之,Move是一项了不起的技术,我相信它将对我们如何开发智能合约产生巨大的影响。


Copyright © 2021.Company 元宇宙YITB.COM All rights reserved.元宇宙YITB.COM