[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-1-wie-evm-code-ausfuehrt-opcodes-stack-gas":3},{"article":4,"author":54},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":7,"meta_description":16,"focus_keyword":17,"og_image":18,"canonical_url":18,"robots_meta":19,"created_at":15,"updated_at":15,"tags":20,"category_name":34,"related_articles":35},"d7000000-0000-0000-0000-000000000101","a0000000-0000-0000-0000-000000000072","Deep EVM #1: Wie die EVM Ihren Code ausfuehrt — Opcodes, Stack und Gas","deep-evm-1-wie-evm-code-ausfuehrt-opcodes-stack-gas","Eine detaillierte technische Anleitung zur Ethereum Virtual Machine: wie Opcodes den Stack manipulieren, wie die Gas-Abrechnung funktioniert und was tatsaechlich passiert, wenn Ihre Transaktion ausgefuehrt wird.","## Die EVM ist eine Stack-Maschine\n\nDie Ethereum Virtual Machine ist nicht wie der x86-Prozessor in Ihrem Laptop. Sie hat keine Register. Stattdessen ist die EVM eine **Stack-Maschine** — jede Berechnung schiebt Daten auf oder entnimmt sie von einem 1024-Elemente-Stack, wobei jedes Element ein 256-Bit-Wort (32 Byte) ist.\n\nWenn Sie einen Smart Contract aufrufen, erhaelt die EVM den Bytecode des Contracts — eine flache Sequenz von Ein-Byte-Opcodes — und beginnt die Ausfuehrung bei Byte 0. Es gibt keine Funktionstabelle, keinen ELF-Header, keine Linking-Phase. Der Bytecode ist das Programm.\n\n```\n\u002F\u002F Solidity:\n\u002F\u002F uint256 result = 2 + 3;\n\n\u002F\u002F Kompiliert zu Bytecode:\n\u002F\u002F PUSH1 0x02  PUSH1 0x03  ADD\n\n\u002F\u002F Stack-Trace:\n\u002F\u002F []           -> PUSH1 0x02 -> [2]\n\u002F\u002F [2]          -> PUSH1 0x03 -> [2, 3]\n\u002F\u002F [2, 3]       -> ADD        -> [5]\n```\n\nJeder Opcode entnimmt seine Operanden vom Stack-Top und legt das Ergebnis zurueck. Der ADD-Opcode entnimmt zwei Werte, addiert sie und legt die Summe auf den Stack. Dies unterscheidet sich grundlegend von Register-Architekturen, bei denen Sie Quell- und Zielregister angeben.\n\n## Opcode-Kategorien\n\nDie EVM definiert etwa 140 Opcodes, gruppiert nach funktionalen Kategorien:\n\n### Arithmetik und Vergleich\n- **ADD, SUB, MUL, DIV, MOD** — grundlegende 256-Bit-Ganzzahlarithmetik. Alle kosten 3 Gas (G_verylow-Stufe).\n- **SDIV, SMOD** — vorzeichenbehaftete Division und Modulo im Zweierkomplement.\n- **ADDMOD, MULMOD** — modulare Arithmetik: `(a + b) % N` und `(a * b) % N` in einem Opcode. Kritisch fuer Operationen auf elliptischen Kurven, kosten 8 Gas.\n- **EXP** — Potenzierung. Kostet 10 Gas + 50 pro Byte des Exponenten, was ihn zu einem der teuersten arithmetischen Opcodes macht.\n- **LT, GT, SLT, SGT, EQ, ISZERO** — Vergleichs-Opcodes, die 1 (wahr) oder 0 (falsch) auf den Stack legen.\n\n### Bitweise Operationen\n- **AND, OR, XOR, NOT** — bitweise Logik, jeweils 3 Gas.\n- **SHL, SHR, SAR** — Linksverschiebung, logische Rechtsverschiebung, arithmetische Rechtsverschiebung (eingefuehrt mit Constantinople, EIP-145). Vorher erforderten Verschiebungen MUL\u002FDIV mit Zweierpotenzen.\n- **BYTE** — Extrahiert ein einzelnes Byte aus einem 32-Byte-Wort. `BYTE(0, x)` gibt das hoechstwertige Byte zurueck.\n\n### Stack-Manipulationen\n- **POP** — oberstes Element entfernen.\n- **PUSH1 — PUSH32** — 1 bis 32 Bytes unmittelbarer Daten auf den Stack legen. PUSH1 ist der haeufigste Opcode in bereitgestelltem Bytecode.\n- **DUP1 — DUP16** — das N-te Stack-Element an die Spitze duplizieren.\n- **SWAP1 — SWAP16** — das oberste Element mit dem N-ten Element darunter tauschen.\n\n### Umgebungs- und Blockinformationen\n- **CALLER** (msg.sender), **CALLVALUE** (msg.value), **CALLDATALOAD**, **CALLDATASIZE**, **CALLDATACOPY** — Zugriff auf den Transaktionskontext.\n- **NUMBER**, **TIMESTAMP**, **BASEFEE**, **CHAINID** — Block-Level-Informationen.\n- **BALANCE**, **EXTCODESIZE**, **EXTCODECOPY** — Abfrage von Daten anderer Konten.\n\n## Gas-Zeitplan\n\nJeder Opcode hat Gaskosten. Gas erfuellt zwei Funktionen: Es verhindert Endlosschleifen (Halteproblem) und bewertet Rechenressourcen fair.\n\nDie Gaskosten verteilen sich auf Stufen:\n\n| Stufe | Gas | Beispiele |\n|-------|-----|-----------|\n| Null | 0 | STOP, RETURN, REVERT |\n| Basis | 2 | ADDRESS, ORIGIN, CALLER |\n| Sehr niedrig | 3 | ADD, SUB, LT, GT, AND, OR, POP |\n| Niedrig | 5 | MUL, DIV, MOD |\n| Mittel | 8 | ADDMOD, MULMOD, JUMP |\n| Hoch | 10 | JUMPI |\n| Speziell | variabel | SLOAD, SSTORE, CALL, CREATE |\n\nDie teuersten Opcodes sind diejenigen, die mit dem Zustand interagieren:\n\n```\n\u002F\u002F Gaskosten fuer Zustandszugriff (nach EIP-2929):\n\u002F\u002F SLOAD (kalt):  2100 Gas\n\u002F\u002F SLOAD (warm):   100 Gas\n\u002F\u002F SSTORE (kalt, 0->ungleich Null): 22100 Gas\n\u002F\u002F SSTORE (warm):    100 Gas (+ 20000 wenn 0->ungleich Null)\n\u002F\u002F CALL (kalt):   2600 Gas\n\u002F\u002F CALL (warm):    100 Gas\n\u002F\u002F BALANCE (kalt): 2600 Gas\n\u002F\u002F BALANCE (warm):   100 Gas\n```\n\n## Kalter und warmer Zugriff (EIP-2929)\n\nEIP-2929 (Berlin-Upgrade, April 2021) fuehrte das Konzept der **Zugriffsliste** ein — eine Menge von Adressen und Speicherslots pro Transaktion, auf die bereits zugegriffen wurde.\n\nBeim ersten Zugriff auf einen Speicherslot oder eine externe Adresse in einer Transaktion gilt er als \"kalt\" und kostet zusaetzliches Gas. Wiederholte Zugriffe sind \"warm\" und guenstig. Deshalb ist die Reihenfolge der Speicher-Slot-Lesevorgaenge fuer die Gasoptimierung wichtig.\n\n```solidity\n\u002F\u002F In Solidity ist dieses Muster teuer:\nfunction bad() external view returns (uint256) {\n    \u002F\u002F Erster Slot-Lesevorgang: 2100 Gas (kalt)\n    uint256 a = myStorage;\n    \u002F\u002F ... Logik ...\n    \u002F\u002F Zweiter Lesevorgang: 100 Gas (warm)\n    uint256 b = myStorage;\n    return a + b;\n}\n\n\u002F\u002F Im Speicher zwischenspeichern:\nfunction good() external view returns (uint256) {\n    uint256 cached = myStorage; \u002F\u002F 2100 Gas (kalt), nur einmal\n    return cached + cached;     \u002F\u002F 6 Gas (ADD + DUP)\n}\n```\n\n## Ausfuehrungsablauf: Was in einer Transaktion passiert\n\nWenn Sie eine Transaktion senden, die einen Contract aufruft, ist dies die vollstaendige Ausfuehrungssequenz:\n\n1. **Transaktionsvalidierung** — Nonce-Pruefung, Guthaben >= value + gas * gasPrice, Signaturverifikation.\n2. **Intrinsischer Gasabzug** — 21.000 Gas fuer die Transaktion selbst, plus 16 Gas fuer jedes Nicht-Null-Byte der Calldata und 4 fuer Null-Bytes.\n3. **Kontext-Einrichtung** — Die EVM erstellt einen Ausfuehrungskontext: Code, Calldata, Aufrufer, Wert, verbleibendes Gas.\n4. **Programmzaehler beginnt bei 0** — Die EVM liest den Opcode an Position 0 und fuehrt ihn aus.\n5. **Sequentielle Ausfuehrung** — Jeder Opcode wird ausgefuehrt, Gas wird abgezogen. JUMP und JUMPI ermoeglichen nichtlinearen Kontrollfluss, aber nur zu Positionen, die mit JUMPDEST markiert sind.\n6. **Beendigung** — Die Ausfuehrung endet durch STOP (Erfolg, keine Rueckgabedaten), RETURN (Erfolg, mit Rueckgabedaten), REVERT (Fehler, Zustand wird zurueckgesetzt) oder Gaserschoepfung.\n7. **Zustandsfestschreibung oder Rollback** — Bei Erfolg werden alle Zustandsaenderungen festgeschrieben. Bei Rollback werden alle Aenderungen in diesem Aufrufkontext rueckgaengig gemacht.\n\n## Programmzaehler und JUMP\n\nDer Programmzaehler (PC) ist ein implizites Register, das die aktuelle Position im Bytecode verfolgt. Die meisten Opcodes erhoehen den PC um 1 (oder 1 + N fuer PUSH-Opcodes). Zwei Opcodes aendern den PC direkt:\n\n- **JUMP** — entnimmt eine Zieladresse vom Stack, setzt PC auf diesen Wert. Die Zieladresse muss einen JUMPDEST-Opcode enthalten, sonst wird die Transaktion rueckgaengig gemacht.\n- **JUMPI** — bedingter Sprung. Entnimmt Zieladresse und Bedingung. Wenn die Bedingung ungleich Null ist — Sprung; andernfalls sequentielle Ausfuehrung fortsetzen.\n\nSo implementiert die EVM if\u002Felse, Schleifen und Funktionsdispatch. Der Solidity-Compiler generiert einen Funktionsselektor, der die ersten 4 Bytes der Calldata laedt, mit bekannten Signaturen vergleicht und JUMPI zum entsprechenden Codeblock ausfuehrt.\n\n```\n\u002F\u002F Funktionsdispatch (vereinfachter Bytecode):\n\u002F\u002F CALLDATALOAD(0) -> SHR(224) -> function_selector\n\u002F\u002F DUP1 PUSH4 0xa9059cbb EQ PUSH2 0x00a4 JUMPI  \u002F\u002F transfer(address,uint256)\n\u002F\u002F DUP1 PUSH4 0x70a08231 EQ PUSH2 0x00d2 JUMPI  \u002F\u002F balanceOf(address)\n\u002F\u002F PUSH1 0x00 DUP1 REVERT                         \u002F\u002F Fallback: revert\n```\n\n## Unteraufrufe: CALL, STATICCALL, DELEGATECALL\n\nContracts koennen andere Contracts mit drei Aufruf-Opcodes aufrufen:\n\n- **CALL** — Standardaufruf. Erstellt einen neuen Ausfuehrungskontext mit eigenem Stack und Speicher. Der Aufgerufene arbeitet unabhaengig; wenn er zurueckgesetzt wird, werden nur seine Aenderungen rueckgaengig gemacht.\n- **STATICCALL** — Nur-Lese-Aufruf (EIP-214). Jeder zustandsaendernde Opcode (SSTORE, CREATE, LOG, SELFDESTRUCT) innerhalb des Aufgerufenen verursacht einen sofortigen Rollback.\n- **DELEGATECALL** — Fuehrt den Code des Aufgerufenen aus, aber im Speicherkontext des Aufrufers. msg.sender und msg.value bleiben vom urspruenglichen Aufruf erhalten. So funktionieren Proxy-Muster und Bibliotheken.\n\nJeder Aufruf-Opcode nimmt 7 Stack-Argumente: gas, address, value (ausser STATICCALL\u002FDELEGATECALL), argsOffset, argsLength, retOffset, retLength. Gaskosten: 100 (warm) oder 2600 (kalt) plus Zuschlag fuer Wertuebertragung.\n\n## Gas-Rueckerstattungen und ihre Grenzen\n\nHistorisch gab das Loeschen eines Speicherslots von ungleich Null auf Null eine Gas-Rueckerstattung — als Anreiz zur Zustandsbereinigung. Nach EIP-3529 (London-Upgrade) ist die maximale Rueckerstattung auf 20% des gesamten verbrauchten Gases begrenzt (vorher 50%). Dies zerstoerte die Arbitrage von Gas-Token (CHI, GST2), die Rueckerstattungen zur Gewinnerzielung ausnutzten.\n\nVerbleibende Rueckerstattungsquellen:\n- SSTORE: Setzen eines Nicht-Null-Slots zurueck auf Null erstattet 4.800 Gas.\n- SELFDESTRUCT: Als Rueckerstattungsquelle in EIP-3529 entfernt.\n\n## Praktische Auswirkungen fuer MEV\n\nWenn Sie MEV-Bots bauen, ist das Verstaendnis der EVM auf Opcode-Ebene keine Option, sondern eine Wettbewerbsanforderung. Jede eingesparte Gas-Einheit bei der Ausfuehrung Ihres Bots ist Gewinnmarge. Wichtige Erkenntnisse:\n\n- **Vor dem Senden simulieren** — verwenden Sie `eth_call` oder eine lokale EVM (revm, EVMONE) fuer die Ausfuehrungstrace und praezise Gaskostenberechnung vor dem Senden des Bundles an den Builder.\n- **Kalten Zugriff minimieren** — Speicherslots ueber Zugriffslisten (EIP-2930) vorwaermen.\n- **STATICCALL fuer Lesevorgaenge verwenden** — etwas guenstiger und garantiert keine Zustandsmutation.\n- **Opcode-Kosten kennen** — ein schlecht platzierter SLOAD kann 2.100 Gas kosten; in der wettbewerbsintensiven MEV-Umgebung ist das der Unterschied zwischen Gewinn und Verlust.\n\n## Fazit\n\nDie EVM ist elegant in ihrer Einfachheit: eine Stack-Maschine mit 256-Bit-Woertern, ein flaches Bytecode-Format und ein Gas-Abrechnungssystem, das jede Operation bewertet. Das Verstaendnis dieses Fundaments — Opcodes, Stack und Gas — ist die Voraussetzung fuer alles andere in dieser Serie: Speicherlayout, Storage-Optimierung, Sicherheitsprimitive und schliesslich das Schreiben von reinem Yul.\n\nIm naechsten Artikel werden wir die vier Datenbereiche der EVM untersuchen: Stack, Memory, Storage und Calldata — und warum die richtige Wahl bestimmt, ob Ihr Contract $0,50 oder $50 pro Ausfuehrung kostet.","\u003Ch2 id=\"die-evm-ist-eine-stack-maschine\">Die EVM ist eine Stack-Maschine\u003C\u002Fh2>\n\u003Cp>Die Ethereum Virtual Machine ist nicht wie der x86-Prozessor in Ihrem Laptop. Sie hat keine Register. Stattdessen ist die EVM eine \u003Cstrong>Stack-Maschine\u003C\u002Fstrong> — jede Berechnung schiebt Daten auf oder entnimmt sie von einem 1024-Elemente-Stack, wobei jedes Element ein 256-Bit-Wort (32 Byte) ist.\u003C\u002Fp>\n\u003Cp>Wenn Sie einen Smart Contract aufrufen, erhaelt die EVM den Bytecode des Contracts — eine flache Sequenz von Ein-Byte-Opcodes — und beginnt die Ausfuehrung bei Byte 0. Es gibt keine Funktionstabelle, keinen ELF-Header, keine Linking-Phase. Der Bytecode ist das Programm.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F Solidity:\n\u002F\u002F uint256 result = 2 + 3;\n\n\u002F\u002F Kompiliert zu Bytecode:\n\u002F\u002F PUSH1 0x02  PUSH1 0x03  ADD\n\n\u002F\u002F Stack-Trace:\n\u002F\u002F []           -&gt; PUSH1 0x02 -&gt; [2]\n\u002F\u002F [2]          -&gt; PUSH1 0x03 -&gt; [2, 3]\n\u002F\u002F [2, 3]       -&gt; ADD        -&gt; [5]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Jeder Opcode entnimmt seine Operanden vom Stack-Top und legt das Ergebnis zurueck. Der ADD-Opcode entnimmt zwei Werte, addiert sie und legt die Summe auf den Stack. Dies unterscheidet sich grundlegend von Register-Architekturen, bei denen Sie Quell- und Zielregister angeben.\u003C\u002Fp>\n\u003Ch2 id=\"opcode-kategorien\">Opcode-Kategorien\u003C\u002Fh2>\n\u003Cp>Die EVM definiert etwa 140 Opcodes, gruppiert nach funktionalen Kategorien:\u003C\u002Fp>\n\u003Ch3>Arithmetik und Vergleich\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>\u003Cstrong>ADD, SUB, MUL, DIV, MOD\u003C\u002Fstrong> — grundlegende 256-Bit-Ganzzahlarithmetik. Alle kosten 3 Gas (G_verylow-Stufe).\u003C\u002Fli>\n\u003Cli>\u003Cstrong>SDIV, SMOD\u003C\u002Fstrong> — vorzeichenbehaftete Division und Modulo im Zweierkomplement.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>ADDMOD, MULMOD\u003C\u002Fstrong> — modulare Arithmetik: \u003Ccode>(a + b) % N\u003C\u002Fcode> und \u003Ccode>(a * b) % N\u003C\u002Fcode> in einem Opcode. Kritisch fuer Operationen auf elliptischen Kurven, kosten 8 Gas.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>EXP\u003C\u002Fstrong> — Potenzierung. Kostet 10 Gas + 50 pro Byte des Exponenten, was ihn zu einem der teuersten arithmetischen Opcodes macht.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>LT, GT, SLT, SGT, EQ, ISZERO\u003C\u002Fstrong> — Vergleichs-Opcodes, die 1 (wahr) oder 0 (falsch) auf den Stack legen.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Bitweise Operationen\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>\u003Cstrong>AND, OR, XOR, NOT\u003C\u002Fstrong> — bitweise Logik, jeweils 3 Gas.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>SHL, SHR, SAR\u003C\u002Fstrong> — Linksverschiebung, logische Rechtsverschiebung, arithmetische Rechtsverschiebung (eingefuehrt mit Constantinople, EIP-145). Vorher erforderten Verschiebungen MUL\u002FDIV mit Zweierpotenzen.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>BYTE\u003C\u002Fstrong> — Extrahiert ein einzelnes Byte aus einem 32-Byte-Wort. \u003Ccode>BYTE(0, x)\u003C\u002Fcode> gibt das hoechstwertige Byte zurueck.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Stack-Manipulationen\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>\u003Cstrong>POP\u003C\u002Fstrong> — oberstes Element entfernen.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>PUSH1 — PUSH32\u003C\u002Fstrong> — 1 bis 32 Bytes unmittelbarer Daten auf den Stack legen. PUSH1 ist der haeufigste Opcode in bereitgestelltem Bytecode.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>DUP1 — DUP16\u003C\u002Fstrong> — das N-te Stack-Element an die Spitze duplizieren.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>SWAP1 — SWAP16\u003C\u002Fstrong> — das oberste Element mit dem N-ten Element darunter tauschen.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Umgebungs- und Blockinformationen\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>\u003Cstrong>CALLER\u003C\u002Fstrong> (msg.sender), \u003Cstrong>CALLVALUE\u003C\u002Fstrong> (msg.value), \u003Cstrong>CALLDATALOAD\u003C\u002Fstrong>, \u003Cstrong>CALLDATASIZE\u003C\u002Fstrong>, \u003Cstrong>CALLDATACOPY\u003C\u002Fstrong> — Zugriff auf den Transaktionskontext.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>NUMBER\u003C\u002Fstrong>, \u003Cstrong>TIMESTAMP\u003C\u002Fstrong>, \u003Cstrong>BASEFEE\u003C\u002Fstrong>, \u003Cstrong>CHAINID\u003C\u002Fstrong> — Block-Level-Informationen.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>BALANCE\u003C\u002Fstrong>, \u003Cstrong>EXTCODESIZE\u003C\u002Fstrong>, \u003Cstrong>EXTCODECOPY\u003C\u002Fstrong> — Abfrage von Daten anderer Konten.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"gas-zeitplan\">Gas-Zeitplan\u003C\u002Fh2>\n\u003Cp>Jeder Opcode hat Gaskosten. Gas erfuellt zwei Funktionen: Es verhindert Endlosschleifen (Halteproblem) und bewertet Rechenressourcen fair.\u003C\u002Fp>\n\u003Cp>Die Gaskosten verteilen sich auf Stufen:\u003C\u002Fp>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Stufe\u003C\u002Fth>\u003Cth>Gas\u003C\u002Fth>\u003Cth>Beispiele\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Null\u003C\u002Ftd>\u003Ctd>0\u003C\u002Ftd>\u003Ctd>STOP, RETURN, REVERT\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Basis\u003C\u002Ftd>\u003Ctd>2\u003C\u002Ftd>\u003Ctd>ADDRESS, ORIGIN, CALLER\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Sehr niedrig\u003C\u002Ftd>\u003Ctd>3\u003C\u002Ftd>\u003Ctd>ADD, SUB, LT, GT, AND, OR, POP\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Niedrig\u003C\u002Ftd>\u003Ctd>5\u003C\u002Ftd>\u003Ctd>MUL, DIV, MOD\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Mittel\u003C\u002Ftd>\u003Ctd>8\u003C\u002Ftd>\u003Ctd>ADDMOD, MULMOD, JUMP\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Hoch\u003C\u002Ftd>\u003Ctd>10\u003C\u002Ftd>\u003Ctd>JUMPI\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Speziell\u003C\u002Ftd>\u003Ctd>variabel\u003C\u002Ftd>\u003Ctd>SLOAD, SSTORE, CALL, CREATE\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>Die teuersten Opcodes sind diejenigen, die mit dem Zustand interagieren:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F Gaskosten fuer Zustandszugriff (nach EIP-2929):\n\u002F\u002F SLOAD (kalt):  2100 Gas\n\u002F\u002F SLOAD (warm):   100 Gas\n\u002F\u002F SSTORE (kalt, 0-&gt;ungleich Null): 22100 Gas\n\u002F\u002F SSTORE (warm):    100 Gas (+ 20000 wenn 0-&gt;ungleich Null)\n\u002F\u002F CALL (kalt):   2600 Gas\n\u002F\u002F CALL (warm):    100 Gas\n\u002F\u002F BALANCE (kalt): 2600 Gas\n\u002F\u002F BALANCE (warm):   100 Gas\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"kalter-und-warmer-zugriff-eip-2929\">Kalter und warmer Zugriff (EIP-2929)\u003C\u002Fh2>\n\u003Cp>EIP-2929 (Berlin-Upgrade, April 2021) fuehrte das Konzept der \u003Cstrong>Zugriffsliste\u003C\u002Fstrong> ein — eine Menge von Adressen und Speicherslots pro Transaktion, auf die bereits zugegriffen wurde.\u003C\u002Fp>\n\u003Cp>Beim ersten Zugriff auf einen Speicherslot oder eine externe Adresse in einer Transaktion gilt er als “kalt” und kostet zusaetzliches Gas. Wiederholte Zugriffe sind “warm” und guenstig. Deshalb ist die Reihenfolge der Speicher-Slot-Lesevorgaenge fuer die Gasoptimierung wichtig.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F In Solidity ist dieses Muster teuer:\nfunction bad() external view returns (uint256) {\n    \u002F\u002F Erster Slot-Lesevorgang: 2100 Gas (kalt)\n    uint256 a = myStorage;\n    \u002F\u002F ... Logik ...\n    \u002F\u002F Zweiter Lesevorgang: 100 Gas (warm)\n    uint256 b = myStorage;\n    return a + b;\n}\n\n\u002F\u002F Im Speicher zwischenspeichern:\nfunction good() external view returns (uint256) {\n    uint256 cached = myStorage; \u002F\u002F 2100 Gas (kalt), nur einmal\n    return cached + cached;     \u002F\u002F 6 Gas (ADD + DUP)\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"ausfuehrungsablauf-was-in-einer-transaktion-passiert\">Ausfuehrungsablauf: Was in einer Transaktion passiert\u003C\u002Fh2>\n\u003Cp>Wenn Sie eine Transaktion senden, die einen Contract aufruft, ist dies die vollstaendige Ausfuehrungssequenz:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Transaktionsvalidierung\u003C\u002Fstrong> — Nonce-Pruefung, Guthaben &gt;= value + gas * gasPrice, Signaturverifikation.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Intrinsischer Gasabzug\u003C\u002Fstrong> — 21.000 Gas fuer die Transaktion selbst, plus 16 Gas fuer jedes Nicht-Null-Byte der Calldata und 4 fuer Null-Bytes.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Kontext-Einrichtung\u003C\u002Fstrong> — Die EVM erstellt einen Ausfuehrungskontext: Code, Calldata, Aufrufer, Wert, verbleibendes Gas.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Programmzaehler beginnt bei 0\u003C\u002Fstrong> — Die EVM liest den Opcode an Position 0 und fuehrt ihn aus.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Sequentielle Ausfuehrung\u003C\u002Fstrong> — Jeder Opcode wird ausgefuehrt, Gas wird abgezogen. JUMP und JUMPI ermoeglichen nichtlinearen Kontrollfluss, aber nur zu Positionen, die mit JUMPDEST markiert sind.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Beendigung\u003C\u002Fstrong> — Die Ausfuehrung endet durch STOP (Erfolg, keine Rueckgabedaten), RETURN (Erfolg, mit Rueckgabedaten), REVERT (Fehler, Zustand wird zurueckgesetzt) oder Gaserschoepfung.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Zustandsfestschreibung oder Rollback\u003C\u002Fstrong> — Bei Erfolg werden alle Zustandsaenderungen festgeschrieben. Bei Rollback werden alle Aenderungen in diesem Aufrufkontext rueckgaengig gemacht.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"programmzaehler-und-jump\">Programmzaehler und JUMP\u003C\u002Fh2>\n\u003Cp>Der Programmzaehler (PC) ist ein implizites Register, das die aktuelle Position im Bytecode verfolgt. Die meisten Opcodes erhoehen den PC um 1 (oder 1 + N fuer PUSH-Opcodes). Zwei Opcodes aendern den PC direkt:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>JUMP\u003C\u002Fstrong> — entnimmt eine Zieladresse vom Stack, setzt PC auf diesen Wert. Die Zieladresse muss einen JUMPDEST-Opcode enthalten, sonst wird die Transaktion rueckgaengig gemacht.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>JUMPI\u003C\u002Fstrong> — bedingter Sprung. Entnimmt Zieladresse und Bedingung. Wenn die Bedingung ungleich Null ist — Sprung; andernfalls sequentielle Ausfuehrung fortsetzen.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>So implementiert die EVM if\u002Felse, Schleifen und Funktionsdispatch. Der Solidity-Compiler generiert einen Funktionsselektor, der die ersten 4 Bytes der Calldata laedt, mit bekannten Signaturen vergleicht und JUMPI zum entsprechenden Codeblock ausfuehrt.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F Funktionsdispatch (vereinfachter Bytecode):\n\u002F\u002F CALLDATALOAD(0) -&gt; SHR(224) -&gt; function_selector\n\u002F\u002F DUP1 PUSH4 0xa9059cbb EQ PUSH2 0x00a4 JUMPI  \u002F\u002F transfer(address,uint256)\n\u002F\u002F DUP1 PUSH4 0x70a08231 EQ PUSH2 0x00d2 JUMPI  \u002F\u002F balanceOf(address)\n\u002F\u002F PUSH1 0x00 DUP1 REVERT                         \u002F\u002F Fallback: revert\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"unteraufrufe-call-staticcall-delegatecall\">Unteraufrufe: CALL, STATICCALL, DELEGATECALL\u003C\u002Fh2>\n\u003Cp>Contracts koennen andere Contracts mit drei Aufruf-Opcodes aufrufen:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>CALL\u003C\u002Fstrong> — Standardaufruf. Erstellt einen neuen Ausfuehrungskontext mit eigenem Stack und Speicher. Der Aufgerufene arbeitet unabhaengig; wenn er zurueckgesetzt wird, werden nur seine Aenderungen rueckgaengig gemacht.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>STATICCALL\u003C\u002Fstrong> — Nur-Lese-Aufruf (EIP-214). Jeder zustandsaendernde Opcode (SSTORE, CREATE, LOG, SELFDESTRUCT) innerhalb des Aufgerufenen verursacht einen sofortigen Rollback.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>DELEGATECALL\u003C\u002Fstrong> — Fuehrt den Code des Aufgerufenen aus, aber im Speicherkontext des Aufrufers. msg.sender und msg.value bleiben vom urspruenglichen Aufruf erhalten. So funktionieren Proxy-Muster und Bibliotheken.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Jeder Aufruf-Opcode nimmt 7 Stack-Argumente: gas, address, value (ausser STATICCALL\u002FDELEGATECALL), argsOffset, argsLength, retOffset, retLength. Gaskosten: 100 (warm) oder 2600 (kalt) plus Zuschlag fuer Wertuebertragung.\u003C\u002Fp>\n\u003Ch2 id=\"gas-rueckerstattungen-und-ihre-grenzen\">Gas-Rueckerstattungen und ihre Grenzen\u003C\u002Fh2>\n\u003Cp>Historisch gab das Loeschen eines Speicherslots von ungleich Null auf Null eine Gas-Rueckerstattung — als Anreiz zur Zustandsbereinigung. Nach EIP-3529 (London-Upgrade) ist die maximale Rueckerstattung auf 20% des gesamten verbrauchten Gases begrenzt (vorher 50%). Dies zerstoerte die Arbitrage von Gas-Token (CHI, GST2), die Rueckerstattungen zur Gewinnerzielung ausnutzten.\u003C\u002Fp>\n\u003Cp>Verbleibende Rueckerstattungsquellen:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>SSTORE: Setzen eines Nicht-Null-Slots zurueck auf Null erstattet 4.800 Gas.\u003C\u002Fli>\n\u003Cli>SELFDESTRUCT: Als Rueckerstattungsquelle in EIP-3529 entfernt.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"praktische-auswirkungen-fuer-mev\">Praktische Auswirkungen fuer MEV\u003C\u002Fh2>\n\u003Cp>Wenn Sie MEV-Bots bauen, ist das Verstaendnis der EVM auf Opcode-Ebene keine Option, sondern eine Wettbewerbsanforderung. Jede eingesparte Gas-Einheit bei der Ausfuehrung Ihres Bots ist Gewinnmarge. Wichtige Erkenntnisse:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Vor dem Senden simulieren\u003C\u002Fstrong> — verwenden Sie \u003Ccode>eth_call\u003C\u002Fcode> oder eine lokale EVM (revm, EVMONE) fuer die Ausfuehrungstrace und praezise Gaskostenberechnung vor dem Senden des Bundles an den Builder.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Kalten Zugriff minimieren\u003C\u002Fstrong> — Speicherslots ueber Zugriffslisten (EIP-2930) vorwaermen.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>STATICCALL fuer Lesevorgaenge verwenden\u003C\u002Fstrong> — etwas guenstiger und garantiert keine Zustandsmutation.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Opcode-Kosten kennen\u003C\u002Fstrong> — ein schlecht platzierter SLOAD kann 2.100 Gas kosten; in der wettbewerbsintensiven MEV-Umgebung ist das der Unterschied zwischen Gewinn und Verlust.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"fazit\">Fazit\u003C\u002Fh2>\n\u003Cp>Die EVM ist elegant in ihrer Einfachheit: eine Stack-Maschine mit 256-Bit-Woertern, ein flaches Bytecode-Format und ein Gas-Abrechnungssystem, das jede Operation bewertet. Das Verstaendnis dieses Fundaments — Opcodes, Stack und Gas — ist die Voraussetzung fuer alles andere in dieser Serie: Speicherlayout, Storage-Optimierung, Sicherheitsprimitive und schliesslich das Schreiben von reinem Yul.\u003C\u002Fp>\n\u003Cp>Im naechsten Artikel werden wir die vier Datenbereiche der EVM untersuchen: Stack, Memory, Storage und Calldata — und warum die richtige Wahl bestimmt, ob Ihr Contract $0,50 oder $50 pro Ausfuehrung kostet.\u003C\u002Fp>\n","de","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:29.886385Z","Detaillierte Anleitung zur Ethereum Virtual Machine: Opcodes, Stack-Operationen, Gas-Abrechnung, kalter und warmer Zugriff erklaert.","EVM Opcodes",null,"index, follow",[21,26,30],{"id":22,"name":23,"slug":24,"created_at":25},"c0000000-0000-0000-0000-000000000016","EVM","evm","2026-03-28T10:44:21.513630Z",{"id":27,"name":28,"slug":29,"created_at":25},"c0000000-0000-0000-0000-000000000020","Gas Optimization","gas-optimization",{"id":31,"name":32,"slug":33,"created_at":25},"c0000000-0000-0000-0000-000000000014","Solidity","solidity","Blockchain",[36,42,48],{"id":37,"title":38,"slug":39,"excerpt":40,"locale":12,"category_name":34,"published_at":41},"d0000000-0000-0000-0000-000000000611","Die Ethereum-Interoperabilitaetsschicht: Wie 55+ L2s zu einer Chain werden","ethereum-interoperabilitaetsschicht-55-l2s-eine-chain","Ethereum hat 55+ Layer-2-Rollups, die Liquiditaet und Nutzererfahrung fragmentieren. Die Ethereum-Interoperabilitaetsschicht — bestehend aus Cross-Rollup-Messaging, Shared Sequencern und Based Rollups — zielt darauf ab, sie zu einem einzigen komponierbaren Netzwerk zu vereinen.","2026-03-28T10:44:45.264352Z",{"id":43,"title":44,"slug":45,"excerpt":46,"locale":12,"category_name":34,"published_at":47},"d0000000-0000-0000-0000-000000000610","ZK-Beweise jenseits von Rollups: Verifizierbare KI-Inferenz auf Ethereum","zk-beweise-jenseits-von-rollups-verifizierbare-ki-inferenz-ethereum","Zero-Knowledge-Beweise sind nicht mehr nur ein Skalierungswerkzeug. Im Jahr 2026 ermoeglicht zkML verifizierbare KI-Inferenz on-chain, ZK-Coprozessoren verlagern schwere Berechnungen off-chain mit On-Chain-Verifizierung, und neue Beweissysteme wie SP1 und Jolt machen es praktikabel.","2026-03-28T10:44:45.257775Z",{"id":49,"title":50,"slug":51,"excerpt":52,"locale":12,"category_name":34,"published_at":53},"d0000000-0000-0000-0000-000000000587","EIP-7702 in der Praxis: Smart-Account-Flows nach Pectra erstellen","eip-7702-in-der-praxis-smart-account-flows-nach-pectra-erstellen","EIP-7702 ermoeglicht jedem Ethereum-EOA, innerhalb einer einzelnen Transaktion voruebergehend als Smart Contract zu agieren. So implementieren Sie Batch-Transaktionen, Gas-Sponsoring und Social Recovery mit dem neuen Account-Abstraction-Primitiv.","2026-03-28T10:44:43.781201Z",{"id":13,"name":55,"slug":56,"bio":57,"photo_url":18,"linkedin":18,"role":58,"created_at":59,"updated_at":59},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]