0

Is it possible to allocate storage for a state variable in Solidity? I have the following smart contract

contract Demo {

    uint256 sharedCounter;

    function countUp() external {
        sharedCounter = sharedCounter+1;
    }
}

The contract has a shared variable, which all contract users can set/increase. The problem is, that the first user to call countUp will use a lot more gas than the following users, because he initially sets the sharedCounter variable to a non-zero value. According to the Ethereum yellow paper, the first user to call countUp will have to pay 20.000 gas to set the variable, the following users only 5.000 as they only update it.

I want countUp to be fair and to cost the same for every user. The first idea would be to set sharedCounter = 1 in the constructor. This way the initial 20.000 gas is paid in the constructor. The problem is that this way the counter would be wrong.

Another idea is to set sharedCounter = 0, but this also won't help because the value is still zero and the first user still has to pay more.

Is there a possibility to allocate storage for sharedCounter in the constructor without setting the value? I was thinking of something like this (although I know this is not working)

constructor() {
    sharedCounter = new uint256;
}

1 Answer 1

3

Changing a value from 0 to a non-0 value will always cost 20,000 gas. There is no way to pre-initialise a variable with a value of 0, to make it not cost 20,000 gas when changing the value.

An alternative approach to get around this is to initialise the variable as 1, and use a getter to get the value of the variable, e.g.

contract Demo {
  uint256 private _counter = 1;

  function counter() public view returns (uint256) {
    return _counter - 1;
  }

  function increment() public {
    _counter++;
  }
}

From contracts calling your contract it will appear as if the counter is 0, but the first contract to increment it bye one will pay the same as the other ones.

2
  • Thanks, that is a good temporary solution. But just for I have the feeling it is not a good idea to have an inconsistent state in the contract. For example when I would want to access _counter in another function, I would ether need to remember, that I have to subtract one or I need to always call the getter, which is very expensive. So you say there is no way to allocate storage without setting to a non-zero value?
    – Codey
    Commented Oct 16, 2021 at 11:13
  • 2
    There just isn't. The cost does not depend on some explicit allocation (there's no such concept for storage) but on changing the value from zero to non-zero. Also, an internal call is not really that expensive. A jump costs 10 gas, which is nothing compared to the 20k gas you're worrying about. It's also something that you should leave up to the optimizer (it will inline the function if it's worth it).
    – cameel
    Commented Oct 16, 2021 at 16:59

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.