12

I was working with constant variables in a contract

contract X{

uint constant var1=now;
uint var2=now;

function checkConstant() returns(uint,uint){
    return (var1,var2);
}} 

I was wondered each time I call checkConstant(..) , the return value of var1 was different but value of var2 was same.
So, I do not understand when I declare a variable as constant why it gets initialised each time a function is invokend, ideally it should get an initial value at time of contract deployment and maintain this value throughout life of contract.

  • you should make the function constant too, just a side note. – Roland Kofler Aug 11 '16 at 9:33
  • why should I make function constant? Note: This is just a sample scenario, actually I was using constant variable (reward) in a non-constant function (transfer) of cryptocurrency. – Prashant Prabhakar Singh Aug 11 '16 at 9:50
  • 1
    if you don't change the state then constant is useful because you can call the function without transactions and get the return value. But of course with transfer this is a whole other thing. – Roland Kofler Aug 11 '16 at 10:28
  • this question is worth tons of gold ( if not BitCoins) - well asked! – gor Oct 3 '17 at 19:44
9

This works as documented, although it is not intuitive, the reason becomes quickly clear:

State variables can be declared as constant [...] This has the effect that the compiler does not reserve a storage slot for these variables and every occurrence is replaced by their constant value.

https://solidity.readthedocs.io/en/latest/contracts.html

3

Details documented in TIB (Today I Burnt) 0.01 ETH Using Constant State Variables In A Solidity Contract.

Using a constant state variables produces unexpected results, for example:

uint256 public constant PRESALE_START_DATE = now;
uint256 public constant PRESALE_END_DATE = PRESALE_START_DATE + 15 minutes;
uint256 public constant OWNER_CLAWBACK_DATE = PRESALE_START_DATE + 20 minutes;

The variables:

PRESALE_START_DATE will ALWAYS have the current time value
PRESALE_END_DATE will ALWAYS have a date 15 minutes in the future
OWNER_CLAWBACK_DATE will ALWAYS have a date 20 minutes in the future

Sample contract at 0xe67907329dafd1ff826523e3f491bec8733f7376. Refresh the page and you will see these constant variables update. DO NOT SEND FUNDS TO THIS CONTRACT

I've created issue #76 - Please add a warning about using Constant State Variables in Ethereum Contract Security Techniques and Tips.



Update Mar 24 2017

A few other examples where the constant is not constant.

From TIB (Today I Burnt) 0.01 ETH Using Constant State Variables In A Solidity Contract:

pragma solidity ^0.4.8;

contract Test {

    bytes32 public constant MY_DATE = keccak256(now);

    function check() constant returns (bytes32) {
        return MY_DATE;
    }
}

From the comment by @TjadenHess below:

pragma solidity ^0.4.8;

contract Test {

    address public constant MY_ADDRESS = msg.sender;

    function check() constant returns (address) {
        return MY_ADDRESS;
    }
}
  • 3
    This is a pretty serious issue... The bigger problem is if someone does address constant owner = msg.sender... – Tjaden Hess Mar 24 '17 at 3:34
  • Should be fixed in 0.4.10 - see reddit.com/r/ethdev/comments/60xklu/… – The Officious BokkyPooBah Mar 24 '17 at 3:44
  • 1
    That's good. I did a quick scan of the blockchain and the only vulnerable contract I came up with was yours, so I guess it's not as common as I thought. Still good that it's being fixed quickly though – Tjaden Hess Mar 24 '17 at 4:00
  • 1
    I just scraped etherscan for all the contracts with published code, then used regexs to find any constant global variable definitions. It's not super thorough, but since most important contracts are on etherscan, and constant variable definitions are pretty easy to search for, it should be pretty good. – Tjaden Hess Mar 24 '17 at 4:24
  • 2
    Solidity 0.4.10 flags a warning that: initial value for constant must be compile-time constant. This will fail to compile with the next breaking version change – o0ragman0o Mar 24 '17 at 5:12
2

Looking at the bytecode, the TIMESTAMP instruction itself is the constant value. This makes sense as constant values are compiled as literals (inline with the bytecode). Using a state variable instead assigns the value of now during construction and it will keep that value.

contract constTest
    {
       uint constant public constNow = now;
       uint constant public ffff = 0xffff;
       uint public stateNow = now;
    }

Disassembly of uint constant public constNow = now;

...
104 JUMPDEST
105 TIMESTAMP
106 DUP2
107 JUMP
...

Compared with a literal value in constant ffff = 0xffff;

....
155 JUMPDEST
156 PUSH2 ffff
159 DUP2
160 JUMP
....

The effective workaround is to use a state variable instead of constant when working with the now/TIMESTAMP instruction.

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.