EVM 操作碼
操作碼是以太坊虛擬機(EVM)懂得執行的單一指令,例如把兩個數字相加(ADD)、儲存一個值,或呼叫另一份合約。可以把 EVM 想成一台極簡單的計算機,它一個位元組接一個位元組地讀取一條長長的位元組帶子;它讀到的每個位元組就是一個操作碼,明確告訴它下一步該做什麼。操作碼大約有 140 個,而所有曾經執行過的智能合約,歸根究柢都只是這些微小指令的序列。
每個操作碼都編碼成單一位元組,因此取值範圍從 0x00 到 0xFF。它們可分成幾大族:算術與比較(ADD 0x01、MUL 0x02、LT 0x10)、位元邏輯(AND、OR、XOR)、環境與區塊上下文(CALLER 0x33、TIMESTAMP 0x42)、堆疊/記憶體/儲存搬移(MLOAD 0x51、SSTORE 0x55)、流程控制(JUMP 0x56、JUMPI 0x57)、日誌(LOG0–LOG4),以及系統呼叫(CALL 0xF1、CREATE 0xF0、REVERT 0xFD)。PUSH 族(PUSH1 0x60 到 PUSH32 0x7F,外加 Shanghai 升級新增的 PUSH0 0x5F)很特別:它們是唯一攜帶內聯立即數的操作碼,會把要推入的常數直接嵌在操作碼位元組後面的位元組碼裡。
EVM 是一台堆疊機,因此幾乎每個操作碼都是從堆疊頂端彈出輸入、再把結果推回去。ADD 彈出兩個字並推回它們的和;SSTORE 彈出一個鍵和一個值寫進永久儲存,不推回任何東西。關鍵在於,每個操作碼還有固定或依公式計算的 gas 成本——算術很便宜,儲存寫入則非常昂貴——這正是協定計量並限制每一次運算的方式。
操作碼是以太坊協定向每個用戶端承諾必須完全一致實作的基石契約。只要兩個用戶端對哪怕一個操作碼的行為有分歧,它們就會算出不同的狀態根,鏈也會因此分裂。正因如此,操作碼的語意在黃皮書中被逐位元精確規範,任何變動(新增 PUSH0、重新定價 SLOAD)都需要謹慎而協調的硬分叉。
PUSH1 0x03 // stack: [3] PUSH1 0x02 // stack: [2, 3] ADD // stack: [5]
最精簡的操作碼序列;PUSH 內聯攜帶其運算元,ADD 消耗堆疊上的兩個字。
並非 0x00–0xFF 的每個位元組都有指派;未指派的值是「無效」操作碼,會立即中止執行並耗光所有剩餘 gas,這與有序的 REVERT 不同。