Solidity – Créer un smart contract évolutif

logo Solidity

Les smart contracts déployés sur la blockchain Ethereum sont par natures immuables, c’est à dire qu’on ne peut en faire évoluer le code source. Dans le contexte du développement d’une application distribuée (DApp) ceci n’est pas concevable.
Le cycle de vie de l’application nécessite obligatoirement de pouvoir faire évoluer le code source d’un smart contract en vue de corriger des bugs ou intégrer de nouvelles évolutions fonctionnelles ou techniques.

Cet article présente une solution basée sur les outils OpenZepplin pour construire et déployer un smart contract puis ensuite le faire évoluer.

Personnellement, j’ai réalisé cette intégration avec Ganache et Truffle mais rien ne vous empêche d’utiliser d’autres outils comme Hardhat par exemple.

Principe général

En tout état de cause il n’est pas possible de modifier un smart contract (SC) déployé sur la blockchain. La solution technique qui permet son évolution est de placer devant le smart contract un proxy. TOUS les appels passent par le proxy qui les redirigent automatiquement et de manière transparente vers le smart contract.

Pour mettre à jour le code du smart contract il faut donc :

  • Déployer une nouvelle version du smart contract
  • Modifier le Proxy pour qu’il renvoie les appels vers la bonne version

L’outillage OpenZepplin prend tout en charge ce qui simplifie grandement l’effort à produire pour atteindre l’objectif.
En fait, 3 smart contracts seront déployés :

  • Un smart contract pour notre implémentation
  • Un smart contract proxy (OpenZepplin)
  • Un smart contract d’administratiuon du proxy (OpenZepplin)

Développement

La suite de l’article montre la mise à jour d’un smart contract déployé localement sur Ganache.

Une première version est déployée, puis une 2ème et enfin une 3ème.

Version 1

La version initiale du smart contract contient simplement une valeur qu’il est possible de mettre à jour ainsi qu’un constructeur :

[pastacode lang= »javascript » manual= »%2F%2F%20SPDX-License-Identifier%3A%20MIT%0Apragma%20solidity%20%3E%3D0.4.22%20%3C0.9.0%3B%0A%20%0A%2F%2F%2F%20%40author%20Emmanuel%20Collin%0A%2F%2F%2F%20%40notice%0A%2F%2F%2F%20%40dev%0Acontract%20MyContractV1%20%20%7B%0A%20%0A%20%20%20%20uint%20private%20value%3D0%3B%0A%20%0A%20%20%20%20constructor(uint%20v)%20%7B%0A%20%20%20%20%20%20%20%20setValue(v)%3B%0A%20%0A%20%20%20%20%7D%0A%20%0A%20%20%20%20function%20getValue()%20public%20view%20returns%20(uint)%20%7B%0A%20%20%20%20%20%20%20%20return%20value%3B%0A%20%20%20%20%7D%0A%20%0A%20%20%20%20function%20setValue(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20value%20%3D%20v%3B%0A%20%20%20%20%7D%0A%20%0A%7D%0A » message= »Smart Contract version 1″ highlight= » » provider= »manual »/]

Déploiement

Le smart contract est déployé avec la valeur initiale de 100.

[pastacode lang= »javascript » manual= »%2F%2F%202_deploy_contracts.js%0Aconst%20MYCONTRACTV1%20%3D%20artifacts.require(%22.%2FMyContractV1.sol%22)%3B%0A%0Amodule.exports%20%3D%20async(deployer)%20%3D%3E%20%7B%0A%0A%20%20await%20deployer.deploy(MYCONTRACTV1%2C%20100)%3B%0A%20%20const%20contractInstance%20%3D%20await%20MYCONTRACTV1.deployed()%3B%0A%20%20console.log(%22V1%20Smart%20Contract%20address%20%3A%20%22%2CcontractInstance.address)%3B%0A%0A%20%20return%20null%3B%0A%7D%3B%0A » message= »Déploiement de la version 1″ highlight= » » provider= »manual »/]

Tests

Utiliser la console Truffle pour tester la version 1 :

[pastacode lang= »bash » manual= »truffle(ganache)%3E%20const%20contractV1%20%3D%20await%20MyContractV1.deployed(100)%3B%20%0A%20(await%20contractV1.getValue()).toString()%3Bundefined%20%0Atruffle(ganache)%3E%20%20(await%20contractV1.getValue()).toString()%3B%20%0A’100’%20%0Atruffle(ganache)%3E » message= » » highlight= » » provider= »manual »/]

Tout est OK, passons à la version 2.

Version 1 en mode évolutif (Upgradable Smart Contract)

Avant de déployer la version 2 il y a quelques étapes à suivre pour rendre notre SC évolutif et compatible avec les outils OpenZepplin.

Installation du plugin OpenZepplin pour Truffle

Il faut installer le plugin pour Truffle qui prendra en charge le travail pour nous :

npm install –save-dev @openzeppelin/truffle-upgrades

[pastacode lang= »markup » manual= »npm%20install%20–save-dev%20%40openzeppelin%2Ftruffle-upgrades%20%0Anpm%20WARN%20deprecated%20uuid%403.3.2%3A%20Please%20upgrade%20%20to%20version%207%20or%20higher.%20%20Older%20versions%20may%20use%20Math.random()%20in%20certain%20circumstances%2C%20which%20is%20known%20to%20be%20problematic.%20%20See%20https%3A%2F%2Fv8.dev%2Fblog%2Fmath-random%20for%20details.%20%0A%0Aadded%20441%20packages%2C%20removed%2023%20packages%2C%20changed%2054%20packages%2C%20and%20audited%201535%20packages%20in%2043s%20%0A%0A139%20packages%20are%20looking%20for%20funding%20%0A%20%20run%20%60npm%20fund%60%20for%20details%20%0A%0A35%20vulnerabilities%20(23%20moderate%2C%209%20high%2C%203%20critical)%20%0A%0ATo%20address%20issues%20that%20do%20not%20require%20attention%2C%20run%3A%20%0A%20%20npm%20audit%20fix%20%0A%0ASome%20issues%20need%20review%2C%20and%20may%20require%20choosing%20%0Aa%20different%20dependency.%20%0A%0ARun%20%60npm%20audit%60%20for%20details.%20″ message= »Installation plugin pour Truffle » highlight= »1″ provider= »manual »/]

Modifier le code source

Il y a 2 petites évolutions à faire sur le code de la version 1 pour qu’elle puisse être prise en compte par le plugin :

  • Supprimer le constructeur. Il est remplacer par une fonction (initialize() dans notre cas) qui fait le même travail. Cette fonction sera appelée par le plugin lors du déploiement.
  • Supprimer l’initialisation de la propriété « value »

[pastacode lang= »javascript » manual= »%2F%2F%20SPDX-License-Identifier%3A%20MIT%0Apragma%20solidity%20%3E%3D0.4.22%20%3C0.9.0%3B%0A%0A%2F%2F%2F%20%40author%20Emmanuel%20Collin%0A%2F%2F%2F%20%40notice%0A%2F%2F%2F%20%40dev%0Acontract%20MyContractV1%20%20%7B%0A%0A%20%20%20%20uint%20private%20value%3B%0A%0A%20%20%20%20function%20initialize(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20setValue(v)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20getValue()%20public%20view%20returns%20(uint)%20%7B%0A%20%20%20%20%20%20%20%20return%20value%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20setValue(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20value%20%3D%20v%3B%0A%20%20%20%20%7D%0A%0A%7D%0A » message= »Version 1 en mode évolutif » highlight= »9,11,12,13″ provider= »manual »/]

Les détails au sujet de ces 2 modifications sont donnés dans ce chapitre de la documentation du plugin.

Déploiement de la version 1

Le code de déploiement évolue aussi sensiblement pour utiliser le plugin :

[pastacode lang= »markup » manual= »%2F%2F%20migrations%2F3_deploy_upgradeable_contract.js%0Aconst%20%7B%20deployProxy%20%7D%20%3D%20require(‘%40openzeppelin%2Ftruffle-upgrades’)%3B%0A%0Aconst%20MyContractV1%20%3D%20artifacts.require(‘MyContractV1’)%3B%0A%0Amodule.exports%20%3D%20async%20function%20(deployer)%20%7B%0A%20%20await%20deployProxy(MyContractV1%2C%20%5B142%5D%2C%20%7B%20deployer%2C%20initializer%3A%20’initialize’%20%7D)%3B%0A%7D%3B » message= »Déploiement de la version 2″ highlight= » » provider= »manual »/]

Cette fois le contrat sera déployé avec la valeur initiale 142.

Résultat du déploiement :

[pastacode lang= »bash » manual= »…%0A3_deploy_upgradeable_contract.js%0A%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%0A%0A%20%20%20Replacing%20’MyContractV1’%0A%20%20%20————————%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200xd6e08f79b326fa0f2a1a6398418338dcb710f906b191236de0e68187ca6be940%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200x9F4117A5a0cC73eAc3a6c136191FceCe2710bb72%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%209%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665324320%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x6742aF78E1E4Ba1883873bEf8DB4829FA0c28b4a%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.97878906%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20136669%20(0x215dd)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.00273338%20ETH%0A%0A%0A%20%20%20Deploying%20’ProxyAdmin’%0A%20%20%20———————-%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200x652c7944ce74a2a09eed25eb459bae6e238dbcbf93809fca2ffe2277b935bf29%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200x96B5e8eB02fF5E0700732a8b6e931ABbCAE09e6c%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%2010%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665324321%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x6742aF78E1E4Ba1883873bEf8DB4829FA0c28b4a%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.96909372%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20484767%20(0x7659f)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.00969534%20ETH%0A%0A%0A%20%20%20Deploying%20’TransparentUpgradeableProxy’%0A%20%20%20—————————————%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200xa085a64260fcf1ef09aaccf347fcaafa1c9fdcaeba4c9dafeef21724008414e4%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200x67aa0b798C50EcD4320eFD8Ef0De03Fbe55D30c1%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%2011%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665324322%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x6742aF78E1E4Ba1883873bEf8DB4829FA0c28b4a%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.95696146%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20606613%20(0x94195)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.01213226%20ETH%0A%0A…%0A » message= »Résultat du déploiement » highlight= »39″ provider= »manual »/]

On constate bien le déploiement des 3 smart contracts.

Tests

Déploiement

[pastacode lang= »bash » manual= »truffle(ganache)%3E%20const%20contractV1%20%3D%20await%20MyContractV1.deployed()%3B%0Aundefined%0Atruffle(ganache)%3E%20contractV1.address%0A’0x67aa0b798C50EcD4320eFD8Ef0De03Fbe55D30c1’%0Atruffle(ganache)%3E » message= » » highlight= »4″ provider= »manual »/]

L’adresse de contractV1 est bien celle du proxy TransparentUpgradeableProxy !

Invocation du SC via le proxy

[pastacode lang= »bash » manual= »truffle(ganache)%3E%20(await%20contractV1.getValue()).toString()%3B%0A’142′ » message= »Test de la version 1 en mode proxy » highlight= » » provider= »manual »/]

Version 2

Nous pouvons maintenant passer à la version 2 de notre smart contract. Le code source est modifié pour ajouter la fonction add() qui permet d’ajouter un nombre à la propriété « value ».

Développement

[pastacode lang= »bash » manual= »%2F%2F%20SPDX-License-Identifier%3A%20MIT%0Apragma%20solidity%20%3E%3D0.4.22%20%3C0.9.0%3B%0A%0A%2F%2F%2F%20%40author%20Emmanuel%20Collin%0A%2F%2F%2F%20%40notice%0A%2F%2F%2F%20%40dev%0Acontract%20MyContractV2%20%20%7B%0A%0A%20%20%20%20uint%20private%20value%3B%0A%0A%20%20%20%20function%20initialize(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20setValue(v)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20getValue()%20public%20view%20returns%20(uint)%20%7B%0A%20%20%20%20%20%20%20%20return%20value%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20setValue(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20value%20%3D%20v%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20add(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20setValue(getValue()%20%2B%20v)%3B%0A%20%20%20%20%7D%0A%0A%7D%0A » message= »Version 2 du smart contract » highlight= »23,24,25″ provider= »manual »/]

Déploiement

[pastacode lang= »bash » manual= »const%20%7B%20upgradeProxy%20%7D%20%3D%20require(‘%40openzeppelin%2Ftruffle-upgrades’)%3B%0A%0Aconst%20MyContractV1%20%3D%20artifacts.require(‘MyContractV1’)%3B%0Aconst%20MyContractV2%20%3D%20artifacts.require(‘MyContractV2’)%3B%0A%0Amodule.exports%20%3D%20async%20function%20(deployer)%20%7B%0A%20%20const%20existing%20%3D%20await%20MyContractV1.deployed()%3B%0A%20%20await%20upgradeProxy(existing.address%2C%20MyContractV2%2C%20%7B%20deployer%20%7D)%3B%0A%7D%3B » message= »Déploiement de la version 2″ highlight= »7,8″ provider= »manual »/]

A la ligne 7, on récupère l’adresse du proxy (existing)

A la ligne 8 on modifie le proxy pour déployer la version 2 et pointer dessus.

[pastacode lang= »markup » manual= »3_deploy_upgradeable_contract.js%0A%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%0A%0A%20%20%20Replacing%20’MyContractV1’%0A%20%20%20————————%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200xe0446bf8aa2e00f93952e1f9a27dc0aea46a3f26f3efdf1329764649242f682a%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200xf778A97f5840281122061a52F33585F719E8f4c2%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%205%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665325731%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x0381962bD9B48A87534f6F7C2ceFCAE2b2E87EA0%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.98815564%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20136669%20(0x215dd)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.00273338%20ETH%0A%0A%0A%20%20%20Deploying%20’ProxyAdmin’%0A%20%20%20———————-%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200x53f9fb7b22ad68171fb06308793d6c9f1b256b7ec9b96733416ab021ee029d08%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200xCE4Bd3A1f2a37378D30f017db906E57bd6bf1824%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%206%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665325731%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x0381962bD9B48A87534f6F7C2ceFCAE2b2E87EA0%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.9784603%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20484767%20(0x7659f)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.00969534%20ETH%0A%0A%0A%20%20%20Deploying%20’TransparentUpgradeableProxy’%0A%20%20%20—————————————%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200x6c1a80930a171491d9d45d96a8d61ad18cd9bc9546a88fd9106a3adf26291688%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200x34275c222Cf18e28EbB1ecBc7c4b23aDd4baEbE7%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%207%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665325732%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x0381962bD9B48A87534f6F7C2ceFCAE2b2E87EA0%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.9663278%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20606625%20(0x941a1)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.0121325%20ETH%0A%0A%0A%20%20%20%3E%20Saving%20migration%20to%20chain.%0A%20%20%20%3E%20Saving%20artifacts%0A%20%20%20————————————-%0A%20%20%20%3E%20Total%20cost%3A%20%20%20%20%20%20%20%20%20%200.02456122%20ETH%0A%0A%0A4_deploy_upgradeable_contract_v2.js%0A%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%0A%0A%20%20%20Replacing%20’MyContractV2’%0A%20%20%20————————%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200xc5231aa4c55e56fa66e4e8caf397f7669fdbd34c768e09a9507ff8c2e0a1986c%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200x44A6b605696cB63ABc6d1670896ae38dF6988C6F%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%209%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665325734%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x0381962bD9B48A87534f6F7C2ceFCAE2b2E87EA0%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.96217872%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20179941%20(0x2bee5)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.00359882%20ETH » message= »Résultat du déploiement » highlight= »38″ provider= »manual »/]

Tests

Déploiement

[pastacode lang= »bash » manual= »truffle(ganache)%3E%20const%20contractV1%20%3D%20await%20MyContractV1.deployed()%3B%0Aundefined%0Atruffle(ganache)%3E%20const%20contractV2%20%3D%20await%20MyContractV2.at(contractV1.address)%3B%0Aundefined%0Atruffle(ganache)%3E%20contractV1.address%0A’0x34275c222Cf18e28EbB1ecBc7c4b23aDd4baEbE7’%0Atruffle(ganache)%3E%20contractV2.address%0A’0x34275c222Cf18e28EbB1ecBc7c4b23aDd4baEbE7′ » message= »Tests de la version 2″ highlight= » » provider= »manual »/]

L’adresse de la version 2 est bien celle du proxy : ‘0x34275c222Cf18e28EbB1ecBc7c4b23aDd4baEbE7’

Invocation du smart contract

[pastacode lang= »bash » manual= »truffle(ganache)%3E%20(await%20contractV2.getValue()).toString()%3B%0A’142′ » message= »Version 2 – Lecture de la valeur initiale » highlight= » » provider= »manual »/]

[pastacode lang= »bash » manual= »truffle(ganache)%3E%20await%20contractV2.add(10)%3B%0A%7B%0A%20%20tx%3A%20’0xaed8cbf957ca9909fce79a097f9fd99d751f30a30eedb86812c6d2354b190f1c’%2C%0A%20%20receipt%3A%20%7B%0A%20%20%20%20transactionHash%3A%20’0xaed8cbf957ca9909fce79a097f9fd99d751f30a30eedb86812c6d2354b190f1c’%2C%0A%20%20%20%20transactionIndex%3A%200%2C%0A%20%20%20%20blockHash%3A%20’0xfddc15ec6b90e71287d52ff3eae225024343c8b43b346e6fa1f5a23a838b8aa7’%2C%0A%20%20%20%20blockNumber%3A%2012%2C%0A%20%20%20%20from%3A%20’0x0381962bd9b48a87534f6f7c2cefcae2b2e87ea0’%2C%0A%20%20%20%20to%3A%20’0x34275c222cf18e28ebb1ecbc7c4b23add4baebe7’%2C%0A%20%20%20%20gasUsed%3A%2030476%2C%0A%20%20%20%20cumulativeGasUsed%3A%2030476%2C%0A%20%20%20%20contractAddress%3A%20null%2C%0A%20%20%20%20logs%3A%20%5B%5D%2C%0A%20%20%20%20status%3A%20true%2C%0A%20%20%20%20logsBloom%3A%20’0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000’%2C%0A%20%20%20%20rawLogs%3A%20%5B%5D%0A%20%20%7D%2C%0A%20%20logs%3A%20%5B%5D%0A%7D » message= »Version 2 – Appel de la fonction add() » highlight= » » provider= »manual »/]

[pastacode lang= »bash » manual= »truffle(ganache)%3E%20(await%20contractV2.getValue()).toString()%3B%0A’152′ » message= »Version 2 – Vérification de la nouvelle valeur » highlight= » » provider= »manual »/]

Remarques :

Que se passe-t-il si on appelle la fonction add() depuis contractV1 ?

[pastacode lang= »bash » manual= »truffle(ganache)%3E%20await%20contractV1.add(10)%3B%0AUncaught%20TypeError%3A%20contractV1.add%20is%20not%20a%20function%0A%20%20%20%20at%20evalmachine.%3Canonymous%3E%3A1%3A20″ message= »Appel de la fonction add() depuis la version 1″ highlight= »2″ provider= »manual »/]

Une erreur évidement, la fonction add() n’existe pas sur cette version.

Que renvoie la fonction getValue() appelée depuis la version 1 ?

[pastacode lang= »bash » manual= »truffle(ganache)%3E%20(await%20contractV1.getValue()).toString()%3B%0A’152′ » message= » » highlight= » » provider= »manual »/]

Elle renvoie la même chose ce qui confirme que les 2 versions partagent le même contexte, les mêmes données.

Version 3

La version 3 vise à ajouter une nouvelle donnée (propriété) au smart contract (count) ainsi qu’une fonction pour en consulter la valeur (getCount). « count » est un entier qui est incrémenté automatiquement à chaque fois que la valeur de la propriété value change.

Développement

[pastacode lang= »bash » manual= »%2F%2F%20SPDX-License-Identifier%3A%20MIT%0Apragma%20solidity%20%3E%3D0.4.22%20%3C0.9.0%3B%0A%0A%2F%2F%2F%20%40author%20Emmanuel%20Collin%0A%2F%2F%2F%20%40notice%0A%2F%2F%2F%20%40dev%0Acontract%20MyContractV3%20%20%7B%0A%0A%20%20%20%20uint%20private%20value%3B%0A%20%20%20%20uint%20private%20count%3B%0A%0A%20%20%20%20function%20initialize(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20setValue(v)%3B%0A%20%20%20%20%20%20%20%20count%20%3D%200%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20getValue()%20public%20view%20returns%20(uint)%20%7B%0A%20%20%20%20%20%20%20%20return%20value%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20setValue(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20value%20%3D%20v%3B%0A%20%20%20%20%20%20%20%20count%2B%2B%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20add(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20setValue(getValue()%20%2B%20v)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20getCount()%20public%20view%20returns%20(uint)%20%7B%0A%20%20%20%20%20%20%20%20return%20count%3B%0A%20%20%20%20%7D%0A%0A%7D%0A » message= »Version 3 du smart contract » highlight= »10,30,31,32″ provider= »manual »/]

Déploiement

[pastacode lang= »bash » manual= »const%20%7B%20upgradeProxy%20%7D%20%3D%20require(‘%40openzeppelin%2Ftruffle-upgrades’)%3B%0A%0Aconst%20MyContractV1%20%3D%20artifacts.require(‘MyContractV1’)%3B%0Aconst%20MyContractV3%20%3D%20artifacts.require(‘MyContractV3’)%3B%0A%0Amodule.exports%20%3D%20async%20function%20(deployer)%20%7B%0A%20%20const%20existing%20%3D%20await%20MyContractV1.deployed()%3B%0A%20%20await%20upgradeProxy(existing.address%2C%20MyContractV3%2C%20%7B%20deployer%20%7D)%3B%0A%7D%3B » message= »Déploiement de la version 3″ highlight= » » provider= »manual »/]

Tests

[pastacode lang= »bash » manual= »truffle(ganache)%3E%20const%20contractV1%20%3D%20await%20MyContractV1.deployed()%3B%0Aundefined%0Atruffle(ganache)%3E%20const%20contractV2%20%3D%20await%20MyContractV2.at(contractV1.address)%3B%0Aundefined%0Atruffle(ganache)%3E%20const%20contractV3%20%3D%20await%20MyContractV3.at(contractV1.address)%3B%0Aundefined%0Atruffle(ganache)%3E%20contractV1.address%0AcontractV2.address%0AcontractV3.address%0A’0xfF8b6f16Bedb4FF11098Ab06649Ddd0B0c8A9720’%0Atruffle(ganache)%3E%20’0xfF8b6f16Bedb4FF11098Ab06649Ddd0B0c8A9720’%0Atruffle(ganache)%3E%20’0xfF8b6f16Bedb4FF11098Ab06649Ddd0B0c8A9720’%0Atruffle(ganache)%3E%20(await%20contractV3.getValue()).toString()%3B%0A’142’%0Atruffle(ganache)%3E%20(await%20contractV3.getCount()).toString()%3B%0A’0’%0Atruffle(ganache)%3E%20await%20contractV3.add(10)%3B%0A%7B%0A%20%20tx%3A%20’0xffef16f8589b23cece9348a6d248c16a663082a74b55b022128548c382da0731’%2C%0A%20%20receipt%3A%20%7B%0A%20%20%20%20transactionHash%3A%20’0xffef16f8589b23cece9348a6d248c16a663082a74b55b022128548c382da0731’%2C%0A%20%20%20%20transactionIndex%3A%200%2C%0A%20%20%20%20blockHash%3A%20’0x3fc626025cee38042d88556d35fa546b656fcf22487c1a7afcde635bba533176’%2C%0A%20%20%20%20blockNumber%3A%2015%2C%0A%20%20%20%20from%3A%20’0x21a554540e9a005ef517a2bbe7e3a447aa64290f’%2C%0A%20%20%20%20to%3A%20’0xff8b6f16bedb4ff11098ab06649ddd0b0c8a9720’%2C%0A%20%20%20%20gasUsed%3A%2051436%2C%0A%20%20%20%20cumulativeGasUsed%3A%2051436%2C%0A%20%20%20%20contractAddress%3A%20null%2C%0A%20%20%20%20logs%3A%20%5B%5D%2C%0A%20%20%20%20status%3A%20true%2C%0A%20%20%20%20logsBloom%3A%20’0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000’%2C%0A%20%20%20%20rawLogs%3A%20%5B%5D%0A%20%20%7D%2C%0A%20%20logs%3A%20%5B%5D%0A%7D%0Atruffle(ganache)%3E%20(await%20contractV3.getValue()).toString()%3B%0A’152’%0Atruffle(ganache)%3E%20(await%20contractV3.getCount()).toString()%3B%0A’1’%0Atruffle(ganache)%3E » message= »Tests de la version 3″ highlight= » » provider= »manual »/]

All good !

Références