
在區(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)致此筆交易失敗。
如果一個(gè)struct中有多個(gè)uint,則盡可能使用較小的uint,solidity會(huì)將這些uint打包在一起,從而占用較小的存儲(chǔ)空間
(相關(guān)資料圖)
不同數(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里用,完全不用花錢。
布爾類型 bool 實(shí)際為 uint8,即使用 8 位的存儲(chǔ)空間,每個(gè)存儲(chǔ)插槽能裝入 32 個(gè)布爾類型值。而布爾值只能有兩個(gè)值:True 或 False,其實(shí)只需要在單個(gè)存儲(chǔ)位中就可以保存布爾值。
操作符 || 和 && 適用常見的短路規(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)該將貴的方法放在后面
將多個(gè)變量堆疊在一起
將錯(cuò)誤原因字符串與require語句一起附加,以便更容易理解contract調(diào)用還原的原因。但是,這些字符串在部署的字節(jié)碼中占用空間。每個(gè)原因字符串至少需要32個(gè)字節(jié),因此請(qǐng)確保您的字符串符合32個(gè)字節(jié),否則會(huì)變得更加昂貴。
從智能合約內(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。
如果您希望部署同一contract的多個(gè)副本,則考慮僅部署一個(gè)實(shí)現(xiàn)contract和多個(gè)代理contract,將其邏輯委派給實(shí)現(xiàn)contract。這將允許這些contract共享相同的邏輯但不同的數(shù)據(jù)。
因?yàn)橐还P交易的基礎(chǔ) gas 消耗是 21000,批量操作相比多次操作,能減少多次的交易帶來的基礎(chǔ) gas 消耗。
沒有參數(shù)的事件是750 GAS。理論上每個(gè)附加參數(shù)將增加256個(gè)GAS,但事實(shí)上,它會(huì)更多。
你可以使用智能合約中的幾個(gè)內(nèi)置哈希函數(shù):keccak256,sha256和ripemd160。參數(shù)越多,消耗的氣體越多。耗氣量:ripemd160> sha256> keccak256。因此,如果沒有其他目的,建議使用keccak256函數(shù)。
我們引入的庫通常只需要用到其中的部分功能,這意味著其中可能會(huì)包含大量對(duì)于你的智能合約而言其實(shí)是冗余的solidity代碼。如果可以在你自己的合約里安全有效地實(shí)現(xiàn)所依賴的庫功能,那么就能夠達(dá)到優(yōu)化solidity合約的gas利用的目的。
顯式聲明函數(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成本。
使用編譯器 solc 編譯合約時(shí)啟動(dòng)優(yōu)化器 optimizer,它將簡(jiǎn)化復(fù)雜的表達(dá)方式,能減小編譯后的合約字節(jié)碼大小,從而減少部署時(shí)的 gas 消耗,同時(shí)也能減少合約調(diào)用時(shí)的消耗。
在 solidity 中,聲明為 constant 或者 immutable 的狀態(tài)變量即常量。constant 修飾的常量的值在編譯時(shí)確定,而 immutable 修飾的常量的值在部署時(shí)確定。盡量使用常量,常量是合約字節(jié)碼的一部分,不占用存儲(chǔ)插槽,使用常量比變量更省 gas。在部署時(shí),常量消耗的 gas 更少。
使用默克爾樹。在合約中保存一組數(shù)據(jù)的merkleRoot,提供verify方法驗(yàn)證某條數(shù)據(jù)在這組數(shù)據(jù)中。相比使用一個(gè) mapping 或數(shù)組來保存全部數(shù)據(jù),減少了 gas 消耗。
標(biāo)簽: 存儲(chǔ)空間 數(shù)據(jù)類型 布爾類型