Warum verbraucht ein Solidity-Wurf alles Gas?

Wenn Sie throweine Ausnahme machen, wird das gesamte Gas verbraucht . Was ist die Begründung für diese Designentscheidung?

Antworten (4)

Das gesamte Gas wird verbraucht, da das EVM im Wesentlichen nur eine Ausnahme hat: Gas aus.

Um dies klarer zu sehen, werfen Sie einen Blick auf den Unterschied zwischen einer „reinen“ Ausnahme und einem Fehler aufgrund von fehlerhaftem/fehlerhaftem/ungültigem EVM-Code. Out of Gas ist ersteres. Jetzt gibt es Fehler wie Stack-Unterlauf, ungültiger JUMP und ungültiger Opcode: Sie können als "Ausnahmen" bezeichnet werden, aber sie sind eher Fehler als eine EVM-Ausnahme, da der Entwickler des Vertrags keinen gültigen EVM-Code gemäß den Regeln geschrieben hat des EVM. Beispielsweise ist ein ungültiger Opcode so, als würde man in Javascript „class“ statt „function“ schreiben: natives Javascript hat im Gegensatz zu einer Sprache wie Java keine „class“. Bei einem Stack-Unterlauf ist es so, als würde der Entwickler dem EVM sagen, dass er 2 Zahlen hinzufügen soll, aber der Entwickler gibt die 2. Zahl nicht an.

Beachten Sie auch, wie sich „Ausnahme“ in der EVM von anderen Sprachen unterscheidet. Zum Beispiel gibt es in der EVM keine Division-durch-Null-Ausnahme (obwohl Solidity 0.4+ dafür eine Ausnahme generiert). Unter der Annahme eines gültigen EVM-Codes gibt es keine Ausnahmen außer „Kein Gas“.

Da es nur eine Out of Gas-Ausnahme gibt, wurden diese anderen Fehler gemacht, um sich als Out of Gas zu verhalten. Dies steht relativ im Einklang mit einigen Ethereum-Designprinzipien der Verallgemeinerung und Minimierung der Komplexität. Mit anderen Worten, beim Implementieren des Verhaltens von Stapelunterlauf, ungültigem JUMP und ungültigem Opcode ist es für das Protokoll einfacher und einfacher, die Implementierung und das Verhalten von Out of Gas wiederzuverwenden.

Andere Antworten haben erklärt, wie Solidity throwzu einem ungültigen JUMP kompiliert wird. (Serpent verwendet stattdessen einen ungültigen Opcode und ruft ihn invalidanstelle von auf throw.)

BEARBEITEN: Die Byzantium-Version enthält EIP 140 , einen neuen Opcode, der REVERTin der EVM benannt ist und der:

bietet eine Möglichkeit, die Ausführung zu stoppen und Zustandsänderungen rückgängig zu machen, ohne das gesamte bereitgestellte Gas zu verbrauchen, und mit der Möglichkeit, einen Grund zurückzugeben.

throwwird zugunsten von revert(), require(), verworfenassert()

classist ein gültiges Schlüsselwort in Javascript, das zum Definieren einer Klasse verwendet wird.
@0xcaff Danke, ja, JavaScript entwickelt sich auch und classwurde in ECMAScript 2015 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… hinzugefügt (es braucht noch Zeit, bis ECMA-Standards allgemein bekannt und angenommen werden).

Der Solidity throw-Befehl wird zu einem ungültigen JUMP - Befehl kompiliert (dh ein Sprung zu einer ungültigen Stelle).

Der Abschnitt 9.4.2 des Gelben Papiers erklärt, wie das außergewöhnliche Halten funktioniert, in Kapitel 8 wird erklärt, dass in diesem Fall kein Gas zurückerstattet wird.

In Kapitel 8 heißt es:

Genau wie bei der Vertragserstellung wird, wenn die Ausführung auf außergewöhnliche Weise angehalten wird (dh aufgrund eines erschöpften Gasvorrats, eines Stapelunterlaufs, eines ungültigen Sprungziels oder einer ungültigen Anweisung), kein Gas an den Anrufer zurückerstattet und der Zustand wird auf den Punkt zurückgesetzt unmittelbar vor der Saldoübertragung (dh σ).

Und zurück zu Kapitel 7:

Wenn eine solche Ausnahme nicht auftritt, wird das verbleibende Gas an den Urheber zurückerstattet und der jetzt geänderte Zustand kann bestehen bleiben.

Warum das so entschieden wurde, ist mir nicht bekannt.

Zum Teil glaube ich, dass dies eine Sicherheitsentscheidung war, um sicherzustellen, dass das Spammen des Netzwerks mit gefälschten Transaktionen den Absender Gas kostet. Wenn zum Beispiel Gas nach einem Wurf zurückerstattet wurde, könnte ein böswilliger Akteur einen Vertrag erstellen, der etwas Gas verbraucht und dann werfen würde. Dieser Akteur könnte dann eine oder mehrere Transaktionen mit einem hohen Gaspreis und viel Gas senden, wodurch seine Transaktionen unter den Standard-Miner-Bedingungen Vorrang erhalten. Ihre Transaktionen könnten das gesamte Gas in jedem Block aufnehmen, sodass keine anderen Transaktionen durchgeführt werden könnten, und wenn ihnen das Gas zurückgegeben würde, könnten sie dies auf unbestimmte Zeit kostenlos tun. Wenn Gas verbraucht wird, würde dies sie eine Menge Äther kosten.

Die throwAnweisung ist ein EVM-Hack, der alle Änderungen rückgängig macht, die durch die aktuelle Vertragsausführung vorgenommen wurden. Es nutzt die außergewöhnliche Beendigung von EVM aus, die auch das gesamte Gas verbraucht.

Das erklärt nicht die Begründung, warum es so konzipiert ist. Viele Beispiele in der Solidity-Dokumentation verwenden so, throwals sei dies der beste Weg, Dinge zu tun. Aber es ist eindeutig nicht, wenn es den Anrufer die maximale Gebühr kostet.
Nach Ihrer Erklärung sollte es höchstens so viel Gas kosten, wie bereits in der Transaktion verbraucht wurde, bis die Ausnahme auftrat (eine naive Implementierung könnte jede Operation einzeln "rückgängig machen").
Dies würde das Hinzufügen eines Systems erfordern, um alle Zustandsänderungen zu verfolgen, einschließlich derjenigen in Aufrufen zu anderen Verträgen, was realistischerweise nicht möglich ist