---
title: "Solidity 中的 selfdestruct 是什么？"
description: "它是什么、工作原理，以及如何上手"
---

# Solidity 中的 selfdestruct 是什么？

**更新**：根据 [EIP-6049](https://eips.ethereum.org/EIPS/eip-6049) 的要求，selfdestruct 已在 Ethereum 的 Shanghai 升级中被弃用。本文现已过时，仅反映该功能之前的运作方式。

_Selfdestruct_ 是 [Solidity](https://www.alchemy.com/overviews/solidity) 中的一个关键字，开发者用它来终止合约。在 2021 年的一篇研究论文《Why Do Smart Contracts Self-Destruct? Investigating the Selfdestruct Function on Ethereum》中，约有 800 份合约使用了 _selfdestruct_ 关键字，这使其成为[学习 Solidity](https://www.alchemy.com/overviews/learn-solidity) 时需要理解的一个重要概念。

本文将定义 _selfdestruct_ 是什么、说明其用途，并给出在 [Solidity](https://www.alchemy.com/dapps/solidity) 智能合约中实现 _selfdestruct_ 的示例。

## **什么是 selfdestruct？**

Selfdestruct 是一个用于终止合约的关键字，它会从 Ethereum 区块链上移除合约字节码，并将合约中的资金发送到指定地址。

_Selfdestruct_ 起源于 2016 年，当时 Ethereum 区块链和去中心化组织（[DAO](https://www.alchemy.com/dapps/top/daos)）都还处于早期阶段。最早的一个 DAO 曾因黑客攻击损失了 360 万 ETH。由于 Solidity 合约的不可变性，该攻击持续了数天。由于当时不存在销毁合约的方法，早期的 DAO 开发者只能分叉整条区块链以阻止进一步的攻击。

因此，_selfdestruct_ 被创建出来，作为面对安全威胁时的一个退出方式。它最初被称为“suicide function”，从 **Solidity v0.5.0** 开始改名为 _selfdestruct_。

### 开发者为什么使用 selfdestruct 函数？

开发者使用 selfdestruct 函数，主要是为了提高智能合约代码的安全性、清理不再使用的合约，以及快速转移 Ethereum 资产。

在需要升级智能合约时，_selfdestruct_ 会很有用。例如，[ERC-20 框架](https://www.alchemy.com/overviews/erc20-solidity)是 Ethereum 上所有同质化代币的标准实现，用以实现互操作性。任何不符合 ERC-20 标准接口的代币，都很难与其他合约交互。

在这种情况下，开发者会选择切换到新合约，而不是升级现有合约。因此，他们可以使用 _selfdestruct_ 函数从当前合约中提取资金，再构建一个具备所需功能的新合约。

开发者使用 _selfdestruct_ 函数还为了防范潜在的安全威胁。根据同一份 [2021 年 selfdestruct 智能合约报告](https://arxiv.org/pdf/2005.07908.pdf#:~:text=On%20the%20one%20hand%2C%20using,an%20attack%20vector%20for%20attackers)，当开发者发现合约存在安全漏洞时，_selfdestruct_ 函数可以帮助他们立即终止有缺陷的合约，并替换为安全的合约。

### 使用 selfdestruct 有哪些缺点？

selfdestruct 函数的缺点在于它无法找回 ERC-20 代币，也无法在合约自毁后重新路由代币。

通常，调用 _selfdestruct_ 函数的开发者未能及时就合约终止一事进行沟通。即便团队发布了更新通知，消息传播的速度也可能不够快。结果是，有些人可能仍会向已销毁的合约发送资金，误以为它仍在运行。在这种情况下，资金将永久丢失。

使用 _selfdestruct_ 的第二个缺点是，它只能转移 Ether（ETH），无法转移其他 ERC-20 代币，例如山寨币，或遵循 ERC-721 代币标准的 NFT。一旦调用 _selfdestruct_，这些资产将永远无法找回。

#### 为什么有人认为 selfdestruct 函数存在风险？

selfdestruct 函数使恶意开发者更容易实施 rug pull。

该函数使开发者能够调用 _selfdestruct_，并将资金导向自己的个人钱包。因此，一些协议用户和开发者对使用 _selfdestruct_ 函数持复杂态度。

## selfdestruct 是如何工作的？

Selfdestruct 的工作方式是：从链上清除合约字节码，将所有剩余资金发送到指定地址，然后向开发者返还一部分 Gas 费用。

一份合约由两个部分组成：状态和函数。这两部分定义了合约的行为和[可调用的函数](https://www.alchemy.com/overviews/solidity-functions)。移除字节码意味着该合约不再有任何定义其内容的组成部分，使该合约无法被调用。

_Selfdestruct_ 函数有一个必需参数，用于指明调用者希望在合约销毁后，将合约中的资金发送到哪个地址。

### **什么是负 Gas，为何它很重要？**

负 Gas 指的是当开发者使用 selfdestruct 函数时，Ethereum 链退还的那部分交易费用。

Ethereum 通过将移除链上数据所节省的 Gas 作为奖励返还给调用者，以此鼓励使用 _selfdestruct_ 函数。当一份合约调用 _selfdestruct_ 函数时，该笔交易所用总 Gas 的一半会退还给调用者。

### selfdestruct 会移除该合约在 Ethereum 链上的历史记录吗？

不会。selfdestruct 函数不会移除合约在 Ethereum 链上的历史记录——它只会移除合约的字节码。

Ethereum 是一条区块链，是一个公共账本，由一个由多个互联节点组成的网络始终保存着该区块链状态的副本。因此，在调用 _selfdestruct_ 函数之前完成的所有数据和交易，都会被永久记录在链上，无法更改。

### 调用 selfdestruct 函数后，资金是否会永久丢失？

**既是又不是：现有的 ETH 会被发送到调用者在函数中指定的另一个地址，而 ERC-20 代币则会丢失。**

此外，如果有人向已完成自毁（即已终止）的合约发送资金，这些资金不会被重新路由，将会丢失。

## selfdestruct 函数示例

该程序的目标是允许铸造 NFT，直到合约中的 ETH 达到一定数量为止。一旦达到该数量，程序会将所有 Ether 作为奖励发送给最后一位铸造者的钱包。每个人可以用 1 Ether 铸造多个 NFT，但每次只能铸造一个。**该合约并非用于生产环境，仅作示例用途。**

该铸造合约的主要问题在于，它使用 “_this.balance_” 来验证合约资金是否足够以触发结束条款。因此，攻击者可以轻易发送一笔金额，将合约资金推高至超过设定限额，然后使用 _selfdestruct_ 关键字将资金重定向到自己声明的构造函数中。

因此，在使用 _selfdestruct_ 时，开发者必须谨慎选择用于满足特定条件的变量。应避免使用任何指向合约地址或合约资金的引用，因为这些数值可以被人为操纵。

## **如何使用 selfdestruct 函数**

初始化一个 selfdestruct 函数很简单：你需要在函数内使用 selfdestruct 关键字，并指定一个 payable 地址，用于在 selfdestruct 函数被调用后接收合约资金。

以下是 Solidity 课程中通常会讲授的一个 _selfdestruct_ 函数示例：

以下是这段代码所做的事情：

- 该函数的名称是 *destroy*
- 该参数将地址指定为 *apocalypse*
- 当 destroy 函数被调用时，地址通过 apocalypse 变量指定
- [该函数的可见性被声明为 public](https://www.alchemy.com/overviews/solidity-function-visibility)，因此其他合约可以访问它
- 随后，我们使用 _selfdestruct_ 关键字，在将 apocalypse 变量声明为 payable 后将其传入

由于该函数是 public 的，这本身就代表了一个潜在的安全隐患。为应对这一点，可以考虑添加 _onlyOwner_ 修饰符，或使用 [require 语句](https://www.alchemy.com/overviews/solidity-require)来确认只有所有者才能调用 destroy 函数。

### 通过 Alchemy 的 Solidity 开发者课程学习 Solidity 和 selfdestruct 函数

_Selfdestruct_ 是一种在发生安全漏洞、开发者需要升级合约或需要移除旧合约时终止合约的保险机制。尽管 _selfdestruct_ 的使用在 Solidity 开发者社区中仍存在争议，但该函数的引入已经帮助防范了许多潜在的黑客攻击。

想进一步了解 _selfdestruct_ 等重要函数，[成为更优秀的 Solidity 开发者](https://www.alchemy.com/overviews/how-to-become-a-solidity-developer)，可以报名参加 Alchemy University 提供的[免费、为期 7 周的 Ethereum Bootcamp](https://university.alchemy.com/?a=d1bd288312)。如果你刚开始接触开发，Alchemy 的 **3 周 JavaScript 速成课程**是学习 Ethereum bootcamp 前很好的先修课程。
