Contributions de l’étude
Dans cette étude, deux contrats intelligents Solidity ont été utilisés comme entrées de vérification. Le premier était un contrat de type Simple DAO utilisé comme étude de cas de réentrance. Le second était un contrat de registre allégé/transition d’État conçu pour tester les contraintes au niveau du contrat contre les doubles dépenses. Le code source original de Solidity servait d’entrée aux processus d’abstraction et de vérification définis dans ce protocole. Le processus général de transformation utilisé pour ces contrats est illustré à la Figure 1, qui montre la transformation progressive du code source Solidity dans les modèles FSM, Événement-B et SMV lors de la vérification.
Modélisation de la frontière
La modélisation formelle se concentre sur la logique de contrôle-flux des smart contracts, incluant le comportement d’entrée et de sortie des fonctions, l’exécution interne et les transitions d’état au niveau du contrat. La visibilité des fonctions (publique, externe, interne et privée) était représentée avec le comportement d’appel correspondant pertinent à l’analyse de la réentrance. Les types de transitions abstraites (appel, envoi, transfert) étaient traités comme des opérations de transfert d’ethers.
Des invariants au niveau du contrat ont été définis pour garantir l’unicité des transactions et éviter les doubles dépenses dans la frontière d’abstraction. Pour représenter les exigences de sélection de validation et d’intégrité du bloc, la couche d’abstraction logique protocolaire a été définie en fonction des transitions d’état au niveau du protocole de la preuve de travail et de la preuve de mise en jeu.
La frontière d’abstraction n’incluait pas les éléments de la couche réseau, notamment la planification des messages à livrer et les délais causés par un nombre quelconque de sauts, la résolution de fork, les adversaires du réseau employant des stratégies byzantines, la sémantique de la machine virtuelle Ethereum et la sémantique du gaz contrôlée par les nœuds réseau, la propagation des exceptions, les exécutions asynchrones, le comportement de repli complexe et la finalité au niveau du réseau. Ainsi, les résultats de la détermination des doubles dépenses ne s’appliquent qu’aux invariants au niveau du contrat et ne constituent pas un accord de finalité au niveau du réseau.
Outils et configuration
La plateforme Rodin servait à modéliser, affiner, générer des obligations de preuve et décharger le modèle Event-B (version 3.7.0), qui permettait aux indicateurs PP, ML, SMT et Atelier-B de décharger automatiquement et de manière interactive les épreuves. la version 2.0.0 de nuXmv a été exécutée sur les modèles SMV générés en mode exploration CTL complète pour effectuer la vérification des modèles CTL.
Toutes les exécutions de vérification étaient effectuées dans un environnement informatique contrôlé utilisant Ubuntu 22.04 LTS, OpenJDK 11 et Python 3.10.12. Web3 (7.6.0), NetworkX (3.4.2), Matplotlib (3.8.0), Graphviz (0.20.3), NumPy (1.26.4) et Pandas (2.2.2) ont été utilisés pour implémenter des éléments de simulation et de visualisation. Cette conception garantissait que les résultats formels de vérification et de simulation pouvaient être reproduits lors de l’exécution dans les mêmes conditions d’exécution.
Flux de travail de transformation
Ce processus de vérification comportait quatre phases. Les contrats de solidité ont d’abord été traduits en une représentation de la Machine à États Finis (FSM-SC). Le modèle FSM-SC a ensuite été encodé en Événement-B, avec des invariants et des degrés de raffinement clairement spécifiés. L’abstraction FSM-SC a été traduite en modèle SMV dans nuXmv. Les résultats de la vérification ont été présentés sous forme de statistiques sur la décharge de l’obligation de preuve et le modèle CTL, et des contre-exemples ont été fournis en cas de cas.
Construction FSM
Chaque contrat était abstrait comme une machine à états finis définie comme :

Où :
S = ensemble des états
S₀ = état initial
T = relation de transition
V = cartographie de visibilité
G = prédicats de garde
A = actions/mises à jour d’état.
Algorithme 1 : Construction FSM à partir de Solidity
Entrée : Code source Solidity
Sortie : FSM-SC
1) Analyser l’arbre syntaxique abstrait du contrat de Solidity.
2) Créer l’état initial S₀ à partir de la définition du constructeur.
3) Pour chaque fonction Solidity f, créer un état de contrôle distinct S_f et enregistrer la visibilité V(f) ∈ {public, externe, interne, privé}.
4) Pour chaque instruction dans la fonction f, dériver une transition t en extrayant des prédicats de garde à partir des conditions requise/assert et des actions issues des mises à jour des variables d’état.
5) Ajouter la transition t à T.
6) Créer des types de transition explicites pour les opérations de transfert Ether (appel, envoi, transfert), appels internes et externes, appel délégué, autodestruction, utilisation de tx.origin, branches conditionnelles et constructions de boucles.
7) Retour FSM-SC = (S, S₀, T, V, G, A).
Et chaque fonction de solidité est associée à un état de contrôle FSM différent. Pour la compréhension des vulnérabilités, les flux d’exécution pertinents pour les vulnérabilités, par exemple ces flux avec des appels externes suivis de mises à jour d’équilibre, ont été explicitement abstraits en transitions ordonnées. La figure 2 décrit un exemple de diagramme FSM-SC pour le contrat de type SimpleDAO, montrant comment les états d’entrée, les transitions d’appel externe et les séquences de mise à jour d’état ont été abstraits durant cette étape de construction.
Encodage de FSM dans l’Événement-B
La transition FSM était représentée par des constructions Événement-B. Toutes les transitions correspondent à des événements d’Événement-B, y compris des gardes et des actions particulières.
Algorithme 2 : encodage FSM vers Événement-B
Entrée : FSM-SC
Sortie : machine événement-B et contexte
1) Définir STATE_SET et FONCTION dans le contexte contractuelle.
2) Déclarer les variables représentant l’état de contrôle FSM et l’état au niveau du contrat.
3) Représenter chaque état de contrôle FSM s ∈ S en utilisant current_state ∈ STATE_SET.
4) Pour chaque transition (s → s′, g, a), créer un événement Événement-B E_t avec :
5) OÙ current_state = s ∧ g
6) ALORS current_state := s′ ∥ appliquer(a)
7) Encoder les contraintes de visibilité en utilisant des gardes dérivés de V(f).
8) Définir les invariants inv1–inv9 pour capturer les propriétés de sécurité et de cohérence.
9) Définir l’INITIALISATION en attribuant S₀ et valeurs par défaut.
L’ensemble des états, l’état actuel, la visibilité de la fonction, la pile d’appels, l’horodatage de la transaction, le statut de transfert Ether, le drapeau d’appel délégué, le drapeau d’autodestruction et la condition de vérification sont quelques-unes des variables capturées dans le modèle Événement-B. Les invariants (inv1-inv9) et les actions des initialisations (acte1-acte6) correspondent à celles de la spécification formelle. La figure 3 présente également une représentation graphique de la manière dont les événements clés pertinents pour les vulnérabilités, en particulier les transitions liées à la réentrance, sont maintenus dans l’encodage Événement-B. Cette figure explique comment les schémas structurels du modèle FSM-SC illustré à la Figure 2 sont mappés en événements Événement-B vérifiables.
Stratégie de raffinement
Deux niveaux de raffinement ont été mis en place. Les invariants de contrôle de contrôle contractuel de haut niveau et les invariants du cœur étaient représentés au niveau abstrait. Le niveau affiné a ajouté des restrictions spécifiques au contrat, notamment des restrictions de pile d’appels, des restrictions de visibilité et des conditions de prévention de la réentrée.
Algorithme 3 : Affinement et décharge de l’obligation de preuve
Entrée : Machine abstraite et machine raffinée
Résultats : obligations de preuve et statistiques de décharge
1) Générer des obligations de preuve pour la machine abstraite dans Rodin.
2) Exécuter des épreuves automatiques activées et enregistrer les résultats de décharge.
3) Générer des obligations de vérification de raffinage pour la machine affinée.
4) Appliquer des mesures automatiques aux obligations de raffinement.
5) Remplir les obligations restantes de manière interactive lorsque cela est nécessaire.
6) Statistiques de preuve d’exportation et rapports d’état.
La déclaration de preuves comprenait le nombre d’invariants, les niveaux de raffinement, les obligations de preuve générées, le taux de décharge automatique, le taux de décharge interactive et le taux de décharge final.
Spécification des propriétés CTL et vérification des modèles
L’abstraction FSM-SC a été traduite en un modèle SMV pour la vérification temporelle en temps de branchement dans nuXmv.
Algorithme 4 : Vérification FSM vers SMV et CTL
Sortie : résultat de vérification PASS/FAIL et traces contre-exemples (le cas échéant)
1. Enregistrer les états de contrôle FSM comme un état énuméré de variables SMV.
2. Convertir les transitions FSM en missions prochaines (état) protégées.
3. Maintenir des indicateurs pour les conditions pertinentes à la vulnérabilité, telles que les appels externes et les mises à jour d’équilibre.
4. Coder les propriétés CTL dans nuXmv et effectuer la vérification des modèles.
5. Si une propriété échoue, générez des traces contre-exemples représentant les séquences de transition FSM.
La vérification CTL comprenait les exigences d’ordre de réentrée, la finalisation des mises à jour d’état après les opérations de transfert, la limitation de l’entrée récursive non contrainte dans les sections critiques et l’évitement des blocages.
Propriétés de sécurité vérifiées
Le contrat de type Simple DAO qui empêche la réentrée a été confirmé en assurant un ordre sûr entre appels externes et mises à jour d’état via des invariants et des contraintes CTL. Lorsque cela était permis, ces agents vérifiaient les contraintes de contrôle d’accès, s’assurant que les transitions non autorisées étaient restreintes par des invariants. Le modèle du registre réduit a vérifié les invariants de l’unicité des transactions et de la cohérence du registre au niveau de prévention dans le contrat.
Résultats rapportés
La section Résultats fournit des rapports sur les métriques structurelles FSM, les métriques du modèle Événement-B, et les statistiques pour la preuve d’obligation et la vérification CTL. Les résultats de la preuve formelle, ainsi que ceux de la vérification par modèle CTL, sont donnés séparément pour distinguer la preuve de garanties de correction par les invariants, et la preuve d’une vérification temporelle utilisant la vérification temporelle.