在圖書館中使用 external over public 會降低 gas 成本嗎?
我有一個圖書館
實用程序.sol
library Utils { struct UtilType { unit var1; bool var2; } function addExtra(UtilType storage state, uint extra) public { state.var1 += extra; } }
注意庫中函式的
public
可見性。並且該功能的使用如下:addExtra``utils.sol
我的契約.sol
import "utils.sol" contract MyContract { using Utils for UtilsType; UtilsType state; function foo(uint extra) public { state.addExtra(extra); } }
- 將更
public
改為external
減少myutils.sol
外部函式呼叫成本並節省任何氣體?- 如果是這樣,節省氣體是否僅由於
uint
變數而不是結構類型而發生,因為它是儲存記憶體?
將函式聲明為
external
而不是public
根本不會影響 gas 使用,無論是在合約中還是在庫中。在早期版本的 Solidity 中,只有外部函式可以接受
calldata
參數。公開一個函式會迫使你使用更昂貴的memory
參數。這個限制在 Solidity 0.6.9 中被取消了。這可能是誤解最初的來源。使用外部函式可以降低通話成本,但這並不是因為它們的可見性。除此之外,它們之間的選擇只影響分析(有些事情可能會被禁止),而不是程式碼生成。在這兩種情況下,您將獲得完全相同的字節碼。
例子
您可以自己檢查字節碼是否相同。
讓我們把這個簡單的庫放在一個名為的文件中
lib.sol
:library L { enum E {A, B, C} struct S { address[50] addresses; } function f( uint a, string memory b, bytes1[] calldata c, mapping(E => S[]) storage d, function() external e ) public returns ( uint, string memory, bytes1[] calldata, mapping(E => S[]) storage, function() external ) { return (a, b, c, d, e); } }
然後執行編譯器兩次,將可見性更改為
external
第二次執行之前:solc lib.sol --bin --metadata-hash none > public.bin sed -i s/public/external/ lib.sol solc lib.sol --bin --metadata-hash none > external.bin diff public.bin external.bin
即使沒有啟用優化器,輸出也是空的,這意味著絕對沒有區別。
在編譯器中實現
您可以檢查編譯器程式碼,以了解不只是這個簡單的範例具有這種行為方式。
對於外部/公共功能,您可能會在兩個地方有所不同:
- 在外部調度中 - 查看作為 calldata 的一部分提供的選擇器並決定執行哪個函式的程式碼。它由
ContractCompiler::appendFunctionSelector()
.- 在函式體本身中,由
ContractCompiler::visit(FunctionDefinition const&)
.請注意,在這兩種情況下,都沒有區分
public
vs的條件external
。調度檢查了一個介面函式列表,其中包括公共函式和外部函式。它由 建構
ContractDefinition::interfaceFunctionList()
,它遍歷合約中的所有函式並FunctionDefinition::isPartOfExternalInterface()
用作過濾器。這反過來呼叫Declaration::isPublic()
,儘管名稱如此,但它有一個>=
可見性條件,因此它也匹配外部函式:bool isPublic() const { return visibility() >= Visibility::Public; }
您可以更深入地了解身體是如何生成的,但您也不會在那裡找到任何特殊情況。