该文章详细介绍了Solidity中的selfdestruct关键字,包括其定义、工作原理、用途以及相关示例。文章回顾了selfdestruct的历史及其在以太坊智能合约中的重要性,同时讨论了使用该功能的安全性问题与潜在风险。尽管功能已在以太坊的上海升级中被弃用,但文章提供的背景与实例仍具有参考价值。
更新:selfdestruct
在上海以太坊升级中被弃用,按照 EIP-6049 的要求。本文现在已经过时,仅反映此特性以前的工作方式。
selfdestruct
是 Solidity 中的一个关键字,用于开发者想要终止合约时。在一篇2021年的研究论文《智能合约为何自毁?——研究以太坊的selfdestruct函数》中,大约有800个合约包含了 selfdestruct
关键字,使其成为学习 Solidity 过程中的重要概念。
本文定义了 selfdestruct
的功能,描述了它的目的,并提供了在 Solidity 智能合约中实现 selfdestruct
的示例。
**Selfdestruct**
是一个用于终止合约的关键字,它会从以太坊区块链中移除字节码,并将任何合约资金发送到指定地址。
selfdestruct
起源于2016年,当时以太坊区块链和去中心化组织(DAO)还在形成阶段。最早的一个DAO遭黑客攻击损失了360万ETH。由于 Solidity 合约的不可变性,攻击持续了数天。因为当时并没有销毁合约的方法,早期的 DAO 开发者不得不分叉整个区块链以防止进一步的漏洞。
因此,selfdestruct
被创建出来,以便在出现安全威胁时作为一个出口。尽管它起初被称为“自杀函数”,但是从 Solidity v0.5.0 开始它被重新命名为 selfdestruct
。
selfdestruct
函数?开发者使用 selfdestruct
函数主要是为了提高智能合约代码的安全性,清理未使用的合约,以及快速转移以太坊资产。
selfdestruct
在开发者需要升级智能合约时显得尤为重要。例如,ERC-20 框架 是以太坊上所有可替代代币互操作性的标准实现。任何不符合 ERC-20 标准的代币将难以与其他合约进行交互。
在这种情况下,开发者会改用一个新合约,而不是升级当前合约。因此,他们可能会使用 selfdestruct
函数从当前合约中提取资金,并构建一个具有所需功能的新合约。
开发者还使用 selfdestruct
函数来预防潜在的安全威胁。根据同一篇 2021 年关于 selfdestruct 的智能合约报告,当开发者发现合约中存在安全缺陷时,selfdestruct
函数帮助他们立即终止有缺陷的合约,并用安全的合约来替代它。
selfdestruct
的缺点是什么?使用 selfdestruct
函数的缺点在于无法恢复 ERC-20 代币,并且在自毁后无法重新路由代币。
通常,selfdestruct
函数由未能及时传达合约终止信息的开发者调用。即使团队沟通更新,信息也可能传播得不够快。因此,有些人可能会将资金发送到被销毁的合约,以为它仍然是活动状态。在这种情况下,资金将会丢失。
使用 selfdestruct
的第二个缺点是它仅能转移以太(ETH),无法转移其他 ERC-20 代币,例如遵循 ERC-721 代币标准的替代币或 NFTs。一旦调用了 selfdestruct
,这些资产将无法恢复。
selfdestruct
函数是危险的?selfdestruct
函数使恶意开发者更容易执行 rug pulls。
这个函数使得开发者可以调用 selfdestruct
,并将资金直接送往他们个人的钱包。因此,一些协议用户和开发者对使用 selfdestruct
函数表达了不同的看法。
selfdestruct
是如何工作的?**Selfdestruct**
通过从链上删除合约字节码、将任何流动性发送到指定地址以及将部分Gas费退还给开发者来工作。
合约由两个部分组成:状态和函数。这些组成部分定义了合约的行为和 可调用函数。删除字节码意味着合约没有定义它的任何组成部分,从而使得合约无法被调用。
selfdestruct
函数有一个必需的参数,指明调用者希望合约资金在销毁后去向何处。
负Gas是指以太坊链在开发者使用 selfdestruct
函数时退还的交易费用的一部分。
以太坊通过奖励调用者因从区块链中移除数据而节省的Gas来激励使用 selfdestruct
函数。当合约调用 selfdestruct
函数时,交易中使用的总Gas的50%将退还给调用者。
selfdestruct
是否会移除合约在以太坊区块链上的历史记录?不,selfdestruct
函数不会从以太坊链中移除合约的历史,只会移除合约的字节码。
以太坊是一个区块链,一个公共区块账本,其中相互连接的节点网络始终保留区块链状态的副本。因此,调用 selfdestruct
函数之前所做的所有数据和交易都被永久记录在链上,无法更改。
selfdestruct
函数后资金是否会永久丢失?不及是,现有的 ETH 会发送到调用该函数指定的另一个地址,而 ERC-20 代币则会丢失。
此外,如果有人向一个自毁的合约(即终止合约)发送资金,这些资金将不会被重新路由,并且将会丢失。
**Selfdestruct**
函数示例这个程序的目标是允许铸造 NFT,直到合约中的 ETH 达到一定数额。一旦达到,程序会将所有以太发送到最后一位铸造者的钱包作为奖励。每个人可以用1以太铸造多个NFT,但每次只能铸造一个。这个合约不适合在生产中使用,仅供示例用途。
// SPDX-License-Identifier : MIT
pragma solidity ^0.8.17;
contract Mint{
address public minter;
uint public target = 30 Ether;
function depositMintingEther() public payable {
require(msg.value == 1 Ether, "每次只能铸造一个 NFT");
uint bal = address(this).balance;
require(bal <= target, "NFT 已用完");
if(bal == target){
lastMinter = msg.sender;
}
}
function receiveFunds() public {
require(msg.sender == lastMinter);
(bool success, ) = msg.sender.call{value : address(this).balance}("");
require(success, "无法发送资金");
}
}
contract Attack{
Mint badMinter;
constructor(Mint _badMinter) {
badMinter = Mint(_badMinter);
}
function spoiler () public payable{
address payable mintAddress = payable(address(badMinter))
selfdestruct(mintAddress));
}
}
铸造合约的主要问题是它使用“this.balance
”来验证合约是否有足够的资金来触发结束条件。因此,攻击者可以轻松发送资金使合约超过指定限额,然后使用 selfdestruct
关键字将资金重定向到他们声明的构造函数。
因此,在使用 selfdestruct
时,开发者必须小心使用的变量以满足特定条件。避免使用任何对合约地址或合约资金的引用,因为它们可能会被人为操控。
初始化一个 selfdestruct
函数很简单:你需要在一个函数内使用 selfdestruct
关键字,并指定一个可以在调用 selfdestruct
函数后接收合约资金的可支付地址。
以下是通常在 Solidity 课程中教授的 selfdestruct
函数示例:
function destroy(address apocalypse) public {
selfdestruct(payable(apocalypse));
}
代码的功能如下:
函数的名称是 destroy
参数指定了地址为 apocalypse
当调用 destroy 函数时,地址通过 apocalypse 变量指定
函数可见性声明为 public,这样其他合约也可以访问它。
然后使用 selfdestruct
关键字,并在声明为可支付后传递 apocalypse 变量。
现在,由于该函数是公共的,它代表了一种潜在的安全漏洞。为了解决这个问题,可以考虑添加一个 onlyOwner
修饰符或使用 require 语句 确保只有所有者能够调用 destroy 函数。
function destroy(address apocalypse) public {
require(owner == msg.sender, "只有所有者可以调用此函数");
selfdestruct(payable(apocalypse));
}
selfdestruct
函数selfdestruct
充当了在安全漏洞发生时终止合约的保护措施,当开发者想升级合约或删除旧合约时使用。尽管在 Solidity 开发者社区中 selfdestruct
的使用仍然存在争议,但该函数的引入帮助保护了很多潜在的黑客攻击。
- 原文链接: alchemy.com/overviews/se...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!