Warum werden konstante Zustandsvariablen jedes Mal initialisiert?

Ich habe mit konstanten Variablen in einem Vertrag gearbeitet

contract X{

uint constant var1=now;
uint var2=now;

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

Ich habe mich jedes Mal gewundert, wenn ich anrufe checkConstant(..), dass der Rückgabewert von var1unterschiedlich war, der Wert von var2jedoch gleich war.
Wenn ich also eine Variable als konstant deklariere, verstehe ich nicht, warum sie jedes Mal initialisiert wird, wenn eine Funktion aufgerufen wird. Idealerweise sollte sie zum Zeitpunkt der Vertragsbereitstellung einen Anfangswert erhalten und diesen Wert während der gesamten Vertragslaufzeit beibehalten.

Sie sollten die Funktion auch konstant machen, nur eine Randnotiz.
Warum sollte ich die Funktion konstant machen? Hinweis: Dies ist nur ein Beispielszenario, eigentlich habe ich eine konstante Variable (Belohnung) in einer nicht konstanten Funktion (Übertragung) der Kryptowährung verwendet.
Wenn Sie den Status nicht ändern, ist die Konstante nützlich, da Sie calldie Funktion ohne Transaktionen ausführen und den Rückgabewert erhalten können. Aber bei Transfer ist das natürlich etwas ganz anderes.
Diese Frage ist Tonnen von Gold wert (wenn nicht BitCoins) - gut gestellt!

Antworten (3)

Dies funktioniert wie dokumentiert, obwohl es nicht intuitiv ist, wird der Grund schnell klar:

Zustandsvariablen können als konstant deklariert werden [...] Dies bewirkt, dass der Compiler keinen Speicherplatz für diese Variablen reserviert und jedes Auftreten durch ihren konstanten Wert ersetzt wird.

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

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

Die Verwendung einer konstanten Zustandsvariablen führt zu unerwarteten Ergebnissen, zum Beispiel:

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;

Die Variablen:

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

Mustervertrag unter 0xe67907329dafd1ff826523e3f491bec8733f7376 . Aktualisieren Sie die Seite und Sie werden sehen, wie diese konstanten Variablen aktualisiert werden. SENDEN SIE KEINE GELDMITTEL AN DIESEN VERTRAG

Ich habe Problem Nr. 76 erstellt – Bitte fügen Sie eine Warnung über die Verwendung konstanter Zustandsvariablen in Sicherheitstechniken und Tipps für Ethereum-Kontrakte hinzu .



Update 24. März 2017

Ein paar andere Beispiele, bei denen die Konstante nicht konstant ist.

Von TIB (Today I Burnt) 0.01 ETH unter Verwendung konstanter Zustandsvariablen in einem Soliditätsvertrag :

pragma solidity ^0.4.8;

contract Test {

    bytes32 public constant MY_DATE = keccak256(now);

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

Aus dem Kommentar von @TjadenHess unten:

pragma solidity ^0.4.8;

contract Test {

    address public constant MY_ADDRESS = msg.sender;

    function check() constant returns (address) {
        return MY_ADDRESS;
    }
}
Dies ist ein ziemlich ernstes Problem ... Das größere Problem ist, wenn jemand es tut address constant owner = msg.sender...
Sollte in 0.4.10 behoben sein - siehe reddit.com/r/ethdev/comments/60xklu/…
Das ist gut. Ich habe die Blockchain schnell gescannt und der einzige anfällige Vertrag, der mir eingefallen ist, war Ihrer, also schätze ich, dass er nicht so häufig ist, wie ich dachte. Trotzdem gut, dass es schnell behoben wird
Aus Interesse, wie haben Sie einen schnellen Scan der Blockchain durchgeführt?
Ich habe gerade Etherscan nach allen Verträgen mit veröffentlichtem Code durchsucht und dann Regexs verwendet, um alle konstanten globalen Variablendefinitionen zu finden. Es ist nicht besonders gründlich, aber da sich die meisten wichtigen Verträge auf Etherscan befinden und Definitionen konstanter Variablen ziemlich einfach zu suchen sind, sollte es ziemlich gut sein.
Solidity 0.4.10 kennzeichnet eine Warnung, dass:initial value for constant must be compile-time constant. This will fail to compile with the next breaking version change

Betrachtet man den Bytecode, so ist die TIMESTAMP-Anweisung selbst der konstante Wert. Dies ist sinnvoll, da konstante Werte als Literale (inline mit dem Bytecode) kompiliert werden. Die Verwendung einer Zustandsvariablen weist stattdessen den Wert von nowwährend der Konstruktion zu und behält diesen Wert bei.

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

Demontage vonuint constant public constNow = now;

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

Verglichen mit einem wörtlichen Wert inconstant ffff = 0xffff;

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

Die effektive Problemumgehung besteht darin, eine Zustandsvariable anstelle einer Konstante zu verwenden, wenn Sie mit der now/ TIMESTAMP-Anweisung arbeiten.