Почему постоянные переменные состояния инициализируются каждый раз?

Я работал с постоянными переменными в контракте

contract X{

uint constant var1=now;
uint var2=now;

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

Каждый раз, когда я звоню, меня удивляло checkConstant(..), что возвращаемое значение var1было другим, но значение var2было одинаковым.
Итак, я не понимаю, когда я объявляю переменную как константу, почему она инициализируется каждый раз, когда вызывается функция, в идеале она должна получать начальное значение во время развертывания контракта и поддерживать это значение на протяжении всего срока действия контракта.

вы также должны сделать функцию постоянной, просто примечание.
почему я должен сделать функцию постоянной? Примечание. Это всего лишь пример сценария, на самом деле я использовал постоянную переменную (вознаграждение) в непостоянной функции (переводе) криптовалюты.
если вы не меняете состояние, то константа полезна, потому что вы можете выполнять callфункцию без транзакций и получать возвращаемое значение. Но, конечно, с переносом это совсем другое дело.
этот вопрос стоит тонны золота (если не биткойнов) — правильно задан!

Ответы (3)

Это работает, как задокументировано, хотя и не интуитивно понятно, причина быстро становится понятной:

Переменные состояния могут быть объявлены как константы [...] Это приводит к тому, что компилятор не резервирует слот для хранения этих переменных, и каждое вхождение заменяется их постоянным значением.

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

Подробности задокументированы в TIB (Today I Burnt) 0,01 ETH с использованием постоянных переменных состояния в контракте Solidity .

Использование постоянных переменных состояния приводит к неожиданным результатам, например:

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;

Переменные:

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

Пример контракта по адресу 0xe67907329dafd1ff826523e3f491bec8733f7376 . Обновите страницу, и вы увидите обновление этих постоянных переменных. НЕ ОТПРАВЛЯЙТЕ СРЕДСТВА НА ДАННЫЙ КОНТРАКТ

Я создал проблему № 76. Пожалуйста, добавьте предупреждение об использовании постоянных переменных состояния в методах и советах по безопасности контрактов Ethereum .



Обновление от 24 марта 2017 г.

Несколько других примеров, когда константа непостоянна.

Из TIB (сегодня я сгорел) 0,01 ETH с использованием постоянных переменных состояния в контракте Solidity :

pragma solidity ^0.4.8;

contract Test {

    bytes32 public constant MY_DATE = keccak256(now);

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

Из комментария @TjadenHess ниже:

pragma solidity ^0.4.8;

contract Test {

    address public constant MY_ADDRESS = msg.sender;

    function check() constant returns (address) {
        return MY_ADDRESS;
    }
}
Это довольно серьезная проблема... Большая проблема в том, что если кто-то это сделает address constant owner = msg.sender...
Должно быть исправлено в 0.4.10 — см. reddit.com/r/ethdev/comments/60xklu/…
Это хорошо. Я быстро просканировал блокчейн, и единственный уязвимый контракт, который я нашел, был вашим, поэтому я думаю, что это не так распространено, как я думал. Все равно хорошо, что быстро исправляют
Ради интереса, как вы сделали быстрое сканирование блокчейна?
Я просто прочесал etherscan для всех контрактов с опубликованным кодом, а затем использовал регулярные выражения, чтобы найти любые постоянные определения глобальных переменных. Это не очень тщательно, но поскольку наиболее важные контракты находятся на etherscan, а определения постоянных переменных довольно легко найти, это должно быть довольно хорошо.
Solidity 0.4.10 помечает предупреждение о том, что:initial value for constant must be compile-time constant. This will fail to compile with the next breaking version change

Глядя на байт-код, сама инструкция TIMESTAMP является постоянным значением. Это имеет смысл, поскольку постоянные значения компилируются как литералы (встроенные в байт-код). Вместо этого использование переменной состояния присваивает значение nowво время построения, и оно сохранит это значение.

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

Разборкаuint constant public constNow = now;

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

По сравнению с буквальным значением вconstant ffff = 0xffff;

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

Эффективным обходным решением является использование переменной состояния вместо константы при работе с инструкцией now/ .TIMESTAMP