5

I want to double-check something.

I had been writing upgradable smart contact that uses a lot of constants. As far as I can see, smart contracts aren't storing constant variables in their storage. Meaning those variables can't cause memory collisions for upgradable smart contracts.

I wrote some simple code to test it myself, and that seems to be the case.

//SPDX-License-Identifier: UNLICENCED

pragma solidity 0.8.3;  

contract ReadStorage {

    ///////////////// Main Functionality /////////////////////
    uint firstVariable = 1;

    // Public Constant
    uint public constant secondVariable = 2;

    function updateFirstVariable(uint newValue) public {
        firstVariable = newValue;
    }


    function readFirstVariable() public view returns (uint) {
        return firstVariable;

    }

    ///////////////// Assembly Functions /////////////////////
    function updateSlot(uint256 slotNumber, uint256 newValue) public {

        assembly {
            sstore(slotNumber, newValue)
        }
    }

    function readSlot(uint slotNumber) public view returns (uint value) {
        assembly{
            value := sload(slotNumber)
        }

    }


}

My question now is: Where are constants stored if not in storage? Are they somehow "embedded" in the contract during the compiling? The EVM has to read those values from somewhere. I assume the constants are maybe added to bytecode or something like that. But I wasn't able to find an explanation. So I would appreciate it if someone could explain it in more detail.

3 Answers 3

6

Constants are not stored anywhere. They are replaced with their constant value in every usage at compilation time.

For example, the following code. Notice how when I'm returning a constant from a function it suggests that I could use the pure modifier instead of view because there's nothing to read from storage, since the value 100 of the constant will be used directly in the function.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

contract Example {

    uint256 constant VALUE = 100;

    function getValue() public pure returns(uint256) {
        return VALUE;   
    }

}

Would be something like this after compilation:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

contract Example{

    function getValue() public pure returns(uint256) {
        return 100;   
    }

}
4
  • So if I, for example, had: unit public constant SECONDS_PER_HOUR = 3600. Every time I use SECONDS_PER_HOUR it's equivalent to simply writing 3600 The constant just makes it more readable?
    – Sky
    Dec 5, 2022 at 14:23
  • 2
    Exactly. Look at my examples. The compiler will remove the definition of the constant and will simply use the value itself in every usage. Dec 5, 2022 at 14:24
  • does this mean a large constant used many times can cause code bloat?
    – user253751
    Dec 5, 2022 at 22:38
  • Not really. It's way more efficient to use constants than storage values. Dec 5, 2022 at 23:40
3

You are correct that constants (i.e. variables marked with the constant or view or pure modifier) in Solidity are not stored in contract storage. These variables are evaluated at compile-time and the resulting values are "embedded" in the generated bytecode of the contract.

When a contract is deployed to the Ethereum blockchain, the bytecode that is stored on the blockchain includes the values of all constants defined in the contract. When a contract function marked as constant, view, or pure is called, the EVM looks up the value of the constants from the bytecode and uses it in the execution of the function.

Here's an example to illustrate how this works. Consider the following contract:

pragma solidity 0.8.3;

contract MyContract {
  uint public constant firstVariable = 1;
  uint public constant secondVariable = 2;

  function getSum() public view returns (uint) {
    return firstVariable + secondVariable;
  }
}

When this contract is compiled, the values of the firstVariable and secondVariable constants are "embedded" in the bytecode of the contract. The resulting bytecode might look something like this:

0x6080604052600436106100405763ffffffff7c010000000000000000000000000000000000...(etc)

0

Constants in Solidity are not stored in contract storage, but rather they are baked into the bytecode of the contract when it is compiled. When the contract is deployed, the constant values are included in the bytecode that is sent to the Ethereum blockchain.

The bytecode of a contract is a sequence of bytes that represents the contract's code and data. When a contract is compiled, the constant values are included in the bytecode in a way that is efficient for the Ethereum Virtual Machine (EVM) to read and use them.

For example, consider the following contract:

pragma solidity ^0.8.3;

contract ConstantContract {
    uint public constant foo = 42;
}

When this contract is compiled, the constant value of 42 for the foo variable will be included in the contract's bytecode. When the contract is deployed, the bytecode will be sent to the Ethereum blockchain and stored in the contract's storage. When the contract is executed, the EVM will be able to read the value of foo from the bytecode and use it in the contract's logic.

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.