Zum Hauptinhalt springen
BlockchainMar 28, 2026

Deep EVM #18: EVM-Bytecode debuggen — Traces, Stack-Dumps und cast run

OS
Open Soft Team

Engineering Team

Debugging auf Bytecode-Ebene

Wenn eine Solidity-Transaktion revertiert, erhalten Sie typischerweise eine beschreibende Fehlermeldung. Wenn eine Huff- oder Yul-Transaktion revertiert, erhalten Sie ein leeres Revert-Payload ohne Kontext. Debugging auf Bytecode-Ebene erfordert andere Werkzeuge und mentale Modelle.

cast run: Transaktionen nachspielen

cast run ist das maechtigste Debugging-Werkzeug fuer On-Chain-Transaktionen:

# Transaktion nachspielen mit vollstaendigem Trace
cast run 0x1234...abcd --rpc-url mainnet -vvvv

# Nur den Trace einer bestimmten Adresse anzeigen
cast run 0x1234...abcd --rpc-url mainnet -vvvv \
  --label 0xContract:MyContract

Die Ausgabe zeigt jeden Opcode, den Stack-Zustand und Gasverbrauch:

[0] PUSH1 0x80
    Stack: [0x80]
    Gas: 499979
[2] PUSH1 0x40
    Stack: [0x80, 0x40]
    Gas: 499976
[4] MSTORE
    Stack: []
    Gas: 499964

forge debug: Interaktiver Debugger

# Test im Debug-Modus starten
forge debug test/MyTest.t.sol --sig "testSwap()"

# Bestimmte Transaktion debuggen
forge debug --fork-url mainnet 0x1234...abcd

Der interaktive Debugger ermoeglicht:

  • Schritt-fuer-Schritt durch Opcodes navigieren
  • Stack und Memory zu jedem Zeitpunkt inspizieren
  • Breakpoints an bestimmten Programmzaehlern setzen
  • Storage-Aenderungen verfolgen

Haeufige Debugging-Szenarien

1. Leerer Revert

Problem: Transaktion revertiert ohne Fehlermeldung.

Loesung:

# Trace analysieren — suche den letzten REVERT-Opcode
cast run 0x... -vvvv | grep -A5 "REVERT"

Haeufige Ursachen:

  • Stack-Unterlauf (Opcode versucht, mehr zu entnehmen als vorhanden)
  • JUMPDEST-Fehler (Sprung zu einer Position ohne JUMPDEST)
  • Gaserschoepfung in einem Unteraufruf

2. Falsches Ergebnis

Problem: Contract gibt falschen Wert zurueck.

Loesung: Stack-Zustand vor RETURN pruefen:

# RETURN-Opcode finden und Memory inspizieren
cast run 0x... -vvvv | grep -B10 "RETURN"

3. Out-of-Gas

Problem: Transaktion laeuft aus dem Gas.

Loesung:

# Gas-Verbrauch pro Opcode analysieren
cast run 0x... -vvvv | awk '/Gas:/ {print $NF}' | sort -n

Opcode-Trace lesen

Ein typischer Trace fuer einen ERC-20-Transfer:

// Funktionsselektor laden
PUSH1 0x00 CALLDATALOAD  // [calldata[0:32]]
PUSH1 0xe0 SHR           // [selector]

// Gegen transfer(address,uint256) pruefen
DUP1 PUSH4 0xa9059cbb EQ // [selector==transfer, selector]
PUSH2 0x00a4 JUMPI       // Springe wenn match

// Bei transfer:
JUMPDEST                  // <- Sprungziel
PUSH1 0x04 CALLDATALOAD  // [to_address]
PUSH1 0x24 CALLDATALOAD  // [amount, to_address]

Debugging-Checkliste fuer Huff

  1. Stack-Kommentare in jedem Makro pruefen
  2. takes() und returns() Deklarationen verifizieren
  3. Jeden externen Aufruf mit cast run nachverfolgen
  4. Gas-Budget pro Pfad mit forge test –gas-report analysieren
  5. Differentielles Testen gegen Solidity-Referenz durchfuehren
  6. Edge Cases testen: leere Calldata, maximale Werte, Reentrancy

Fazit

EVM-Bytecode-Debugging ist eine Kunst, die Uebung erfordert. cast run und forge debug sind Ihre wichtigsten Werkzeuge. Der Schluessel: Verstehen Sie den Stack-Zustand zu jedem Zeitpunkt der Ausfuehrung, und Sie werden jedes Problem loesen koennen.