
Fuzzer de contratos inteligentes Ethereum

Echidna é uma criatura estranha que come bugs e é altamente eletrossensível (com desculpas a Jacob Stanley)
Mais seriamente, Echidna é um programa em Haskell projetado para fuzzing/testes baseados em propriedades de contratos inteligentes Ethereum. Ele usa campanhas sofisticadas de fuzzing baseadas em gramática, fundamentadas em uma ABI de contrato, para falsificar predicados definidos pelo usuário ou asserções Solidity. Projetamos o Echidna com modularidade em mente, para que possa ser facilmente estendido para incluir novas mutações ou testar contratos específicos em casos específicos.
.. e um belo logotipo artesanal em alta resolução.
A funcionalidade central do Echidna é um executável chamado echidna, que recebe um contrato e uma lista
de invariantes (propriedades que devem sempre permanecer verdadeiras) como entrada. Para cada invariante, ele gera
sequências aleatórias de chamadas ao contrato e verifica se a invariante se mantém. Se conseguir encontrar alguma forma
de falsificar a invariante, ele imprime a sequência de chamadas que o faz. Se não conseguir, você tem alguma
garantia de que o contrato é seguro.
As invariantes são expressas como funções Solidity com nomes que começam com echidna_, não têm argumentos e retornam um booleano. Por exemplo, se você tem alguma variável balance que nunca deve ficar abaixo de 20, você pode escrever uma função extra no seu contrato como esta:```solidity
function echidna_check_balance() public returns (bool) {
return(balance >= 20);
}
Para verificar essas invariantes, execute:```sh
$ echidna myContract.sol
Um exemplo de contrato com testes pode ser encontrado em tests/solidity/basic/flags.sol. Para executá-lo, você deve executar:```sh $ echidna tests/solidity/basic/flags.sol
O Echidna deve encontrar uma sequência de chamadas que falsifique `echidna_sometimesfalse` e deve ser incapaz de encontrar uma entrada falsificadora para `echidna_alwaystrue`.
### Modos de teste
O exemplo acima usa o modo **property** padrão, mas o Echidna suporta vários modos de teste, configurados via `testMode` no arquivo de configuração ou `--test-mode` na CLI:
* **`property`** (padrão): Testa funções com prefixo `echidna_` que retornam `bool`.
* **`assertion`**: Detecta falhas de asserção de `assert()` e dos auxiliares `assertX` do Foundry (`assertTrue`, `assertEq`, etc.).
* **`foundry`**: Executa testes no estilo Foundry, seguindo suas convenções de nomenclatura: testes unitários e de fuzz com prefixo `test` (os com prefixo `testFail` devem reverter) e invariantes stateful com prefixo `invariant` ou `statefulFuzz`. Funções com prefixo `check` e `prove` são pontos de entrada simbólicos, mas como este modo é uma campanha de fuzzing, elas são fuzzed como qualquer outra função de teste.
* **`verification`**: Verifica simbolicamente cada função do contrato usando uma única transação. Funções com prefixo `check` e `prove` são sempre usadas como pontos de entrada.
* **`overflow`**: Detecta over/underflows de inteiros (Solidity >= 0.8.0).
* **`optimization`**: Maximiza o valor de retorno de funções com prefixo `echidna_` que retornam `int256` (usa o mesmo prefixo configurável do modo property).
* **`exploration`**: Coleta cobertura sem verificar propriedades.
### Coletando e visualizando cobertura
Após finalizar uma campanha, o Echidna pode salvar um **corpus** de maximização de cobertura em um diretório especial especificado com a opção de configuração `corpusDir`. Este diretório conterá duas entradas: (1) um diretório chamado `coverage` com arquivos JSON que podem ser reproduzidos pelo Echidna e (2) um arquivo de texto simples chamado `covered.txt`, uma cópia do código-fonte com anotações de cobertura.
Se você executar o exemplo `tests/solidity/basic/flags.sol`, o Echidna salvará alguns arquivos de transações serializadas no diretório `coverage` e um arquivo `covered.$(date +%s).txt` com as seguintes linhas:```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;
}
Nossa ferramenta sinaliza cada traço de execução no corpus com o seguinte "marcador de linha":
* se uma execução terminou com um STOPr se uma execução terminou com um REVERTo se uma execução terminou com um erro de out-of-gase se uma execução terminou com qualquer outro erro (divisão por zero, falha de asserção, etc)O Echidna pode testar contratos compilados com diferentes sistemas de build de contratos inteligentes, incluindo Foundry, Hardhat e Truffle, usando crytic-compile. Para invocar o Echidna com o framework de compilação atual, use echidna ..
Além disso, o Echidna suporta dois modos de teste de contratos complexos. Primeiramente, pode-se aproveitar o estado de rede existente e usá-lo como estado base para o Echidna. Em segundo lugar, o Echidna pode chamar qualquer contrato com uma ABI conhecida passando o código-fonte Solidity correspondente na CLI. Use allContracts: true na sua configuração para ativar isso.
Nosso repositório Building Secure Smart Contracts contém um curso intensivo sobre o Echidna, incluindo exemplos, lições e exercícios.
Existe uma action do Echidna que pode ser usada para executar o echidna como parte de um
workflow do GitHub Actions. Consulte o repositório
crytic/echidna-action para
instruções de uso e exemplos.