以太坊 EVM Opcodes 完整參考手冊:Gas 消耗數學推導與實戰最佳化指南

本文深入剖析 EVM 完整 opcode 指令集,從基礎的算術運算到複雜的存儲操作,提供完整的 Gas 消耗數學推導與實戰最佳化指南。涵蓋記憶體成本二次函數推導、SSTORE 狀態機制、CALL 系列的 cold/warm access 定價模型、日誌操作的 Gas 計算、以及 EOF 時代新 opcode 的完整解析。提供大量 Solidity 和 Assembly 程式碼範例,幫助開發者編寫更省 Gas 的智能合約。

EVM Opcode 完整參考手冊:Gas 消耗推導與實務對照表(2026 最新版)

說真的,每次看到新手工程師寫合約時完全不考慮 Gas,我都替他心疼錢包。EVM Opcode 的 Gas 消耗聽起來是個很無聊的話題,但它是理解以太坊智能合約成本的終極鑰匙。

這篇文章整理了所有 EVM Opcode 的 Gas 消耗數據,用公式推導幫你理解數字的由來,再配上程式碼範例讓你知道「這個 Opcode 在 Solidity 裡長什麼樣子」。如果你正在準備以太坊開發認證考試、或是想在面試時展現深度技術能力,這篇必讀。

資料截止 2026 年 3 月,所有數據基於 EIP-1559 之後的修正版規範。


Opcode 家族全景圖

EVM Opcode 大約有 140 種,我可以把它們分成幾個家族:

EVM Opcode 家族分類:

1. 停止與控制流
   STOP, JUMP, JUMPI, PC, JUMPDEST

2. 算術運算
   ADD, MUL, SUB, DIV, SDIV, MOD, SMOD, ADDMOD, MULMOD, EXP, SIGNEXTEND

3. 比較與邏輯運算
   LT, GT, SLT, SGT, EQ, ISZERO, AND, OR, XOR, NOT, BYTE, SHL, SHR, SAR

4. 密碼學(區塊鏈專用)
   SHA3, KECCAK256

5. 環境資訊
   ADDRESS, BALANCE, ORIGIN, CALLER, CALLVALUE, CALLDATALOAD, CALLDATASIZE, 
   CALLDATACOPY, CODESIZE, CODECOPY, GASPRICE, EXTCODESIZE, EXTCODECOPY,
   RETURNDATASIZE, RETURNDATACOPY, EXTCODEHASH

6. 區塊資訊
   BLOCKHASH, COINBASE, TIMESTAMP, NUMBER, DIFFICULTY, GASLIMIT, CHAINID, BASEFEE

7. 堆疊、記憶體、儲存操作
   PUSH1-PUSH32, DUP1-DUP16, SWAP1-SWAP16, POP, MLOAD, MSTORE, MSTORE8, SLOAD, SSTORE

8. 日誌操作
   LOG0, LOG1, LOG2, LOG3, LOG4

9. 系統操作
   CREATE, CALL, CALLCODE, RETURN, DELEGATECALL, CREATE2, STATICCALL,
   REVERT, INVALID, SELFDESTRUCT

10. Blob 交易(EIP-4844 新增)
    BLOBBASEFEE, BLOBHASH

停止與控制流Opcode

STOP 和 INVALID

STOP   → 0 Gas
INVALID → 0 Gas

STOP 是最簡單的 Opcode,直接終止執行,不消耗任何 Gas。

INVALID 專門用來讓合約 revert,用於 assert 等場景。

Solidity 對應:

// STOP 的行為類似於正常返回
function normalReturn() public pure returns (uint256) {
    return 42; // 執行到這裡正常結束
}

// INVALID 對應 assert 失敗
function assertFail() public pure {
    assert(false); // 這會消耗剩餘所有 Gas
}

JUMPDEST:控制流的標記

JUMPDEST → 1 Gas

JUMPDEST 是跳轉目標的唯一有效 Opcode。任何 JUMP 指令都必須跳到 JUMPDEST。

這個 Opcode 這麼便宜是有原因的:它是安全機制,防止攻擊者跳到合約任意位置執行代碼。

Solidity 中的運用:

function conditionalLogic(bool flag) public pure returns (uint256) {
    if (flag) {
        return 1;
    } else {
        return 0;
    }
    // 編譯器會在這裡放置 JUMPDEST
}

算術運算Opcode

算術運算是 EVM 最基礎的運算,Gas 消耗也相對穩定。

基本算術

ADD      → 3 Gas    (加法)
MUL      → 5 Gas    (乘法)
SUB      → 3 Gas    (減法)
DIV      → 5 Gas    (整數除法,無符號)
SDIV     → 5 Gas    (整數除法,有符號)
MOD      → 5 Gas    (取模,無符號)
SMOD     → 5 Gas    (取模,有符號)
ADDMOD   → 8 Gas    (加法後取模)
MULMOD   → 8 Gas    (乘法後取模)

指數運算

EXP      → 10 Gas(靜態部分)+ 50 Gas per byte(動態部分,指數的位元組數)

EXP 的 Gas 消耗取決於指數的大小!這是一個很重要的細節。

// EXP Gas 消耗對比
contract ExpGasDemo {
    function expSmall() public pure returns (uint256) {
        return 2 ** 10; // 靜態 10 Gas
    }
    
    function expLarge() public pure returns (uint256) {
        return 2 ** 1000000; // 靜態 10 + 50 * 976Gas(很大!)
    }
}

JavaScript 估算 EXP Gas:

const { ethers } = require("ethers");

async function measureExpGas() {
    const provider = new ethers.JsonRpcProvider("https://mainnet.infura.io/v3/YOUR_PROJECT_ID");
    
    const contractABI = [
        "function expSmall() pure returns (uint256)",
        "function expLarge() pure returns (uint256)"
    ];
    const contractAddress = "YOUR_CONTRACT_ADDRESS";
    const contract = new ethers.Contract(contractAddress, contractABI, provider);
    
    const gasSmall = await contract.expSmall.estimateGas();
    const gasLarge = await contract.expLarge.estimateGas();
    
    console.log(`小指數 Gas: ${gasSmall}`);
    console.log(`大指數 Gas: ${gasLarge}`);
    console.log(`差異: ${gasLarge.sub(gasSmall)} Gas`);
}

measureExpGas().catch(console.error);

Python 版本:

from web3 import Web3

def measure_exp_gas():
    w3 = Web3(Web3.HTTPProvider("https://mainnet.infura.io/v3/YOUR_PROJECT_ID"))
    
    contract_address = "YOUR_CONTRACT_ADDRESS"
    abi = [
        {"inputs": [], "name": "expSmall", "outputs": [{"type": "uint256"}], 
         "stateMutability": "pure", "type": "function"},
        {"inputs": [], "name": "expLarge", "outputs": [{"type": "uint256"}], 
         "stateMutability": "pure", "type": "function"}
    ]
    
    contract = w3.eth.contract(address=contract_address, abi=abi)
    
    gas_small = contract.functions.expSmall().estimate_gas()
    gas_large = contract.functions.expLarge().estimate_gas()
    
    print(f"小指數 Gas: {gas_small}")
    print(f"大指數 Gas: {gas_large}")
    print(f"差異: {gas_large - gas_small} Gas")

measure_exp_gas()

比較與邏輯運算Opcode

LT      → 3 Gas    (小於比較,無符號)
GT      → 3 Gas    (大於比較,無符號)
SLT     → 3 Gas    (小於比較,有符號)
SGT     → 3 Gas    (大於比較,有符號)
EQ      → 3 Gas    (相等比較)
ISZERO  → 3 Gas    (零值檢測,相當於 == 0)
AND     → 3 Gas    (位元 AND)
OR      → 3 Gas    (位元 OR)
XOR     → 3 Gas    (位元 XOR)
NOT     → 3 Gas    (位元 NOT)
BYTE    → 3 Gas    (讀取特定位元組)
SHL     → 3 Gas    (左移,EIP-145)
SHR     → 3 Gas    (右移,EIP-145)
SAR     → 3 Gas    (算術右移,EIP-145)

Solidity 對照:

contract LogicalOps {
    function compare(uint256 a, uint256 b) public pure returns (bool) {
        return a < b; // LT opcode
    }
    
    function isZero(uint256 a) public pure returns (bool) {
        return a == 0; // ISZERO opcode
    }
    
    function bitwiseAnd(uint256 a, uint256 b) public pure returns (uint256) {
        return a & b; // AND opcode
    }
    
    // Solidity 0.8.x 支援位移運算
    function shiftOps(uint256 a) public pure returns (uint256, uint256) {
        return (a << 2, a >> 2); // SHL, SHR opcodes
    }
}

密碼學Opcode

SHA3 / KECCAK256

SHA3 → 30 Gas + 6 Gas per word(記憶體成本)

Keccak-256 是以太坊的核心哈希函數,用於很多地方,包括位址計算和狀態根。

Solidity 對應:

contract HashDemo {
    function hashData(bytes memory data) public pure returns (bytes32) {
        return keccak256(data); // SHA3 opcode
    }
    
    // 經常用於產生唯一 ID
    function generateId(address user, uint256 nonce) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(user, nonce));
    }
    
    // 映射查找
    mapping(bytes32 => uint256) public values;
    
    function setValue(bytes32 key, uint256 value) external {
        values[keccak256(abi.encodePacked(key))] = value;
    }
}

Python 實作 Keccak-256 計算:

from web3 import Web3
import sha3

def keccak256_demo():
    w3 = Web3(Web3.HTTPProvider("https://mainnet.infura.io/v3/YOUR_PROJECT_ID"))
    
    # 方法一:使用 web3.py
    data = b"Hello, Ethereum!"
    hash1 = w3.keccak(data)
    print(f"使用 web3.py: {hash1.hex()}")
    
    # 方法二:使用 pysha3
    k = sha3.keccak_256()
    k.update(data)
    hash2 = k.hexdigest()
    print(f"使用 pysha3: {hash2}")
    
    # 驗證兩者相等
    assert hash1.hex() == hash2, "哈希值不一致"
    
    # 模拟合約中的 keccak256 使用
    user = "0x742d35Cc6634C0532925a3b844Bc9e7595f5b5b0"
    nonce = 12345
    packed = w3.codec.encode(['address', 'uint256'], [user, nonce])
    id = w3.keccak(packed)
    print(f"生成的 ID: {id.hex()}")

keccak256_demo()

環境資訊Opcode

這些 Opcode 用於獲取區塊鏈執行環境的資訊。

地址與餘額

ADDRESS      → 2 Gas    (讀取當前合約位址)
BALANCE      → 2600 Gas(冷)/ 100 Gas(熱)
ORIGIN       → 2 Gas    (交易發起者)
CALLER       → 2 Gas    (msg.sender)
CALLVALUE    → 2 Gas    (msg.value)

BALANCE 是昂貴的 Opcode!如果可以的話,用 Solidity 的 address.balance 也要小心。

contract BalanceDemo {
    // 直接調用 BALANCE
    function getBalance(address addr) public view returns (uint256) {
        return addr.balance; // BALANCE opcode
    }
    
    // 改進:避免重複讀取
    function getBalanceCached(address addr) public view returns (uint256) {
        uint256 bal = addr.balance; // 只讀取一次
        // 多次使用的場景
        return bal;
    }
}

JavaScript 查詢餘額:

const { ethers } = require("ethers");

async function checkBalance() {
    const provider = new ethers.JsonRpcProvider("https://mainnet.infura.io/v3/YOUR_PROJECT_ID");
    
    // 方法一:直接用 provider
    const balance1 = await provider.getBalance("0x742d35Cc6634C0532925a3b844Bc9e7595f5b5b0");
    console.log(`ETH 餘額: ${ethers.formatEther(balance1)} ETH`);
    
    // 方法二:使用 ABI
    const abi = [
        "function getBalance(address addr) view returns (uint256)",
        "function getBalanceCached(address addr) view returns (uint256)"
    ];
    const contractAddress = "YOUR_CONTRACT_ADDRESS";
    const contract = new ethers.Contract(contractAddress, abi, provider);
    
    const balance2 = await contract.getBalance("0x742d35Cc6634C0532925a3b844Bc9e7595f5b5b0");
    console.log(`合約查詢餘額: ${ethers.formatEther(balance2)} ETH`);
}

checkBalance().catch(console.error);

Calldata 操作

CALLDATALOAD   → 3 Gas(熱讀取)
CALLDATASIZE   → 2 Gas
CALLDATACOPY   → 3 Gas per word + memory cost

Calldata 是函數呼叫的輸入資料,存儲在只讀記憶體中。

contract CalldataDemo {
    // 高效:直接使用 calldata
    function efficientFunc(uint256 a, uint256 b) 
        public 
        pure 
        returns (uint256) 
    {
        return a + b;
    }
    
    // 低效:複製到 memory
    function inefficientFunc(uint256 a, uint256 b) 
        public 
        pure 
        returns (uint256) 
    {
        uint256 memoryA = a; // 不必要的複製
        uint256 memoryB = b;
        return memoryA + memoryB;
    }
}

區塊資訊

BLOCKHASH  → 20 Gas(讀取最近 256 個區塊的哈希)
COINBASE   → 2 Gas(區塊獎勵地址)
TIMESTAMP  → 2 Gas(區塊時間戳)
NUMBER     → 2 Gas(區塊號)
DIFFICULTY → 2 Gas(區塊難度)
GASLIMIT   → 2 Gas(區塊 Gas 上限)
CHAINID    → 2 Gas(Chain ID,EIP-1344)
BASEFEE    → 2 Gas(基礎費用,EIP-1559)
contract BlockInfoDemo {
    function getBlockInfo() public view returns (
        uint256 blockNumber,
        uint256 timestamp,
        uint256 difficulty,
        uint256 gasLimit,
        uint256 baseFee
    ) {
        return (
            block.number,
            block.timestamp,
            block.difficulty,
            block.gaslimit,
            block.basefee
        );
    }
    
    // 使用 BLOCKHASH 驗證隨機數
    function verifyRandom(uint256 seed) public view returns (bytes32) {
        return blockhash(block.number - 1 - (seed % 256));
    }
}

Python 讀取區塊資訊:

from web3 import Web3

def get_block_info():
    w3 = Web3(Web3.HTTPProvider("https://mainnet.infura.io/v3/YOUR_PROJECT_ID"))
    
    # 獲取最新區塊
    block = w3.eth.get_block('latest')
    
    print(f"區塊號: {block['number']}")
    print(f"時間戳: {block['timestamp']}")
    print(f"難度: {block['difficulty']}")
    print(f"Gas 上限: {block['gasLimit']}")
    print(f"Base Fee: {block.get('baseFeePerGas', 'N/A')}")
    
    # 讀取特定區塊的 hash
    if block['number'] >= 256:
        past_block = w3.eth.get_block(block['number'] - 256)
        past_hash = past_block['hash']
        print(f"256 區塊前的 hash: {past_hash.hex()}")
    
    # 讀取 BLOCKHASH(特殊函數)
    target_block = block['number'] - 1
    block_hash = w3.eth.get_block(target_block)['hash']
    print(f"目標區塊 hash: {block_hash.hex()}")

get_block_info()

堆疊、記憶體、儲存操作Opcode

這是 EVM Opcode 中最重要的一類,直接影響合約的 Gas 消耗。

棧操作

PUSH1-PUSH32 → 3 Gas(每個)
POP         → 2 Gas
DUP1-DUP16  → 3 Gas
SWAP1-SWAP16 → 3 Gas

PUSH 和 POP 用於棧的進出操作。DUP 用於複製棧頂元素。SWAP 用於交換棧頂元素。

// Solidity 棧操作編譯示例
contract StackDemo {
    // 這個函數編譯後會產生多個 PUSH 和 SWAP
    function complexCalc(uint256 x) public pure returns (uint256) {
        uint256 a = x + 1;     // PUSH1 1, ADD
        uint256 b = x * 2;     // PUSH1 2, MUL
        uint256 c = a + b;     // DUP, ADD
        return c - x;          // SWAP, SUB
    }
}

記憶體操作

MLOAD  → 3 Gas + memory expansion cost
MSTORE → 3 Gas + memory expansion cost
MSTORE8 → 3 Gas + memory expansion cost(儲存單一位元組)

記憶體操作是 EVM 最複雜的 Gas 計算之一。記憶體越大,擴展成本越高。

contract MemoryDemo {
    // 記憶體寫入
    function storeToMemory() public pure returns (bytes32) {
        bytes32 value = bytes32(uint256(0x42));
        bytes32 slot;
        
        assembly {
            mstore(slot, value) // MSTORE opcode
        }
        
        return slot;
    }
    
    // 記憶體讀取
    function loadFromMemory(bytes32 slot) public pure returns (bytes32) {
        bytes32 value;
        
        assembly {
            value := mload(slot) // MLOAD opcode
        }
        
        return value;
    }
}

儲存操作:最貴的Opcode

SLOAD → 2100 Gas(冷讀取)/ 100 Gas(熱讀取)
SSTORE → 20000 Gas(0→非0)/ 2900 Gas(非0→非0)/ 100 Gas(非0→0,退款)

SSTORE 是所有 Opcode 中最貴的之一。寫入狀態是 Ethereum 最大的成本來源。

contract StorageDemo {
    uint256 public value;
    
    // 寫入新值:最貴
    function setNewValue(uint256 _value) external {
        value = _value; // 20000 Gas (0→非0)
    }
    
    // 更新現存值:較便宜
    function updateValue(uint256 _value) external {
        if (value != _value) { // SLOAD 讀取
            value = _value;    // SSTORE (非0→非0) = 2900 Gas
        }
    }
    
    // 清除值:退還部分 Gas
    function clearValue() external {
        delete value; // SSTORE (非0→0),退還 10000 Gas
    }
}

JavaScript 實驗 SSTORE 成本:

const { ethers } = require("ethers");

async function measureSstoreGas() {
    const provider = new ethers.JsonRpcProvider("https://mainnet.infura.io/v3/YOUR_PROJECT_ID");
    const signer = await provider.getSigner();
    
    const contractABI = [
        "function setNewValue(uint256 _value) external",
        "function updateValue(uint256 _value) external",
        "function clearValue() external"
    ];
    const contractAddress = "YOUR_CONTRACT_ADDRESS";
    const contract = new ethers.Contract(contractAddress, contractABI, signer);
    
    // 估算 Gas(不同操作的成本差異)
    const gasNew = await contract.setNewValue.estimateGas(42);
    const gasUpdate = await contract.updateValue.estimateGas(100);
    const gasClear = await contract.clearValue.estimateGas();
    
    console.log(`設定新值 Gas: ${gasNew}`);
    console.log(`更新現存值 Gas: ${gasUpdate}`);
    console.log(`清除值 Gas: ${gasClear}`);
    
    // 發送實際交易觀察
    const tx = await contract.setNewValue(42);
    await tx.wait();
    
    const receipt = await provider.getTransactionReceipt(tx.hash);
    console.log(`實際 Gas 使用: ${receipt.gasUsed.toString()}`);
}

measureSstoreGas().catch(console.error);

Python 版本:

from web3 import Web3

def measure_sstore_gas():
    w3 = Web3(Web3.HTTPProvider("https://mainnet.infura.io/v3/YOUR_PROJECT_ID"))
    
    contract_address = "YOUR_CONTRACT_ADDRESS"
    abi = [
        {"inputs": [{"name": "_value", "type": "uint256"}], 
         "name": "setNewValue", "outputs": [], 
         "stateMutability": "nonpayable", "type": "function"},
        {"inputs": [], "name": "clearValue", "outputs": [], 
         "stateMutability": "nonpayable", "type": "function"}
    ]
    
    contract = w3.eth.contract(address=contract_address, abi=abi)
    account = w3.eth.accounts[0]
    
    # 估算不同操作的 Gas
    gas_new = contract.functions.setNewValue(42).estimate_gas()
    gas_clear = contract.functions.clearValue().estimate_gas()
    
    print(f"設定新值估算 Gas: {gas_new}")
    print(f"清除值估算 Gas: {gas_clear}")
    
    # 發送交易並查看實際消耗
    tx_hash = contract.functions.setNewValue(42).transact({
        'from': account,
        'gas': gas_new + 10000  # 增加 buffer
    })
    
    receipt = w3.eth.get_transaction_receipt(tx_hash)
    print(f"實際 Gas 使用: {receipt['gasUsed']}")
    
    # 計算退款
    gas_refund = min(receipt['gasUsed'] // 2, 10000)  # refund 上限
    print(f"預估退款: {gas_refund}")

measure_sstore_gas()

系統操作Opcode

這些 Opcode 用於創建合約、呼叫其他合約、管理執行流程。

CREATE 與 CREATE2

CREATE    → 32000 Gas + memory cost
CREATE2   → 32000 Gas + memory cost + 200 Gas per word(salt)

CREATE2 是 EIP-1014 新增的 Opcode,允許用確定的鹽值創建合約,實現「新人際地址」。

contract CreateDemo {
    // 使用 CREATE
    function createNewContract(bytes memory bytecode) external returns (address) {
        address newContract;
        assembly {
            newContract := create(0, add(bytecode, 0x20), mload(bytecode))
        }
        return newContract;
    }
    
    // 使用 CREATE2(更好的可預測性)
    function createNewContract2(
        bytes memory bytecode,
        bytes32 salt
    ) external returns (address) {
        address newContract;
        assembly {
            newContract := create2(
                0,
                add(bytecode, 0x20),
                mload(bytecode),
                salt
            )
        }
        return newContract;
    }
}

CALL 系列

CALL     → 2600 Gas(冷)/ 100 Gas(熱)+ 被呼叫合約執行成本
CALLCODE → 2600 Gas(冷)/ 100 Gas(熱)+ 被呼叫合約執行成本
DELEGATECALL → 2600 Gas(冷)/ 100 Gas(熱)
STATICCALL → 2600 Gas(冷)/ 100 Gas(熱)

DELEGATECALL 是代理合約(Proxy Pattern)的核心,STATICCALL 用於 view 函數呼叫。

contract CallDemo {
    address public target;
    
    constructor(address _target) {
        target = _target;
    }
    
    // 標準呼叫
    function callTarget(bytes memory data) external returns (bytes memory) {
        (bool success, bytes memory result) = target.call(data);
        require(success, "Call failed");
        return result;
    }
    
    // 代理呼叫(保持 msg.sender)
    function delegateCallTarget(bytes memory data) external returns (bytes memory) {
        (bool success, bytes memory result) = target.delegatecall(data);
        require(success, "Delegatecall failed");
        return result;
    }
    
    // 靜態呼叫(不能修改狀態)
    function staticCallTarget(bytes memory data) external view returns (bytes memory) {
        (bool success, bytes memory result) = target.staticcall(data);
        require(success, "Staticcall failed");
        return result;
    }
}

RETURNDATA 系列(EIP-211)

RETURNDATASIZE → 2 Gas
RETURNDATACOPY → 3 Gas per word + memory cost

這些 Opcode 用於處理跨合約呼叫的返回值。

contract ReturnDataDemo {
    function getReturnData(address target, bytes memory data) 
        external 
        returns (bytes memory) 
    {
        (bool success, bytes memory returnData) = target.call(data);
        
        if (!success) {
            // 分析 revert 原因
            if (returnData.length > 0) {
                // returnData 包含 error signature + data
                return returnData;
            }
        }
        
        return returnData;
    }
}

SELFDESTRUCT

SELFDESTRUCT → 0 Gas(執行成本)+ 2400 Gas(退款機會)

SELFDESTRUCT 可以刪除合約並將剩餘 ETH 發送到指定地址。

contract SelfDestructDemo {
    address public owner;
    
    constructor() {
        owner = msg.sender;
    }
    
    // 緊急解鎖資金
    function emergencyWithdraw() external {
        require(msg.sender == owner, "Not owner");
        selfdestruct(payable(owner));
    }
}

日誌操作Opcode

LOG0 → 375 Gas + memory cost
LOG1 → 375 + 8*topic Gas + memory cost
LOG2 → 375 + 8*topic Gas + memory cost
LOG3 → 375 + 8*topic Gas + memory cost
LOG4 → 375 + 8*topic Gas + memory cost

每個 indexed 參數(topic)額外消耗 8 Gas。

Solidity 事件編譯:

contract EventDemo {
    // LOG0:無 indexed 參數
    event NoIndexed(uint256 a, uint256 b);
    
    // LOG1:一個 indexed 參數
    event OneIndexed(address indexed user, uint256 value);
    
    // LOG2:兩個 indexed 參數
    event TwoIndexed(
        address indexed from,
        address indexed to,
        uint256 amount
    );
    
    // 觸發事件
    function triggerEvents(uint256 a, uint256 b) external {
        emit NoIndexed(a, b);
        emit OneIndexed(msg.sender, a + b);
        emit TwoIndexed(msg.sender, tx.origin, a);
    }
}

Blob 交易Opcode(EIP-4844)

2024 年 Dencun 升級新增的 Opcode,用於處理 Blob 資料。

BLOBBASEFEE → 2 Gas(讀取 Blob 基礎費用)
BLOBHASH    → 3 Gas(讀取 Blob 雜湊值)
contract BlobDemo {
    function getBlobInfo() public view returns (bytes32, uint256) {
        return (
            blobhash(0),    // 第一個 Blob 的 hash
            blobbasefee     // Blob 基礎費用
        );
    }
}

Gas 消耗速查表

常用 Opcode Gas 消耗對照

┌────────────┬────────┬─────────────────────────────────┐
│ Opcode     │ Gas    │ 說明                            │
├────────────┼────────┼─────────────────────────────────┤
│ STOP       │ 0      │ 停止執行                        │
├────────────┼────────┼─────────────────────────────────┤
│ ADD        │ 3      │ 加法                            │
│ MUL        │ 5      │ 乘法                            │
│ DIV        │ 5      │ 除法                            │
│ EXP        │ 10+50n │ 指數(n=指數位元組數)          │
├────────────┼────────┼─────────────────────────────────┤
│ LT, GT, EQ│ 3      │ 比較運算                        │
│ AND, OR    │ 3      │ 位元運算                        │
├────────────┼────────┼─────────────────────────────────┤
│ SHA3       │ 30+6w  │ Keccak(w=記憶體 word 數)     │
├────────────┼────────┼─────────────────────────────────┤
│ SLOAD      │ 2100/100│ 冷/熱讀取                      │
│ SSTORE     │ 20k/2.9k│ 寫入新值/更新現存值           │
├────────────┼────────┼─────────────────────────────────┤
│ CALL       │ 2600/100│ 冷/熱呼叫                      │
│ CREATE     │ 32000   │ 創建合約                       │
│ CREATE2    │ 32000+200w│ 確定性創建                    │
├────────────┼────────┼─────────────────────────────────┤
│ LOG0-4     │ 375+8n │ 日誌(n=topic 數)             │
├────────────┼────────┼─────────────────────────────────┤
│ SELFDESTRUCT│ 0     │ 自毀                            │
└────────────┴────────┴─────────────────────────────────┘

實務工具推薦

Gas 分析工具

// 使用 Tenderly 進行 Gas 分析
const { Tenderly, Network } = require("@tenderly/sdk");

const tenderly = new Tenderly({
    network: Network.Mainnet,
    accessKey: "YOUR_ACCESS_KEY",
    secretKey: "YOUR_SECRET_KEY"
});

async function gasAnalysis() {
    const simulation = await tenderly.simulate({
        from: "0x...",
        to: "YOUR_CONTRACT_ADDRESS",
        method: {
            name: "yourFunction",
            params: { /* 參數 */ }
        },
        blockNumber: 19000000
    });
    
    console.log(`Gas 使用: ${simulation.gas_used}`);
    console.log(`Opcode 計數:`, simulation.opcode_counts);
}

gasAnalysis();

Opcode 追蹤

# 使用 eth-ape 追蹤 Opcode
# pip install eth-ape

from ape import accounts, networks

def opcode_tracking():
    with networks.ethereum.mainnet.use_provider("alchemy"):
        account = accounts.load("my_account")
        
        # 發送交易並追蹤
        receipt = account.call(
            target="YOUR_CONTRACT_ADDRESS",
            selector="yourFunction(uint256)",
            args=[42]
        )
        
        # 分析 Opcode 使用
        for trace in receipt.trace:
            print(f"Opcode: {trace['opcode']}, Gas: {trace['gas']}")

opcode_tracking()

結語:Opcode 是底層,工程師要懂

寫這麼多Opcode 資料,不是要你背起來,而是讓你知道:合約的 Gas 消耗不是玄學,是可以追蹤和最佳化的

當你能用 Opcode 的視角看合約時,你會發現很多以前忽略的最佳化點:

這些問題的答案,都在 Opcode 的 Gas 消耗邏輯裡。


資料截止日期:2026 年 3 月

一級來源

二級來源

工具資源

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。

目前尚無評論,成為第一個發表評論的人吧!