以太坊虛擬機

EVM 位元組碼

位元組碼是智能合約編譯後的機器層形式:一條扁平的位元組字串,內容只有操作碼及其內聯資料,可供 EVM 直接執行。你用 Solidity 這類高階語言寫合約,編譯器把它翻譯出來,真正存在鏈上的就是這條原始位元組字串——例如 0x6080604052...——人類很少直接閱讀,但每個節點都會原封不動地執行它。

一個微妙卻關鍵的區別,是建立位元組碼(creation bytecode)與執行期位元組碼(runtime bytecode)之分。部署合約時,你在交易中送出的是建立(init)位元組碼。EVM 會執行這段 init 程式碼一次——它跑建構子、設定初始儲存,然後回傳執行期位元組碼,協定再把它永久存放在新合約的地址。之後對該合約的每次呼叫,只會執行這段已儲存的執行期程式碼;建構子邏輯已消失,無法再被呼叫。

執行期位元組碼幾乎總是以一段分派器(dispatcher)開頭:這段短前言讀取 calldata 的前四個位元組(函式選擇器),與每個公開函式的選擇器逐一比對,再跳到相符的程式碼。Solidity 還會在已部署的位元組碼尾端附加一段 CBOR 編碼的中繼資料,內含原始碼/中繼資料的雜湊(通常是 IPFS 或 Swarm 雜湊)與編譯器版本,這正是瀏覽器能驗證所公開的原始碼是否與鏈上程式碼相符的依據。

一旦儲存,執行期位元組碼便不可變——沒有任何操作碼能覆寫合約自身的程式碼。因此可升級性其實是靠間接層假造的:代理合約持有儲存,並 delegatecall 進入一份地址可更換的獨立實作合約。真正的程式碼替換,只曾透過 SELFDESTRUCT 後再以 CREATE2 重新部署達成,這種「變形」(metamorphic)技巧如今因 SELFDESTRUCT 被棄用而大致失效。

24,576 位元組(EIP-170)的上限限制的是執行期位元組碼,而非建立位元組碼,所以龐大的建構子沒問題,但過大的已部署合約必須拆分(例如透過鑽石模式)。