Wie wurde der State-Bloat-Angriff durchgeführt, der zur EIP 150-Hardfork führte?

Ich verstehe das, SELFDESTRUCTund die falsche Preisgestaltung von Opcodes ermöglichte es, viele leere Konten billig zu erstellen, wie in erklärt Warum durften leere Konten in der Blockchain sein? Die Antwort auf diese Frage beinhaltet auch eine Transaktion, die viele leere Konten geschaffen hat. Wie hat diese Transaktion/Angriff funktioniert? Wenn ein Vertrag aufruft SELFDESTRUCT, kann er nicht SELFDESTRUCTwieder ... oder doch?

Antworten (1)

Alte Geschichte, aber hier geht's :-)

Es gab einen Koordinierungsvertrag für den ersten Angriff. Eine spätere Version hatte einen komplexeren Algorithmus, um die leeren Kontoadressen zu generieren, vermutlich um zu versuchen, zukünftige Aufräumarbeiten zu vereiteln. Dieser hat den Adressraum nur inkrementell durchgearbeitet.

Jedes Mal, wenn der Koordinierungsvertrag aufgerufen wurde – und er wurde 4750 Mal aufgerufen – tat er Folgendes:

(1) Erstellen Sie einen untergeordneten Vertrag .

0000 PUSH32 0x6004600c60003960046000f3600035ff00000000000000000000000000000000
0021 PUSH1 0x00
0023 MSTORE
0024 PUSH1 0x20
0026 PUSH1 0x00
0028 PUSH1 0x00
002a CREATE

Dadurch wird eine einzelne Kopie des folgenden untergeordneten Vertrags unter einer neuen Adresse erstellt:

;; Child contract (in full)
PUSH1 0x00
CALLDATALOAD
SELFDESTRUCT

PUSH32Der Code für diesen untergeordneten Vertrag ist in den ersten des koordinierenden Vertrags eingebettet :

0000 PUSH32 0x6004600c60003960046000f3600035ff00000000000000000000000000000000

Die ersten 12 Bytes davon sind der Code für den Konstruktor des untergeordneten Vertrags; die nächsten vier Bytes sind wie oben der untergeordnete Vertragscode selbst.

(2) Einen Zähler aus dem Speicher laden:

002b PUSH1 0x00
002d SLOAD
002e DUP1

Dadurch werden die erstellten leeren/aufgeblähten Konten nachverfolgt, und nachfolgende Aufrufe an den koordinierenden Vertrag können dort fortgesetzt werden, wo der vorherige aufgehört hat.

(3) Schleife über den Rest des Vertrags: Jede Schleifeniteration ruft den untergeordneten Vertrag 40 Mal auf (dh der folgende Code wird 40 Mal dupliziert)

0030 PUSH1 0x01
0032 ADD
0033 DUP1
0034 PUSH1 0x00
0036 MSTORE
0037 PUSH1 0x00
0039 DUP1
003a PUSH1 0x20
003c DUP2
003d DUP1
003e DUP8
003f PUSH1 0x06
0041 CALL
0042 POP

Hier wird eins zum Zähler hinzugefügt, dupliziert, eine Kopie zurück in den Speicher gestellt und dann der untergeordnete Vertrag mit der anderen Kopie des Zählers als Anrufdaten aufgerufen.

Der untergeordnete Vertrag interpretiert die an ihn gesendeten Daten (den Zähler) als Adresse, und wenn er SELFDESTRUCTes ist, sendet er seinen (Null-)Wert an diese Adresse, wodurch ein leeres aufgeblähtes Konto erstellt wird.

Der entscheidende Punkt dabei ist, dass sich der untergeordnete Vertrag bis zum Ende der Ausführung der aktuellen Transaktion nicht selbst zerstört, sodass er innerhalb einer Transaktion viele Male aufgerufen werden kann. Die Beschreibung im gelben Papier lautet „Ausführung stoppen und Konto zur späteren Löschung registrieren“ (Hervorhebung von mir); es wird bei Beendigung der aktuellen Transaktion gelöscht. Es reicht aus, wenn der untergeordnete Vertrag nur bei jedem Aufruf des koordinierenden Vertrags neu erstellt wird; es kann dann viele Male von dort aus aufgerufen werden.

(4) Überprüfen Sie das verbleibende Gas, und wenn es ausreichend ist, gehen Sie zurück und wiederholen Sie alle vierzig Aufrufe erneut, wobei Sie den Adresszähler weiter erhöhen.

0328 GAS
0329 PUSH2 0x6000
032c LT
032d PUSH3 0x00002f
0331 JUMPI

So konnte jeder Abruf des Koordinierungsvertrags je nach ursprünglich gelieferter Gasmenge Tausende von aufgeblähten Konten erstellen.

(5) Speichern Sie abschließend den Adresszähler bereit für den nächsten Aufruf.

0332 PUSH1 0x00
0334 SSTORE

Das Problem war natürlich, dass das Erstellen eines Kontos über SELFDESTRUCT nicht annähernd so viel Gas verbrauchte, wie es hätte tun sollen. Dies wurde in EIP150 behandelt: langfristige Änderungen der Gaskosten .