Solidity 智能合約 Gas 優化技巧 - 變數順序
說明
你也許不知道,Solidity 宣告變數的順序也會影響 gas 的消耗。由於 EVM 的操作都是以 32 bytes 為單位進行,所以編譯器會嘗試在讀寫變數時,將小於 32 bytes 的變數打包成 32 bytes 一組來進行存取,以達到節省存取次數的目的。不過編譯器並沒有足夠聰明,能自動將合約的變數做最佳化的分組。他會將固定大小的變數,依序每 32 bytes 為一組。例如下面的例子:
1 | contract MyContract { |
在執行 test()
時,雖然看起來寫入了四個變數,但是由於這四個變數加起來剛好是 32 bytes ,可以做一次性的寫入,所以實際上執行一個 SSTORE ,消耗 20000 gas 。接著看下面的例子:
1 | contract MyContract { |
中間插入了另一個變數,結果造成 a
, b
, e
和 c
會被分為一組, d 獨立為一組。同樣的 test()
造成兩次寫入,消耗 40000 gas 。最後再看一個例子:
1 | contract MyContract { |
這和第一個例子不同的地方是,在 test()
中的 a
和 b
寫入之後,做了一些其他的事情,最後才寫入 c
和 d
。結果這次會造成兩次的寫入,因為在執行 do something
的時候,編譯器判斷為打包的動作已經結束,就送出寫入。不過由於只有一組資料,所以這個程式結果會產生一新增和一次修改,總共會消耗 25000 gas 。
優化策略
根據上面的特性,我們可以很容易的知道如何進行應對。
正確的排序與分組
將資料大小能剛好 32 bytes 的湊成一組,並且將時常一起更新的放一起。
不好
1 | contract MyContract { |
好
1 | contract MyContract { |
我們假設 hp
和 mp
較常一起更新,而 maxHp
和 maxMp
較常一起更新,所以避免交錯排列。
一次性讀寫
如上面的例子,盡量一次性讀寫。
不好
1 | function test() { |
好
1 | function test() { |
這個特性在 struct
上也是有效。
延伸閱讀
本部落格所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明來自 小殘的程式光廊!
Comment