WEB3DEV

Cover image for Como testar smart contracts Ethereum: boas práticas de auditoria
Adriano P. Araujo
Adriano P. Araujo

Posted on • Atualizado em

Como testar smart contracts Ethereum: boas práticas de auditoria

Quando desenvolvemos um projeto baseado em blockchain Ethereum, a primeira coisa a fazer é garantir a segurança do smart contract e a qualidade do código. Caso contrário, você pode perder uma enorme quantidade de dinheiro.

Como você deve ter ouvido, a carteira Parity Ethereum perdeu US$30 milhões por causa de vulnerabilidades de código. Por este motivo, o Satoshi Pie fund perdeu 32,4% do seu patrimônio. Em 2016, o invasor invadiu a DAO e levou US$50 milhões.

Estes exemplos mostram claramente que mesmo um pequeno defeito ou erro pode resultar em consequências ruins. Portanto, testar os smart contracts é uma parte crucial do processo de criá-los.

O objetivo da auditoria de smart contracts é encontrar erros de código, verificar a lógica do programa e garantir que tudo esteja bem. Uma auditoria de alta qualidade permitirá que você elimine riscos, ansiedade e economize seus nervos e recursos.

Como se preparar para testar smart contracts

A preparação tem um papel importante, ajudando os auditores a definirem os objetivos do projeto, definir mais rapidamente as vulnerabilidades e melhorar o processo de testes.

Além disso, tenha em mente que a preparação começa a partir do momento em que você começa a criar os smart contracts. É por isso que é importante conhecer as vulnerabilidades de um smart contract e as formas de se proteger delas.

Recomendo seguir as seguintes dicas:

1. Forneça uma especificação detalhada

Fornecer uma especificação técnica clara é sempre uma boa ideia, pois ajuda os desenvolvedores blockchain a entender claramente os objetivos do smart contract, casos de uso e princípios de funcionamento.

Embora seja importante, muitas empresas não a criam. No entanto, a maioria dos engenheiros afirma que o documento permite esclarecer o pensamento e aumentar as chances de sucesso do projeto.

Na especificação, descreva o comportamento pretendido de um smart contract: como cada função deve funcionar, como não deve e como todas elas devem funcionar juntas. Use diagramas, pois eles também permitem que você veja possíveis alternativas e veja como as pessoas podem interpretar mal seu código.

2. Documente o processo de implantação de smart contracts

Embora o código do seu smart contract possa ser excelente, há algumas etapas importantes a serem seguidas antes de sua implantação. Para evitar contratempos e economizar esforços da equipe, forneça a documentação do processo de implantação.

Um processo bem documentado que inclui a ordem em que os contratos serão implantados, quais versões do compilador serão usadas para quais contratos, etc., ajudará você a evitar vulnerabilidades dos smart contracts.

3. Limpe o repositório do projeto
Um código de smart contract de qualidade, sem confusão, facilitará e automatizará o trabalho dos auditores. Ao preparar o projeto para o processo de teste, remova quaisquer arquivos, contratos ou pedaços de código não utilizados e desnecessários.

Além disso, você deve especificar quais contratos são utilizados apenas para auditoria (o que significa que eles não fazem parte do sistema final) e quais deles são reutilizados do código testado ou herdados do validado.

Como testar smart contracts Ethereum

O processo de auditoria de um smart contract é semelhante ao teste de qualquer outro código: um conjunto de chamadas de método padrão é criado no ambiente predefinido e as declarações são escritas para seus resultados.

A auditoria é um processo que consiste em:

  • Desenvolvimento do teste
  • Teste de alterações de estado do smart contract
  • Teste do evento
  • Teste do erro
  • Verificação do remetente da mensagem

Para auditar seu projeto, é conveniente usar as práticas de Behavior Driven Development (BDD), que junto com os testes permitem criar documentação e casos de uso. Agora, há uma ampla variedade de frameworks, bibliotecas e outras ferramentas para auditar smart contracts.
Embora o desenvolvimento de teste no Solidity seja limitado aos recursos dessa linguagem de programação, você pode usar JavaScript, o framework Truffle, Parity e outras tecnologias confiáveis.

Auditoria de smart contracts com Truffle

Hoje o Truffle é o framework mais popular para Ethereum. Truffle é um framework do Node.js usado para compilar, vincular e implementar smart contracts. O framework é escrito de maneira completamente modular, permitindo que os engenheiros escolham a funcionalidade de que precisam.

Enquanto no Truffle v.2 os testes são criados em JavaScript, no Truffle v.3 os desenvolvedores adicionaram a capacidade de escrever testes no Solidity, cuja sintaxe é semelhante à do JavaScript.

O Truffle oferece muitos recursos úteis que incluem gerenciamento binário, vinculação de bibliotecas, suporte à implantação personalizada, framework de migrações, deploy de script, acesso a centenas de pacotes externos, executor de script externo e auditoria de contrato automatizada com Mocha e Chai - tudo para evitar falhas nos smart contracts.

Ao falar do fato de que os sistemas blockchain geralmente não funcionam muito rápido, os auditores usam clientes de teste blockchain, por exemplo, TestRPC que emula quase completamente o trabalho da API JSON RPC dos clientes Ethereum.

Além dos métodos padrão, o TestRPC também implementa vários métodos adicionais, como evm_increaseTime e evm_mine. Uma boa alternativa para aplicar o TestRPC é usar um dos clientes padrão, por exemplo, Parity, que roda em modo dev e tem transações confirmadas instantaneamente.

Para começar a trabalhar com o framework Truffle, instale-o via npm:

npm install -g truffle

Em seguida, execute o comando truffle init para criar a estrutura do projeto:

$ mkdir solidity-test-example
$ cd solidity-test-example/
$ truffle init

Os contratos devem estar localizados no diretório contracts/ e os testes – no diretório test/. Quando você compila contratos, o Truffle espera que cada contrato seja colocado em um arquivo separado e o nome do contrato seja igual ao nome do arquivo.

Desenvolvimento de testes com framework Truffle

Os testes utilizam objetos JavaScript que representam abstrações para trabalhar com contratos, fazendo o mapeamento entre as operações em objetos e chamadas de métodos JSON RPC do cliente Ethereum. Esses objetos são criados automaticamente quando você compila o código-fonte para arquivos * .sol.

As chamadas de todos os métodos são assíncronas e retornam Promises, eliminando assim a preocupação com o rastreamento de confirmações das transações. Para evitar grandes quantidades de código ilegível, use async/await para escrever os testes.

Além disso, para simplificar o trabalho, é melhor não misturar migrações e criação de instâncias dos testes. Em vez disso, crie-os no próprio teste usando o código que cria uma nova instância de contrato antes de chamar cada função do teste. Para isso, você pode usar a função beforeEach async.

const congressInitialParams = {
minimumQuorumForProposals: 3,
minutesForDebate: 5,
marginOfVotesForMajority: 1,
congressLeader: accounts[0]
};
let congress;
beforeEach(async function() {
congress = await Congress.new(…Object.values(congressInitialParams));
});

Como testar eventos

Eventos no Ethereum podem ser usados ​​para os seguintes propósitos:

  • Para retornar valores de métodos que alteram o estado do contrato
  • Para criar um histórico de alteração do estado dos smart contracts
  • Para ser usado como um repositório de informações barato e conveniente

Tomemos o seguinte exemplo. Você precisa verificar se ao chamar o novo método de proposta, adicionando uma frase ao contrato, é criado um registro de evento Proposal Added.

Para isso, primeiro, crie um membro de DAO no teste e uma proposta em seu nome. Em seguida, crie um assinante para o evento ProposalAdded e verifique se após a chamada do método newProposal, o evento ocorreu e seus atributos correspondem aos dados transmitidos.

Um código newProposalfunction:
/* Function to create a new proposal */
function newProposal(
address beneficiary,
uint etherAmount,
string JobDescription,
bytes transactionBytecode
)
onlyMembers
returns (uint proposalID)

Como testar as alterações do estado do smart contract

Na Ethereum, o método addMember é responsável por alterar o estado dos smart contracts. Para testar esse método, verifique se ele registra as informações sobre o participante da DAO no array de estruturas de membros.

/criando um membro/
function addMember(address targetMember, string memberName) onlyOwner {
uint id;
if (memberId[targetMember] == 0) {
memberId[targetMember] = members.length;
id = members.length++;
members[id] = Member({member: targetMember, memberSince: now, name: memberName});
} else {
id = memberId[targetMember];
Member m = members[id];
}
MembershipChanged(targetMember, true);
}
function removeMember(address targetMember) onlyOwner {
if (memberId[targetMember] == 0) throw;
for (uint i = memberId[targetMember]; i
members[i] = members[i+1];
}
delete members[members.length-1];
Members.length–;
}

Usando a matriz com contas de teste, adicione participantes do contrato no teste. Em seguida, verifique se a função do membro retorna os dados de entrada.

Deve-se notar que toda vez que o método addMember é chamado, uma transação é criada e o estado da Blockchain é alterado, ou seja, as informações são registradas no livro-razão distribuído.

Como testar erros e verificação do remetente da mensagem

Uma maneira geral de interromper o trabalho do método de contrato são as exceções que podem ser criadas usando a instrução throw. Você pode precisar de uma exceção se sua tarefa for restringir o acesso ao método.

Para fazê-lo implementar um modificador que verifique um endereço de conta que chamou um método: se não corresponder às condições (não é o proprietário do contrato que chama o método), uma exceção é criada.

Algumas dicas para evitar erros de smart contracts

*1. Use a cobertura do teste de Solidity *

Para a auditoria de smart contracts, use a cobertura Solidity. Ele ajudará você a medir a cobertura de teste e definir partes do código que ainda não foram testadas ou que precisam de mais atenção. Certamente, 100% de cobertura de teste não é uma panacéia, por isso também é importante escrever um código de teste de qualidade desde o início.

2. Use linters

Os linters permitem que os desenvolvedores Ethereum aprimorem a qualidade do código, tornando o código mais fácil de ler e revisar. Existem muitos linters que você pode usar. Por exemplo, Solcheck é um linter JavaScript para código Solidity.

Solhint é um linter que ajuda os engenheiros a evitar erros e vulnerabilidades nos smart contracts do Solidity. Solhint fornece validações de Guia de Segurança e Estilo.

3. Faça análise estática

Nos testes de smart contracts, a análise estática permite encontrar vulnerabilidades e inseguranças de código.

Para fazer a análise de código, você pode usar ferramentas como Oyente que analisa o código e detecta vulnerabilidades comuns, Manticore, que permite uma análise binária dinâmica com suporte EVM, e Solgraph que permite visualizar o fluxo de controle da função de smart contracts e identificar possíveis inseguranças .

4. Prepare-se para o fracasso

Apesar dos testes precisos, um smart contract ainda pode ter alguns erros ou vulnerabilidades, você deve estar sempre preparado para falhas. Portanto, certifique-se de que seu código seja capaz de responder aos bugs do smart contract.

Para isso, crie um plano de atualização eficaz para correção de bugs e aprimoramentos de código. Gerencie a quantidade de dinheiro em risco, estabelecendo limitação de taxa e um uso máximo. Além disso, se algo der errado, pause seu contrato.


Este artigo foi escrito por Sergey V., e traduzido por Adriano P. de Araujo. O artigo original pode ser encontrado aqui.

Latest comments (0)