开发智能合约时使用受限语言Solidity中的函式库的注意事项

2019-01-08 10:29:13 来源:elecfans
标签:

 

Solidity(或者更概略的说,EVM),在软件工程师的生产效率和语言表达能力都还有好长一段路需要走。如果你曾经在以太坊上开发智能合约,到现在你应该已经察觉,Solidity真是个绑手绑脚的语言。

 

特别是在你是从Swift或Javascript转行过来开发Solidity。用Solidity开发程序,这个语言允许软件工程师能做的事情,还有整个语言的表达能力,都让人有种倒退走的感觉。


这种感觉有时候真的会让人发飙。

 

但为什么它是受限的语言

Solidity和其他能够被编译成能够在EVM(以太坊虚拟机)上运作的bytecode(位组码),都会受到某些限制,因为:

 

· 当你要执行你的程序的时候,你的程序会在整个系统上的每一台节点上运作。当一个节点收到新的区块的时候,这个节点就会验证这个区块的完整性。在以太坊上这些验证包含了,这个区块所包含的所有计算是正确的,而且合约的每个状态都是计算正确的。

 

· 这造成了,即便EVM是图灵完备,大量的计算会十分昂贵(甚至会因为超过燃料(gas)上限而直接不被允许),因为每个节点都需要把这些计算计算一遍。也就因此把整个以太网络拖慢。

 

· 标准函式库(standard library)还没被开发完成。尤其是数组和字串都很难用。我本人都还曾经自己实作过操作字串的函式库,就为了一些很基本,我们之前都习以为常的功能。

 

· 你所写的合约没办法从外界(EVM之外)获得任何数据,除非透过交易(Oracle)。而且当一笔交易被布署到网络上,他就没把办法再升级改版(除非是透过migration或是纯储存合约(pure storage contract))。

 

这些限制有些是以太坊必须一定存在的限制(就像是你永远不可能会有办法储存你Google Photos上照片的备份在链上,或者单纯透过链上的计算资源去做图像辨识,但这也没什么关系啦)。但其他限制会存在,只是因为这是一个十分新的科技(虽然真的进步的超级快),但这个技术也将会一直改善。

 

好的所以我到底要怎么解决这个问题?

当我们在开发项目的时候,我们可能在未来会对合约做更改。我们可以透过横跨不同合约间信息传递的方式去间接解决这个问题。在进入可升级智能合约(Upgradable Smart Contracts)的实作之前,让我们先来了解它的限制。

 

在Solidity,函式库(library)是一种特殊的合约,这种合约不会储存任何数据(storage),并且也不能持有任何以太币。有时候我们可以试着把函式库当成一种以太坊虚拟机(EVM)的单例(Singleton)就好。这个单例是一段可以被其他合约呼叫的代码,而且这段代码在被呼叫的时候不需要重新布署。这个特性解决了一些我们所面对的大问题,比如说:

 

· 布署所需的燃料(gas)花费:因为同样的代码不需要一而再再而三地被布署,所以一个很明显的优势就是能够节省大量的燃料。并且不同的合约可以都倚赖同一个已经被布署出去的函式库。

 

· 繁冗的代码在区块链重复出现:这明显的是上面那点所伴随来的好处,布署的次数比较少,区块链上的纪录也就比较少。

 

· 代码升级:在之前的状况是,如果需要修改程序错误或者帮合约改版,就需要重新布署一个新的,因而与之前合约独立的合约(甚至更惨的状况是像之前一样要对以太方进行硬分岔)。这个问题因此被解决了

 

有没有开始觉得函式库是一个很厉害的东西了阿?不幸的是,函式库也有一些限制,下面是几点是关于函式库我们必须知道的重要信息:

 

· 没有储存(storage)的能力

· 函式库能够操纵其他合约的储存(storage)

· 函式库不能有任何payable的函式(funcTIon)。

· 函式库不能有任何fallback的函式(funcTIon)。

· 函式库不能有事件日志(event log)。

· Libraries can be used to fire event logs for the contract which uses it.

· 函式库是不能被继承的

· 虽然函式库不能直接被继承,但是函式库可以跟其他函式库接在一起,就能像一个一般合约一样的使用被接上的函式库,单这样使用,函式库本身的限制依然还会在。

 

这几点可能在一开始会让人听起来很混乱,但是别灰心,这边有一个非常棒的资源可以协助你了解函式库。

 

但至少接下来,我们只会用上一些,因为了解、实作可升级智能合约所必须了解的部分就好了。

 

函式库是如何运作的?

函式库是一种特殊的合约,这种合约不能有任何payable函式,而且也不能有任何fallback函式(这些限制在编译期间就被强行限制了,因此可以让函式库这种合约绝无可能持有任何资金)。函式库是透过函式库关键字(library L{})去定义的,就像一个合约会透过(contract C{})去定义一样。

 

library L{

funcTIon a() returns (address) {

return address(this);

}

}

contract C{

funcTIon a() constant returns (address) {

//This will behave as if the library code was written within this contract

return L.a();

}

}

 

要呼叫一个函式库里面的函式必须用特别的指令(DELEGATECALL),这个指令会传递呼叫函式的信息(calling context)到函式库,因此就几乎像是一个都在同个合约里面,合约自己处理自己的指令。我真的蛮喜欢在Solidity文件里面阐述这件事情的角度。

 
关注与非网微信 ( ee-focus )
限量版产业观察、行业动态、技术大餐每日推荐
享受快时代的精品慢阅读