Aportaciones de estudio
En este estudio, se utilizaron dos contratos inteligentes Solidity como entradas de verificación. El primero fue un contrato al estilo Simple DAO que se utilizó como caso de estudio de reentrada. El segundo era un contrato de libro mayor/transición de estado simplificado diseñado para probar las restricciones a nivel de contrato frente al doble gasto. El código fuente original de Solidity servía como entrada a los procesos de abstracción y verificación definidos en este protocolo. El proceso general de transformación utilizado para dichos contratos se ilustra en la Figura 1, que muestra la transformación gradual del código fuente de Solidity en los modelos FSM, Evento-B y SMV durante la verificación.
Modelado de frontera
El modelado formal se centra en la lógica de control y flujo de los contratos inteligentes, incluyendo el comportamiento de entrada y salida de funciones, la ejecución interna y las transiciones de estado a nivel de contrato. La visibilidad de funciones (pública, externa, interna y privada) se representó junto con el comportamiento correspondiente de la pila de llamadas relevante para el análisis de reentrancia. Los tipos de transiciones abstractas (llamada, envío, transferencia) se trataban como operaciones para transferir éteres.
Se definieron invariantes a nivel de contrato para asegurar la unicidad de la transacción y evitar el doble gasto dentro del límite de abstracción. Para representar los requisitos de selección de validación e integridad del bloque, la capa de abstracción lógica-protocolo se definió en términos de las transiciones de estado a nivel de protocolo tanto de Proof of Work como de Proof of Stake.
El límite de abstracción no incluía elementos de la capa de red, incluyendo la programación de los mensajes a entregar y los retrasos causados por cualquier número de saltos, resolución de forks, adversarios de la red empleando estrategias bizantinas, semántica de la Máquina Virtual de Ethereum y semántica de gas controlada por nodos de red, propagación de excepciones, ejecuciones asíncronas, comportamientos de retroceso complejos y finalización a nivel de red. Por tanto, los resultados de la determinación del doble gasto solo se aplican a invariantes a nivel de contrato y no constituyen un acuerdo a nivel de red sobre la finalidad.
Herramientas y configuración
La plataforma Rodin se utilizó para modelar, refinar, generar obligaciones de prueba y ejecutar el modelo Evento-B (versión 3.7.0), que permitía que los probadores PP, ML, SMT y Atelier-B descargaran pruebas de forma automática e interactiva. la versión 2.0.0 de nuXmv se ejecutó en los modelos SMV generados en modo de exploración CTL completa para realizar comprobaciones de modelos CTL.
Todas las ejecuciones de verificación se realizaron en un entorno computacional controlado usando Ubuntu 22.04 LTS, OpenJDK 11 y Python 3.10.12. Web3 (7.6.0), NetworkX (3.4.2), Matplotlib (3.8.0), Graphviz (0.20.3), NumPy (1.26.4) y Pandas (2.2.2) se utilizaron para implementar elementos de simulación y visualización. Este diseño garantizaba que los resultados formales de verificación y simulación pudieran reproducirse cuando se ejecutaban bajo las mismas condiciones de ejecución.
Flujo de trabajo de transformación
Este proceso de verificación constaba de cuatro fases. Los contratos de solidez se tradujeron primero en una representación de Máquina de Estados Finitos (FSM-SC). El modelo FSM-SC fue posteriormente codificado en Evento-B, con invariantes y grados de refinamiento claramente especificados. La abstracción FSM-SC se tradujo en un modelo SMV en nuXmv. Los resultados de la verificación se informaron como estadísticas sobre la cancelación de obligaciones de prueba y la verificación por modelo CTL, y se proporcionaron contraejemplos como casos.
Construcción de FSM
Cada contrato se abstrajo como una Máquina de Estados Finitos definida como:

Donde:
S = conjunto de estados
S₀ = estado inicial
T = relación de transición
V = mapeo de visibilidad
G = predicados de guardia
A = acciones/actualizaciones de estado.
Algoritmo 1: Construcción FSM a partir de Solidity
Entrada: Código fuente de Solidity
Salida: FSM-SC
1) Analizar el árbol sintáctico abstracto del contrato de Solidity.
2) Crear el estado inicial S₀ a partir de la definición del constructor.
3) Para cada función de solidez f, crear un estado de control distinto S_f y registrar visibilidad V(f) ∈ {público, externo, interno, privado}.
4) Para cada sentencia dentro de la función f, se deriva una transición t extrayendo predicados de guardia de condiciones de requerimiento/afirmación y acciones de actualizaciones de variables de estado.
5) Añadir la transición t a T.
6) Crear tipos de transición explícitos para operaciones de transferencia Ether (llamada, envío, transferencia), llamadas internas y externas, llamada delegada, autodestrucción, uso de tx.origin, ramas condicionales y construcciones de bucle.
7) Retorno FSM-SC = (S, S₀, T, V, G, A).
Y cada función de solidez está asociada a un estado de control FSM diferente. Para la comprensión de vulnerabilidades, los flujos de ejecución relevantes para vulnerabilidades, por ejemplo, tales flujos con llamadas externas seguidas de actualizaciones de balance, se abstrajeron explícitamente en transiciones ordenadas. La Figura 2 describe un diagrama de ejemplo FSM-SC para el contrato al estilo SimpleDAO, mostrando cómo se abstrajeron los estados de entrada, las transiciones de llamadas externas y las secuencias de actualización de estado durante esta etapa de construcción.
Codificación de FSM en Evento-B
La transición FSM se representó como constructos Evento-B. Todas las transiciones corresponden a eventos del Evento-B, incluyendo guardias y acciones particulares.
Algoritmo 2: Codificación FSM a Evento-B
Entrada: FSM-SC
Salida: Máquina de evento B y contexto
1) Definir STATE_SET y FUNCIÓN en el contexto contractual.
2) Declarar variables que representen el estado de control FSM y el estado a nivel de contrato.
3) Representar cada estado de control FSM s ∈ S usando current_state ∈ STATE_SET.
4) Para cada transición (s → s′, g, a), crear un evento Evento-B E_t con:
5) DONDE current_state = s ∧ g
6) ENTONCES current_state := s′ ∥ aplicar(a)
7) Codificar restricciones de visibilidad usando guardas derivadas de V(f).
8) Definir invariantes inv1–inv9 para capturar propiedades de seguridad y consistencia.
9) Definir la INICIALIZACIÓN asignando valores S₀ y por defecto.
El conjunto de estados, el estado actual, la visibilidad de la función, la pila de llamadas, la marca de tiempo de la transacción, el estado de transferencia de Ether, la bandera de llamada de delegado, la bandera de autodestrucción y la condición de verificación son algunas de las variables que se capturan en el modelo Evento-B. Los invariantes (inv1-inv9) y las acciones de las inicializaciones (acto1-acto6) coinciden con las de la especificación formal. La Figura 3 también ofrece una representación gráfica de cómo se mantienen los eventos clave relevantes para vulnerabilidades, especialmente las transiciones relacionadas con la reentrancia, en la codificación Evento-B. Esta figura explica cómo los patrones estructurales del modelo FSM-SC mostrado en la Figura 2 se mapean en eventos verificables de Evento-B.
Estrategia de refinamiento
Se implementaron dos niveles de refinamiento. Los invariantes de control de control de alto nivel del contrato y núcleos se representaban a nivel abstracto. El nivel refinado añadió restricciones específicas del contrato, incluyendo restricciones de pila de llamadas, restricciones de visibilidad y condiciones de prevención de reentrada.
Algoritmo 3: Refinamiento y exoneración de la prueba y la obligación
Entrada: Máquina abstracta y máquina refinada
Resultados: Obligaciones de prueba y estadísticas exhaladas
1) Generar obligaciones de demostración para la máquina abstracta en Rodin.
2) Ejecutar probadores automáticos habilitados y registrar los resultados de descarga.
3) Generar obligaciones de prueba de refinamiento para la máquina refinada.
4) Aplicar evaluadores automáticos a las obligaciones de refinamiento.
5) Cumplir con las obligaciones restantes de forma interactiva cuando sea necesario.
6) Estadísticas de pruebas de exportación e informes de estado.
La presentación de pruebas incluyó el número de invariantes, los niveles de refinamiento, las obligaciones de prueba generadas, la tasa de descarga automática, la tasa de descarga interactiva y la tasa final de descarga.
Especificación de propiedades CTL y verificación de modelos
La abstracción FSM-SC se tradujo en un modelo SMV para la verificación temporal en tiempo de ramificación en nuXmv.
Algoritmo 4: FSM a SMV y comprobación CTL
Salida: resultado de verificación PASS/FAIL y trazas de contraejemplo (si las hay)
1. Registrar los estados de control FSM como un estado enumerado de variables SMV.
2. Convertir transiciones FSM en asignaciones de siguiente estado protegidas.
3. Mantener alertas para condiciones relevantes para vulnerabilidades, como llamadas externas y actualizaciones de balance.
4. Codificar propiedades CTL en nuXmv y realizar comprobaciones de modelos.
5. Si una propiedad falla, genera trazas de contraejemplo que representen secuencias de transición FSM.
La comprobación CTL incluía requisitos de órdenes de reentrada, finalización de actualizaciones de estado tras operaciones de transferencia, limitación de la entrada recursiva sin restricciones en secciones críticas y evitación de bloqueos.
Propiedades de seguridad verificadas
El contrato tipo DAO simple que evita la reentrada se confirmó asegurando un orden seguro entre llamadas externas y actualizaciones de estado mediante invariantes y restricciones CTL. Cuando se permitía, estos guardias comprobaban las restricciones de control de acceso, asegurándose de que las transiciones no autorizadas estuvieran restringidas por invariantes. El modelo del libro mayor reducido verificó los invariantes de la unicidad de las transacciones y la consistencia del libro mayor a nivel de prevención dentro del contrato.
Resultados reportados
La sección de Resultados proporciona informes sobre métricas estructurales de FSM, métricas del modelo Evento-B y estadísticas para la verificación de prueba de obligación y CTL. Los resultados de la prueba formal y los de la verificación de modelos CTL se presentan por separado para distinguir la evidencia de garantías de corrección por invariantes y la evidencia de una verificación temporal mediante verificación temporal.