Ir al contenido principal
Change page

Verificación de contratos inteligentes

Última edición: , 23 de noviembre de 2023

Los contratos inteligentes están diseñados para ser "trustless", o sin confianza, lo que significa que los usuarios no deben tener que confiar en terceros (por ejemplo, desarrolladores y empresas) antes de interactuar con un contrato. Como requisito para esta no necesidad de confianza, los usuarios y otros desarrolladores deben poder verificar el código fuente de un contrato inteligente. La verificación del código fuente asegura a los usuarios y los desarrolladores que el código de contrato publicado es el mismo código que se ejecuta en la dirección del contrato en la cadena de bloques de Ethereum.

Es importante hacer la distinción entre "verificación del código fuente" y "verificación formal". La verificación del código fuente, que se va a explicar en detalle a continuación, hace referencia a constatar que el código fuente proporcionado de un contrato inteligente en un lenguaje de alto nivel (por ejemplo, Solidity) se compila en el mismo bytecode que se va a ejecutar en la dirección del contrato. Por el otro lado, la verificación formal hace referencia a verificar la corrección de un contrato inteligente, lo que significa que el contrato se comporta según lo esperado. Aunque depende del contexto, generalmente la verificación de contratos se refiere a la verificación del código fuente.

¿Qué es la verificación del código fuente?

Antes de implementar un contrato inteligente en la Máquina virtual de Ethereum (EVM), los desarrolladores compilan el código fuente del contrato, el cual consiste en instrucciones escritas en Solidity u otro lenguaje de programación de alto nivel, en bytecode. Dado que la EVM no puede interpretar instrucciones de alto nivel, es necesario compilar el código fuente a bytecode (es decir, instrucciones de bajo nivel para la máquina) para ejecutar la lógica del contrato en la EVM.

La verificación del código fuente implica comparar el código fuente de un contrato inteligente con el bytecode compilado utilizado durante la creación del contrato para detectar la existencia de cualquier diferencia. Verificar los contratos inteligentes es importante porque el código del contrato que se difunde puede ser diferente del que se ejecuta en la cadena de bloques.

La verificación de un contrato inteligente permite investigar lo que hace un contrato a través del lenguaje de alto nivel en el que está escrito, sin necesidad de leer código de máquina. Las funciones, los valores y generalmente los nombres de las variables y los comentarios suelen permanecer iguales en el código fuente original que se compila e implementa. Esto facilita mucho la lectura del código. La verificación del código fuente también permite la documentación del código, para que los usuarios finales sepan para qué está diseñado un contrato inteligente.

¿Qué es una verificación completa?

Existen partes del código fuente que no afectan al bytecode compilado, como los comentarios o los nombres de variables. Eso significa que dos códigos fuente con nombres de variables diferentes y comentarios diferentes podrían verificar el mismo contrato. Con eso, un actor malicioso podría agregar comentarios engañosos o proporcionar nombres confusos a las variables dentro del código fuente y hacer que el contrato se verifique con un código fuente diferente al código fuente original.

Es posible evitar dicho escenario agregando datos adicionales al bytecode que sirvan como una garantía criptográfica de la exactitud del código fuente y como una huella digital de la información de compilación. La información necesaria se encuentra en los metadatos del contrato en Solidity(opens in a new tab), y el hash de este archivo se agrega al bytecode de un contrato. Puede verlo en acción en el playground de metadatos(opens in a new tab).

El archivo de metadatos contiene información sobre la compilación del contrato, incluidos los archivos fuente y sus hashes. Esto significa que, si cambia cualquier configuración de compilación o incluso un byte en uno de los archivos fuente, el archivo de metadatos cambia. En consecuencia, el hash del archivo de metadatos, que se agrega al bytecode, también cambia. Esto quiere decir que, si el bytecode de un contrato y el hash de metadatos agregado coinciden con el código fuente y la configuración de compilación proporcionados, podemos estar seguros de que este es exactamente el mismo código fuente utilizado en la compilación original; ni siquiera un solo byte es diferente.

Este tipo de verificación que utiliza el hash de metadatos se denomina "verificación completa(opens in a new tab)" (también conocida como "verificación perfecta"). Si los hashes de los metadatos no coinciden o no se tienen en cuenta en la verificación, se trataría de una "coincidencia parcial", la cual actualmente es la forma más común de verificar contratos. De esta forma, sin la verificación completa, se corre el riesgo de que se inserte código malicioso(opens in a new tab) que no se refleje en el código fuente verificado. La mayoría de los desarrolladores no son conscientes de la verificación completa y no guardan el archivo de metadatos de su compilación, por lo que hasta ahora la verificación parcial ha sido el método estándar para verificar contratos.

¿Por qué es importante la verificación del código fuente?

No necesidad de confianza

La no necesidad de confianza ("truslessness") es posiblemente la premisa más importante para los contratos inteligentes y las aplicaciones descentralizadas (dApps). Los contratos inteligentes son "inmutables" y no pueden ser modificados; un contrato solo va a ejecutar la lógica comercial definida en el código en el momento de la implementación. Esto significa que los desarrolladores y las empresas no pueden manipular el código de un contrato luego de implementarlo en Ethereum.

Para que un contrato inteligente no necesite confianza, el código del contrato debe estar disponible para su verificación independiente. Si bien el bytecode compilado de cada contrato inteligente está disponible públicamente en la cadena de bloques, el lenguaje de bajo nivel es difícil de entender, tanto para los desarrolladores como para los usuarios.

Los proyectos disminuyen las suposiciones de confianza al hacer público el código fuente de sus contratos. Pero esto conlleva otro problema: es difícil verificar que el código fuente publicado coincida con el bytecode del contrato. En este escenario, se pierde el valor de la no necesidad de confianza porque los usuarios deben confiar en que los desarrolladores no van a cambiar la lógica comercial de un contrato (es decir, cambiando el bytecode) antes de implementarlo en la cadena de bloques.

Las herramientas de verificación de código fuente proporcionan garantías de que los archivos de código fuente de un contrato inteligente coinciden con el código de emsamblaje. El resultado es un ecosistema sin confianza, donde los usuarios no confían ciegamente en terceros y en su lugar verifican el código antes de depositar fondos en un contrato.

Seguridad del usuario

Con los contratos inteligentes, generalmente hay mucho dinero en juego. Esto requiere garantías de seguridad más altas y la verificación de la lógica de un contrato inteligente antes de utilizarlo. El problema es que los desarrolladores inescrupulosos pueden engañar a los usuarios insertando código malicioso en un contrato inteligente. Sin verificación, los contratos inteligentes maliciosos pueden tener puertas traseras(opens in a new tab), mecanismos de control de acceso controvertidos, vulnerabilidades explotables y otras cosas que ponen en riesgo la seguridad de los usuarios y que podrían pasar desapercibidas.

Publicar los archivos de código fuente de un contrato inteligente facilita que las personas interesadas, como los auditores, evalúen el contrato en busca de posibles vectores de ataque. Con múltiples partes verificando de manera independiente un contrato inteligente, los usuarios tienen garantías más sólidas de su seguridad.

Cómo verificar el código fuente de los contratos inteligentes de Ethereum

Implementar un contrato inteligente en Ethereum requiere enviar una transacción con una carga útil de datos (código bytecode compilado) a una dirección especial. La carga útil de datos se genera compilando el código fuente, junto con los argumentos constructor(opens in a new tab) de la instancia del contrato que se adjuntan a la carga útil de datos en la transacción. La compilación es determinista, lo que significa que siempre produce la misma salida (es decir, el bytecode del contrato) si se utilizan los mismos archivos fuente y ajustes de compilación (como por ejemplo la versión del compilador, el optimizador, etc).

Diagrama que muestra la verificación del código fuente de un contrato inteligente

Verificar un contrato inteligente básicamente consta de los siguientes pasos:

  1. Ingresar en un compilador los archivos de origen y la configuración de compilación.

  2. El compilador produce el bytecode del contrato.

  3. Obtener el bytecode del contrato implementado en una dirección específica.

  4. Comparar el bytecode implementado con el bytecode recompilado. Si los códigos coinciden, el contrato se verifica con el código fuente y la configuración de compilación proporcionados.

  5. Además, si los hashes de metadatos al final del bytecode coinciden, la coincidencia será completa.

Tenga en cuenta que esta es una descripción simplificada de la verificación y existen muchas excepciones que no funcionarían de esta manera, como sería el caso de tener variables inmutables(opens in a new tab).

Herramientas de verificación de código fuente

El proceso tradicional de verificar contratos puede ser complejo. Es por eso que tenemos herramientas para verificar el código fuente de los contratos inteligentes implementados en Ethereum. Estas herramientas automatizan gran parte de la verificación del código fuente y también curan contratos verificados en beneficio de los usuarios.

Etherscan

Aunque es mayormente conocido como un explorador de cadena de bloques de Ethereum, Etherscan también ofrece un servicio de verificación de código fuente(opens in a new tab) para desarrolladores y usuarios de contratos inteligentes.

Etherscan le permite volver a compilar el bytecode del contrato a partir de la carga útil de datos original (código fuente, dirección de la biblioteca, configuración del compilador, dirección del contrato, etc). Si el bytecode recompilado está asociado con el bytecode (y a los parámetros constructor) del contrato en la cadena, el contrato está verificado(opens in a new tab).

Una vez verificado, el código fuente de su contrato recibe una etiqueta de "Verificado" y se publica en Etherscan para que otros puedan auditarlo. También se agrega a la sección de Contratos verificados(opens in a new tab), que es un repositorio de contratos inteligentes con código fuente verificado.

Etherscan es la herramienta más utilizada para verificar contratos. Sin embargo, la verificación de contratos de Etherscan tiene una desventaja: no compara el hash de metadatos del bytecode en la cadena con el bytecode recompilado. Por lo tanto, las coincidencias en Etherscan son coincidencias parciales.

Más información sobre la verificación de contratos en Etherscan(opens in a new tab).

Sourcify

Sourcify(opens in a new tab) es otra herramienta para verificar contratos que es de código abierto y descentralizada. Sourcify no es un explorador de bloques y solo verifica contratos en distintas redes basadas en la Máquina virtual de Ethereum(opens in a new tab). Sourcify actúa como una infraestructura pública sobre la cual otras herramientas pueden construir, y tiene como objetivo permitir interacciones con contratos más amigables para los humanos utilizando la Interfaz Binaria de Aplicación (ABI, por sus siglas en inglés) y comentarios NatSpec que se encuentran en el archivo de metadatos.

A diferencia de Etherscan, Sourcify admite coincidencias completas con el hash de metadatos. Los contratos verificados se alojan en su correspondiente repositorio público(opens in a new tab) en HTTP y en IPFS(opens in a new tab), que es un almacenamiento descentralizado cuya dirección es determinada por su contenido(opens in a new tab). Esto permite obtener el archivo de metadatos de un contrato a través de IPFS, ya que el hash de metadatos añadido es un hash de IPFS.

Además, también se pueden recuperar los archivos de código fuente a través de IPFS, ya que los hashes de IPFS de estos archivos también se encuentran en los metadatos. Un contrato puede ser verificado proporcionando el archivo de metadatos y los archivos de origen a través de su API o Interfaz de Usuario (UI)(opens in a new tab), o utilizando complementos. La herramienta de monitoreo de Sourcify también escucha las creaciones de contratos en nuevos bloques e intenta verificar los contratos si sus metadatos y archivos de origen están publicados en IPFS.

Más información sobre la verificación de contratos en Sourcify(opens in a new tab).

Antiguamente

La plataforma Tenderly(opens in a new tab) permite a los desarrolladores de Web3 crear, probar, monitorear y operar contratos inteligentes. Al combinar herramientas de depuración con observabilidad y bloques de construcción de infraestructura, Tenderly ayuda a los desarrolladores a acelerar el desarrollo de contratos inteligentes. Para habilitar por completo las funciones de Tenderly, los desarrolladores deben realizar la verificación del código fuente(opens in a new tab) utilizando varios métodos.

Es posible verificar un contrato de forma privada o pública. Si se verifica de forma privada, el contrato inteligente es visible solo para usted (y otros miembros de su proyecto). Verificar un contrato de manera pública lo hace visible para todos los usuarios de la plataforma Tenderly.

Puede verificar contratos utilizando el Panel(opens in a new tab), el plugin de Hardhat para Tenderly(opens in a new tab) o la Línea de Comandos (CLI)(opens in a new tab).

Cuando verifica contratos a través del Panel, necesita importar el archivo fuente o el archivo de metadatos generado por el compilador de Solidity, la dirección/red y la configuración del compilador.

Usar el complemento de Hardhat para Tenderly permite tener un mayor control sobre el proceso de verificación con menos esfuerzo, lo que permite elegir entre la verificación automática (sin código) y la verificación manual (basada en código).

Más información

¿Le ha resultado útil este artículo?