Tutoral Solidity : créer un registre des contrats pour les mettre à jour

0

Une des particularités de la blockchain, et ce qui en fait incontestablement sa force est l’immuabilité des données, ce qui est déployé sur une blockchain reste en l’état indéfiniment, contrairement à d’autres supports de données.

Mais ce point fort est aussi une contrainte importante pour les développeurs, puisque le code d’un smart contrat déployé sur la blockchain ne peut plus être modifié.

Pour contourner ce problème, le langage Solidity nous permet de faire en sorte que les contrats s’appellent entre eux, voir même se créent entre eux.

Lorsque la taille de l’application augmente et que les contrats se multiplient au fur et à mesure de l’ajout de fonctionnalité, il devient difficile de gérer toutes les adresses et les différentes versions à chaque mise à jour.

Pour régler ce problème, un design pattern efficace en Solidity consiste à créer un registre de tous les contrats dans lequel un mapping associe le nom du contrat avec son adresse. Cela permet d’appeler un contrat par son nom et de récupérer ainsi automatiquement l’adresse de la dernière version, ainsi tous les contrats se serviront automatiquement de la dernière version des autres contrats, même si l’adresse change. Voyons comment mettre cela en place.

Commençons par créer notre structure pour le registre :

// SPDX-License-Identifier: GPL-3.
pragma solidity >=0.4.22 <0.9.0;

contract RegistreContrat {
}

Pour stocker les détails des contrats nous ajoutons un struct qui permet pour chaque contrat de définir le propriétaire, l’adresse du contrat, et sa version :

   struct DetailContrat {
      address proprietaire;
      address contratAddresse;
      uint16 version;
   }

Ajoutons maintenant un mapping pour pour tenir le registre à jour :

mapping(string => DetailContrat) registre;

Et enfin une fonction permettant d’enregistrer et de mettre à jour dans le registre un contrat avec sa version et son adresse, sans oublier de vérifier que la mise à jour est bien faite par le propriétaire du contrat :

   function enregistrerContrat(string memory nom, address adresse, uint16 version) public  {
       
      require(version >= 1);
      
      DetailContrat memory info = registre[nom];

       if (info.contratAddresse == address(0)) {
          info = DetailContrat({
             proprietaire: msg.sender,
             contratAddresse: adresse,
             version: version
          });
       } else {
          require(info.proprietaire == msg.sender); 
          info.contratAddresse = adresse;
          info.version = version;
       }
       registre[nom] = info;

   }

Pour que les autres contrats puissent se servir du registre, on oublie pas la fonction permettant de récupérer les détails du contrat (l’adresse et la version) :

function contratDetails(string memory nom)  public view returns(address, uint16) {
  return (registre[nom].contratAddresse, registre[nom].version);
}

Le code complet de notre registre est désormais complet :

// SPDX-License-Identifier: GPL-3.
pragma solidity >=0.4.22 <0.9.0;

contract RegistreContrat {
    
   struct DetailContrat {
      address proprietaire;
      address contratAddresse;
      uint16 version;
   }

   mapping(string => DetailContrat) registre;
   
   function enregistrerContrat(string memory nom, address adresse, uint16 version) public  {
       
      require(version >= 1);
      
      DetailContrat memory info = registre[nom];

       if (info.contratAddresse == address(0)) {
          info = DetailContrat({
             proprietaire: msg.sender,
             contratAddresse: adresse,
             version: version
          });
       } else {
          require(info.proprietaire == msg.sender); 
          info.contratAddresse = adresse;
          info.version = version;
       }
       registre[nom] = info;

   }
   
    function contratDetails(string memory nom)  public view returns(address, uint16) {
      return (registre[nom].contratAddresse, registre[nom].version);
    }
}

Pour le tester nous allons créer un autre contrat (par exemple le contrat pour stocker un message disponible ici), puis l’enregistrer dans notre registre.

Sur Remix, compilez le code d’un contrat message, puis déployez le. Ensuite, compilez et déployez sur votre blockchain le registre. Vous pourrez ainsi enregistrer le contrat avec son nom et son adresse dans le registre, puis récupérer ses informations en appelant la fonction contratDetails :

C’est terminé, nous disposons maintenant de la possibilité de mettre à jour notre code sur la blockchain grâce au registre. Cela impose par contre une nouvelle contrainte : traiter les logiques métiers et les données dans des contrats différents, pour ne pas perdre des données lors de la mise à jour des contrats, ou prévoir dans son contrat des fonctions pour transférer les données dans le nouveau contrat, qui devra lui avoir la possibilité de réceptionner ces données.

LAISSER UN COMMENTAIRE

Please enter your comment!
Please enter your name here

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.