
Ethereum Smart Contract Fuzzer

Echidna ist ein seltsames Wesen, das Bugs frisst und äußerst elektrosensibel ist (mit Entschuldigung an Jacob Stanley)
Im Ernst: Echidna ist ein Haskell-Programm, das für Fuzzing/property-basiertes Testen von Ethereum-Smart-Contracts entwickelt wurde. Es verwendet ausgefeilte grammatikbasierte Fuzzing-Kampagnen auf Basis einer Contract-ABI, um benutzerdefinierte Prädikate oder Solidity-Assertions zu widerlegen. Wir haben Echidna mit Blick auf Modularität entworfen, sodass es leicht erweitert werden kann, um neue Mutationen aufzunehmen oder bestimmte Contracts in speziellen Fällen zu testen.
.. und ein wunderschönes handgefertigtes Logo in hoher Auflösung.
Die Kernfunktionalität von Echidna ist eine ausführbare Datei namens echidna, die einen Contract und eine Liste
von Invarianten (Eigenschaften, die immer wahr bleiben sollten) als Eingabe erhält. Für jede Invariante generiert sie
zufällige Sequenzen von Aufrufen an den Contract und prüft, ob die Invariante gilt. Wenn sie einen Weg findet,
die Invariante zu widerlegen, gibt sie die Aufrufsequenz aus, die dies bewirkt. Wenn nicht, haben Sie eine gewisse
Sicherheit, dass der Contract sicher ist.
Invarianten werden als Solidity-Funktionen ausgedrückt, deren Namen mit echidna_ beginnen, keine Argumente haben und einen Boolean zurückgeben. Wenn Sie beispielsweise eine balance-Variable haben, die niemals unter 20 fallen sollte, können Sie eine zusätzliche Funktion wie diese in Ihren Contract schreiben:```solidity
function echidna_check_balance() public returns (bool) {
return(balance >= 20);
}
Um diese Invarianten zu überprüfen, führe aus:```sh
$ echidna myContract.sol
Ein Beispielvertrag mit Tests ist zu finden unter tests/solidity/basic/flags.sol. Um ihn auszuführen, sollten Sie Folgendes ausführen:```sh $ echidna tests/solidity/basic/flags.sol
Echidna sollte eine Aufrufsequenz finden, die `echidna_sometimesfalse` falsifiziert, und sollte nicht in der Lage sein, eine falsifizierende Eingabe für `echidna_alwaystrue` zu finden.
### Testmodi
Das obige Beispiel verwendet den Standardmodus **property**, aber Echidna unterstützt mehrere Testmodi, die über `testMode` in der Konfigurationsdatei oder `--test-mode` auf der CLI konfiguriert werden:
* **`property`** (Standard): Testet Funktionen mit dem Präfix `echidna_`, die `bool` zurückgeben.
* **`assertion`**: Erkennt Assertion-Fehler von `assert()` und Foundrys `assertX`-Helfern (`assertTrue`, `assertEq` usw.).
* **`foundry`**: Führt Foundry-Style-Tests aus und folgt dabei dessen Namenskonventionen: Unit- und Fuzz-Tests mit Präfix `test` (bei solchen mit Präfix `testFail` wird ein Revert erwartet) und zustandsbehaftete Invarianten mit Präfix `invariant` oder `statefulFuzz`. Funktionen mit Präfix `check` und `prove` sind symbolische Einstiegspunkte, aber da dieser Modus eine Fuzzing-Kampagne ist, werden sie wie jede andere Testfunktion gefuzzt.
* **`verification`**: Verifiziert symbolisch jede Funktion des Contracts mit einer einzigen Transaktion. Funktionen mit Präfix `check` und `prove` werden immer als Einstiegspunkte verwendet.
* **`overflow`**: Erkennt Integer-Über-/Unterläufe (Solidity >= 0.8.0).
* **`optimization`**: Maximiert den Rückgabewert von Funktionen mit Präfix `echidna_`, die `int256` zurückgeben (verwendet dasselbe konfigurierbare Präfix wie der Property-Modus).
* **`exploration`**: Sammelt Coverage, ohne Eigenschaften zu prüfen.
### Sammeln und Visualisieren von Coverage
Nach Abschluss einer Kampagne kann Echidna ein Coverage-maximierendes **Korpus** in einem speziellen Verzeichnis speichern, das mit der Konfigurationsoption `corpusDir` angegeben wird. Dieses Verzeichnis enthält zwei Einträge: (1) ein Verzeichnis namens `coverage` mit JSON-Dateien, die von Echidna wiedergegeben werden können, und (2) eine Klartextdatei namens `covered.txt`, eine Kopie des Quellcodes mit Coverage-Annotationen.
Wenn Sie das Beispiel `tests/solidity/basic/flags.sol` ausführen, speichert Echidna einige Dateien mit serialisierten Transaktionen im Verzeichnis `coverage` und eine Datei `covered.$(date +%s).txt` mit den folgenden Zeilen:```text
*r | function set0(int val) public returns (bool){
* | if (val % 100 == 0)
* | flag0 = false;
}
*r | function set1(int val) public returns (bool){
* | if (val % 10 == 0 && !flag0)
* | flag1 = false;
}
Unser Tool markiert jeden Ausführungs-Trace im Korpus mit dem folgenden "Zeilenmarker":
*, wenn eine Ausführung mit einem STOP endeter, wenn eine Ausführung mit einem REVERT endeteo, wenn eine Ausführung mit einem Out-of-Gas-Fehler endetee, wenn eine Ausführung mit einem anderen Fehler endete (Division durch Null, Assertion-Fehler usw.)Echidna kann Verträge testen, die mit verschiedenen Smart-Contract-Build-Systemen kompiliert wurden, darunter Foundry, Hardhat und Truffle, unter Verwendung von crytic-compile. Um Echidna mit dem aktuellen Kompilierungs-Framework aufzurufen, verwenden Sie echidna ..
Darüber hinaus unterstützt Echidna zwei Modi zum Testen komplexer Verträge. Erstens kann man den vorhandenen Netzwerkzustand nutzen und diesen als Basis-Zustand für Echidna verwenden. Zweitens kann Echidna jeden Vertrag mit bekannter ABI aufrufen, indem die entsprechende Solidity-Quelle in der CLI übergeben wird. Verwenden Sie allContracts: true in Ihrer Konfiguration, um dies zu aktivieren.
Unser Repository Building Secure Smart Contracts enthält einen Crashkurs zu Echidna, einschließlich Beispielen, Lektionen und Übungen.
Es gibt eine Echidna-Action, mit der echidna als Teil eines GitHub-Actions-Workflows ausgeführt werden kann. Bitte lesen Sie das Repository crytic/echidna-action für Anweisungen zur Verwendung und Beispiele.