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 Answer 1

3

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.

2
  • 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 Commented Sep 25, 2018 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. Commented Sep 25, 2018 at 15:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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