當(dāng)前簡(jiǎn)訊:Solidity如何優(yōu)化Gas費(fèi)用

2022-12-22 14:13:12 來源:51CTO博客

在區(qū)塊鏈中,每一筆智能合約的運(yùn)行,都要根據(jù)復(fù)雜度消耗一筆GAS費(fèi);如果你要將值寫入存儲(chǔ),則需要花費(fèi)很多。如果你只是使用堆棧,它的成本會(huì)低一些;智能合約solidity語言的編寫,不僅要考慮安全,也要考慮語言的優(yōu)化,在Ethereum上的交易gas是有上限的,特別是針對(duì)一些復(fù)雜業(yè)務(wù)的處理,有可能會(huì)導(dǎo)致gas超高,嚴(yán)重者導(dǎo)致此筆交易失敗。

0、Struct結(jié)構(gòu)

如果一個(gè)struct中有多個(gè)uint,則盡可能使用較小的uint,solidity會(huì)將這些uint打包在一起,從而占用較小的存儲(chǔ)空間


(相關(guān)資料圖)

1、選擇變量數(shù)據(jù)類型

不同數(shù)據(jù)類型的存儲(chǔ)GAS消耗不同,我們應(yīng)該選擇 gas 消耗更小的數(shù)據(jù)類型。

盡量使用256位的變量,如果你只存儲(chǔ)一個(gè)uint8,則EVM將用零填充所有缺少的數(shù)字,這會(huì)耗費(fèi)gas、此外,EVM執(zhí)行計(jì)算也會(huì)轉(zhuǎn)化為 uint256 ,因此除uint256之外的任何其他類型也必須進(jìn)行轉(zhuǎn)換。

通常情況下我們不會(huì)考慮使用 uint 變種,因?yàn)闊o論如何定義 uint的大小,Solidity 為它保留256位的存儲(chǔ)空間。例如,使用 uint8 而不是uint(uint256)不會(huì)節(jié)省任何 gas。

有一種情況例外:把 uint 綁定到 struct 里面。如果一個(gè) struct 中有多個(gè) uint,則盡可能使用較小的 uint, Solidity 會(huì)將這些 uint 打包在一起,從而占用較少的存儲(chǔ)空間。

當(dāng) uint 定義在一個(gè) struct 中的時(shí)候,盡量使用最小的整數(shù)子類型以節(jié)約空間。 并且把同樣類型的變量放一起(即在 struct 中將把變量按照類型依次放置),這樣 Solidity 可以將存儲(chǔ)空間最小化。

為了避免存儲(chǔ)操作,可以在數(shù)組后面加上 memory關(guān)鍵字, 表明這個(gè)數(shù)組是僅僅在內(nèi)存中創(chuàng)建,不需要寫入外部存儲(chǔ),并且在函數(shù)調(diào)用結(jié)束時(shí)它就解散了。與在程序結(jié)束時(shí)把數(shù)據(jù)保存進(jìn) storage 的做法相比,內(nèi)存運(yùn)算可以大大節(jié)省gas開銷 – 把這數(shù)組放在view里用,完全不用花錢。

2、布爾類型

布爾類型 bool 實(shí)際為 uint8,即使用 8 位的存儲(chǔ)空間,每個(gè)存儲(chǔ)插槽能裝入 32 個(gè)布爾類型值。而布爾值只能有兩個(gè)值:True 或 False,其實(shí)只需要在單個(gè)存儲(chǔ)位中就可以保存布爾值。

3、使用短路規(guī)則

操作符 || 和 && 適用常見的短路規(guī)則。

這意味著,假設(shè)f(x) 和 g(y) 返回 true 的概率一樣,那么:

在表達(dá)式 f(x) || g(y) 中,如果 f(x) 的計(jì)算結(jié)果為真,則不會(huì)執(zhí)行 g(y)。因此應(yīng)該將貴的方法放在后面。

在表達(dá)式 f(x) && g(y) 中,如果 f(x) 的計(jì)算結(jié)果為假,則不會(huì)執(zhí)行 g(y)。因此應(yīng)該將貴的方法放在后面

4、通過匯編將變量打包到單個(gè)插槽中

將多個(gè)變量堆疊在一起

5、使用簡(jiǎn)短的原因字符串

將錯(cuò)誤原因字符串與require語句一起附加,以便更容易理解contract調(diào)用還原的原因。但是,這些字符串在部署的字節(jié)碼中占用空間。每個(gè)原因字符串至少需要32個(gè)字節(jié),因此請(qǐng)確保您的字符串符合32個(gè)字節(jié),否則會(huì)變得更加昂貴。

6、調(diào)用內(nèi)部函數(shù)更便宜

從智能合約內(nèi)部調(diào)用其內(nèi)部函數(shù)比調(diào)用其公共函數(shù)便宜,因?yàn)楫?dāng)您調(diào)用公共函數(shù)時(shí),所有參數(shù)將再次復(fù)制到內(nèi)存中并傳遞給該函數(shù)。相反,當(dāng)您調(diào)用內(nèi)部函數(shù)時(shí),將傳遞這些參數(shù)的引用,并且它們不會(huì)再次復(fù)制到內(nèi)存中。這節(jié)省了一點(diǎn)gas。

7、使用代理模式進(jìn)行大規(guī)模部署

如果您希望部署同一contract的多個(gè)副本,則考慮僅部署一個(gè)實(shí)現(xiàn)contract和多個(gè)代理contract,將其邏輯委派給實(shí)現(xiàn)contract。這將允許這些contract共享相同的邏輯但不同的數(shù)據(jù)。

8、盡量使用批量操作

因?yàn)橐还P交易的基礎(chǔ) gas 消耗是 21000,批量操作相比多次操作,能減少多次的交易帶來的基礎(chǔ) gas 消耗。

9、事件

沒有參數(shù)的事件是750 GAS。理論上每個(gè)附加參數(shù)將增加256個(gè)GAS,但事實(shí)上,它會(huì)更多。

10、哈希

你可以使用智能合約中的幾個(gè)內(nèi)置哈希函數(shù):keccak256,sha256和ripemd160。參數(shù)越多,消耗的氣體越多。耗氣量:ripemd160> sha256> keccak256。因此,如果沒有其他目的,建議使用keccak256函數(shù)。

11、刪減不必要的Solidity庫

我們引入的庫通常只需要用到其中的部分功能,這意味著其中可能會(huì)包含大量對(duì)于你的智能合約而言其實(shí)是冗余的solidity代碼。如果可以在你自己的合約里安全有效地實(shí)現(xiàn)所依賴的庫功能,那么就能夠達(dá)到優(yōu)化solidity合約的gas利用的目的。

12、顯式聲明Solidity合約函數(shù)的可見性

顯式聲明函數(shù)的可見性不僅可以提高智能合約的安全性,同時(shí)也有利于優(yōu)化合約執(zhí)行的gas成本。例如,通過顯式地標(biāo)記函數(shù)為外部函數(shù)(External),可以強(qiáng)制將函數(shù)參數(shù)的存儲(chǔ)位置設(shè)置為calldata,這會(huì)節(jié)約每次函數(shù)執(zhí)行時(shí)所需的Ethereum 的 gas成本。

13、編譯合約時(shí)使用優(yōu)化器

使用編譯器 solc 編譯合約時(shí)啟動(dòng)優(yōu)化器 optimizer,它將簡(jiǎn)化復(fù)雜的表達(dá)方式,能減小編譯后的合約字節(jié)碼大小,從而減少部署時(shí)的 gas 消耗,同時(shí)也能減少合約調(diào)用時(shí)的消耗。

14、常量

在 solidity 中,聲明為 constant 或者 immutable 的狀態(tài)變量即常量。constant 修飾的常量的值在編譯時(shí)確定,而 immutable 修飾的常量的值在部署時(shí)確定。盡量使用常量,常量是合約字節(jié)碼的一部分,不占用存儲(chǔ)插槽,使用常量比變量更省 gas。在部署時(shí),常量消耗的 gas 更少。

15、默克爾樹

使用默克爾樹。在合約中保存一組數(shù)據(jù)的merkleRoot,提供verify方法驗(yàn)證某條數(shù)據(jù)在這組數(shù)據(jù)中。相比使用一個(gè) mapping 或數(shù)組來保存全部數(shù)據(jù),減少了 gas 消耗。

標(biāo)簽: 存儲(chǔ)空間 數(shù)據(jù)類型 布爾類型

上一篇:天天微頭條丨LiveQing視頻平臺(tái)Linux系統(tǒng)安裝使用說明
下一篇:今日熱門!Oracle19C windows安裝部署