Zum Hauptinhalt springen
BlockchainMar 28, 2026

Deep EVM #3: Gas verstehen — Warum Ihr Contract kostet, was er kostet

OS
Open Soft Team

Engineering Team

Gas ist keine vage Metrik

Entwickler behandeln Gas oft als vagen “Kosten”-Wert. In Wirklichkeit ist Gas ein praezise definiertes Ressourcenabrechnungssystem mit exakten Formeln. Jeder Opcode, jedes Byte Calldata, jeder Storage-Zugriff hat deterministische Gaskosten, die im Yellow Paper und nachfolgenden EIPs definiert sind.

Intrinsisches Gas

Bevor Ihr Contract-Code auch nur einen Opcode ausfuehrt, hat Ihre Transaktion bereits Gas verbraucht:

  • Basis: 21.000 Gas fuer jede Transaktion
  • Calldata: 16 Gas pro Nicht-Null-Byte, 4 Gas pro Null-Byte
  • Contract-Erstellung: Zusaetzlich 32.000 Gas fuer CREATE-Transaktionen
  • Zugriffsliste: 2.400 Gas pro Adresse, 1.900 Gas pro Storage-Schluessel

Ein einfacher ETH-Transfer (keine Calldata) kostet genau 21.000 Gas. Ein ERC-20-Transfer hat ~68 Bytes Calldata, was weitere ~1.088 Gas hinzufuegt, bevor die Contract-Ausfuehrung ueberhaupt beginnt.

Gaskosten der haeufigsten Operationen

OperationGas (kalt)Gas (warm)Hinweise
ADD, SUB33Immer gleich
MUL, DIV55Immer gleich
SLOAD2.10010021x Unterschied!
SSTORE (0->ungleich 0)22.10020.000Teuerster Opcode
SSTORE (ungleich 0->ungleich 0)5.0002.900Aenderung
CALL2.600100Ohne Wertuebertragung
MLOAD/MSTORE33Plus Erweiterung
LOG0375375Plus 8 Gas/Byte

EIP-2929: Kalter vs. warmer Zugriff

Das Berlin-Upgrade (April 2021) fuehrte das entscheidende Konzept der Zugriffslisten ein. Der erste Zugriff auf einen Slot oder eine Adresse in einer Transaktion ist “kalt” und teuer. Jeder nachfolgende Zugriff ist “warm” und guenstig.

Diese Unterscheidung hat massive Auswirkungen auf die Gasoptimierung:

// Muster 1: Naive Implementierung (teuer)
function naive() external {
    // Kalt: 2.100 Gas
    if (balances[msg.sender] > 0) {
        // Warm: 100 Gas
        uint256 bal = balances[msg.sender];
        // Kalt: 22.100 Gas (neuer Slot)
        balances[recipient] += bal;
        // Warm: 2.900 Gas (Aenderung eines warmen Slots)
        balances[msg.sender] = 0;
    }
}

// Muster 2: Optimiert (guenstiger)
function optimized() external {
    uint256 bal = balances[msg.sender]; // Kalt: 2.100
    if (bal > 0) {
        balances[msg.sender] = 0;        // Warm: 2.900
        balances[recipient] += bal;       // Kalt: 5.000
    }
}

SSTORE-Gasmechanik im Detail

SSTORE ist bei weitem der komplexeste Opcode in Bezug auf Gaskosten. Die Kosten haengen vom aktuellen Wert, dem neuen Wert und dem urspruenglichen Wert (zu Beginn der Transaktion) ab:

  • Null auf ungleich Null: 22.100 Gas (kalt) — Sie belegen neuen Speicherplatz
  • Ungleich Null auf anderen ungleich Null: 5.000 Gas (kalt) — Aenderung
  • Ungleich Null auf Null: 5.000 Gas + 4.800 Gas Rueckerstattung — Freigabe von Speicher
  • Warme Variante: Jeweils 2.900 Gas statt 5.000 fuer warme Slots

Rueckerstattungsmechanismen

Gas-Rueckerstattungen belohnen die Bereinigung von Zustand. Die wichtigste Rueckerstattung:

  • SSTORE: ungleich Null auf Null -> 4.800 Gas Rueckerstattung

Nach EIP-3529 ist die Gesamtrueckerstattung auf 20% des verbrauchten Gases begrenzt. Dies bedeutet: Wenn Ihre Transaktion 100.000 Gas verbraucht, koennen Sie maximal 20.000 Gas zurueckerstattet bekommen, unabhaengig davon, wie viele Slots Sie bereinigen.

Bewaehrte Optimierungsmuster

1. Storage-Lesevorgaenge cachen

// Schlecht: Drei separate SLOAD-Operationen
function bad() external view returns (uint256) {
    return data[0] + data[1] + data[2]; // 3x SLOAD
}

// Gut: In lokalen Variablen cachen
function good() external view returns (uint256) {
    uint256 a = data[0]; // SLOAD
    uint256 b = data[1]; // SLOAD
    uint256 c = data[2]; // SLOAD
    return a + b + c;    // Nur Stack-Operationen
}

2. Variablen in Storage-Slots packen

// Schlecht: 3 Slots (3x SLOAD fuer vollstaendiges Lesen)
contract Bad {
    uint256 a;
    uint256 b;
    bool c;
}

// Gut: 2 Slots
contract Good {
    uint128 a;
    uint128 b;
    bool c; // Neuer Slot, aber weniger insgesamt
}

3. Calldata statt Memory verwenden

// Schlecht: Kopiert Array in Memory
function bad(uint256[] memory arr) external { ... }

// Gut: Liest direkt aus Calldata
function good(uint256[] calldata arr) external { ... }

4. Short-Circuit-Auswertung

// Guenstige Pruefung zuerst
require(amount > 0 && balances[msg.sender] >= amount);
// Wenn amount == 0, wird SLOAD nie ausgefuehrt

Fazit

Gasoptimierung ist keine Schwarze Magie — es ist angewandte Physik der EVM. Jede Operation hat praezise, deterministische Kosten. Indem Sie diese Kosten verstehen und die richtigen Muster anwenden, koennen Sie die Gaskosten Ihrer Contracts erheblich reduzieren. Der Schluessel: Messen Sie mit EXPLAIN ANALYZE (fuer die EVM heisst das forge test --gas-report), optimieren Sie die teuersten Pfade, und vergessen Sie nie den Unterschied zwischen kaltem und warmem Zugriff.