我受到另一个问题的启发,学习了更多关于堆栈深度攻击的知识。
当我试图在Remix上运行attack(1023)时,我的合同是:
pragma solidity ^0.4.14;
contract Attacker {
uint x;
function attack(uint y) {
if (y > x) {
this.delegatecall(bytes4(sha3('attack(uint256)')), --y);
}
else {
throw ; // doesn't matter, we never get here
}
}
}使用3M汽油,我就用光了228个电话。最后,DELEGATECALL指令似乎使用了大约1.5k的气体。但是在第一部,我看到的是94k。下面是生成该数字的步骤:
attack(1023)发布于 2017-08-03 06:53:43
更新。我把答案留在下面,因为它有一些有趣的观点,但我想我终于找到了真相。
关键点隐藏在微妙之处页面中:
呼叫或创建最多可以消耗呼叫时剩余气体的63/64;如果呼叫要求超过这个规定的最大值,那么无论要求多少气体,内部调用都只能有规定的最大气体。
这一点在YP中解释得很清楚,所以我不知道我是怎么错过的:-)

所以,您的调用并没有消耗那么多气体,而是不能将所有要调用的气体传递到递归中的下一个调用。如果你的初始气体在6.4M左右,那么你的第一份CALLed合同将收到比你想象的少大约10万的气体。我想这就是你所看到的。在合同终止时,没有传递给呼叫的剩余气体仍未使用,也没有用完。
所以-不是Remix故障(对不起,Remix!)如果有的话,看起来testrpc没有强制执行。
我觉得这是Remix的报道问题。我对您针对testrpc的合同做了一个小小的改动(也就是说,在我自己的环境中,不是Remix ),但是没有看到相同的情况。
pragma solidity ^0.4.13;
contract Attacker {
uint256 x;
function attack(uint256 y) payable returns(uint256) {
if (y > 0) {
this.delegatecall(bytes4(sha3('attack(uint256)')), --y);
}
else {
// Save the remaining gas in storage so that we can access it later
x = msg.gas;
return;
}
}
}开始的y是使用delegatecall的次数。它把剩余的气体留在储存中,可以用eth_getStorageAt访问。
结果(y是委托调用的次数,值是gas剩余,diff是这个和以前的gas之间的差异)。
在每种情况下,差异都是1112个气体,包括零委托和一个委托之间的差异(除了一个额外的64个气体,我认为这是由于y=0时初始调用数据中的额外零字节造成的;这是按4 gas计费的,而不是一个非零字节的68 )。
这基本上就是我所期望的,这就是为什么我认为Remix在这里一定有点摇摇欲坠。
编辑:只是为了确认Remix的呆滞。使用同样的程序:从气体的内部度量(msg.gas放在存储中),Remix报告说,每增加一段时间,就会再使用大约45000个气体;然而,Remix在合同选项卡上报告的合同执行成本只增加了每个代表团1339个燃气。
请注意,气体是在sstore of x之前计算的,因此我们看不到(很大的)成本。但这并不重要,因为这是一次性的。
https://ethereum.stackexchange.com/questions/23578
复制相似问题