EIP-2930:被低估的以太坊升級——存取清單交易完整解析

說到以太坊的 EIP,多數人只記得 EIP-1559 這個明星。但其實同一批升級裡還有另一個提案,雖然關注度低很多,卻帶來了根本性的改變。它就是 EIP-2930。這篇文章深入解析存取清單交易的技術細節,包括 EIP-2718 交易類型信封、EIP-2929 狀態存取 Gas 成本、以及存取清單如何實際降低 Gas 費用。同時探討 EIP-2930 對 ERC-4337 帳戶抽象和未來 EIP-7702 的深遠影響。

EIP-2930:被低估的以太坊升級——存取清單交易完整解析

說到以太坊的 EIP,多數人只記得 EIP-1559 這個明星。倫敦升級那年,1559 搶盡了所有風頭,彷彿以太坊的費用市場改革就靠這一個提案了。

但其實同一批升級裡還有另一個提案,雖然關注度低很多,卻帶來了根本性的改變。它就是 EIP-2930。

這傢伙到底做了什麼?簡單說:它讓交易發送前可以「預先告知」要存取的資料,驗證者因此能提前準備,大幅節省 Gas。概念類似搬家前先列清單,讓師傅知道沙發在哪、鋼琴在哪,比到了現場一件件指給他看有效率多了吧?

今天就來把 EIP-2930 的技術細節全部拆開來說。

EIP-2930 之前的世界:EIP-1559 的小兄弟

要理解 EIP-2930,得先知道它是什麼上下文裡誕生的。

Berlin 升級套餐

2021 年 4 月的 Berlin 升級包含四個 EIP:

EIP-1559 其實是倫敦升級(2021 年 8 月)的成員,不是 Berlin 的。Berlin 升級的四個提案都是在為 1559 做準備,確保費用市場改革能夠順利運作。

當時的背景問題

在 EIP-2930 之前,每次交易執行都要重新「摸索」需要的資料。智慧合約可能存取任何儲存槽,但驗證者不知道你要用哪些,只能等你用到時現場讀取。

這導致幾個問題:

冷儲存存取費用高:讀取從未接觸過的儲存槽,要付出較高的 Gas。因為驗證者需要真的去磁碟讀取,不能靠快取。

重複存取也收費:即使同一個值被多人讀取過,每次讀取都收費,沒有減免。

交易大小限制:傳統交易格式比較固定,擴展性有限。

EIP-2930 就是要解決這些問題。

存取清單(Access List)是什麼?

核心概念很直白:交易發送時附帶一份「我要用到哪些地址和儲存槽」的清單。

格式長這樣

{
  address: "0x1...",    // 要存取的合約位址
  storageKeys: [         // 要存取的儲存槽列表
    "0x0...",           // 第一個槽
    "0x1...",           // 第二個槽
    // ...
  ]
}

一筆交易可以宣告多個合約位址,每個位址下可以列出多個儲存槽。

實際例子

假設你要在 Uniswap 把 ETH 換成 USDC。執行時可能需要:

// 典型 Uniswap V2 swap 需要存取的位址和槽
{
  address: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",  // Uniswap V2 Router
  storageKeys: [
    "0x0000...",  // 工廠位址
    "0x0001...",  // 工廠某個狀態
  ]
},
{
  address: "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc",  // USDC/ETH 交易對
  storageKeys: [
    "0x0000...",  // 準備金 1
    "0x0001...",  // 準備金 2
  ]
},
{
  address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",  // USDC 合約
  storageKeys: [
    "0x0000...",  // 總供給量
  ]
}

提前告知這些,驗證者就能預先載入資料,大幅降低處理成本。

EIP-2718:交易類型信封

在談 EIP-2930 的技術實現之前,需要先了解 EIP-2718。

為什麼需要交易類型?

傳統以太坊交易的 RLP 編碼格式是固定的:

[nonce, gasPrice, gasLimit, to, value, data, v, r, s]

這九個欄位的意義和位置都寫死在黃皮書裡。想擴展?只能發新版本的交易,但舊節點不認識怎麼辦?

EIP-2718 定義了一個信封機制:

TransactionType || TransactionPayload

第一個位元組是「交易類型 ID」,後面的內容根據類型有不同的解釋。

好處:

交易類型註冊表

EIP-2718 建立了簡單的類型註冊約定:

類型 ID用途
0x0傳統交易(Legacy)
0x1EIP-2930 存取清單交易
0x2EIP-1559 費用市場交易
0x3+未來擴展預留

這個設計允許往後繼續增加新的交易類型,不用擔心格式衝突。

EIP-2930 交易格式

EIP-2930 定義的新型交易,格式如下:

# EIP-2930 交易結構
rlp([
    chainId,          # 鏈 ID(1 = 主網)
    nonce,            # 發送者交易計數
    gasPrice,         # 單價(類似傳統交易)
    gasLimit,         # Gas 上限
    to,               # 目標位址(空 = 部署合約)
    value,            # 轉帳金額
    data,             # 交易資料
    accessList,       # 存取清單
    yParity,          # v 值(用於簽章恢復)
    r,                # 簽章 r 值
    s                 # 簽章 s 值
])

相比傳統交易的九個欄位,多了三個新成員:

簽章變化

EIP-2930 使用 EIP-155 的簽章格式來防範 replay:

v = chainId * 2 + 35 + yParity

對主網(chainId=1)來說:

這確保 EIP-2930 交易只能在正確的鏈上執行。

Gas 計算的變化

這是 EIP-2930 最核心的部分:Gas 怎麼省?

存取清單的 Gas 折扣

EIP-2929 定義了狀態存取的 Gas 成本:

存取類型成本說明
Cold 存取(首次接觸)2100 / 2600第一次讀取合約/儲存槽
Warm 存取(重複接觸)100 / 100在最近區塊中被存取過

Cold = 冰的,要從磁碟讀取。Warm = 熱的,還在記憶體快取裡。

存取清單的減免邏輯

當交易宣告了存取清單後:

宣告的位址:視為 Warm,正常存取成本 100 Gas

宣告的儲存槽

未宣告的存取:正常收費,無法享受折扣

實際計算示例

假設一筆交易執行時:

// 沒有存取清單
讀取合約 A 的槽 X(首次) → 2600 Gas
讀取合約 B 的槽 Y(首次) → 2600 Gas
執行合約邏輯 → 50000 Gas
─────────────────────────
總計:31200 Gas

// 有存取清單
存取清單宣告:[A, X] 和 [B, Y]
讀取合約 A 的槽 X(已宣告) → 100 + 100 = 200 Gas
讀取合約 B 的槽 Y(已宣告) → 100 + 100 = 200 Gas
執行合約邏輯 → 50000 Gas
─────────────────────────
總計:20400 Gas

節省超過 30%!在複雜的 DeFi 交易中,存取清單往往能省下更多。

EIP-2930 與 EIP-1559 的關係

很多人搞混這兩個 EIP 的定位。

EIP-1559:費用市場改革

不包含存取清單

EIP-2930:交易格式擴展

不涉及費用市場

為什麼要分開?

設計上的考量:

  1. 解耦合:將費用市場和交易格式改為獨立變更
  2. 漸進式部署:EIP-2930 在 Berlin(2021.4),EIP-1559 在倫敦(2021.8)
  3. 向後相容:舊節點可以處理新格式

實務上,EIP-2930 為 EIP-1559 交易提供了底層支援。倫敦升級後,你發送的 1559 交易實際上底層也遵循 2930 的信封格式。

誰在使用存取清單?

瀏覽器錢包

多數現代錢包(MetaMask、Trezor Suite、Rabby)現在發送交易時都會幫你構造存取清單。

MetaMask 的實際行為:

開發者層面

如果你用 ethers.js 或 viem 發送交易,庫已經幫你處理好了:

// ethers.js 會自動添加存取清單
const tx = await contract.function(params, {
  // 這裡 ethers 會幫你估算並添加存取清單
});

console.log(tx.accessList);
// [
//   {
//     address: "0x...",
//     storageKeys: ["0x...", "0x..."]
//   }
// ]

RPC 節點

Erigon(原 TurboGeth)和 Nethermind 節點對存取清單有優化處理。Geth 雖然也支援,但優化程度較低。

存取清單的限制

EIP-2930 不是銀彈,有些情況下效果有限:

無法完全預測

智慧合約執行的分支可能無法事先知道:

function execute(uint256 choice) external {
    if (choice == 0) {
        // 讀取合約 A
    } else {
        // 讀取合約 B
    }
}

如果你選項 0,卻宣告了 B 的存取,浪費。如果選項 1,宣告了 A,也浪費。存取清單的準確性取決於對合約邏輯的理解程度。

過度宣告的問題

有些工具為了省麻煩,直接宣告大量常見位址和槽,反而增加交易大小(calldata),抵消了 Gas 節省的優勢。

calldata 的 Gas 成本是每 byte 16 gas(cold),如果宣告太多無用的存取,反而得不償失。

與 EIP-1559 的取捨

EIP-1559 的 Priority Fee 機制已經能有效控制等待時間。對多數用戶來說,存取清單的好處可能不明顯。但對大型 DeFi 操作、機構交易、批量交易,累積下來節省的就相當可觀了。

EIP-2930 的技術深水區

簽章處理

EIP-2930 的簽章格式與傳統交易不同。需要注意的是,外部簽章(off-chain signing)時要注意這點:

// 構造 EIP-2930 交易
const tx = {
  type: 1,  // EIP-2930 類型
  chainId: 1,
  nonce: 5,
  gasPrice: 30000000000,  // 30 gwei
  gasLimit: 200000,
  to: "0x742d35Cc6634C0532925a3b8D4C9B0d8a8f6b123",
  value: 0,
  data: "0x...",
  accessList: [
    { address: "0x...", storageKeys: ["0x..."] }
  ],
  yParity: 0,
  r: "0x...",
  s: "0x..."
};

簽章的 r, s 值仍然使用 secp256k1 橢圓曲線,但 yParity 取代了原本的 v 值來判斷簽章恢復。

交易驗證順序

節點收到 EIP-2930 交易後,驗證順序:

  1. 格式檢查:確認交易類型、長度、編碼正確
  2. 簽章驗證:使用 EIP-155 公式恢復發送者
  3. 鏈 ID 驗證:確保交易發往正確的網路
  4. Nonce 檢查:匹配發送者當前 nonce
  5. 餘額檢查:確保能支付 Gas
  6. Gas Limit 檢查:不超過區塊上限
  7. 存取清單預處理:將宣告的位址加入快取

注意存取清單的預處理是在所有基本檢查通過之後才執行的。

EIP-2930 的後續影響

EIP-2930 雖然低調,但為後續發展奠定基礎:

EIP-3074(未實現):這個提案打算讓 EOA 能夠委托執行權力給合約,類似一個「授權跳板」。它的設計就建立在存取清單的技術之上。

EIP-7702(2026 Pectra):EOA 臨時變身合約帳戶,這個提案某種程度上是 3074 的進化版,同樣依賴存取清單的底層機制。

所以 EIP-2930 不只是一次 Gas 優化,它是為未來更激進的帳戶改造預留的接口。

實戰:如何構造存取清單

使用 ethers.js

import { ethers } from "ethers";

const provider = new ethers.providers.JsonRpcProvider("...");

const wallet = new ethers.Wallet("0x...", provider);

// 構造帶存取清單的交易
const tx = {
  to: "0x...",  // Uniswap Router
  value: ethers.utils.parseEther("1.0"),
  // ethers 會自動估計存取清單
};

const populatedTx = await wallet.populateTransaction(tx);
console.log("存取清單:", populatedTx.accessList);

手動構造(進階)

const accessList = [
  {
    address: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
    storageKeys: []
  }
];

const tx = {
  type: 1,
  chainId: 1,
  accessList: accessList,
  // ... 其他欄位
};

工具推薦

常見問題

Q: 普通轉帳需要加存取清單嗎?

不需要。EOA 對 EOA 的轉帳不涉及合約存取,加存取清單反而增加開銷。

Q: EIP-2930 和 EIP-1559 哪個先實施?

EIP-2930 先(Berlin 升級,2021 年 4 月),EIP-1559 後(倫敦升級,2021 年 8 月)。

Q: 存取清單會讓交易變大嗎?

會的。calldata 要多承載存取清單的資料。不過對於複雜交易,省下來的 Gas 通常比額外花費的多。

Q: 存取清單可以加快交易確認速度嗎?

不能直接加速,但可以省 Gas。速度主要由 Gas 單價和網路擁堵程度決定。

結語

EIP-2930 是一個「幕後英雄」型的提案。沒有 1559 那樣戲劇性的 Base Fee 燃燒機制,沒有那麼多媒體報導,但它實際上改變了交易傳輸的方式,為未來的協議升級預留了空間。

下次你用 MetaMask 發送 DeFi 交易時,交易能被順暢執行,Gas 計算能這麼精確,存取清單功不可沒。

理解這些底層機制,不只考試能用,在 debug 複雜交易、分析 Gas 最佳化、評估 Layer 2 方案的底層時,都會派上用場。


延伸閱讀

資料截止日期:2026 年 3 月

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

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

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