Aptos move语言学习二

admin 2022年10月1日04:47:16评论248 views字数 4802阅读16分0秒阅读模式

通过之前的文章 - Aptos初步学习, 已经对aptos有了大概的认识。本文通过学习move的基本语法,并和solidity进行安全方面的对比,更深一步的走进move。

 首先看下面代码段: 

Aptos move语言学习二 

这整个是一个模块,封装了逻辑方法和资源。调用通过脚本的形式去调用。 

首先0xCAFE表示一个地址,下面所有的这些方法和资源都是定义在上述的地址空间下。 

整个aptos会有非常多的地址空间。类似下图: 

Aptos move语言学习二

 模块的名字就是basiccoin,类似于solidity的合约名。接下来struct就是一个结构体,这个struct被一个has修饰,hash后面会跟几个属性,key就是一个属性。首先struct Coin是自定义的一个变量,即是一个资源,这个资源不是move语言原生的。了解过大部分区块链的都知道,比如ethereum,这条链上运行了很多资产,比如erc20代币。对于这些表示资产的代币,需要进行严格的限制。 

其实has这部分很好理解,就是表示move对资源的约束,限制资源的一些能力。 

能力分为以下4个: 

1.key:因为合约里的逻辑和资源都是在地址上存储,key的意思就是可以把coin当作一个key去查询。可能这样的解释还是比较模糊,因为代币会有很多地址持有,这个类型可以存放在别的账户之下,能成为资源。 

2.copy:这个类型可以被复制,在用struct的时候会拿走所有权,,如果不想要拿走所有权,可以借用或者复制一次,所以copy赋予了后者可行性。(这点和rust类似)。 

3.store:这是可以存储在ledger status的资料,不止是模块内部运算方便而定义的。(永远记录在账本上)类似于以太坊坊的storage插槽。 

4.drop:这个算是move特性,这个类型被取用之后不处理也没事,但是move语言取用了这个类型就必须要处理,这个特性标记了这个struct被取用之后可以不进行处理,变量的作用范围推出,就会被清除。resource资源只会具备key和store两种能力,所以对比solidity是相对安全的。 

然后看下面的function,public函数可见性,fun关键字,mint函数名。两个参数, 

一个是signer,一个u64(0~2^64-1)。signer也表示一个资源,但是这个资源是内置的,不能copy,表示sender。类似以太坊的msg.sender,即调用者。在上篇文章中讲述过,这个就是方法的调用者,不用传值。signer只有一种能力,就是drop。 

看到下面用&account,这表示一个引用类型。move程序的最初发展也是一个栈。 

Aptos move语言学习二 

string这个长度未知所以引入了一个堆,把这个string放在堆里面。假设现在有一个d=c,通过这么一条语句,现在d也能访问到c。当有很多引用的时候就不能删掉这块区域,否则会产生空指针。所以堆上的内存管理就会很麻烦。参照jvm对堆的管理,谁引用了就标价加1,谁释放了就标记减1。引用数等于0,这块内存就会被回收。这种处理手段就会比较费事,所以move引入一个机制ownership,即拥有权,只有具有拥有权,才可对内存区域进行回收,程序也会在编译的时候进行检查。 

ownership有3条规则: 

1.每个value都有一个owner; 
2.任何时候一个value都只有一个owner; 
3.owner一旦退出代码作用范围,value就会被回收。 

正常来说赋值操作分为深拷贝和浅拷贝。浅拷贝只两个指针指向同一个内存空间。 

深拷贝只又开辟了一个内存空,等于说复制了一个一样的内存空间,两个指针指向不同的内存空间,里面的数据相同。但对于此种,内存空间的开销都相对较大,所以考虑一个相对便宜的方式。 

move使用了引用类型。比如d=c,c实际保存了一个指针,指向一内存空间。 

d其实保存了一个指针指向c。rust把这种说法叫做借,所以开销很小。借不发生ownership转移。借默认不可以修改里面的值,如果必须要改的话,需要加上mut关键字。 

move也是如此,所以保证了内存的安全和不必要的内存开销。类似下图:

Aptos move语言学习二 

 参考下面代码,对比move和solidity的安全性。 

Aptos move语言学习二

Aptos move语言学习二

首先resource是move的核心,move安全就是因为resource安全。resource是struct定义的一种变量,存储在某一个地址下。reource有4种能力,上文说过,通过对resource能力的约束来保证安全性。看到solidity的transfer其实有无限转移的,当from和to一样之后,balance这个mapping的映射获得的value是一样的,所以会覆盖掉。 

不过move这边使用了引用类型,指向了同一片地址空间,所以不会产生这样的问题。在真实操作的时候,参照上文的指针图片,这个纸箱同一个地址单元,操作的同一个地址空间,先减后加,所以值不会发生改变。也正因为这个存储性质,所以move会相对安全,并且资源根据上下文的需求,都会通过has进行能力约束。 

通过翻看move白皮书,肯定能看到一句话。First-class Resources,翻译过来就是资源是一等公民,resouces和value是对应的概念,传统的编程语言,包括以太坊智能合约语言中,对于数字资产的记账是采用的 Value 方式,这会导致一个问题:记账是有可能记错的。事实上记错账的智能合约相当得多。Move 合约采用了一种吸收了传统理论「线性逻辑」的类型,叫做资源类型。数字资产可以用「资源类型」来定义,这样一来,数字资产就像资源一样,满足线性逻辑中的一些特性: 

1.数字资产不能被复制 

2.数字资产不能凭空消失 

First-class Resources 的真正含义是 数字资产是一等公民,这句话可以引申出,Move 是为操作数字资产而生的智能合约语言。从技术角度讲,数字资产可以作为合约的变量,数字资产可以存储,可以赋值,可以作为函数/过程的参数,也可以作为函数/过程的返回值。而 Move 的静态类型系统使得智能合约代码能够在编译期,也就是部署前就可以通过编译器检查出绝大多数的资源使用错误。保证智能合约不再像以前那样的脆弱不堪。 

内存这块看完之后,分别看看move和solidity调用这部分。solidity这部分相对熟悉都知道solidity调用方式非常灵活,call,delegatecall。灵活也就代表会出问题,以太坊经典重入问题,delegatecall修改的是当前合约的数据(从而引入了代理合约)。当然这些灵活都是有利有弊的,它在带来方便的同时也带来了问题。如果在运行之前,我们不清楚某一步的函数调用究竟是调用了哪一个函数,直到程序运行的时候,通过观察,我们才能知道的话,那么这个函数调用被称为是「动态」的。反之,则是静态的。Move语言采用静态调用,静态调用指程序A在调用程序B时,在运行之前就已经确定调用的对象,在运行过程中不改变调用对象。静态调用提升了运行的安全性。动态调用过程中,恶意用户可以通过制造恶意合约,调用目标函数,从而完成攻击。静态调用解决了动态调用存在的问题,增强网络运行的稳定性。Move只能修改当前合约的数据,Solidity被调用合约可以修改调用合约的数据(delegatecall)。 

当然move采用静态调用就会舍弃掉灵活性,move通过在调用的时候引入script脚本程序,把一个长调用链代表不同功能的transaction,一个脚本可以调用多个transaction。Move语言的合约可组合性源自于其Module(模块)的设计,基于Module间的组合只需要对Module进行升级和优化,所有使用过这个Module的其他合约都会自动使用最新的版本,加速使用Move语言的智能合约升级优化的速度。这地方代替了使用代理合约升级的功能。 

其实灵活这部分,move引入了泛型。了解过java等一些主流编程语言的都会了解这一概念。把一个具体的数据结构抽象出来并且适配一定范围的数据类型定义,即在声明一个数据类型时不需要直接告诉程序,而是使用<T>充当占位符,当真正使用到的时候再去告诉程序<T>是个什么类型,而避免重新定义。 

Aptos move语言学习二 

因为Solidity基于接口机制,为程序的设计带来了强大的扩展性,却很难约束接口的实现。同时通过动态调用,满足不同合约间的相互调用。Move则是基于泛型和Resource提供了另一种实现,这样的机制下,既保证了行为的确定性,也具备足够的扩展性.对于上文提到的对resource通过has进行能力约束,同样可以对泛型进行能力约束。 

类似下图: 

Aptos move语言学习二 

Solidity基于接口机制和动态调用在带来强大扩展性的同时,也带来很大的安全问题,诸如无限增发、Token丢失、Delegatecall漏洞等,持续出现过大量的攻击事件和漏洞。 

Move 通过省略某些特性限制了语言的表达能力,主要是动态调度和通用指针,基于Ability+Resource设计了一套资源管理特性,确保不可能在Move中复制或隐式丢弃任何资源。语言和VM层面的保障,将极大降低Move生态开发人员处理漏洞的代价和成本。 

调用说完,接下来再对比一下两者的函数可见性。这部分和solidity也有区别,比solidity更丰富。 

1.private:当前Module可见(Move函数的默认可见性) 

2.friend:当前address下被授权的Module可见  (可理解为solidity引入了函数约束的可.见性,一般对调用者地址进行鉴权) 

3.public:所有Module可见,但是用户不能直接作为交易使用(跟Solidity不一样,Solidity是调用public的合约函数发起链上交易) 

4.entry或者script:交易的入口 

以上4种可见性,函数可见性是逐渐放大的。 

首先private和public基本在任何编程语言下都是通用的,这部分可以跳过。来看一下friend的可见性: 

可见性的本质是控制函数对外的访问权限。friend的作用是控制「相同address下,跨Module的函数调用」,这样精细化的访问控制,能更好的避免函数泄露的问题。受信任的模块可以调用当前模块中定义的任何具有public(friend)可见性的函数。 

Aptos move语言学习二 

1.模块不能将自己声明为友元。 

2.编译器必须知道友元模块 

3.好友模块必须在同一个账户地址内 

4.朋友关系不能创建循环模块依赖关系 (即不能A approve B,B approve C) 

5.模块的好友列表不能包含重复项 

然后是entry和script可以理解为etherscan合约内容的writecontract 

是用户跟链上交互的入口。大致区别如下图: 

Aptos move语言学习二 

总结

本文通过存储,调用和函数可见性3个方面探索了move的特性及安全还有和solidity的区别。当面对一个新技术的时候,永远都是充满挑战的,目前看来move语言自身的安全性非常健壮,但是未来的安全风险永远是未知的。 

我们专注区块链安全生态整体安全性,以及操作系统/浏览器安全/移动安全,将会持续更新Aptos及move语言学习文章,敬请关注!


Aptos move语言学习二

Numen 导航

Numen 官网
https://numencyber.com/ 
GitHub
https://github.com/NumenCyber
Twitter
https://twitter.com/@numencyber
Medium
https://medium.com/@numencyberlabs

LinkedIn

https://www.linkedin.com/company/numencyber/


原文始发于微信公众号(Numen Cyber Labs):Aptos move语言学习二

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月1日04:47:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Aptos move语言学习二http://cn-sec.com/archives/1326822.html

发表评论

匿名网友 填写信息