Gas-Limit
在大循環中處理塊氣體限制
我有一個這樣的循環:
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 ()
.