什么是 selfdestruct

  • Alchemy
  • 发布于 2023-10-10 17:47
  • 阅读 116

该文章详细介绍了Solidity中的selfdestruct关键字,包括其定义、工作原理、用途以及相关示例。文章回顾了selfdestruct的历史及其在以太坊智能合约中的重要性,同时讨论了使用该功能的安全性问题与潜在风险。尽管功能已在以太坊的上海升级中被弃用,但文章提供的背景与实例仍具有参考价值。


更新selfdestruct 在上海以太坊升级中被弃用,按照 EIP-6049 的要求。本文现在已经过时,仅反映此特性以前的工作方式。

selfdestruct 是 Solidity 中的一个关键字,用于开发者想要终止合约时。在一篇2021年的研究论文《智能合约为何自毁?——研究以太坊的selfdestruct函数》中,大约有800个合约包含了 selfdestruct 关键字,使其成为学习 Solidity 过程中的重要概念。

本文定义了 selfdestruct 的功能,描述了它的目的,并提供了在 Solidity 智能合约中实现 selfdestruct 的示例。

什么是 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,为什么相关?

负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 关键字,并指定一个可以在调用 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));
}

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

selfdestruct 充当了在安全漏洞发生时终止合约的保护措施,当开发者想升级合约或删除旧合约时使用。尽管在 Solidity 开发者社区中 selfdestruct 的使用仍然存在争议,但该函数的引入帮助保护了很多潜在的黑客攻击。

  • 原文链接: alchemy.com/overviews/se...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Alchemy
Alchemy
江湖只有他的大名,没有他的介绍。