(Cover designed by jannoon028 / Freepik)
作者:Irara @ imToken Labs
校稿:Nic、Cyan、ChangWu @ imToken Labs;FengYi @ imToken Wallet
本文將深入介紹 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。
在介紹 EIP-3855 之前,我們先來簡單了解 Ethereum 中最重要的 EVM 概念!
我們為了讓智能合約在獨立且安全的環境中執行,而從 Ethereum 節點中會切出一塊具有儲存、執行等功能的運算環境,我們將之稱之為 EVM 虛擬機
而這個 EVM 具備執行智能合約所需的堆疊、記憶體、紀錄 Gas 費用及儲存下一行指令位址等各種必要元件,以便完成開發人員要求的各種計算
我們用 Solidity 等語言所撰寫的智能合約,要先編譯成一連串 EVM Opcode,這一連串 Opcode 稱為 Bytecode。我們接著來進行一段簡單的操作就會比較清楚!
有興趣的讀者可以透過 EtherVM 了解更多關於 Opocde 的介紹。
首先,我們先在 Remix 上編譯下方這份簡易的加法智能合約,編譯完成後就可從 artifacts 資料夾中看到包含此智能合約 Bytecode 與 Opcode 的 Json 資訊檔
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.2 <0.9.0;
contract AddContract {
function addFunction(uint256 x, uint256 y) public pure returns (uint256) {
return x + y;
}
}
與此同時,這個智能合約也已部署到 Goerli 測試網中,我們可點選在 Etherscan 上的【Switch To Opcodes View】鈕從 Bytecode 切換到 Opcode 觀看模式。這時,即可得知一連串 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 年的統計數據:
Push1 0x00
指令佔了 2020 年全年度智能合約 Bytecode 的 4.57% 之多(同時也為 PUSH 系列指令之首),它被如此常用,以致於幾乎所有的智能合約中都可看到它的身影!
這時,如果我們新增一個 Opcode 來做和 PUSH1 0x00
完全一樣的事,是否就可以再減少 1 個 200 Gas 的空間消耗?
答案是可以的!EIP-3855 即將會在這一次的上海升級中在 Opcode 中引入一條 PUSH0
新指令,而這個新指令的編號是 0x5F!
會選擇 0x5F 做為
PUSH0
的原因,除了 0x5F 在上海升級前沒有被使用外(空的),而且它也剛好是在PUSH1
(0x60)指令的前一個編號!是一個連續且有意義的指令空間
將 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 費用
EIP-3855 將減少部署智能合約時的 Bytecode 大小
此外,EIP-3855 也可減少過去開發人員在進行各種優化上的成本與風險
本文介紹了 Ethereum 的 EVM(Ethereum Virtual Machine)及 Opcode 的概念,並且深入探討了 EIP-3855 改進的重要意義與影響。一旦這次的上海升級完成,就可減少開發人員部署合約時所需的儲存空間費用,而 EIP-3855 提案和新的特性,也將吸引更多的開發者加入到以太坊的生態中。感謝您閱讀本文!
中文
英文
EIP-3855 提案
EIP-3855 英文討論區
EVM Codes 列表
Ethereum Virtual Machine Opcodes
PDF - ethereum-evm-illustrated
TPS 增長量不大,因為實際在主網上部署合約的交易並不多,假設在一個區塊內有 10 筆部署合約交易(已是相當多)的狀況,若每個合約部署只「一次性」省約 25 個 PUSH0
(25 * 200 * 10 = 50,000 gas ),所以 TPS 可提升的有限。
一般 Solidity 開發人員要等到上海升級完成才能享受到程式碼大小變小的好處,EIP-3855 主要是讓 Solidity 編譯器(將 Solidity 程式碼編譯成 Bytecode,而此 Bytecode 可對應不同的 Opcode)將所有 PUSH1 0x00
改為 PUSH0
,以節省空間、減少 gas 等好處。
此表格參考 EIP-3855 中作者之一 Hugo De la cruz 所統計的 2020 全年度 Ethereum Opcode 數量(區塊高度:8,567,259 ~ 8,582,058 及 12,205,970 ~ 12,817,405)表格,並進行延伸計算