0

I have a loop like this:

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);
   }
}

Well now this loop could get really large as new users sign up.

I was wondering if this would work as loop gets larger? anything i could optimize in this code?

what errors could happen? what is the potential of exceeding the block gas-limit? and how can i handle it when it hits the block gas-limit?

1

Using loops in Solidity is not the best idea to achieve your needs. In your case it would be the best if you force the users to "ask" for the free tokens. Look at my code:

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;
    }
}

Here having only 3 addresses in the usersAddresses array method freeTokens costed 84464 transaction cost and 63192 execution cost while method freeTokensSignle costed me 28261 transaction cost and 5581 execution cost. The arguments from my side for going with the single method is first it takes less gas and second with increasing array usersAddresses the chance of your method getting crashed while executing grows.

But if you still wanna go with the multiple free tokens given at once (which I don't recommend) you should change the i++; to i+=1; in the loop, because i+=1; is faster. With 500 addresses in usersAddresses array transaction cost and execution cost with i++; are 285752 and 264480, but with i+=1; they are 283252 and 261980.

| improve this answer | |
0

anything i could optimize in this code?

Sure, common pattern to increase all user balances by the same amount looks like this:

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;
}

So calling freeTokens will increase number of tokens for all valid users, as one can see by calling getUserTokens ().

| improve this answer | |
  • although that is a good trick but it won't help me. because in my case the 1000 may be vary for different users, it's not a pattern. sorry for my unclear code (edited) – Adrin Nov 5 '19 at 16:43
  • @mikhail what does the ? and : operators do in the getUserTokens(...) function? – NowsyMe Nov 5 '19 at 17:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.