Tiempo estimado: 3 minutos de lectura
¿Qué son las buenas prácticas en Solidity?
Las buenas prácticas en Solidity son un conjunto de reglas, criterios y patrones de programación recomendados para desarrollar smart contracts seguros y fiables.
Puesto que los smart contracts son por naturaleza inmutables y conllevan en muchas ocasiones el manejo de algún tipo de criptoactivo, conviene asegurar un buen diseño de partida.
¿Cómo cumplir con las buenas prácticas en Solidity?
Los criterios son muy amplios y en general dependen del tipo de Smart Contract a desarrollar. Por otra parte, con la evolución del desarrollo blockchain es previsible que cambien y se adapten en el tiempo.
Sin embargo sí puede considerarse que hay un conjunto base de buenas prácticas que podría servir de partida a un análisis más profundo.
1. Seguir una guía de estilo al escribir el código fuente
Se trata de codificar los contratos siguiento convenciones de estilo aceptadas por la comunidad. Como ejemplo se puede revisar la guía de estilo oficial del lenguaje Solidity
2. Control de versiones del compilador
Definir la versión mínima del compilador al inicio del contrato mediante la directiva «pragma» para prevenir incompatibilidades y evitar ataques de versiones más antiguas de Solidity.
3. Optimización del gas consumido
Consiste en programar los Smart Contracts siguiendo una serie de pautas que reduzcan el consumo de gas, de forma general tanto en el despliegue como en la ejecución.
Es fundamental sin embargo encontrar el punto de equilibrio entre un código limpio y mantenible que a su vez optimice el consumo de gas.
En mi artículo sobre optimización de gas en Solidity se exploran varias de las técnicas más comunes.
4. Gestión de errores
- Utilizar require, revert y assert para validar condiciones externas o resultados en la ejecución de llamadas a otros contratos mediante call, delegatecall y staticcall.
- Devolver Custom Errors (disponibles desde Solidity 0.8) para notificar los errores al exterior y facilitar su tratamiento desde las DApps y los contratos llamantes.
- Gestionar excepciones en bloques try/catch cuando sea necesario interrumpir la propagación del error.
5. Uso de eventos
Registrar acciones de interés en la ejecución del contrato mediante eventos para trazar su comportamiento con un gasto mínimo de gas.
En mi artículo sobre eventos en Solidity se detalla cómo crearlos, depurarlos y acceder a su información.
6. Integración de librerías de contratos reputadas
Reutilizar contratos de código abierto que hayan sido auditados y ofrezcan la garantía de uso por parte de la comunidad, como las ofrecidas por OpenZeppelin.
7. Control de Acceso
Desarrollar políticas de control de acceso que limiten los permisos en la llamadas a los contratos. Existen numerosas alternativas como los contratos Ownable o AccessControl de OpenZeppelin para restringir ciertas funciones a administradores o usuarios autorizados.
8. Seguridad en el manejo de Ether
En mi artículo sobre cómo enviar Ether desde un smart contract se concluye que el consenso actual consiste en usar la función «call» y prevenir posibles ataques de reentrada mediante patrones de programación que modifican el estado antes de efectuar las llamadas a contratos externos (Checks-Effects-Interactions) y los llamados guardianes de reentrada (ReentrancyGuard).
9. Protección contra ataques comunes
En un artículo posterior trataré los errores más comunes, los patrones de diseño para evitarlos y su detección mediante herramientas de análisis de vulnerabilidades.
10. Prever la actualización del contrato
Tanto para corregir errores como para incorporar nuevas funciones, puede ser útil diseñar el contrato con vistas a posibles actualizaciones. Para ello se pueden seguir algunos de los patrones principales de actualización de contratos: proxy pattern, eternal storage, data separation, dispatcher, diamond…
Es recomendable utilizar igualmente librerías de terceros confiables como apoyo en la implementación del patrón elegido. Un ejemplo sería Proxies de OpenZeppelin.
11. Usar un linter de código
Como se ha visto existen numerosos criterios y patrones que conforman el núcleo base de buenas prácticas en la programación de Smart Contracts en Solidity.
Si bien asegurar su implementación es responsabilidad inicial del programador, existen herramientas que automatizan el cumplimiento de determinadas reglas, ayudando a detectar posibles errores.
En este apartado se englobarían los «linters» de código, como por ejemplo solhint, detallado en mi artículo sobre formateado y linting de código Solidity.
12. Pruebas exhaustivas
Existen numerosas formas de detectar y corregir errores antes de desplegar los contratos en producción: test unitarios, análisis estático, análisis dinámico, «mutation testing», «fuzzy testing» …
El paso final podría conllevar auditorías de seguridad efectuadas por terceros o lanzar programanas de «bug bounty» para atraer a la comunidad de desarrolladores especializados en seguridad.
Conclusión: programando Smart Contracts seguros y fiables
Programar Smart Contracts no consiste únicamente en plasmar una determinada lógica de negocio o protocolo en la blockchain. Dada su naturaleza inmutable y la gestión de activos digitales con valor, es preciso seguir una serie de reglas y criterios que aseguren en la medida de lo posible la seguridad y eficiencia del código desplegado, generando confianza entre la comunidad de desarrolladores y usuarios.
El conjunto de buenas prácticas engloba múltiples aspectos desde las convenciones de estilo en la escritura del código fuente hasta optimizaciones en el consumo de gas, transferencia segura de Ether, pruebas exhaustivas…
Para dar soporte y ayudar a los desarrolladores a su implementación existen muchas herramientas auxiliares que iré desgranando en otros artículos.
Sigues habitualmente reglas y criterios de buenas prácticas en la programación de tus Smart Contracts. ¿Tienes alguna guía que puedas compartir? ¿Usas alguna herramienta que te facilite la labor? Te invito a que compartas tus experiencias.
Contáctame si estás buscando un programador de Smart Contracts habituado a seguir las mejores prácticas en sus desarrollos. Puedo colaborar en tu proyecto.