Buenas prácticas en el desarrollo de Contratos Inteligentes

Los contratos inteligentes son una de las herramientas claves a la hora del desarrollo de aplicaciones descentralizadas. El problema es que una vez implementados y desplegados en la cadena de bloques, son inmutables y no se puede ni cambiar ni corregir errores. Es por ello que existen una base de vulnerabilidades a tener en cuenta durante su desarrollo y testeo, además de unas buenas prácticas.

Buenas prácticas de desarrollo

En este artículo nos centraremos en las buenas prácticas de desarrollo de un contrato inteligente y debido a su larga extensión, en el siguiente articulo indicaremos las vulnerabilidades más comunes. Durante el desarrollo de un Smart Contract, antes de su lanzamiento a la red principal, se deben considerar ciertos aspectos, pero se debe tener muy seguro como estamos protegiendo los datos críticos que estamos confiando al código. El uso de herramientas como OpenZeppelin que más adelante explicaremos, permite realizar un desarrollo con un sello de garantía de seguridad.

Debes tener en cuenta que tu contrato inteligente será expuesto desde el primer momento que lo publiques en la red principal (Mainnet) y es por ello por lo que necesitas considerar una serie de buenas prácticas para garantizar que pueda hacer frente a las vulnerabilidades existentes y posibles errores. Las prácticas son subjetivas y dependen también del enfoque que tenga el desarrollador.

The State of Ethereum Smart Contracts Security: Vulnerabilities, Countermeasures, and Tool Support
Haozhe Zhou, Amin Milani Fard * and Adetokunbo Makanju *

Desarrollo de Software

Ethereum es un proyecto muy complejo y es por ello por lo que está en constante cambio y nuevos descubrimientos de errores que se deben ir arreglando conforme se descubren. Por consiguiente, es sumamente necesario tener unas buenas prácticas continúas que permitan adaptarse a los nuevos errores y en primer lugar nos podemos centrar en lo más general y son las principales fases de desarrollo de software.

  • Diseño: se detallará el flujo del proceso, las funciones, los atributos y las operaciones que el sistema va a realizar. Además, en esta fase ya se deben considerar las amenazas y vulnerabilidades a la que nuestro contrato inteligente se puede exponer y hacer un diseño modelado de amenazas, así como un diseño de seguridad. Todas las amenazas que se hayan expuesto después deberán ser verificadas en la fase de testing, auditoría y seguimiento.
  • Desarrollo: esta fase es la implementación del código para el desarrollo del contrato inteligente con todas las funciones y flujos previamente definidos en la fase de diseño. En esta fase es donde se puede recurrir a herramientas como ‘listing’ y ‘OpenZeppelin’ teniendo en todo momento en cuenta las vulnerabilidades a las que se expone el contrato. Es por ello que se puede hacer uso de plantillas, estándares de OpenZeppelin, bibliotecas e interfaces de contratos que hayan pasado previamente por una auditoria.
  • Testing: es momento de someter a nuestro contrato a pruebas para verificar su correcto funcionamiento y descubrir nuevas vulnerabilidades en caso de que existan. Se pueden usar marcos de seguridad como Hardhat, Mythrill, Truffle, Mocca, etc. Además, es bastante recomendado utilizar comentarios NatSpec’ para especificar efectos secundarios, así como el parámetro es y valores de retorno esperados. Por útlimo, se deberán hacer revisiones tanto internas como externas, consultando guías de ConsenSys y OpenZeppelin que aportan listas de verificaciones de consideraciones y se pueden recurrir a páginas de usuarios que se dedican a intentar atacar a nuestro contrato inteligente para encontrar vulnerabilidades.
  • Despliegue: es la fase en la que el proyecto / contrato se lleva a producción.
  • Mantenimiento: el Smart contract deberá evaluarse y modificarse durante un periodo de tiempo antes de ser lanzado a la mainnet para así poder garantizar que todo funcionacorrectamente.

Prácticas generales para contratos inteligentes en Ethereum.

Esto no es una biblia que se deba seguir al pie de la letra ya que cada desarrollador tendrá también su propio criterio.

Lo primero de todo es prepararse para tener fallos. Todo contrato inteligente tendrá errores en cualquier momento, ya sea durante la fase de producción, testeo o una vez esté desplegado, es por ello por lo que se debe preparar el contrato ante emergencias y que pueda responder a problemas. Por otra parte, deberás realizar tests unitarios y test exhaustivos de los contratos haciendo un escalado y despliegue incremental que permita un desarrollo modular y sea capaz de solventar todas las vulnerabilidades. De hecho, como hemos comentado anteriormente se puede llegar a ofrecer recompensas por el descubrimiento de errores en el contrato inteligente durante su publicación en la red de pruebas alfa.

Simplicidad y actualización

La simplicidad en el desarrollo de contratos inteligentes es importante, ya que si se hacen muy complejos habrá más probabilidad de que existan errores y será más complicado encontrarlos o incluso arreglarlos. Por otro lado, la tecnología Blockchain y el desarrollo de contratos inteligentes están en constante evolución y más en redes públicas como Ethereum con su lenguaje de programación Solidity que lo van mejorando cada poco tiempo y la red de Ethereum continuará haciendo cambios tal y como se muestra en su roadmap. Es importante estar actualizado de las nuevas técnicas de desarrollo que vayan surgiendo.

Llamadas externas

A la hora de desarrollar código para los contratos inteligentes puede ser común hacer uso de librerías externas o hacer llamadas a fuentes externas, ya sean otros contratos u oráculos, los cuales pueden ejecutar código malicioso de vuelta a nuestro Smart Contract y si no lo tenemos preparado para prevenir ese tipo de ataques pueden entrar en nuestro flujo y originar un bucle hasta vaciar el contrato. Desde el punto de vista de ingeniería de software un contrato inteligente debe ser modular, permitir la reutilización de código para evitar duplicaciones y admitir componentes que sean actualizables. Sin embargo, si nos centramos en la vista desde la arquitectura de seguridad no se comparten los mismos principios y es por ello que se debe mantener el equilibrio entre ambos enfoques.

Cumplir estándares

El contrato deberá cumplir con una serie de normas y estándares para poder ser publicado en ciertas plataformas y sería conveniente tener la seguridad de que se han seguido protocolos, interfaces de contratos previamente testeados. Por otro lado se debe evitar la transferencia de tokens a la dirección 0x00 y la del propio contrato.

OpenZeppelin

Consiste en un proyecto que proporciona un conjunto de herramientas para que un desarrollador pueda construir contratos inteligentes mediante un conjunto completo de productos de seguridad y servicios de auditoría aportados por OpenZeppelin. Ofrece un SDK con un conjunto de herramientas de desarrollo, testing y actualización para contratos inteligentes así como un a biblioteca de contratos inteligentes que han sido probados frente a riesgos y vulnerabilidades, además de poder ser reutilizables y seguros para la red.

Linting

Tener errores en el código durante la fase de desarrollo es inevitable y en aplicaciones web3, pueden llegar a ser problemas muy graves, ya sean a nivel de experiencia de usuario (UX) o comprometiendo la seguridad del sistema. Es por ello por lo que hoy en día se utilizan herramientas tipo lint. Programas que analizan otros programas en busca de posibles problemas tanto con su sintaxis como con su semántica (en contraste con las pruebas unitarias). Es decir, es un proceso de verificación del código en busca de posibles errores. Por lo general, lo realiza una herramienta que busca problemas en el código, como puntos y comas faltantes, corchetes que no coinciden, etc.

Linting puede ahorrar mucho tiempo a los programadores porque encuentra problemas antes de que se ejecuten. De esta manera, los programadores no tienen que revisar manualmente su código para encontrar errores que pueden haber pasado por alto mientras lo escribían. Algunos lenguajes como JavaScript y CSS usan linting como parte de su compilador o intérprete para asegurarse de que se encuentran todos los errores antes de ejecutar el programa.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.