当我在写出另一篇不相关的文章的时候,认识了以太坊生态里创建的假设。本篇文章我将不会描写为什么以太坊假设是有缺陷的以及得出适当的解决方案。首先,我们必须告诉以太坊假设是什么。假设的内容是为了向以太坊智能合约发送到ETH,同时为了防止轻进反击,调用智能合约的 gas limit 应当不少于2300。
魔力数和STATICALL每一个用于transfer函数发送到款项的现代智能合约中(如果我没有记错的话,在Solidity3.0之后),都有一个软编码的常数——2300。例如在这个非常简单的例子中:contract Tester{function() external{address payable paymentAddress = 0x5A0b54D5dc17e0AadC383d2db43B0a0D3E029c4c ;paymentAddress.transfer(5);}}Transfer位转翻译成EVM字节码后如下:CALL 2300, address, ....这个数字为何如此最重要?这样要求是有原因的。这曾多次是避免一类被不属于“轻进”的智能合约漏洞最有效率的方式。交接的概念是,一个智能合约调用另一个智能合约,最后(在同一次继续执行过程中)再行一次调用了原本的智能合约。
交接是在臭名昭著的the DAO黑客事件中被利用的主要漏洞。当时明确提出的解决方案不是通过转变以太坊协议来容许合约制止这种不道德,而是最后通过转变Solidity让向智能合约发送到ETH的配置文件不道德用于十分少量的gas,这样轻进问题就无法再行被利用。
当然,也有一个副作用,这个转变让花钱的智能合约不能在日志里记录一个事件,而无法转变状态或者做到任何别的事。但最近以太坊引进了STATICCALL,作为避免轻进问题的灵丹妙药。它知道是灵丹妙药么?问是——不全是。
首先,我们试着强迫Solidity在我们的测试合约的fallback函数中用于STATICCALL:pragma solidity ^0.5.9;contract Tester{function() external view{}function foo() external view{}}然后编译器用以下报错奖励了我们的冒险精神:browser/test.sol:4:5: TypeError: Fallback function must be payable or non-payable, but is "view".function() external view{^ (Relevant source part starts here and spans across multiple lines).而且,有意思的是,并没具体的“non-payable“关键字来具体地标识一个函数为non-payable。让我们从fallback函数里除去view关键字,检查这个ABI:[{"constant": true,"inputs": [],"name": "foo","outputs": [],"payable": false,"stateMutability": "view","type": "function"},{"payable": false,"stateMutability": "nonpayable","type": "fallback"}]所以,Solidity要求一个fallback函数的stateMutability不能是non-payable或者payable,不容许是“view”。
但我们假装Solidity不那么差劲,而是容许这么做到。然后你就可以让Solidity用于STATICCALL向一个合约的fallback转钱,一切正常了吗?还是敢。STATICCALL的设计很有些类似。当然,你可以在逻辑中用于fallback函数,但是STATICCALL的设计本意是容许外部合约调用而没副作用,只回到计算结果的数据。
Fallback函数实质上没回到数据的概念,虽然如果你上升到调用者和被调用者的编撰层面来看这可以构建。所以,STATICCALL在这个场景下没什么用,除非你在做到什么很少闻的操作者。但是如果你要做到些不少见的事情,为什么不写出一个常规的函数调用而要用fallback函数呢?好吧,我有些跑题。
STATICCALL特别强调的是没副作用。这意味著你不了做到以下操作者:· 变更状态· 调用另一个不会变更状态的合约· 创立合约· 自我封存一个合约· 在日志里记录事件· 给别的合约发送到ETH,或者变更一个合约的余额· 因为一个合约被STATICCALL而接到ETH你能预计到无法变更状态,因为正是从这个角度必要制止了交接错误的再次发生。虽然,我没有预料到在日志里记录事件也被禁令了。
在日志里记录事件对智能合约来说没可见的实际副作用。一旦一个事件被记录在日志里,一个外部(或内部)的智能合约就无法看见这个状态被记录了。这几乎是个空输入。
你向虚空中发送到了数据,但是再也不能接到那些数据,甚至无法仔细观察到那些数据被发送到过。这个副作用只有在区块链外的世界里才可见。
事件一般来说被用来通报外部界面转入区块链,就像说道“这儿再次发生了你可能会感兴趣的事情”。所以,假设以技术纯粹性的名义,STATICCALL十分严苛地继续执行了“无副作用”这条规则。
无副作用里的副作用还包括了只有外部可见的副作用。另外的效果当然是ETH无法在STATICCALL里展开移往。这有效地超越了它作为解决问题轻进问题竞争者的局面。
一般来说来说,当调用fallback函数时,你或者犯了错,或者想给一个合约发送到ETH。当一个合约接到ETH时,它一般来说不会在日志里记录一个事件来告诉他外部程序”嘿,我接到了一笔钱,你有可能想回应做到点什么,给那个用户放个信息之类的”。在有神秘的2300 gas limit时,不了给另一个合约发送到部分ETH,也无法变更合约内的状态,比如改版一下”预计余额“变量之类的。
STATICCALL的唯一用处就是指你想送达ETH的合约的广义函数那里制止轻进反击。这意味著,唯一有效地制止轻进反击,又能发送到ETH、容许建构事件的方式依然是以前的方法,用于神秘的gas limit常数——2300。
这为什么不会是个大问题?这并不是在说道软编码数字在计算机科学里被指出是很差的(提醒:这显然很很差),而是说道软编码数字实质上使一些合约不会在必须以太坊周围的做到一些转变时显得无法运营。动态区块链里的常量这个reddit帖子[1]获取了一些简单的细节,认为了以太坊之前在一次升级中减少了CALL指令和一些其他指令的大于花费(如果我没有记错的话当时大于花费是100,现在是500)。这类疑虑在未来所有gas price调整的时候大都仍然限于。
Nick Johnson认为“有具体gas limit的调用非常少有“。在这句话明确提出的时候,Solidity不会在做到与transfer大于的操作者时把所有能用的gas都移往到一个合约里,于是就留给了利用交接类操作者展开反击的可能性。Solidity在the DAO反击再次发生后引进了2300的gas limit,为了制止再次发生类似于事件。
现在,公平地说道,在配置文件情况下调用外部合约函数(不必transfer)时,Solidity依然不会配置文件把所有gas都发送到过去。而且文档里关于这个操作者的隐患有无数警告。
神秘的2300 gas limit常数意味着增强了那个reddit帖子里认为的问题。比如说,想象一个合约有一个payable的fallback函数,这个函数用于了一些在部署的时候低廉到能在2300 gas limit内继续执行的opcode。但是,为了应付一次反击或者什么之前没有找到的问题,后来这些opcode的价格大幅提高了。
这个合约就不会显得不了用于,不了从那些没有具体地将gas limit提升到低于2300(Solidity警告的不道德)的合约那里拒绝接受ETH。更加差劲的是,具体地提升gas limit不会让那些发动调用的合约曝露在被交接反击的危险性中。所以,这个合约很有可能就必需被弃用了。
根据它接管ETH的实际逻辑(比如倚赖一个特定合约给它发送到ETH),它很有可能像被挡在了墙里一样,里面的钱也不了萃取出来。这个2300 gas limit假设某种程度对向后兼容性危害。它也损害了以太坊协议内的潜在的未来创意。
例如,EIP-1293[2],SSTORE的净gas计量,是一个创意的协议改良,将不会减少还包括存储在内的许多智能合约不道德的成本。它能使存储的gas花费能体现出有区块链上的实际花费,这意味著当在一次继续执行中第二次载入一个存储键值的时候,将不会花费较少gas。这合乎常理,因为从区块链的角度来看,第二次状态改动完全没代价,而第一次状态改动就完全给区块链缴纳了充足的费用。
这个议案曾多次被还包括入了君士坦丁堡末端,但在最后时刻被移除了[3],因为找到这不会给大量现存的智能合约带给危险性隐患[4]。这个辨别是对的,这个改良不会增加状态存储成本,进而带给交接类的反击隐患,即使只有十分激进的2300点gas limit。这件事件中嘲讽的一点是,议案的设计实质上不会增加智能合约轻进维护的gas成本,而且这也是它的主要应用于场景。
现在,为了EIP-1283的交接问题而明确提出的解决方案是EIP-1706[5]。这个议案中的转变可以总结为:净gas值测量带给的费用增加将会在当前继续执行的gas limit高于2300时继续执行。所以,现在这个神秘常量在以太坊共识协议里显得更为根深蒂固。
这将不会有效地被迫任何未来的EVM语言在合约调用时也用于软编码的2300 gas limit来避免轻进反击的危险性。这个神秘的假设基本上解除了存储显得更加低廉的可能性,更加不必托以太坊将来要修缮扩展性问题以及任何别的问题。即使有一天发明者一种神秘方法能将所有存储移至链下,使存储基本免费,存储的实际gas花费依然无法高于2300,否则就不会曝露在交接反击的危险性中。
有可能的解决方案我说道了很多,但这显然是个很难的问题是吧?我们正在辩论区块链,有关区块链的所有技术都很难。这也是个事实,但同时,我也更加偏向不尊重以太坊团队在改良共识协议时刻意特别强调的技术纯粹性。
实质上,网卓新闻网,我实在EIP-1706因为软编码问题会被以太坊主网拒绝接受,它过于纯粹。我个人预测EIP-1283不会被无限期推迟,有可能最后不会重新加入到以太坊2.0里面。
我会怎么解决问题轻进问题?有两个有可能的方案。第一个比较简单:加上个opcode,但是特一个简单的。
我的建议是重新加入这个opcode:MAGICCALLWITHOUTREENTRANCYEXPLOITS这显然是个必须读书太久的简要的名字。但是坦率的说道,这个opcode的起到于CALL基本一样,除了以下转变:· 容许SSTORE(状态变更),就像STATICCALL那样· 其他任何事情都被容许老实说道我不怎么讨厌这个解决方案。我更喜欢解决问题本质问题,容许轻进任何智能合约。理想情况下,可以不存在一个非常简单的opcode,就像这个:KILLMEIFREENTRANT这不会在当前合约早已在调用栈里时暂停继续执行。
这个功能只必须一个老道的开发者工作一晚上就能已完成,然后再行必须一个白天做到安全性测试。这不会容许在避免轻进反击时会牵涉到到存储,并且能用如下的非常简单代码非常低费地构建if callstack.exists(currentAddress) then throw但是说道回去,我实在这样一个过于“纯粹”的opcode总有一天会被考虑到接纳入以太坊。
还有更加纯粹的替代性方案,比如把所有的调用栈曝露给智能合约。如果告诉了调用栈里都有什么,就能非常简单地写出一个Solidity函数来在栈里递归,检查否它自己的地址被包括在它里面,来证明现有的继续执行时在交接。而且当然,如果不出预料之中,合约就不会抛出现异常来制止任何不想的或者预料之外的不道德。这也不会容许在智能合约里重新加入其他特性。
例如,想象你举行了一场智能合约需要参予的众筹。但是,你用黑名单拉黑了一些跟恐怖分子有关的智能合约。恐怖分子能非常简单地部署一个“过路“智能合约,然后让被黑名单挡住的智能合约调用”过路“合约,最后就能调用你的众筹合约。
如果有调用栈的信息,这种不道德就能被找到。现在在以太坊里,几乎无法在链上用智能合约逻辑检测这一点。现在以太坊上制止轻进反击的设计完全都本身不存在安全性风险。
一般来说在合约继续执行的时候,一个变量不会被设置成1,指出正在继续执行。当继续执行已完成后,这个变量不会重置成0。
这样,如果你在过程中继续执行一个合约调用,如果外部合约想新的转入现有合约,这个合约不会看见变量被设置成了1,然后中止执行。然而,如果有些逻辑问题造成继续执行完结了变量没有被重置返0不会怎样?基本来说,这个智能合约就被隔绝了,不了再行被操作者,因为它仍然指出它正在被反击。交接是以太坊生态内的头号,也是被辩论得最少的问题,同时也被一些网站列入在创立智能合约时应当小心的第一号安全性问题。这是造成了the DAO反击和一些其他的反击与出现异常的元凶。
这也是智能合约开发者最无以正确处理的最好问题之一,所有大多数智能合约就非常简单地从根源上杜绝了这个有可能。对我来说,以太坊还没实行什么必要的方法来制止轻进十分不可思议。忽略,依赖容许很多的STATICCALL机制或者神秘的2300 gas limit常数或许优先级更高。在我心中,这有一点有一个一流的解决方案,而非一个创建在假设之上的古怪改动。
涉及读者1.Reddit帖子:https://www.reddit.com/r/ethereum/comments/57n2ql/why_i_believe_the_eip150_hardfork_may_break/2.EIP 1283:https://eips.ethereum.org/EIPS/eip-12833.《What is going on with the Ethereum hard fork update Constantinople?》:https://hackernoon.com/what-is-going-on-with-the-ethereum-hard-fork-update-constantinople-f453af698c0c4.《Constantinople enables new Reentrancy Attack》:https://medium.com/chainsecurity/constantinople-enables-new-reentrancy-attack-ace4088297d95.EIP-1706:https://github.。
本文来源:澳门威尼克斯人网站-www.yqgloves.com