智能合約開發

Gas 最佳化

以太坊上每個操作都耗費 gas,而持久儲存是最昂貴的資源。因此 gas 最佳化主要是「盡量少碰儲存」並「以較便宜方式做算術與資料處理」的技藝。做得好,能把交易成本砍掉一大截;盲目地做,則可能為了微不足道的節省而毀掉可讀性。

高影響的技巧多半圍繞儲存。把數個小變數打包進一個 32 位元組的槽,使單一 SSTORE 一次更新它們全部。在迴圈中重複讀取某個儲存值之前,先把它快取到記憶體或堆疊變數——一次冷 SLOAD 約 2,100 gas、暖的約 100,而一次把零槽變非零的冷 SSTORE 約 20,000 gas。對在編譯期或建構期就固定的值使用 constant 與 immutable,因為它們被烘進位元組碼,完全不耗儲存。對外部函數的陣列引數優先用 calldata 而非 memory 以省去一次複製,並以自訂錯誤取代冗長的 revert 字串(4 位元組的選擇器對上一大串位元組)。

在算術與控制面:由於 Solidity 0.8 會插入自動溢位檢查,把可證明安全的算術(如迴圈計數器)包進 unchecked 區塊以跳過它們。避免對無界陣列做迴圈——其 gas 隨長度成長,可能撞上區塊 gas 上限,若攻擊者能讓陣列變長,這也是一種拒絕服務風險。對一組布林旗標使用位元圖(bitmap),並對只在單一交易內需要的值(例如重入鎖)考慮使用瞬時儲存(EIP-1153 的 TSTORE/TLOAD)。最重要的是要量測:gas 分析器會告訴你哪些儲存寫入才真正主導成本,讓你去最佳化昂貴的那 5%,而非把便宜的 95% 弄得晦澀難懂。

uint128 a; uint64 b; uint64 c;   // these three share ONE 32-byte slot
error Unauthorized();            // cheaper than require(.., "string")
for (uint256 i; i < n;) {
  total += data[i];
  unchecked { ++i; }             // counter can't overflow: skip the check
}

把 gas 花在關鍵處;儲存才是預算所在。

經驗法則:儲存遠勝一切。少寫一次冷 SSTORE(約 20,000 gas)就勝過數千次算術微優化——在把程式碼弄得晦澀之前,先做分析。