La programmation des smart contracts ressemble à bien des égards à la programmation traditionnelle. A première vue, un code smart contract est simple et paraît familier aux programmeurs. De ce fait, nous avons ont souvent l’impression de devoir juste apprendre une nouvelle syntaxe avant de devenir opérationnels.
En se penchant sur des cas concrets (ne serait-ce que pour formuler le cahier des charges) on se rend compte que cette tâche est en réalité des plus difficiles. Elle soulève d’importants défis en terme de sécurité.
En premier lieu, les smart contracts travaillent en transférant directement des unités monétaires (jetons ou crypto-monnaie). Chaque développeur devient ainsi fatalement responsable de l’argent d’autrui, comme s’il travaillait tout le temps sur les serveurs d’une grande banque.
Les contrats sont enracinés dans le concret puisque les unités virtuelles qu’ils manipulent ont une valeur réelle et s’échangent partout contre des vrais euros. Si vous jouez avec de l’argent dans un smart contract bugged, vous risquez sérieusement de le perdre à jamais. De plus, la programmation de smart contracts exige de penser selon une perspective économique que la plupart des programmeurs ne voit pas du premier coup.
A titre d’exemple le SolarCoin est le jeton étalon mondial de la production d’énergie solaire. Bien qu’il ne soit que le jeton d’une Dapp, il s’échange déjà sur plusieurs plateformes contre des monnaies fiduciaires. Les smart contracts de cette Dapp doivent garantir une absence totale de bugs majeurs et mineurs.
Avec les smart contracts on ne développe pas une interface web, un blog ou un jeu vidéo. On devient tous, sur le champ, des développeurs d’une solution à la PayPal, ce qui est une nouveauté absolue.
Même les programmeurs qui font de l’e-commerce, et donc font transiter de l’argent, ne le manipulent pas directement. Ils exploitent une API (d’une banque le plus souvent) qui fait le pont entre leur site et l’argent. En cas de problème avec l’argent, la responsabilité est du fournisseur de l’API puisqu’elle encapsule les parties critiques.
Le bitcoin et l’ether sont du programmable money et les programmeurs se retrouvent à écrire des lignes de code qui changent directement les soldes des comptes-clients… avec toute la responsabilité que cela comporte.
Dans une blockchain on peut même cramer (burn) de l’argent à jamais: une technique qu’on utilise souvent pour horodater des documents. Ce burning délibéré s’est fait parfois à grande échelle. En envoyant vos bitcoin à l’adresse
1CounterpartyXXXXXXXXXXXXXXXUWLpVr
une adresse publique qui ne correspond à aucune clé privée, vous brûlez vos bitcoins à jamais. Et pourtant cette adresse a reçu 978.060.24 $ qui sont maintenant perdus pour toujours. La motivation est simple: Counterparty a émis sa crypto-monnaie (XCP) en échange de ces bitcoins détruits (proof-of-burn).
S’il est possible de brûler des bitcoin pour une raison voulue, il est aussi techniquement possible de les perdre par erreur.
***
Il existe de nombreux pièges dans la conception de smart contracts. La bonne nouvelle est que les développeurs commencent à définir des classes d’erreurs typiques et suggèrent des façons de les fixer/éviter. Hélas, même si cela donne lieu à des best practices de la programmation blockchain, il est évidemment impossible de prévoir tous les cas de figure.
Puisque ces bugs sont liés à la nature unique des smart contracts, on ne peut pas réutiliser des connaissances qui viendraient du développement logiciel traditionnel. Il n’y a pas de problèmes typiques comme l’overflow d’un buffer, des valeurs temporaires retournées, des races conditions ou des memory leaks… il n’y a pas non plus les erreurs les plus typiques de SQL.
Tout cela est caché dans les détails du logiciel qui fait tourner la blockchain: une black-box pour le développeur. Par dessus, il faut qu’il construise son appli dans un monde nouveau, trop vierge pour s’inspirer d’un précédent, trop complexe pour qu’il puisse garantir l’absence de bugs sans une étude complexe et approfondie.
La pratique montre que même dans des cas smart contracts très simples (un jeu de roulette ou un Pierre–feuille–ciseaux) des bugs jaillissent après plusieurs jours de test et/ou des relectures minutieuses.
***
Un smart contract est un programme informatique qui tourne dans la blockchain, c’est-à-dire, qui est exécuté par tous les noeuds consensus du réseau peer-to-peer.
Pour rappel un smart contract est fait de trois parties:
- le code du programme
- une zone de stockage
- le solde du compte.
N’importe quel utilisateur peut créer un contrat en postant une transaction vers la blockchain. Le code d’un contrat est figé à la création et ne peut pas être changé par la suite
Les smart contracts doivent:
- assurer la cohérence des balances des comptes (sans la moindre exception)
- prévoir toutes les tentatives de fraude des acteurs qui voudraient maximiser leurs gains contre le système. Elles sont arbitraires, nombreuses et souvent augmentent de manière exponentielle avec le nombre de lignes de code.
- prévenir plutôt que guérir. Une fois que le smart contract est publié dans la blockchain, c’est définitif.
- …
C’est difficile. Définir des smart contracts revient à programmer des machines à états complexes (state machines), c’est pourquoi on y trouve les erreurs logiques généralement observées dans le codage de ces machines.
Le cas le plus simple d’erreur logique est celui d’un contrat qui perd de l’argent dans des situations d’angle mort: souvent des ramifications de structures de contrôle qui forment un cul de sac imprévu dans lequel l’argent d’un utilisateur reste piégé pour toujours.
Ces anomalies se forment le plus souvent à cause d’un oubli d’un cas logique qui reste non traité ou à cause d’un mismatch des conditions dans un contrôle (très souvent un if-else).
Ce n’est qu’un petit aperçu des bugs possibles. On peut en classer beaucoup d’autres et il y en a un nombre infini parmi les inclassables.
***
Et on n’a pas encore parlé des bugs spécifiques à l’architecture d’une certaine blockchain. Par exemple, le call-stack bug d’Ethereum.
Un contrat peut envoyer un message à un autre contrat, qui peut à son tour envoyer un autre message à un autre contrat. Il se trouve que la blockhain Ethereum (uniquement) limite la pile d’appels résultant à la taille fixe de 1024. Si la profondeur de la pile est proche de cette limite quand l’instruction d’un certain contrat est atteinte, alors des instructions du code peuvent être ignorées. Si malencontreusement ces instructions concernent de l’argent, l’utilisateur en subira les dommages, par exemple il ne sera pas payé dans un jeu de roulette alors qu’il avait gagné.
Ce même bug s’est manifesté dans le jeu Etherpot, une application loterie construite sur Ethereum et disponible pour le grand public.
***
Un grand pouvoir va de pair avec des grandes responsabilités. Une fois publié, le code d’Ethereum fonctionne exactement comme programmé… pour toujours. C’est un des avantages principaux de la plateforme: le code interagit toujours comme promis: il ne peut pas être falsifié et il n’a jamais de downtime. Mais tout ça va de pair avec un prix à payer.
Les inévitables bugs qui guettent tout code informatique peuvent surgir de rien à tout moment. Dans Ethereum par exemple, il y a déjà eu cas où du code, qu’on ne peut plus remplacer, a causé des soucis majeurs.
Un autre exemple? Récemment un développeur se plaignait d’avoir perdu 11 ETH pour un simple faute de frappe. La voyez-vous ?
eth.sendTransaction({from: eth.accounts[1],
to:’ 0x19d……………………………………………6a7g’,
value: web3.toWei(11, « Ether »), gas: 500000})
Il y a un espace de trop après le to, entre le guillemet ‘ et le 0x. Cette erreur fait que l’adresse vers la quelle on envoie les 11 ETH n’est plus la bonne (0x19d… ) mais le pointeur NULL 0x00.
En feuilletant les données publiques de la blockchain Ethereum, on voit que d’autres personnes sont tombées dans le piège.
Le 8 août 2015 une personne a perdu ainsi 2000 ETH.
Au total l’adresse 0x00000, qui n’appartient à personne, a englouti à jamais 5.107 ETH en 9481 transactions.
Dans ce contexte délicat comment s’assurer qu’il n’y a pas de bugs en production? Une seule solution: confier son code à des professionnels.
Une réflexion au sujet de « La programmation de smart contracts: une opération hautement délicate. »