Gas-Limit

在大循環中處理塊氣體限制

  • November 5, 2019

我有一個這樣的循環:

struct User {
   string name; 
   uint tokens;
   uint frozenTokens;
   bool isValid;
}


mapping(address => User) users;
address[] public usersAddresses;


function freeTokens() private {

  uint reciversLength = usersAddresses.length;
  for (uint i = 0; i < reciversLength; i++) {
      User storage theUser = users[usersAddresses[i]];
      theUser.tokens += (theUser.frozenTokens * 10000);
  }
}

現在,隨著新使用者的註冊,這個循環可能會變得非常大。

我想知道這是否會隨著循環變大而起作用?我可以在這段程式碼中優化什麼?

會發生什麼錯誤?超過區塊氣體限制的潛力是什麼?當它達到塊氣體限制時我該如何處理它?

在 Solidity 中使用循環並不是滿足您需求的最佳方法。在您的情況下,如果您強制使用者“要求”免費令牌,那將是最好的。看我的程式碼:

pragma solidity >=0.4.22 <0.6.0;

contract test3 {
   constructor(address[] memory _user_addresses) public {
       usersAddresses = _user_addresses;
   }

   struct User {
       string name; 
       uint tokens;
       bool isValid;
   }

   mapping(address => User) users;
   address[] public usersAddresses;

   function checkUser(address _user_address) public returns(uint) {
       return users[_user_address].tokens;
   }

   function freeTokens() public {
      uint reciversLength = usersAddresses.length;
      for (uint i = 0; i < reciversLength; i++) {
          User storage theUser = users[usersAddresses[i]];
          theUser.tokens += 10000;
      }
   }

   function freeTokensSingle(address _user_address) public {
      User storage theUser = users[_user_address];
      theUser.tokens += 10000;
   }
}

這裡在 usersAddresses 數組方法中只有 3 個地址freeTokens花費了 84464 交易成本和 63192 執行成本,而方法freeTokensSignle花費了我 28261 交易成本和 5581 執行成本。我對使用單一方法的論點是首先它需要更少的氣體,其次是隨著數組 usersAddresses 的增加,您的方法在執行增長時崩潰的可能性。

但是,如果您仍然想同​​時使用多個免費令牌(我不推薦),您應該更改 i++;到 i+=1; 在循環中,因為 i+=1; 是比較快的。usersAddresses 數組中的 500 個地址使用 i++ 的交易成本和執行成本;是 285752 和 264480,但 i+=1;它們是 283252 和 261980。

我可以在這段程式碼中優化什麼?

當然,將所有使用者餘額增加相同數量的常見模式如下所示:

struct User {
 string name; 
 uint tokens;
 bool isValid;
}

mapping (address => User) private users;

uint256 private extraTokens = 0;

function freeTokens () private {
 extraTokens += 10000;
}

function getUserTokens (address user) public view returns (uint256) {
 return users [user].isValie ? users [user].tokens + extraTokens : 0;
}

因此,呼叫freeTokens將增加所有有效使用者的令牌數量,正如呼叫getUserTokens ().

引用自:https://ethereum.stackexchange.com/questions/77232