Solidity 中的 selfdestruct 是什麼?
作者 John Favole
更新:在 Shanghai Ethereum 升級中,Selfdestruct 已依照 EIP-6049 的規範被棄用。本文內容已過時,僅反映此功能過去的運作方式。
Selfdestruct 是 Solidity 中的一個關鍵字,用於開發者想要終止合約時使用。根據 2021 年一篇研究論文〈Why Do Smart Contracts Self-Destruct? Investigating the Selfdestruct Function on Ethereum〉,約有 800 個合約使用了 selfdestruct 關鍵字,使其成為學習 Solidity 時的重要概念。
本文將定義 selfdestruct 是什麼、說明其用途,並提供在 Solidity 智能合約中實作 selfdestruct 的範例。
什麼是 selfdestruct?
Selfdestruct 是一個用於終止合約、從 Ethereum 區塊鏈上移除位元組碼,並將合約中的資金傳送到指定地址的關鍵字。
Selfdestruct 起源於 2016 年,當時 Ethereum 區塊鏈與去中心化組織(DAO)都還處於發展初期。其中一個最早的 DAO 遭駭客攻擊,損失了 360 萬 ETH。由於 Solidity 合約具有不可變性,這次攻擊持續了數天。當時尚不存在銷毀合約的方法,早期的 DAO 開發者只能分岔整條區塊鏈,以防止進一步的漏洞利用。
因此,selfdestruct 被創造出來,作為安全威脅發生時的緊急出口。雖然它最初被稱為「suicide function」,但從 Solidity v0.5.0 起改名為 selfdestruct。
開發者為什麼要使用 selfdestruct 函式?
開發者使用 selfdestruct 函式,主要是為了提升智能合約程式碼的安全性、清理不再使用的合約,以及快速轉移 Ethereum 資產。
當開發者需要升級智能合約時,selfdestruct 就很有幫助。舉例來說,ERC-20 框架是 Ethereum 上所有同質化代幣的標準實作方式,目的是為了互通性。任何未依循 ERC-20 標準的代幣,都會難以與其他合約互動。
在這種情況下,開發者會改用新合約,而不是升級現有合約。因此,他們可以使用 selfdestruct 函式從現有合約中取出資金,並建立一個具備所需功能的新合約。
開發者也會使用 selfdestruct 函式來防範潛在的安全威脅。根據同一份2021 年 selfdestruct 智能合約報告,當開發者在合約中發現安全漏洞時,selfdestruct 函式能協助他們立即終止有缺陷的合約,並以安全的合約取代它。
使用 selfdestruct 有哪些缺點?
selfdestruct 函式的缺點在於:無法回收 ERC-20 代幣,且合約自我銷毀後無法將代幣重新導向。
一般來說,selfdestruct 函式被呼叫時,往往是因為開發者未能及時通知合約即將終止。即使團隊有發出通知,訊息也可能來不及擴散。結果就是,有些人可能會以為合約仍在運作,而將資金傳送到已銷毀的合約,這種情況下資金就會遺失。
使用 selfdestruct 的第二個缺點是,它只能轉移 Ether(ETH),而無法轉移其他 ERC-20 代幣,例如山寨幣,或依循 ERC-721 代幣標準的 NFT。一旦呼叫 selfdestruct,這些資產就永遠無法回收。
為什麼有些人認為 selfdestruct 函式很危險?
selfdestruct 函式讓惡意開發者更容易進行 rug pull。
這個函式讓開發者能夠呼叫 selfdestruct,並將資金導向自己的個人錢包。因此,部分協議使用者與開發者對於使用 selfdestruct 函式抱持著複雜的態度。
selfdestruct 是如何運作的?
selfdestruct 的運作方式是:從鏈上抹除合約的位元組碼、將所有資金傳送到指定地址,然後將部分 gas 費用退還給開發者。
一個合約由兩個部分組成:狀態(state)與函式(functions)。這些部分定義了合約的行為以及可呼叫的函式。移除位元組碼意味著合約不再具備任何定義它的組成部分,使得該合約無法被呼叫。
selfdestruct 函式有一個必要參數,用來指定呼叫者希望合約資金在銷毀後歸屬的地址。
什麼是 negative gas,為什麼它很重要?
Negative gas 指的是交易手續費中的一部分,當開發者使用 selfdestruct 函式時,Ethereum 鏈會退還這部分費用。
Ethereum 透過將移除鏈上資料所節省下來的 gas 回饋給呼叫者,來鼓勵使用 selfdestruct 函式。當合約呼叫 selfdestruct 函式時,該交易所使用的總 gas 有一半會退還給呼叫者。
selfdestruct 會移除合約在 Ethereum 區塊鏈上的歷史紀錄嗎?
不會,selfdestruct 函式不會移除合約在 Ethereum 鏈上的歷史紀錄——它只會移除合約的位元組碼。
Ethereum 是一條區塊鏈,也是一個公開帳本,由一個互相連接的節點網路持續保存區塊鏈狀態的副本。因此,呼叫 selfdestruct 函式之前所發生的所有資料與交易,都會永久記錄在鏈上,無法被更改。
呼叫 selfdestruct 函式後,資金會永久遺失嗎?
有些會,有些不會:現有的 ETH 會被傳送到呼叫者所指定的另一個地址,而 ERC-20 代幣則會遺失。
此外,如果有人在合約已 selfdestruct(即已終止)之後,仍向該合約傳送資金,這些資金將不會被重新導向,並會遺失。
selfdestruct 函式範例
這個程式的目的,是允許鑄造 NFT,直到合約中累積達到一定數量的 ETH 為止。一旦達到此數量,程式會將所有 Ether 作為獎勵傳送給最後一位鑄造者的錢包。每個人可以用 1 Ether 鑄造多個 NFT,但每次只能鑄造一個。此合約並非用於正式環境,僅作為範例用途。
這個鑄造合約的主要問題在於,它使用「this.balance」來驗證合約是否有足夠資金以觸發結束條件。因此,攻擊者可以輕易地傳送一筆金額,讓合約超過指定上限,接著使用 selfdestruct 關鍵字,將資金導向自己宣告的建構子(constructor)。
因此,在使用 selfdestruct 時,開發者必須謹慎選擇用來滿足特定條件的變數。應避免使用任何指向合約地址或合約內資金的參照,因為這些都可能被人為操縱。
如何使用 selfdestruct 函式
初始化 selfdestruct 函式很簡單:你只需要在函式中使用 selfdestruct 關鍵字,並指定一個 payable 地址,該地址會在呼叫 selfdestruct 函式後接收合約資金。
以下是 Solidity 課程中常見的 selfdestruct 函式範例:
以下說明這段程式碼在做什麼:
- 這個函式的名稱是 destroy
- 參數將地址指定為 apocalypse
- 當 destroy 函式被呼叫時,地址會透過 apocalypse 變數指定
- 函式的可見性宣告為 public,讓其他合約也能存取它。
- 接著我們使用 selfdestruct 關鍵字,並在將 apocalypse 變數宣告為 payable 之後傳入。
由於此函式是 public 的,這代表著潛在的安全漏洞。為了應對這一點,你可以考慮加入 onlyOwner 修飾符,或使用 require 陳述式,來確認只有擁有者能呼叫 destroy 函式。
透過 Alchemy 的 Solidity 開發者課程學習 Solidity 與 selfdestruct 函式
Selfdestruct 作為一種安全機制,可在遭遇安全漏洞、開發者想要升級合約,或需要移除舊合約時終止合約。雖然 selfdestruct 的使用在 Solidity 開發者社群中仍存在爭議,但這個函式的出現,確實協助防範了許多潛在的駭客攻擊。
想深入了解像 selfdestruct 這樣的重要函式,並成為更優秀的 Solidity 開發者,可以報名 Alchemy University 的免費七週 Ethereum Bootcamp。如果開發者對開發本身還很陌生,Alchemy 的 三週 JavaScript 速成課程 是開始 Ethereum bootcamp 前很好的先修課程。
相關總覽

打造區塊鏈魔法
Alchemy 結合最強大的 Web3 開發者產品與工具,並提供資源、社群與卓越的支援。


