我了解到,SELFDESTRUCT和操作码的错误定价使得许多空帐户的创建成本很低,正如在为什么允许空账户出现在区块链上?中所解释的,这个问题的答案还包括一个创建了许多空帐户的事务。交易/攻击是如何运作的?当合同调用SELFDESTRUCT时,它不能再次调用SELFDESTRUCT .或者可以吗?
发布于 2017-07-31 14:48:32
古老的历史,但这里有:-)
最初的攻击只有一个协调合同。后来 版本有一个更复杂的算法来生成空的帐户地址,这大概是为了阻止将来的清理工作。这个只是递增地在地址空间中工作。
协调合同每次被称为4750次--它做了以下工作:
(1)订立儿童合约。
0000 PUSH32 0x6004600c60003960046000f3600035ff00000000000000000000000000000000
0021 PUSH1 0x00
0023 MSTORE
0024 PUSH1 0x20
0026 PUSH1 0x00
0028 PUSH1 0x00
002a CREATE这将在新地址上创建以下子合同的一个副本:
;; Child contract (in full)
PUSH1 0x00
CALLDATALOAD
SELFDESTRUCT此子合同的代码嵌入到协调合同的第一个PUSH32中:
0000 PUSH32 0x6004600c60003960046000f3600035ff00000000000000000000000000000000它的前12个字节是子契约构造函数的代码;接下来的4个字节是子契约代码本身,如上面所示。
(2)从储存处装载计数器:
002b PUSH1 0x00
002d SLOAD
002e DUP1这将跟踪正在创建的空/臃肿帐户,并允许随后对协调契约的调用从前一个终止的位置继续。
(3)合同其余部分的循环:每次循环迭代调用子契约40次(即重复以下代码40次)
0030 PUSH1 0x01
0032 ADD
0033 DUP1
0034 PUSH1 0x00
0036 MSTORE
0037 PUSH1 0x00
0039 DUP1
003a PUSH1 0x20
003c DUP2
003d DUP1
003e DUP8
003f PUSH1 0x06
0041 CALL
0042 POP在这里,它向计数器添加一个,复制它,将一个副本放回内存,然后调用与另一个计数器副本的子合同作为调用数据。
子契约将发送给它的数据(计数器)解释为地址,当它SELFDESTRUCTs时,它将(零)值发送到该地址,从而创建了一个空的膨胀帐户。
这里的关键点是,子契约在当前事务执行结束之前实际上不会自毁,因此可以在一个事务中多次调用它。黄纸中的描述是“停止执行并注册帐户以供以后删除”(强调“地雷”);它将在当前事务结束时被删除。仅在每次调用协调契约时才重新创建子契约就足够了;然后可以在其内多次调用该契约。
(4)检查剩余气体,如果有足够的话,然后再回去循环所有40个呼叫,继续增加地址计数器。
0328 GAS
0329 PUSH2 0x6000
032c LT
032d PUSH3 0x00002f
0331 JUMPI因此,每次调用协调合同都能造成数千个账户膨胀,这取决于最初供应的天然气数量。
(5)最后,为下一次调用准备好地址计数器。
0332 PUSH1 0x00
0334 SSTORE当然,问题是,通过自毁建立一个账户并不像它应该使用的那样多。这是在化150:长期天然气成本变化中解决的。
https://ethereum.stackexchange.com/questions/11312
复制相似问题