构造函数是一种特殊的函数,通常在初始化合约时执行关键的任务。在 solidity v0.4.22之前,构造函数被定义为与包含它们的合约具有相同名称的函数。
因此,当一个合约名称在开发过程中发生变化时,如果构造函数的名称没有改变,它就变成了一个正常的、可调用的函数。可以想象,这会导致一些有意思的合约攻击。
坑点分析
正如上面所说,如果我们修改了合约的名称,或者在构造函数名称中有一些笔误,这样构造函数就不再匹配合约的名称,从而会变成一个正常的函数。这会导致可怕的后果,尤其是当构造函数执行特权操作的时侯。请看以下合约: image
这份合约的功能是收集以太币。通过调用withdraw()函数,只允许所有者撤回所有的以太币。问题是,建构函数并非完全以合约的名称命名。具体来说,OwnerWallet和ownerWallet是不一样的。
因此,任何用户都可以调用ownerWallet()函数,将自己定位为所有者,然后通过调用withdraw()来获取合约中的所有以太币。
避坑技巧
不过,这个问题已经在Solidity 0.4.22版本的编译器中得到了解决。这个版本引入了一个构造函数关键字,用该关键字来指定构造函数,而不是要求函数的名称与合约名相匹配。建议使用此关键字指定构造函数,以防止上面强调的命名问题。
真实案例:Rubixi
Rubixi的合约代码是另一个出现这种漏洞的「金字塔计划」。它最初叫做 DynamicPyramid,但是在被部署到Rubixi之前,合约名字已经改变了。而构造函数的名称没有改变,允许任何用户成为创建者。
关于这个bug的一些有趣讨论可以在一些比特币论坛上找到。最终,它允许用户争夺创建者的地位,从金字塔计划中获得费用。