動區動趨-最具影響力的區塊鏈新聞媒體
  • Home
    • Home Layout 1
    • Home Layout 2
    • Home Layout 3
  • Browse
    • News
    • Movie
    • Music
    • Technology
    • Howto & Style
    • Entertainment
    • Gaming
  • Features
    • Youtube Video
    • Vimeo Video
    • Dailymotion Video
    • Self-hosted Video
    • User Profile
    • Playlists
    • User-created Playlist
    • Favorite Playlist (Private)
    • Watch Later Playlist (Private)
    • All JNews Features
No Result
View All Result
  • Login
  • Register
UPLOAD
動區動趨-最具影響力的區塊鏈新聞媒體
No Result
View All Result
Currently Playing

ABS獨家專訪》Gitcoin共同創辦人Scott:台灣是現實與Web3治理的重要交匯點

ABS獨家專訪》Gitcoin共同創辦人Scott:台灣是現實與Web3治理的重要交匯點

ABS獨家專訪》Gitcoin共同創辦人Scott:台灣是現實與Web3治理的重要交匯點

搶先看
ABS獨家專訪》Gate.io CEO韓林:無懼銀行進軍加密服務,台北特別有人情味

ABS獨家專訪》Gate.io CEO韓林:無懼銀行進軍加密服務,台北特別有人情味

搶先看

6 Sci-fi Gadgets in Movie We Wish Actually Existed

Movie

The 10 best games to play on your new PlayStation 4

Gaming

Tesla’s Chinese factory just delivered its first cars

News

以太坊柏林硬分叉|搞懂「Gas開銷計算」改變,新增「訪問清單」功能又如何使用?

以太坊用戶期盼已久的「柏林」硬分叉終於上線,究竟柏林為現有的 GAS 消耗帶來了什麼改變,新引入的訪問清單(Access List)又該如何使用?本文源自於 Franco Victorio 文章《Understanding gas costs after Berlin》,由專欄作者 以太坊愛好者 編譯、撰稿及整理。
(前情提要:以太坊「柏林硬分叉」完成!卻遇客戶端共識錯誤;ETH續刷歷史新高達 2,548 美元)
(事件背景:1 年後終於到來!以太坊「柏林硬分叉」宣布 4月中上線,四個 EIP 提案將納入升級)

 

「柏林」硬分叉在 4 月 15 日啟動,該硬分叉所包含的兩個 EIP (EIP-2929 和 EIP-2930)都會影響事務的 Gas 開銷。

本文會解釋 「柏林」啟動之前,一些指令碼的 Gas 消耗量是如何計算的,而 EIP-2929 對此有何影響,以及 2930 引入的訪問清單(Access List)功能應如何使用。

摘要

這篇文章很長,你如果只想知道結論,看完這部分就可以把網頁關掉了:

  • 柏林硬分叉改變了某些指令碼的 Gas 開銷。如果你在自己的應用中硬編寫了一些指令可使用的 Gas 數量,這些指令可能會卡死。如果真的出現了這種情況,而你的智能合約又是沒法升級的,用戶就需要使用「訪問清單」功能來使用你的應用。
  • 訪問清單功能可略微減少 Gas 開銷,但有些時候也可能會提高 Gas 的總消耗量。
  • geth 客戶端引入了一種新的 RPC 方法,叫做 eth_createAccessList 來簡化訪問清單的生成。

「柏林」升級以前的 Gas 開銷

EVM 所執行的每一個指令碼都有一個對應的 Gas 消耗量。大部分指令碼的消耗量都是固定的:PUSH1 總是消耗 3 gas,而 MUL 消耗 5 gas,等等。有一些指令碼的消耗量是可變的:舉個例子,SHA3 指令碼的開銷由輸入值的長度決定。

我們先了解 SLOAD 和 SSTORE 指令碼,因為這兩個指令碼受 「柏林」 影響最大。後面我們會再談談那些以地址為目標的指令,比如所有的 EXT* 類指令碼和 CALL* 類指令碼,因為它們的 Gas 開銷也被改變了。

「柏林」以前的 SLOAD

在 EIP-2929 實施前,SLOAD 開銷的計算方式很簡單:總是消耗 800 gas。

「柏林」以前的 SSTORE

要講到 Gas 消耗量的計算,SSTORE 指令碼可能是最複雜的了。因為消耗多少取決於該儲存槽當下的值、要寫入的新值、該儲存項是否已經修改過。我們只會分析少數幾種場景,了解個大概。如果你想了解更多,請閱讀本文末尾所附的 EIP 連結。

  • 如果儲存項的值從 0 改為 1(或者任意非零的值),Gas 消耗量是 20000
  • 如果儲存項的值從 1 改為 2(或者任意非零的值),Gas 消耗量是 5000
  • 如果儲存項的值從 1(或任意非零的值) 改為 0,消耗量也是 5000,但你會在事務執行結束後獲得 gas 補貼。我們這裡也不討論 gas 返還機制,因為它不會受到柏林的影響
  • 在一筆事務中,如果儲存項已不是第一次修改,則後續每一次 SSTORE 都消耗 800 gas

細節在這裡並不重要,重要的是,SSTORE 是昂貴的,具體消耗多少 gas 則依賴於多個因素。

延伸閱讀:以太坊有救?改革「ETH手續費市場機制」的 EIP 1559,今年 7月「倫敦硬分叉」將推出

EIP-2929 之後的 Gas 消耗量

EIP-2929 改變了所有這些數值。但在開始之前,我們要先談談該 EIP 引入的一個重要概念:被訪問過的地址和被訪問過的儲存項的鍵(storage key)。

當一個地址或者一個儲存項的鍵,在一筆事務中被 「使用過」 之後,在該筆交易剩下的執行過程中,這個地址(或者這個鍵)都會被當成「已被訪問過的」處理。

舉個例子,如果你在一筆事務中 CALL (調用)另一個合約,那麼該合約的地址就會被標記為 「訪問過的」。類似地,如果你 SLOAD 或者 SSTORE 過一些儲存項槽 ,在該筆事務剩下的執行過程裡,這些槽也會被當成已經訪問過的。

和使用的指令碼無關,即使你只 SLOAD 過某個槽,接下來使用 SSTORE 時,該槽也會被當成已訪問過的。

要注意的是:儲存項的鍵是「內在於」某些地址中的,正如該 EIP 所解釋:

執行事務時,維持單一集合: accessed_addresses: Set[Address] 以及 accessed_storage_keys: Set[Tuple[Address, Bytes32]]

也就是說,當我們說某個儲存槽已被訪問過了,我們的實際意思是:(address, storageKey) 已被訪問過了。

搞清楚了這個概念,我們來談談新的 Gas 消耗量計算模式。

「柏林」以後的 SLOAD

升級前,SLOAD 的 Gas 消耗量是固定的 800。但升級後,Gas 消耗量要看這個儲存槽是否已經被訪問過。

還沒訪問過的,消耗量就是 2100 gas;訪問過的,就是 100 gas。所以,如果某個儲存項槽已經在「已訪問過的儲存項鍵」的集合裡了,就可以省掉 2000 gas。

「柏林」以後的 SSTORE

我們一個一個對比一下,在 EIP-2929 實施後,上面的幾個例子會發生什麼樣的變化:

  • 如果儲存項的值從 0 改為 1(或者任意非零的值),Gas 消耗量是 20000
    • 如果該儲存項鍵還未訪問過,消耗 22100 gas
    • 若已訪問過,消耗 20000 gas
  • 如果儲存項的值從 1 改為 2(或者任意非零的值),Gas 消耗量是 5000
    • 如果該儲存項鍵還未訪問過,消耗 5000 gas
    • 若已訪問過,消耗 2900 gas
  • 如果儲存項的值從 1(或任意非零的值) 改為 0,消耗量保持不變,gas 返還機制也不變
  • 在一筆事務中,如果儲存項已不是第一次修改,則後續每一次 SSTORE 都消耗 100 gas

由此可見,如果某個槽此前已訪問過,則對它的第一次 SSTORE 指令會節省 2100 gas(相比於從未訪問過)。

延伸閱讀:鏈上數據|一文看懂「以太坊世界的現況、各個趨勢、未來」,Defi Eth2 NFT 正加速擴張

總結一下

上面的文字實在囉嗦,我們就直接做一張表,把上面提到的值都匯總一下:

指令碼 「柏林」前 「柏林」後
未訪問過 訪問過
SLOAD 800 2100 100
SSTORE from 0 to 1 20000 22100 20000
SSTORE from 1 to 2 5000 5000 2900
SLOAD+SSTORE* 5800 5000 3000
SSTORE*+SLOAD 5800 5100 3000
SSORE一個已經被寫過的槽 800 100
*從一個非 0 值改為另一個非 0 值,如第三行

注意看最後一行:此時已不再需要區分它到底有沒有被訪問過,因為如果在此之前已被寫入,則必定已被訪問過。

EIP-2930:可選「訪問清單」的事務類型

另一個「柏林」升級包含的 EIP 是 2930。

該 EIP 加入了一種新類型的事務,可以在事務的負載中包含一個「訪問清單」,意思是,你可以在事務執行前就聲明哪些地址和儲存槽應被認為是「訪問過的」 。

舉個例子,對一個未訪問過的槽執行 SLOAD 需要耗費 2100 gas,但如果該儲存槽被包含在了事務的「訪問清單」中,則指令的消耗量機會降為 100 gas。

但如果只要地址和槽被當成「已訪問過的」就可以降低指令的 Gas 消耗量;而訪問清單可以把地址和槽標記為「已訪問過的」;那豈不是說我們可以把這些東西都放在訪問清單中,來獲得 Gas 消耗量的減免?真棒,天賜 Gas!

並不完全如此,因為你每添加一個地址或儲存項鍵,都要支付額外的 Gas。舉個例子。假如我們要向合約 A 發送了一條事務。我們編寫了一條這樣的訪問清單:

accessList: [{
 address: "<address of A>",
 storageKeys: [
  "0x0000000000000000000000000000000000000000000000000000000000000000"
 ]
}]

如果我們發送了一條帶有這條訪問清單的事務,而使用 0x0 儲存槽的第一個指令碼就是 SLOAD,則 Gas 消耗量會是 100 而非 2100,也就是減免了 2000 gas。

但是,在訪問列表中聲明一個儲存項鍵需要額外支付 1900 gas,所以我們只節約了 100 gas。 (如果對該儲存槽的第一個指令是 SSTROE,我們在一個指令中就省下了 2100 gas,也就是總共省下了 200 gas,因為訪問清單本身需要消耗 gas)。

這是不是說,每次使用訪問清單我們都能節省 gas 呢?很遺憾,也不是,因為在訪問清單中填入地址也需要支付 gas。 (也就是我們示例中的 "<address of A>")

訪問過的地址

迄今為止,我們只討論了 SLOAD 和 SSTORE 指令碼,但「柏林」升級還改變了別的指令碼。舉個例子,CALL 指令碼原來的 Gas 消耗量為固定的 700,但 2929 實施後,如果所調用的地址不在訪問清單中,消耗量將提高到 2600;而如果在,則降低為 100。

而且,就像訪問過的儲存鍵一樣,到底哪個指令碼訪問過那個地址並不重要(比如,如果用戶最先調用的是EXTCODESIZE,這一個指令的消耗量是2600,但後續的調用,只要是對同一個地址的,無論是EXTCODESIZE、CALL 還是STATICCALL ,都只消耗100 gas。

那個這個設計對帶有訪問清單的事務有何影響?假設我們向合約 A 發送一條交易,而合約 A 調用了合約 B,而我們在訪問清單中寫入這樣的內容:

accessList: [{ address: "<address of B>", storageKeys: [] }]

我們首先需要為在這條事務的訪問清單中加入這個地址支付 2400 gas,但對 B 使用的第一個指令碼就只需要消耗 100 gas 而不是 2600 gas,這就剩下了 100 gas。

如果B 也需要使用其儲存項,我們又知道它​​將使用哪個鍵,我們也可以把這些鍵包含在訪問列表中,然後為每個鍵的指令省下 100 或 200 gas(取決於第一個指令碼是 SLOAD 還是SSTORE)。

但我們為什麼要加多一個合約來舉例子?我們不是可以這樣寫嗎?

accessList: [
 {address: "<address of A>", storageKeys: []},
 {address: "<address of B>", storageKeys: []},
]

你當然可以這樣做,但不值得,因為EIP-2929 指明了你一開始調用的合約(也即是 tx.to 的目的地)必定會被包含在 accessed_addresses 列表中,所以你就是額外花了 2400 gas ,什麼好處都沒得到。

所以,回頭看我們上面舉的例子:

accessList: [{
 address: "<address of A>",
 storageKeys: [
  "0x0000000000000000000000000000000000000000000000000000000000000000"
 ]
}]

這樣做其實是浪費,除非你在裡面加多幾個儲存項鍵。如果我們假設所有的儲存項鍵的第一個指令都是 SLOAD,那你要至少 24 個鍵,才能賺回來。

而且,如你所見,自己一五一十地分析這些因素、手動生成訪問清單,顯然是極其繁瑣而令人崩潰的事。好在,還有更好的辦法。

延伸閱讀:獨立觀點|以太坊世界停擺 1 天!如何看待「Infura 節點崩潰」及其造成的影響?

eth_createAccessList RPC 方法

Geth 客戶端(從 1.10.2 開始)將包含一個新的 eth_createAccessList RPC 方法,你可以用它來生成訪問清單,就像使用 eth_estimateGas 一樣,只不過返回的不是 Gas 消耗量估計,而是像這樣的數據:

{
 "accessList": [
  {
   "address": "0xb0ee076d7779a6ce152283f009f4c32b5f88756c",
   "storageKeys": [
    "0x0000000000000000000000000000000000000000000000000000000000000000",
    "0x0000000000000000000000000000000000000000000000000000000000000001"
   ]
  }
 ],
 "gasUsed": "0x8496"
}

也就是告訴你一筆事務將會用到的地址和儲存項鍵的清單,以及,假定納入這份訪問清單,將耗用多少 gas。跟 eth_estimateGas 一樣,這也是估計出來的,該筆事務真正上鏈時,會訪問到哪些數據仍有可能改變。

但是,再說一遍,這絕不意味著你只要使用了訪問清單,所用的 Gas 就會比不用清單更少!

我估計隨著時間推移,我們會越來越知道怎麼利用這個功能,但我個人估計,方法的偽代碼形式會像這樣:

let gasEstimation = estimateGas(tx)
let { accessList, gasUsed } = createAccessList(tx)
if (gasUsed > gasEstimation) {
 delete accessList[tx.to]a
}
tx.accessList = accessList;
sendTransaction(tx)

防止合約變磚

值得注意的是,訪問清單功能的主要目的不是節省 Gas。如該 EIP 所述:

緩解由EIP-2929 帶來的合約變磚風險,因為事務可以預先指定、預先支付自身嘗試範文的賬戶和儲存槽。

因此,在實際的執行中,SLOAD 和 EXT* 指令碼都只會消耗 100 gas :這個值低到既足以防止2929 打破某些合約,也可以「解封」被 EIP-1884 封印的合約。

原本,只要一個合約預設了執行的 Gas 開銷,指令碼的 Gas 消耗量變動就有可能導致它變磚。

比如,如果一個合約預設另一個合約的 someFunction 只會用到 34500 gas,因此總是用 someOtherContract.someFunction{gas: 34500}() 調用那個合約,這個合約就有可能變磚。但只要你在事務中添加合適的訪問清單,這個合約就還能運作。

自己驗證

如果你想自己測試一下,複製這個資料庫,這裡面有很多例子,可以使用 Hardhat 和 Geth 客戶端來運行。請仔細閱讀 README 裡的說明。

參考文獻

  • EIP-2929 和 EIP-2930 是兩個跟本文有關的 「柏林」 EIP。
  • EIP-2930 依賴於 「柏林」 升級納入的另一個 EIP:EIP-2718,也叫標準化的事務信封。
  • EIP-2929 大量參考了 EIP-2200,如果你想更深入地理解 Gas 消耗量,你應該從那裡開始。
  • 想了解更複雜的情形中 Gas 消耗量會如何變化,請看這裡。

📍相關報導📍

礦工號召大反攻!「愚人節」遷移算力「51%持續51小時」,武力逼宮以太坊 EIP-1559

V神:以太坊 Rollups「快來了」!無須分片就可擴容百倍,最高達4,000TPS

解讀|除了美圖秀秀,為何上市公司狂買BTC不愛以太坊?機構會是ETH新支柱嗎?


讓動區 Telegram 新聞頻道再次強大!!立即加入獲得第一手區塊鏈、加密貨幣新聞報導。

LINE 與 Messenger 不定期為大家服務

加入好友

加入好友

No Result
View All Result

近期文章

  • 精選文章搶先看!動區登入Access質押訂閱服務,解鎖寶貴資訊快人一步
  • ABS獨家專訪》Gitcoin共同創辦人Scott:台灣是現實與Web3治理的重要交匯點
  • ABS獨家專訪》Gate.io CEO韓林:無懼銀行進軍加密服務,台北特別有人情味
  • 快訊!BTC 現在已來到 58996.2
  • 快訊!BTC 現在已來到 58815.03
Next Post
幣安CZ : 團隊 370 億鎂 BNB 不賣「只燒毀」;Coinbase執行長已脫手 2.91 億鎂股份

幣安CZ : 團隊 370 億鎂 BNB 不賣「只燒毀」;Coinbase執行長已脫手 2.91 億鎂股份

Copyright (c) 2019 by Jegtheme.
  • About
  • Buy JNews
  • Request A Demo
  • Contact

Welcome Back!

Login to your account below

Forgotten Password? Sign Up

Create New Account!

Fill the forms below to register

All fields are required. Log In

Retrieve your password

Please enter your username or email address to reset your password.

Log In

Add New Playlist

- Select Visibility -

    No Result
    View All Result
    • Account
    • BlockTempo Beginner – 動區新手村
    • Change Password
    • Forgot Password?
    • Home 1
    • Home 2
    • Home 3
    • Jin-homepage
    • Latest
    • Login
    • Profile
    • Register
    • Reset Password
    • Trending
    • Users
    • Users List Item
    • 不只加密貨幣,談談那些你不知道的區塊鏈應用|動區新手村
    • 所有文章
    • 關於 BlockTempo

    © 2025 JNews - Premium WordPress news & magazine theme by Jegtheme.