EIP-6780 是修改 SELFDESTRUCT 指令行為的以太坊協議升級,核心改變是:SELFDESTRUCT 現在只在合約「部署的同一筆交易內」被呼叫時,才會完整刪除程式碼、儲存與帳戶;其他情況下(絕大多數實際用例)它只會把合約裡的資金轉出,程式碼與儲存資料全部留在鏈上不變,這跟 SELFDESTRUCT 原本「執行後整個合約消失」的行為完全不同。
這個改變存在,是因為以太坊未來要採用 Verkle Tree 這種新的狀態儲存架構,帳戶資料會被拆分存放在多個鍵值裡,讓「原子性地一次刪除一個帳戶底下所有資料」這件事在技術上變得不切實際且效率低落。EIP-6780 選擇調整 SELFDESTRUCT 的行為去配合新架構的限制,而不是讓整個狀態樹設計為了遷就舊的刪除邏輯而變得異常複雜,這是一個典型的「犧牲舊功能完整性,換取未來擴展性」的工程取捨。
具體規則是兩個分支:分支一,SELFDESTRUCT 在合約部署的同一筆交易內被呼叫——維持舊行為,程式碼、儲存、帳戶全部刪除,這常見於工廠合約模式裡「用完即丟」的輔助合約;分支二,SELFDESTRUCT 在部署完成後、經過一段時間才被呼叫——只執行資金轉出這個動作,合約的程式碼與過去寫入的儲存資料全部原封不動留在鏈上可查,帳戶本身依然存在。分析師要判斷一個「自毀過」的合約目前狀態,必須分別檢查:合約當前餘額是否為零(資金轉出完成)、以及合約程式碼與儲存是否依然可以被查詢(絕大多數情況下是可以的)。
對讀者的實際影響是:如果你在做鏈上盡職調查、追蹤某個合約過去的資金流向或漏洞紀錄,看到「這個合約執行過 SELFDESTRUCT」時,不能直接當作「這個合約已經不存在、可以忽略」的訊號。正確的做法是進一步查核:合約程式碼跟儲存資料是否依然可查(通常可以),過去的交易紀錄與邏輯依然是完整的鏈上證據,不會因為合約執行過自毀指令而消失或變得不可信。
在以太坊早期設計裡,SELFDESTRUCT 是一個智能合約可以呼叫的指令,執行後會把合約裡剩餘的資金轉給指定地址,同時把這個合約的程式碼、儲存資料、帳戶本身全部從鏈上狀態裡刪除——用「消失」來形容相當貼切,這個合約帳戶之後就不存在了。這個設計原本是為了讓開發者可以在合約不再需要時,釋放狀態空間、順便拿回一部分 gas 退款(刪除資料在過去會退還部分 Gas 成本)。
問題出在以太坊長期的擴展性路線圖上。未來以太坊要導入 Verkle Tree 這種新的狀態儲存結構,帳戶資料會被拆分存放在多個不同的鍵值裡。在這種架構下,要「原子性地」一次性刪除一個帳戨底下所有關聯資料,在技術上變得不切實際——不是做不到,而是會讓整個狀態樹的設計變得異常複雜且低效。EIP-6780 的解法不是強行修改整個架構去適應舊的刪除邏輯,而是反過來調整 SELFDESTRUCT 這個指令的行為,讓它配合新架構的限制。
調整後的規則是:如果 SELFDESTRUCT 在合約「部署的同一筆交易」裡被呼叫,它還是維持原本的行為——完整刪除程式碼、儲存與帳戶。但如果是在合約部署完成、經過一段時間之後才呼叫 SELFDESTRUCT(這是絕大多數實際使用情境),它現在只會執行資金轉出這一個動作,合約的程式碼與儲存資料全部原封不動留在鏈上。這個設計保留了「部署時立刻自毀」這種常見於工廠合約模式(用完即丟的輔助合約)的合法使用情境,同時砍掉了會造成問題的刪除行為。
這代表分析師面對一個「執行過 SELFDESTRUCT」的合約時,不能再直接假設它已經從鏈上消失。更準確的情況是:這個合約的餘額會變成零,資金已經轉出,但它的程式碼依然可以被查詢、它過去寫入的儲存資料依然可以被讀取——只是這個合約已經不會再被任何人正常呼叫或互動,變成一個名符其實的「空殼」。對做鏈上盡職調查或追蹤歷史資金流的人來說,這個區別很關鍵:一個「真的被刪除」的合約跟一個「餘額歸零但程式碼仍在」的合約,在風險評估的意義上完全不同——後者的歷史邏輯、過去的漏洞紀錄、曾經的攻擊面,都還能被完整檢視,不會因為合約「看起來」已經自毀就消失不見。
過去判斷一個合約是否「已經死亡」,可能會簡化成「有沒有呼叫過 SELFDESTRUCT」這個二元問題。EIP-6780 之後,這個問題必須拆成至少兩層:合約有沒有餘額(資金是否已被轉出)、以及合約的程式碼與儲存是否還能被查詢(絕大多數情況下答案是「是」)。一個分析平台如果只看「SELFDESTRUCT 事件是否曾被觸發」就把這個合約標記為「已消失」、從追蹤清單移除,實際上可能漏掉了一個仍然承載著完整歷史資料、甚至理論上仍可能被某些殘留權限互動的合約。