Я работал с постоянными переменными в контракте
contract X{
uint constant var1=now;
uint var2=now;
function checkConstant() returns(uint,uint){
return (var1,var2);
}}
Каждый раз, когда я звоню, меня удивляло checkConstant(..)
, что возвращаемое значение var1
было другим, но значение var2
было одинаковым.
Итак, я не понимаю, когда я объявляю переменную как константу, почему она инициализируется каждый раз, когда вызывается функция, в идеале она должна получать начальное значение во время развертывания контракта и поддерживать это значение на протяжении всего срока действия контракта.
Это работает, как задокументировано, хотя и не интуитивно понятно, причина быстро становится понятной:
Переменные состояния могут быть объявлены как константы [...] Это приводит к тому, что компилятор не резервирует слот для хранения этих переменных, и каждое вхождение заменяется их постоянным значением.
Подробности задокументированы в 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 .
Несколько других примеров, когда константа непостоянна.
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
...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
Роланд Кофлер
Прашант Прабхакар Сингх
Роланд Кофлер
call
функцию без транзакций и получать возвращаемое значение. Но, конечно, с переносом это совсем другое дело.гор