¿Por qué las variables de estado constante se inicializan cada vez?

Estaba trabajando con variables constantes en un contrato.

contract X{

uint constant var1=now;
uint var2=now;

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

Me preguntaba cada vez que llamo checkConstant(..), el valor de retorno de var1era diferente pero el valor de var2era el mismo.
Entonces, no entiendo cuando declaro una variable como constante por qué se inicializa cada vez que se invoca una función, idealmente debería obtener un valor inicial en el momento de la implementación del contrato y mantener este valor durante la vigencia del contrato.

también debe hacer que la función sea constante, solo una nota al margen.
¿Por qué debería hacer que la función sea constante? Nota: Este es solo un escenario de muestra, en realidad estaba usando una variable constante (recompensa) en una función no constante (transferencia) de criptomoneda.
si no cambia el estado, la constante es útil porque puede ejecutar callla función sin transacciones y obtener el valor de retorno. Pero, por supuesto, con la transferencia esto es otra cosa.
esta pregunta vale toneladas de oro (si no es BitCoins) - ¡bien hecho!

Respuestas (3)

Esto funciona como está documentado, aunque no es intuitivo, la razón se aclara rápidamente:

Las variables de estado se pueden declarar como constantes [...] Esto tiene el efecto de que el compilador no reserva un espacio de almacenamiento para estas variables y cada aparición se reemplaza por su valor constante.

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

Detalles documentados en TIB (Today I Burnt) 0.01 ETH Uso de variables de estado constante en un contrato de solidez .

El uso de variables de estado constante produce resultados inesperados, por ejemplo:

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;

Las 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

Ejemplo de contrato en 0xe67907329dafd1ff826523e3f491bec8733f7376 . Actualice la página y verá cómo se actualizan estas variables constantes. NO ENVÍE FONDOS A ESTE CONTRATO

Creé el problema n.º 76: agregue una advertencia sobre el uso de variables de estado constante en técnicas y consejos de seguridad de contratos de Ethereum .



Actualización 24 de marzo de 2017

Algunos otros ejemplos donde la constante no es constante.

De TIB (Today I Burnt) 0.01 ETH usando variables de estado constante en un contrato de solidez :

pragma solidity ^0.4.8;

contract Test {

    bytes32 public constant MY_DATE = keccak256(now);

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

Del comentario de @TjadenHess a continuación:

pragma solidity ^0.4.8;

contract Test {

    address public constant MY_ADDRESS = msg.sender;

    function check() constant returns (address) {
        return MY_ADDRESS;
    }
}
Este es un problema bastante serio... El mayor problema es si alguien lo hace address constant owner = msg.sender...
Debería corregirse en 0.4.10: consulte reddit.com/r/ethdev/comments/60xklu/…
Está bien. Hice un escaneo rápido de la cadena de bloques y el único contrato vulnerable que se me ocurrió fue el tuyo, así que supongo que no es tan común como pensaba. Aún así es bueno que se solucione rápidamente.
Por curiosidad, ¿cómo hiciste un escaneo rápido de la cadena de bloques?
Acabo de raspar etherscan para todos los contratos con código publicado, luego usé expresiones regulares para encontrar definiciones de variables globales constantes. No es muy completo, pero dado que la mayoría de los contratos importantes están en etherscan, y las definiciones de variables constantes son bastante fáciles de buscar, debería ser bastante bueno.
Solidity 0.4.10 marca una advertencia de que:initial value for constant must be compile-time constant. This will fail to compile with the next breaking version change

Mirando el código de bytes, la instrucción TIMESTAMP en sí es el valor constante. Esto tiene sentido ya que los valores constantes se compilan como literales (en línea con el código de bytes). El uso de una variable de estado en su lugar asigna el valor de nowdurante la construcción y mantendrá ese valor.

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

Desmontaje deuint constant public constNow = now;

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

Comparado con un valor literal enconstant ffff = 0xffff;

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

La solución efectiva es usar una variable de estado en lugar de una constante cuando se trabaja con la instrucción now/ .TIMESTAMP