Reentrancy-Flag ohne SSTORE?

Ist es möglich, einen Mutex zu erstellen, der Wiedereintritt verhindert, ohne die SSTORE-Operation zu verwenden?

Ich möchte ein Flag erstellen, um einen erneuten Eintritt in meinen Vertrag zu verhindern, der andere Verträge aufruft. Der SSTOREVorgang des Schreibens in den Speicher ist teuer. Gibt es eine Möglichkeit, diesen Mutex im Speicher zu halten, oder mit weniger teuren Operationen?

Ich schreibe mit Solidity, bin aber neugierig auf jede Version. Scheint, als würde dieses Problem für Anwendungsfälle bestehen, die über den Wiedereintrittsschutz hinausgehen. Gebühren zu begrenzen, indem man sie Gsresetnach der Initialisierung auf Gebühren beschränkt, ist das Billigste, was ich mir im Moment vorstellen kann, aber vielleicht fehlt mir etwas.

Antworten (2)

Gibt es eine Möglichkeit, diesen Mutex im Speicher zu halten?

Speicher und Stack in EVM sind für verschachtelte Nachrichtenaufrufe isoliert, was bedeutet, dass es keine Möglichkeit gibt, auf einen Speicher-Mutex-Satz im äußeren Aufruf/der äußeren Transaktion zuzugreifen.

tun es mit weniger teuren Operationen?

Die einzige Möglichkeit, die mir einfällt, besteht darin, den Speicher zu verwenden, da der Speicher im Gegensatz zu Speicher und Stack für denselben Vertrag über verschiedene Nachrichtenaufrufe hinweg geteilt wird. Beachten Sie, dass beim Zurücksetzen des Mutex-Flags der Speicher zurückgesetzt wird, was bedeutet, dass etwas Gas zurückerstattet wird. Im gelben Papier Gsclear = 15000 ist definiert:

Rückerstattung gewährt (zum Rückerstattungszähler hinzugefügt), wenn der Speicherwert von Nicht-Null auf Null gesetzt wird.

Im besten Fall müssten Sie also nur Gsset - Gsclear = 5000Benzin bezahlen. Ich sagte "im besten Fall", weil die Rückerstattung auf maximal die Hälfte (abgerundet) des verwendeten Gesamtbetrags begrenzt ist, wie in Abschnitt 6.2 angegeben. Das Cap wird mindestens 10000 sein, da man immer zuerst den Mutex setzen muss, was 20000 kostet. Im schlimmsten Fall würde man also 10000 Gas bezahlen.

IMHO ist es unvermeidlich, Speicher zu verwenden, daher der SSTOREOpcode :( Nehmen wir diesen einfachen Vertrag als Beispiel. Er verwendet Mutexe, um Wiedereintritt in die withdrawBalance()Funktion zu verhindern.

pragma solidity ^0.4.16;

contract EtherBank{
    mapping(address => uint) public userBalances;
    mapping(address => bool) public withdrawMutex;

    function getBalance(address user) constant returns(uint) {  
        return userBalances[user];
    }

    function addToBalance() {  
        userBalances[msg.sender] += msg.value;
    }

    function withdrawBalance() {  
        if ( withdrawMutex[msg.sender] == true) { throw; }
        withdrawMutex[msg.sender] = true;
        uint amountToWithdraw = userBalances[msg.sender];
        if (amountToWithdraw > 0) {
            if (!(msg.sender.send(amountToWithdraw))) { throw; }
         }
        userBalances[msg.sender] = 0;
        withdrawMutex[msg.sender] = false;
    }
}

Dies ist ein einfacher Bankvertrag aus diesem Blog , dessen Lektüre dringend empfohlen wird, wenn Sie an Reentrancy-Bugs in Smart Contracts interessiert sind. Wie dieses Beispiel zeigt withdrawMutex, wird bei der dauerhaften Speicherung der Vertrag gespeichert.

Sie können Ihren Mutex einfach nicht im Speicher speichern lassen, da er nach jedem Aufruf des Vertrags gelöscht würde. Der Mutex sollte seinen Zustand möglicherweise für viele Aufrufe des Vertrags beibehalten, was impliziert, dass er im permanenten Speicher gespeichert werden sollte. Schlechte Nachrichten für den Gasverbrauch :(

Sie können Reentrancy-Bugs jedoch mit verschiedenen Strategien verhindern, wie die im Blogbeitrag erwähnte. Diese einfache Taktik ist viel benzinkostenfreundlicher:

function withdrawBalance() {  
        uint amountToWithdraw = userBalances[msg.sender];
        userBalances[msg.sender] = 0;
        if (amountToWithdraw > 0) {
        if (!(msg.sender.send(amountToWithdraw))) { throw; }
    }

Also bestellen Sie einfach richtig! ;)