1

I'm trying to to make a contract which lets the user choose any number he likes to populate an array of integers used in a mapping. Then he can choose any index of this array to increase its value by 1.

Below is the function that makes the increment:

    pragma solidity ^0.4.19;

    contract test {

       //the array size is chosen by the user
       mapping (bytes4 => int[]) internal map;

       function _increase(bytes4 _id,uint _index) public {        
           map[_id][_index] = map[_id][_index] + 1;
       }

    }

The problem is, unless you give the array in the mapping a fixed number like:

    mapping (bytes4 => int[1000]) internal map;

The function that increases its numbers throw an error (in remix): Remix Error

Since giving this array any large random number to cover all the possibilities is a waste of unused space, can anyone think in a workarround?

Thanks a lot.

1

You're right. All the attempts to sparsely populate a dynamic array will fail because the index is out of bounds. You can make them longer with .push(value) but you want to be able to bounce around randomly.

On the other hand, you can actually lay out a map of very large fixed-size arrays without increasing gas cost as you might expect. This works:

pragma solidity ^0.4.19;

contract test {

  mapping (bytes4 => int[100000000000]) internal map;

  function _increase(bytes4 _id,uint _index) public {        
    map[_id][_index] = map[_id][_index] + 1;
  }

}

That still has an upper bound and it is not possible for the user to decide the dimensions. You can do this instead of thinking of the second index as an array:

contract Test {

   mapping (bytes32 => mapping(uint => uint)) public map;

   function increase(bytes32 id,uint index) public {        
       map[id][index] = map[id][index] + 1;
   }

}

The switch to bytes32 is because mapping indexes are always 32 bytes, and function inputs have to pack into 32-byte words. There is no savings by clipping it to 4 bytes.

You can make the mapping public to ease the process of retrieving values while testing gas cost with different setups.

Hope it helps.

  • Thanks a lot for your answer! it really helped a lot! But, since I'm new to ethereum and solidity, let just clarify one thing. Manking a big array like you said will not change the gas cost, is that it? actually that's my only concern with this funcion... If the user chooses a number that fits in the array the code still works. thanks – Carlos Eduardo Cardozo Sep 25 '18 at 15:03
  • These indexed types get stored in a namespace using a hash table. Contrary to what you might expect, it doesn't reserve or write out storage space for all the zeroes corresponding to initialized values. If it had to do that, then the following would be prohibitively expensive. contract Big {uint[100000000000000] big;}. Play with it. It doesn't cost any more gas to increase the size of the array and deploy the contract. – Rob Hitchens - B9lab Sep 25 '18 at 15:35

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.