真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

死磕solidity之如何有效的節(jié)省gas.md-創(chuàng)新互聯(lián)

image-20221028092606674

創(chuàng)新互聯(lián)主要為客戶提供服務(wù)項(xiàng)目涵蓋了網(wǎng)頁(yè)視覺(jué)設(shè)計(jì)、VI標(biāo)志設(shè)計(jì)、全網(wǎng)營(yíng)銷推廣、網(wǎng)站程序開(kāi)發(fā)、HTML5響應(yīng)式重慶網(wǎng)站建設(shè)、手機(jī)網(wǎng)站制作設(shè)計(jì)、微商城、網(wǎng)站托管及網(wǎng)頁(yè)維護(hù)、WEB系統(tǒng)開(kāi)發(fā)、域名注冊(cè)、國(guó)內(nèi)外服務(wù)器租用、視頻、平面設(shè)計(jì)、SEO優(yōu)化排名。設(shè)計(jì)、前端、后端三個(gè)建站步驟的完善服務(wù)體系。一人跟蹤測(cè)試的建站服務(wù)標(biāo)準(zhǔn)。已經(jīng)為成都PE包裝袋行業(yè)客戶提供了網(wǎng)站維護(hù)服務(wù)。為什么要強(qiáng)調(diào)優(yōu)化gas的重要性

DAPP中收取的費(fèi)用取決于功能邏輯的復(fù)雜程度,越復(fù)雜消耗的計(jì)算資源越多。并且需要用戶承擔(dān)一部分gas,所以solidity 的優(yōu)化顯得非常的重要。同時(shí)注重優(yōu)化gas的合約開(kāi)發(fā)人員寫(xiě)出來(lái)的合約代碼更安全,質(zhì)量更高。

1. 封裝結(jié)構(gòu)

以u(píng)int 為例,如果我們的程序中包含多個(gè)類似的變量,可以將其封裝在一起,因?yàn)椴还躸int8 ,uint32 ,uint16,solidity都會(huì)為其保留256位。即使你使用uint8也不會(huì)節(jié)省gas.

2. 最小化讀寫(xiě)鏈上數(shù)據(jù)

首先明確一點(diǎn)在讀寫(xiě) memory 變量比讀寫(xiě) storage 變量便宜。

contract NotSaveGas {
uint public var1  = 70;
function f1() external view returns (uint) {
        uint sum = 0;
        for (uint i = 0; i< var1; i++) {
            sum += i;
        }
        return sum;
}

contract SaveGas {
function f2() external view returns (uint) {
        uint sum = 0;

        for (uint i = 0; i< var1; i++) {
            sum += i;
        }
        return sum;
    }
}

請(qǐng)一定要避免f1這種循環(huán)讀寫(xiě) storage 變量,這是比較消耗gas的方式。處理這種問(wèn)題實(shí)際可以定義內(nèi)存變量作為緩存,將數(shù)據(jù)寫(xiě)入,這樣可以節(jié)省大量的gas.

3.打開(kāi) solidity 優(yōu)化器

hardhat 配置:

module.exports = {
  solidity: {
    version: "0.8.9",
    settings: {
      optimizer: {
        enabled: true,
        runs: 1000,
      },
    },
  },
}
4.盡可能減少鏈上數(shù)據(jù)

區(qū)塊鏈上保存數(shù)據(jù)是非常昂貴的,所以需要盡可能將鏈上存儲(chǔ)的信息減少,以此來(lái)節(jié)省大量的交易gas.

使用事件

事件是外部事物(例如用戶界面)從區(qū)塊鏈中獲得通知的內(nèi)置方式。當(dāng)發(fā)出事件時(shí),將通知該事件的監(jiān)視者。更新合約變量時(shí)不會(huì)發(fā)生通知。事件以不同的方式存儲(chǔ),比使用合約存儲(chǔ)便宜得多。合約不能直接訪問(wèn)日志。

IPFS

如果你需要存儲(chǔ)文件之類,可以使用IPFS保存文件,并將存儲(chǔ)的ID保存在鏈上。

無(wú)狀態(tài)合約 Merkle Proofs

如果需要使用區(qū)塊鏈來(lái)驗(yàn)證一些信息是否有效,可以使用 merkle 證明。Merkle 證明使用單一的數(shù)據(jù)塊來(lái)證明更大的數(shù)據(jù)量的有效性。例如,如果有人想證明 "Tx4 "的有效性,他將需要提供 Tx4、Hash3、Hash12 和 Hash5678,然后你的合約將能夠重新計(jì)算 Merkle 根(Hash12345678),并檢查它是否與存儲(chǔ)在區(qū)塊鏈上的根相一致。你將不需要存儲(chǔ)所有交易的哈希值。

image-20221027142237776


5.注重變量順序

Solidity 存儲(chǔ)槽的長(zhǎng)度為 32 字節(jié),但并不是所有的數(shù)據(jù)類型都需要這么大的空間:bool, int8 ... int128, bytes1 ... bytes31 和地址需要的空間小于 32 字節(jié)。solidity 會(huì)嘗試將這些變量打包到同一個(gè)存儲(chǔ)槽中。

如果你接連定義了 2 個(gè)uint128,它們都會(huì)被打包到同一個(gè)存儲(chǔ)槽中,因?yàn)樗鼈兏髡?16 字節(jié)。然而,如果你定義了一個(gè)uint128,接著是一個(gè)unit256,然后是另一個(gè)int128,你將使用 3 個(gè)存儲(chǔ)槽,因?yàn)樵趦蓚€(gè) int128 之間的 unit256 需要一個(gè)完整的存儲(chǔ)槽。

contract T{
    // 不好的方式
    uint128 v1;
    uint256 v2;
    uint128 v3;

    // 推薦方式
    uint128 v1;
    uint128 v3;
    uint256 v2;
}
6.選數(shù)據(jù)類型

如果智能合約只需要一個(gè)狀態(tài)變量,一個(gè)永遠(yuǎn)不會(huì)大于 255 的無(wú)符號(hào)整數(shù)。我們常規(guī)思想可能是想用uint8,會(huì)覺(jué)得節(jié)省gas,實(shí)際并不會(huì)。以太坊操作碼被設(shè)計(jì)為使用 256 位的變量(EVM 堆棧的大?。?,而 uint8 只需要 8 位,EVM 會(huì)在剩余的位上填上 "0",以便能夠操作它。這個(gè)由 EVM 執(zhí)行的填 "0" 操作將花費(fèi) Gas,因此為了節(jié)省交易 Gas,最好使用 uint256 而不是 uint8。

7.獨(dú)立部署庫(kù)

如果在智能合約中重復(fù)使用代碼,最好是將所有的代碼打包到一個(gè)庫(kù)中,并通過(guò)import的方式指向它。

庫(kù)包含:

  • 嵌入式庫(kù):包含內(nèi)部函數(shù)的庫(kù),這些庫(kù)都是嵌入在合約中,和合約一同部署,所以會(huì)比較消耗gas
  • 獨(dú)立庫(kù):包含public和外部函數(shù)的庫(kù),這些庫(kù)只會(huì)被部署一次,同時(shí)被所有導(dǎo)入它的所有合約使用,從而節(jié)省了大量的gas.
8.構(gòu)造函數(shù)

常量和不可變的狀態(tài)變量在合約被部署后不能被改變。區(qū)別在于,常量必須在編譯時(shí)定義,而不可變量可以在構(gòu)造函數(shù)中定義??偸潜M量使用常量,以便使構(gòu)造函數(shù)更便宜。

9.使合約盡可能的小

單個(gè)合約的限制是24KB,所以要想節(jié)省gas,就必須使實(shí)現(xiàn)的合約盡可能的小。

  • revert和assert的提示信息要盡可能的短
  • 修改器: 修改器(modifier)代碼是內(nèi)聯(lián)的,這意味著它會(huì)被添加在所修改的函數(shù)的開(kāi)頭或結(jié)尾。在使用修改器時(shí)減少合約大小的一個(gè)技巧是編寫(xiě)一個(gè)實(shí)現(xiàn)修改器邏輯的函數(shù),然后讓修改器調(diào)用該函數(shù)。這樣實(shí)現(xiàn)修改器的代碼就不會(huì)被復(fù)制,只有函數(shù)調(diào)用會(huì)被復(fù)制。這種技術(shù)只在同一修改器被多次使用時(shí)有效。
modifier TestModifier(uint256 value){
        JudgeLength(value);
        _;
}
function JudgeLength(uint256 value)internal{
    //logic
}
10.最小代理(ERC1167)

如果需要部署多個(gè)功能完全相同的合約,應(yīng)該考慮使用 "最小代理"(在ERC 1167中定義)

最小的代理只是一個(gè)合約,它將把所有的調(diào)用委托給一個(gè)預(yù)先定義的實(shí)現(xiàn)合約。它有一個(gè)定義好的字節(jié)碼,代表最小代理合約的編譯代碼,你只需要把你的實(shí)現(xiàn)合約地址插入其中,你就可以根據(jù)需要部署最小代理的多個(gè)副本。 參考ERC 1167 相關(guān)文章,了解如何使用最小代理)。

由于最小的代理字節(jié)碼非常小,部署它的成本也低到不能再低,因此節(jié)省一堆部署 Gas。

使用最小代理的注意事項(xiàng),你應(yīng)該牢記:最小代理的實(shí)現(xiàn)合約地址不能改變,這意味著你將不能升級(jí)他們的代碼。

11.內(nèi)存位置

以太坊存在4個(gè)內(nèi)存位置,從最便宜到最貴的:calldata、stack、memory、storage。

  • calldata:只適用于輸入?yún)?shù)且參數(shù)是外部函數(shù)的引用數(shù)據(jù)類型(數(shù)組,字符串 ...)。Calldata 參數(shù)是只讀的,如果你有一些需要傳遞給函數(shù)的引用類型,總是考慮使用 calldata,因?yàn)樗亲畋阋说摹?/li>
  • stack:只對(duì)方法中定義的值類型數(shù)據(jù)有效。
  • memory:內(nèi)存是易丟失的 RAM,在 EVM 終止運(yùn)行的時(shí)候會(huì)被移除??梢杂盟鼇?lái)存儲(chǔ)引用數(shù)據(jù)類型,它比storage變量更便宜。當(dāng)向其他函數(shù)傳遞參數(shù),或在你的函數(shù)中聲明臨時(shí)變量時(shí),除非你嚴(yán)格需要使用storage變量,否則應(yīng)該總是使用 memory變量。
  • storage:是最昂貴的存儲(chǔ)位置。存儲(chǔ)數(shù)據(jù)在區(qū)塊鏈上持久存在,請(qǐng)盡量減少鏈上數(shù)據(jù)存儲(chǔ)。
  • 本地存儲(chǔ)變量:本地存儲(chǔ)變量是方法的本地變量,它指向一個(gè)實(shí)際的狀態(tài)變量(存儲(chǔ)在區(qū)塊鏈存儲(chǔ)中)。與其在內(nèi)存中復(fù)制/粘貼存儲(chǔ)數(shù)組以便操作它們,然后將它們復(fù)制回存儲(chǔ),不如簡(jiǎn)單地使用本地存儲(chǔ)變量,直接在存儲(chǔ)上操作。
  • 批處理:與其讓用戶用不同的值多次調(diào)用同一個(gè)函數(shù)(通過(guò)向區(qū)塊鏈發(fā)送多個(gè)交易),不如讓他們通過(guò)傳遞動(dòng)態(tài)大小的數(shù)組,以便可以在一個(gè)單一的交易中批量執(zhí)行相同的功能。這將能夠節(jié)省一些交易基礎(chǔ)開(kāi)銷成本。實(shí)際ERC1155有些思想就是如此
12.盡量減少鏈上操作
  • 字符串:如果可以使用bytes,則盡量使用。如果仍然需要操作,則盡量放在智能合約外部操作。
  • 返回值:對(duì)返回值無(wú)需額外轉(zhuǎn)換,如果這個(gè)是可以通過(guò)鏈外數(shù)據(jù)來(lái)處理。
  • 循環(huán):避免在長(zhǎng)數(shù)組中循環(huán),這不僅會(huì)花費(fèi)大量的 Gas,而且如果 Gas 成本增加到很高的程度(超過(guò) BlockGas 限制),會(huì)使合約無(wú)法執(zhí)行。使用映射來(lái)代替長(zhǎng)數(shù)組,映射是一個(gè)哈希表,可以讓你在一次操作中使用其鍵來(lái)訪問(wèn)任何值,而不是在數(shù)組中循環(huán),直到找到你要找的鍵。
13.利用 view函數(shù)減少gas

當(dāng)用戶從外部調(diào)用一個(gè)view函數(shù),是不需要支付一分 gas 的。

這是因?yàn)?view 函數(shù)不會(huì)真正改變區(qū)塊鏈上的任何數(shù)據(jù) - 它們只是讀取。因此用 view 標(biāo)記一個(gè)函數(shù),意味著告訴 web3.js,運(yùn)行這個(gè)函數(shù)只需要查詢你的本地以太坊節(jié)點(diǎn),而不需要在區(qū)塊鏈上創(chuàng)建一個(gè)事務(wù)(事務(wù)需要運(yùn)行在每個(gè)節(jié)點(diǎn)上,因此花費(fèi) gas)。

在所能只讀的函數(shù)上標(biāo)記上表示“只讀”的“external view 聲明,就能為你的玩家減少在 DApp 中 gas 用量。

注意:如果一個(gè) view 函數(shù)在另一個(gè)函數(shù)的內(nèi)部被調(diào)用,而調(diào)用函數(shù)與 view 函數(shù)的不屬于同一個(gè)合約,也會(huì)產(chǎn)生調(diào)用成本。這是因?yàn)槿绻髡{(diào)函數(shù)在以太坊創(chuàng)建了一個(gè)事務(wù),它仍然需要逐個(gè)節(jié)點(diǎn)去驗(yàn)證。所以標(biāo)記為 view 的函數(shù)只有在外部調(diào)用時(shí)才是免費(fèi)的。


14.使用短路模式排序solidity操作

短路(short-circuiting)是一種使用或/與邏輯來(lái)排序不同成本操作的solidity合約 開(kāi)發(fā)模式,它將低gas成本的操作放在前面,高gas成本的操作放在后面,這樣如果前面的低成本操作可行,就可以跳過(guò)(短路)后面的高成本以太坊虛擬機(jī)操作了。

// f(x) 是低gas成本的操作
// g(y) 是高gas成本的操作

// 按如下排序不同gas成本的操作
f(x) || g(y)
f(x) && g(y)
15.刪除不必要的庫(kù)

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

例如,在下面的solidity代碼中,我們的以太坊合約只是用到了SafeMath庫(kù)的add方法:

import './SafeMath.sol' as SafeMath;

contract SafeAddition {
 function safeAdd(uint a, uint b) public pure returns(uint) {
 return SafeMath.add(a, b);
 }
}

通過(guò)參考SafeMath的這部分代碼的實(shí)現(xiàn),可以把對(duì)這個(gè)solidity庫(kù)的依賴剔除掉:

contract SafeAddition {
 function safeAdd(uint a, uint b) public pure returns(uint) {
 uint c = a + b;
 require(c >= a, "Addition overflow");
 return c;
 }
}
16.精確的聲明函數(shù)的可見(jiàn)性

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

External 可見(jiàn)性比 public 消耗gas 少。

17.避免代碼中死代碼

死代碼(Dead code)是指那些永遠(yuǎn)也不會(huì)執(zhí)行的Solidity代碼,例如那些執(zhí)行條件永遠(yuǎn)也不可能滿足的代碼,就像下面的兩個(gè)自相矛盾的條件判斷里的Solidity代碼塊,消耗了以太坊gas資源但沒(méi)有任何作用:

function deadCode(uint x) public pure {
 if(x< 1 {
    if(x >2) {
        return x;
    }
 }
}
18.避免使用常量結(jié)果的循環(huán)

如果一個(gè)循環(huán)計(jì)算的結(jié)果是無(wú)需編譯執(zhí)行Solidity代碼就可以預(yù)測(cè)的,那么 就不要使用循環(huán),這可以可觀地節(jié)省gas。例如下面的以太坊合約代碼就可以 直接設(shè)置num變量的值:

function constantOutcome() public pure returns(uint) {
  uint num = 0;
  for(uint i = 0; i< 100; i++) {
    num += 1;
  }
  return num;
}
19.合并循環(huán)

有時(shí)候在Solidity智能合約中,你會(huì)發(fā)現(xiàn)兩個(gè)循環(huán)的判斷條件一致,那么在這種情況下就沒(méi)有理由不合并它們。例如下面的以太坊合約代碼:

function loopFusion(uint x, uint y) public pure returns(uint) {
  for(uint i = 0; i< 100; i++) {
    x += 1;
  }
  for(uint i = 0; i< 100; i++) {
    y += 1;
  }
  return x + y;
}
20.去除循環(huán)中的比較運(yùn)算

如果在循環(huán)的每個(gè)迭代中執(zhí)行比較運(yùn)算,但每次的比較結(jié)果都相同,則應(yīng)將其從循環(huán)中刪除。

function unilateralOutcome(uint x) public returns(uint) {
  uint sum = 0;
  for(uint i = 0; i<= 100; i++) {
    if(x >1) {
      sum += 1;
    }
  }
  return sum;
}
********************
最終的定稿 : https://github.com/blockchainGuide/blockchainguide
公眾號(hào) : 區(qū)塊鏈技術(shù)棧
********************

參考

https://medium.com/coinmonks/smart-contracts-gas-optimization-techniques-2bd07add0e86 本文由博客一文多發(fā)平臺(tái) OpenWrite 發(fā)布!

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧


標(biāo)題名稱:死磕solidity之如何有效的節(jié)省gas.md-創(chuàng)新互聯(lián)
當(dāng)前URL:http://weahome.cn/article/eeccc.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部