[Solidity] 智能合約函式名稱對Gas消耗的影響

你也許不會想到,函式名稱也會對 Gas 消耗造成影響,事實上,在最糟的情況下,甚至會有上千 Gas 的差距。我們來看看下面程式:

contract Test {
function b() public {
}
}

上面程式執行 b() 會消耗 125 Gas,接著改成下面:

contract Test {
function a() public {
}

function b() public {
}
}

這次執行 b() 變成消耗 147 Gas,一樣的空函式怎麼消耗增加了呢?試著執行 a() 會發現只消耗 125 Gas。

原來在智能合約中,函式存在前後順序,排序越後面的會消耗越多,每差一個順位就會多 22 Gas。此時你可能會想把它改成下面:

contract Test {
function b() public {
}
    function a() public {
}
}

但結果卻沒有變化,b() 一樣消耗 147 Gas,因為函式的排序是依據 Method ID。在這個例子中,他們的 Method ID 如下:

a: 0x0dbe671f
b: 0x4df7e3d0

依據這個規則我們再多加了一個函式:

contract Test {
function a() public {
}
    function b() public {
}
    function f() public {
}
}

他們的 Method ID 如下:

a: 0x0dbe671f
b: 0x4df7e3d0
f: 0x26121ff0

排序之後我們可以得到 a < f < b 的順序,猜猜這次執行 b() 會花多少 Gas?沒錯,答案是會消耗 169 Gas。

參與排序的成員

事實上,所有公用成員都會被列入計算。所以除了函式之外,屬性也會被列入計算,也包含 constant。例如:

contract Test {
uint256 public a;
    function b() public {
}
}

b() 會消耗147 Gas。

當然繼承的公用屬性和函式也都會列入計算,所以當合約功能較多後,公用成員可能會有幾十個。假設有 50 個的話,最後一個函式就多了一千的消耗。

函式簽章

在說明 Method ID 產生規則之前,要先知道函式簽章的規則,函式簽章包含函式名稱和參數型別。例如:

function func() public {
}
function func2(address[] addr, uint256 amount) public {
}

上面兩個函式的簽章分別為:

func()
func2(address[],uint256)

為了參與排序,屬性也會有簽章存在,再以同樣方式產生 Method ID。一般屬性視為沒有參數的函式,且只看名稱不看型別,無論是 uint256 還是 address。mapping 則將 Key 視為第一個參數,例如:

uint256 public a;
address public b;
mapping(address => uint256) public c;

簽章

a()
b()
c(address)

Method ID

Method ID 的產生規則如下:

keccack256(函式簽章) 取前四 bytes

所以上面的 a(), b() 和 f() 函式簽章拿去做keccak256 (可利用我寫的線上工具) 可以得到下面結果:

0dbe671f81a573cff601b9c227db0ed2e5339d3e0a07edc45c42f315a9cb8f0f
4df7e3d0fdffd35719c59893b4839a04b686be9ac7bec9cdd04a272e9ad7c628
26121ff025a6ba40cf27bcfb7cd50bcb8eab64881826af3760564c9e1ffa71eb

可以看出前四個 Bytes 正是 Method ID。

結論

在暸解了這些運作原理之後,我們可以做出以下兩種應對方式:

  1. 減少公用成員
  2. 將常用函式順位提高

第一點很容易理解與執行,而第二點我們可以透過命名的方式來達成。但是要人工的方式,命名到雜湊值剛好較低的方式並不容易。於是我寫了一個小工具來處理這個問題。以上面的例子來說,假設 b() 是常用的函式,若想將它提升順位,可以輸入函式簽章 b(),程式會自動找出一個 Method ID 前兩個 bytes 為零,結尾亂碼的新名稱:

b_A6Q(): 0x0000e3fa

另外由於 Method ID 會出現在 input data 中,所以除了排序提升的 Gas 減少之外,還額外省了128 Gas (請參考上一篇提到的交易資料 Gas 計算)。

Like what you read? Give Yi-Cyuan Chen a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.