
Découvrez l'importance des smart contracts évolutifs dans les applications décentralisées. Apprenez comment ils permettent les mises à jour, corrections de bugs et une sécurité renforcée grâce au modèle proxy.

Les smart contracts ont transformé notre façon d'envisager les applications décentralisées en introduisant des programmes auto-exécutables qui éliminent le besoin d'intermédiaires. Ils s'exécutent de manière transparente sur des réseaux blockchain décentralisés, offrant des avantages tels que l'absence de confiance requise et une sécurité accrue. Cependant, leur immuabilité, autrefois considérée comme un atout, représente un défi majeur : une fois déployé, un smart contract ne peut pas être modifié. Cette rigidité rend difficile la mise en œuvre des mises à jour nécessaires ou la correction de bugs.
Dans cet article, nous allons explorer le concept de smart contracts évolutifs, expliquer pourquoi ils sont essentiels et détailler leur fonctionnement, en nous concentrant particulièrement sur leur implémentation sur Linea zkEVM.
Les smart contracts évolutifs résolvent les limitations des smart contracts traditionnels en permettant des modifications et des améliorations après le déploiement. Alors que les smart contracts traditionnels sont reconnus pour leur immuabilité, les contrats évolutifs combinent la sécurité de l'immuabilité avec la flexibilité d'adaptation. Cela permet aux développeurs de mettre en œuvre des mises à jour sans perturber les utilisateurs ni les obliger à migrer vers un nouveau contrat.
Dans les contrats traditionnels, les bugs ou failles de sécurité sont permanents une fois déployés. Les contrats évolutifs y remédient en permettant des mises à jour après le déploiement, résolvant ainsi des problèmes clés tels que :
1. Corrections de bugs et vulnérabilités de sécurité : Les développeurs peuvent corriger les vulnérabilités après le déploiement, protégeant ainsi les actifs des utilisateurs.
2. Adaptabilité : Les contrats évolutifs permettent une intégration fluide avec de nouveaux protocoles, maintenant les applications à jour avec les avancées technologiques.
3. Améliorations de la sécurité : Face à l'évolution des cybermenaces, ces contrats facilitent la mise en œuvre de nouvelles mesures de sécurité sans avoir à redéployer l'intégralité du contrat.
4. Flexibilité de gouvernance : Les Organisations Autonomes Décentralisées (DAOs) peuvent utiliser le vote communautaire pour gérer le processus de mise à jour, garantissant transparence et participation des parties prenantes.
5. Mises à jour simplifiées : Contrairement aux contrats traditionnels qui nécessitent un redéploiement complexe et une migration des données, les contrats évolutifs rationalisent les mises à jour pour une expérience plus efficace et conviviale.
Pour créer un smart contract évolutif, la méthode la plus courante est le modèle proxy. Cette approche sépare la logique du contrat de ses données, permettant aux développeurs de mettre à jour la logique tout en conservant le même stockage de données.
Voici comment cela fonctionne :
Contrat Proxy : Ce contrat détient le stockage (variables d'état) et sert d'interface pour les utilisateurs.
Contrat d'Implémentation : Ce contrat contient le code exécutable (logique métier).
Délégation : Le contrat proxy délègue les appels de fonctions au contrat d'implémentation en utilisant le delegatecall d'Ethereum. Cela permet au proxy d'exécuter le code de l'implémentation tout en conservant le même stockage.
Lorsqu'une mise à jour est nécessaire, le contrat proxy est redirigé vers un nouveau contrat d'implémentation, permettant des mises à jour de la logique sans modifier le stockage du contrat ni perturber les utilisateurs. Voici un exemple utilisant un contrat proxy DAO pour illustrer ce processus :
Deux éléments importants à noter sont le slot de stockage pour l'adresse du contrat d'implémentation et le slot de stockage pour l'adresse de l'administrateur. Ce sont des identifiants délibérés et uniques utilisés pour calculer un slot de stockage pour l'adresse d'implémentation au sein du contrat proxy.
Lors de l'utilisation du modèle proxy avec delegatecall (nous examinerons cette fonction de plus près prochainement), le contrat d'implémentation opère dans le contexte du stockage du proxy. Cela signifie :
Espace de stockage partagé : Les deux contrats partagent la même disposition de stockage.
Risque d'écrasement : Sans une gestion rigoureuse, les variables du contrat proxy pourraient être écrasées par le contrat d'implémentation.
En utilisant un identifiant unique haché :
Isolation : Cela garantit que les slots de stockage utilisés par le proxy sont peu susceptibles d'entrer en conflit avec les variables du contrat d'implémentation.
Cohérence : Le même slot de stockage est utilisé de manière cohérente dans tout le contrat, partout où l'adresse d'implémentation est nécessaire.
Un autre aspect important est le constructeur du contrat proxy. Il inclut un paramètre _implementation, ce qui signifie que le contrat d'implémentation doit être déployé en premier, et son adresse est transmise en argument lors du déploiement du contrat proxy.
Nous avons maintenant les fonctions fallback et receive, qui sont des fonctions Solidity jouant un rôle crucial dans le transfert des appels et des transferts d'Ether vers le contrat d'implémentation. Elles gèrent les situations où un contrat reçoit des appels ou des fonds ne correspondant à aucune de ses fonctions explicitement définies. Voici une explication détaillée de ce que font ces fonctions :
Mécanisme de secours : La fonction fallback en Solidity est une fonction spéciale qui s'exécute dans deux conditions principales :- Lorsqu'une fonction inexistante dans le contrat est appelée.
Lorsque des données sont envoyées au contrat sans correspondre à aucune signature de fonction.
Délégation : Dans le contexte du contrat DAOProxy, la fonction fallback délègue tous ces appels au contrat d'implémentation actuel.
Fonctionnement dans DAOProxy :
Gestion des appels de fonctions :- Lorsqu'un utilisateur appelle une fonction non définie dans le contrat proxy, la fonction fallback est déclenchée.
C'est courant car le contrat proxy contient principalement des fonctions administratives comme upgradeTo et changeAdmin, plutôt que les fonctions de logique métier du contrat d'implémentation.
Délégation à l'implémentation :- La fonction fallback appelle _delegate(implementation()), transmettant l'appel au contrat d'implémentation.
_delegate est une fonction interne qui utilise delegatecall pour exécuter le code de l'implémentation tout en opérant dans le contexte de stockage du proxy.
Contexte d'exécution :- Tous les changements d'état se produisent dans le stockage du proxy.
msg.sender et msg.value restent inchangés, préservant le contexte de l'appelant d'origine.
Réception d'Ether : La fonction receive, introduite dans Solidity 0.6.0, est exécutée lorsqu'un contrat reçoit de l'Ether sans données associées (c'est-à-dire lorsque msg.data est vide).
Délégation des transferts d'Ether : Dans le contrat DAOProxy, les transferts d'Ether simples sont délégués au contrat d'implémentation.
Fonctionnement dans DAOProxy :
Gestion des transferts d'Ether :- Lorsque quelqu'un envoie de l'Ether à l'adresse du contrat proxy sans données, la fonction receive est déclenchée.
Cela se produit via une transaction qui spécifie uniquement l'adresse to et la valeur (montant en Ether), sans appeler de fonction spécifique.
Délégation à l'implémentation :- Comme la fonction fallback, receive appelle _delegate(implementation()), transmettant le transfert d'Ether au contrat d'implémentation.
Le contrat d'implémentation définit ensuite comment gérer l'Ether reçu (par exemple, mise à jour des soldes, émission d'événements).
Nous avons maintenant la fonction _delegate, qui permet au proxy de transmettre les appels de fonctions au contrat d'implémentation tout en préservant le contexte de l'appel d'origine. Cela permet à la logique du contrat d'être mise à jour au fil du temps sans modifier l'adresse du contrat ni perturber son état.
Les autres fonctions sont des getters et setters qui nous aident à gérer les variables d'état de notre contrat proxy. Pour ce faire, nous utilisons le mot-clé assembly, qui permet aux développeurs d'inclure du code assembleur bas niveau directement dans leurs contrats. Cette fonctionnalité offre un accès direct aux instructions de l'Ethereum Virtual Machine (EVM), permettant un contrôle plus précis du comportement du contrat, une optimisation de la consommation de gas et l'exécution d'opérations qui ne sont pas directement disponibles ou sont moins efficaces dans le code de haut niveau de Solidity.
La grande question est maintenant : comment interagissons-nous avec notre smart contract d'implémentation en utilisant ce contrat proxy ?
Pour ce faire, nous avons besoin de l'ABI du smart contract d'implémentation. Puisque le proxy délègue les appels au contrat d'implémentation, vous avez besoin de son ABI pour savoir quelles fonctions vous pouvez appeler. De plus, nous utiliserons l'adresse du contrat proxy lors des interactions avec la blockchain, et non celle du contrat d'implémentation. Le proxy détient l'état et délègue les appels à l'implémentation, donc toutes les interactions doivent passer par le proxy.
Imaginons que nous ayons un projet JavaScript et que nous utilisions Ethers.js pour interagir avec la blockchain. Voici à quoi cela ressemblerait :
Ainsi, nous appelons la fonction imaginaire setValue dans notre contrat d'implémentation en utilisant notre contrat proxy.
Maintenant que nous parlons de contrats évolutifs, une autre question importante se pose : comment mettre à jour mes contrats ?
Tout d'abord, seul l'administrateur (la personne qui a déployé le contrat proxy) peut mettre à jour le contrat d'implémentation. Pour ce faire, l'administrateur doit d'abord déployer une nouvelle version du contrat d'implémentation sur la blockchain. Ensuite, il doit appeler la fonction upgradeTo dans le contrat proxy, en passant la nouvelle adresse du contrat en paramètre. Cela ressemblerait à ceci :
await proxyContract.connect(adminSigner).upgradeTo(newImplementationAddress);Les smart contracts évolutifs sont essentiels dans le développement blockchain car ils permettent des modifications et des améliorations après le déploiement. En tirant parti du modèle proxy, les développeurs peuvent introduire de nouvelles fonctionnalités de manière fluide, corriger des bugs et répondre aux exigences changeantes sans perturber l'expérience utilisateur ni migrer les actifs.
Cependant, un grand pouvoir implique de grandes responsabilités. Il est crucial d'aborder les contrats évolutifs avec une compréhension approfondie de leur mécanique, de leurs implications en matière de sécurité et des meilleures pratiques. Assurer la cohérence de la disposition du stockage, mettre en œuvre des contrôles d'accès robustes et tester minutieusement les mises à jour sont des étapes essentielles pour se prémunir contre les risques potentiels.
Lorsque vous vous lancez dans la création de contrats évolutifs, envisagez d'utiliser des outils établis comme le Plugin Upgrades d'OpenZeppelin pour simplifier le processus et renforcer la sécurité. Bon développement !
Traduit par IA. Peut contenir des erreurs. Veuillez toujours vérifier les informations.