本文將深入介紹 Ethereum Opcode 的最新成員:PUSH0
在過去,我們只能使用 PUSH1 0x00
(= 0x6000)來達成將數值 0 存入 EVM 的 Stack 中,而上海升級中包含諸多 EIP 之一的 EIP-3855 提案則引入了 PUSH0
(= 0x5F)這項新的 Opcode 來達成相同的效果。透過節省 1 Byte 的指令空間(0x6000 → 0x5F),減少了智能合約編譯後的 Bytecode 大小,進一步降低智能合約部署的成本。
而本文將會快速地帶到 EVM、Bytecode 與 Opcode 的基本概念,並一步一步地帶你瞭解 PUSH0 的核心意義和對現有合約的影響。
文章會從 EVM、Opcode 到 PUSH0 詳細說明,若您為區塊鏈開發人員,我們可用一句話函蓋整篇文章:
EIP-3855 引入新 Opcode:PUSH0(0x5F)來取代 PUSH1 0x00(0x6000),因減少 1 Byte 指令空間,所以減少了部署智能合約的 200 Gas,所有合約加總一年大約可省 1,362.23 ETH。
1、EVM 與 Opcode 概念
在介紹 EIP-3855 之前,我們先來簡單了解 Ethereum 中最重要的 EVM 概念!
EVM(Ethereum Virtual Machine)
我們為了讓智能合約在獨立且安全的環境中執行,而從 Ethereum 節點中會切出一塊具有儲存、執行等功能的運算環境,我們將之稱之為 EVM 虛擬機
而這個 EVM 具備執行智能合約所需的堆疊、記憶體、紀錄 Gas 費用及儲存下一行指令位址等各種必要元件,以便完成開發人員要求的各種計算
EVM 架構,原圖連結:https://ethereum.org/en/developers/docs/evm/
Bytecode 與 Opcode
我們用 Solidity 等語言所撰寫的智能合約,要先編譯成一連串 EVM Opcode,這一連串 Opcode 稱為 Bytecode。我們接著來進行一段簡單的操作就會比較清楚!
有興趣的讀者可以透過 EtherVM 了解更多關於 Opocde 的介紹。
首先,我們先在 Remix 上編譯下方這份簡易的加法智能合約,編譯完成後就可從 artifacts 資料夾中看到包含此智能合約 Bytecode 與 Opcode 的 Json 資訊檔
Remix 智能合約線上編譯工具
與此同時,這個智能合約也已部署到 Goerli 測試網中,我們可點選在 Etherscan 上的【Switch To Opcodes View】鈕從 Bytecode 切換到 Opcode 觀看模式。這時,即可得知一連串 Opcode 稱為 Bytecode
Etherscan 區塊鏈瀏覽器
這裡就只截取這份合約部份的 Opcode
部份 Bytecode 與 Opcode 對照表
現在我們有了 EVM、Bytecode、Opcode 的概念後,那 EIP-3855 到底要改進什麼問題呢?
前面的例子中,我們了解到若想要將一個零的值推到 Stack 中,這個動作會被編譯成「PUSH 0x00」(兩個 Byte,分別是 0x60 及 0x00,其中 0x00 代表零的值,所以 0x6000 整整佔了 2 個 Byte 的 Storage 空間!
1 Byte Bytecode 空間需要支付 200 Gas 的費用。
另外,執行 1 個 PUSH1 的操作需支付 3 Gas,而 PUSH0 也是,所以 PUSH0 主要是減少編譯後的程式碼大小,但實際上執行時的 Gas 消耗和 PUSH1 是一樣的
我們來看一下以下關於 Push1 0x00
指令在 2020 年的統計數據:
表格截取自下方附錄 2
Push1 0x00
指令佔了 2020 年全年度智能合約 Bytecode 的 4.57% 之多(同時也為 PUSH 系列指令之首),它被如此常用,以致於幾乎所有的智能合約中都可看到它的身影!
這時,如果我們新增一個 Opcode 來做和 PUSH1 0x00
完全一樣的事,是否就可以再減少 1 個 200 Gas 的空間消耗?
答案是可以的!EIP-3855 即將會在這一次的上海升級中在 Opcode 中引入一條 PUSH0
新指令,而這個新指令的編號是 0x5F!
會選擇 0x5F 做為 PUSH0
的原因,除了 0x5F 在上海升級前沒有被使用外(空的),而且它也剛好是在 PUSH1
(0x60)指令的前一個編號!是一個連續且有意義的指令空間
3、EIP-3855 帶來的改變
將 0x6000 指令瘦身至 0x5F 有一個最重要的改變,就是部署合約時的 Gas 費用變便宜了!程式碼中每個使用到 PUSH1 0x00
的地方都可以因為這個改變而省下 200 Gas!
那我們一樣以 2020 全年度使用 340,557,331 次 0x6000 指令來計算,大約需耗費 340,557,331 x 200 Gas = 68,111,466,200 Gas。接著若以 1 Gas 需支付 20 GWei 來計算,也就是可以為整個網路省下整整約 1,362.23 ETH,而且各個 Ethereum 節點也可省下不少儲存空間
此外,對於開發人員來說,也可減少使用一些特殊優化手段來減少 PUSH1 0x00
的 200 Gas 開銷,例如使用 DUP 指令(將 Stack 中指定的值,如:0 值推到 Stack 中)等。使用 0x5F 代表著可減少開發人員進行各種優化成本與風險,也利於估算智能合約的 Gas 費用
4、文章重點整理與結論
重點整理
-
EIP-3855 將減少部署智能合約時的 Bytecode 大小
-
此外,EIP-3855 也可減少過去開發人員在進行各種優化上的成本與風險
結論
本文介紹了 Ethereum 的 EVM(Ethereum Virtual Machine)及 Opcode 的概念,並且深入探討了 EIP-3855 改進的重要意義與影響。一旦這次的上海升級完成,就可減少開發人員部署合約時所需的儲存空間費用,而 EIP-3855 提案和新的特性,也將吸引更多的開發者加入到以太坊的生態中。感謝您閱讀本文!
5、參考資料與附錄
參考資料
-
中文
-
英文
-
EIP-3855 提案
-
EIP-3855 英文討論區
-
EVM Codes 列表
-
Ethereum Virtual Machine Opcodes
-
PDF - ethereum-evm-illustrated
-
附錄 1:關於 EIP-3855 常見問題
EIP-3855 提案通過後是否可提升 TPS(每秒交易數)?
TPS 增長量不大,因為實際在主網上部署合約的交易並不多,假設在一個區塊內有 10 筆部署合約交易(已是相當多)的狀況,若每個合約部署只「一次性」省約 25 個 PUSH0
(25 * 200 * 10 = 50,000 gas ),所以 TPS 可提升的有限。
一般 Solidity 開發人員如何應用此 EIP-3855 提案?
一般 Solidity 開發人員要等到上海升級完成才能享受到程式碼大小變小的好處,EIP-3855 主要是讓 Solidity 編譯器(將 Solidity 程式碼編譯成 Bytecode,而此 Bytecode 可對應不同的 Opcode)將所有 PUSH1 0x00
改為 PUSH0
,以節省空間、減少 gas 等好處。
附錄 2:2020 年「PUSH」系列指令數量統計表
此表格參考 EIP-3855 中作者之一 Hugo De la cruz 所統計的 2020 全年度 Ethereum Opcode 數量(區塊高度:8,567,259 ~ 8,582,058 及 12,205,970 ~ 12,817,405)表格,並進行延伸計算。