Affrontement de contrat intelligent: Hyperledger Fabric vs MultiChain vs Ethereum vs Corda

Nœud source: 1585333

Il y a plus d'une façon de mettre du code sur une blockchain

Dans la plupart des discussions sur les chaînes de blocs, la notion de «contrats intelligents» ne tarde pas à apparaître. Dans l'imagination populaire, les contrats intelligents automatisent l'exécution des interactions entre les parties, sans avoir besoin d'un intermédiaire de confiance. En exprimant les relations juridiques en code plutôt qu'en mots, ils promettent de permettre que les transactions se déroulent directement et sans erreur, délibérée ou non.

D'un point de vue technique, un contrat intelligent est quelque chose de plus spécifique : un code informatique qui vit sur une blockchain et définit les règles des transactions de cette chaîne. Cette description semble assez simple, mais derrière elle se cache une grande variation dans la façon dont ces règles sont exprimées, exécutées et validées. Lors du choix d'une plateforme blockchain pour une nouvelle application, la question « Cette plateforme prend-elle en charge les contrats intelligents ? n'est pas le bon à demander. Au lieu de cela, nous devons nous demander : "Quel type de contrats intelligents cette plateforme prend-elle en charge ?"

Dans cet article, mon objectif est d'examiner certaines des principales différences entre les approches de contrat intelligent et les compromis qu'elles représentent. Je vais le faire en examinant quatre plates-formes de chaînes de blocs d'entreprise populaires qui prennent en charge une forme de code en ligne personnalisé. Tout d'abord, IBM Hyperledger Fabric, qui appelle ses contrats «chaincode». Deuxièmement, notre plateforme MultiChain, qui présente filtres intelligents dans la version 2.0. Troisième, Ethereum (et son autorisé Quorum ainsi que Terrier spin-offs), qui a popularisé le nom de «contrat intelligent». Et enfin, R3 Corda, qui fait référence aux «contrats» dans ses transactions. Malgré toutes les terminologies différentes, en fin de compte, toutes ces références se réfèrent à la même chose - un code spécifique à l'application qui définit les règles d'une chaîne.

Avant d'aller plus loin, je dois avertir le lecteur qu'une grande partie du contenu suivant est de nature technique et suppose une certaine familiarité avec la programmation générale et les concepts de base de données. Pour le meilleur ou pour le pire, cela ne peut être évité - sans entrer dans les détails, il est impossible de prendre une décision éclairée quant à l'utilisation d'une blockchain pour un projet particulier, et (si oui) le bon type de blockchain à utiliser.

Les bases de la blockchain

Commençons par un peu de contexte. Imaginez une application partagée par plusieurs organisations, basée sur une base de données sous-jacente. Dans une architecture centralisée traditionnelle, cette base de données est hébergée et administrée par une seule partie à laquelle tous les participants font confiance, même s'ils ne se font pas confiance. Les transactions qui modifient la base de données ne sont initiées que par des applications sur les systèmes de cette partie centrale, souvent en réponse aux messages reçus des participants. La base de données fait simplement ce qu'on lui dit, car l'application est implicitement approuvée pour ne lui envoyer que des transactions qui ont du sens.

Les blockchains offrent un autre moyen de gérer une base de données partagée, sans intermédiaire de confiance. Dans une blockchain, chaque participant exécute un «nœud» qui détient une copie de la base de données et traite indépendamment les transactions qui la modifient. Les participants sont identifiés à l'aide de clés publiques ou «adresses», chacune ayant une clé privée correspondante connue uniquement du propriétaire de l'identité. Bien que les transactions puissent être créées par n'importe quel nœud, elles sont «signées numériquement» par la clé privée de leur initiateur afin de prouver leur origine.

Les nœuds se connectent les uns aux autres de manière poste à poste, propageant rapidement les transactions et les «blocs» dans lesquels elles sont horodatées et confirmées sur le réseau. La blockchain elle-même est littéralement une chaîne de ces blocs, qui forme un journal ordonné de chaque transaction historique. Un «algorithme de consensus» est utilisé pour garantir que tous les nœuds parviennent à un accord sur le contenu de la blockchain, sans nécessiter de contrôle centralisé. (Notez que certaines de ces descriptions ne s'appliquent pas à Corda, dans lequel chaque nœud n'a qu'une copie partielle de la base de données et il n'y a pas de blockchain globale. Nous en reparlerons plus tard.)

En principe, toute application de base de données partagée peut être architecturée en utilisant une blockchain en son cœur. Mais cela crée un certain nombre de défis techniques qui n'existent pas dans un scénario centralisé:

  • Règles de transaction. Si un participant peut modifier directement la base de données, comment pouvons-nous nous assurer qu'il respecte les règles de l'application? Qu'est-ce qui empêche un utilisateur de corrompre le contenu de la base de données de manière libre-service?
  • Déterminisme. Une fois ces règles définies, elles seront appliquées plusieurs fois par plusieurs nœuds lors du traitement des transactions pour leur propre copie de la base de données. Comment s'assurer que chaque nœud obtient exactement le même résultat?
  • Prévention des conflits. Sans coordination centrale, comment traiter deux transactions qui respectent chacune les règles de l'application, mais qui sont néanmoins en conflit? Les conflits peuvent provenir d'une tentative délibérée de jouer le système, ou être le résultat innocent de la malchance et du timing.

Alors, où les contrats intelligents, les filtres intelligents et le code de chaîne entrent-ils en jeu? Leur objectif principal est de travailler avec l'infrastructure sous-jacente d'une blockchain afin de résoudre ces défis. Les contrats intelligents sont l'équivalent décentralisé du code d'application - au lieu de s'exécuter en un seul endroit central, ils s'exécutent sur plusieurs nœuds de la blockchain, créant ou validant les transactions qui modifient le contenu de cette base de données.

Commençons par les règles de transaction, le premier de ces défis, et voyons comment elles sont exprimées respectivement dans Fabric, MultiChain, Ethereum et Corda.

Règles de transaction

Les règles de transaction remplissent une fonction spécifique dans les bases de données basées sur la blockchain - restreignant la transformations qui peut être effectuée sur l'état de cette base de données. Cela est nécessaire car les transactions d'une blockchain peuvent être lancées par n'importe lequel de ses participants, et ces participants ne se font pas suffisamment confiance pour leur permettre de modifier la base de données à volonté.

Voyons deux exemples de la nécessité de règles de transaction. Tout d'abord, imaginez une blockchain conçue pour agréger et horodater des documents PDF publiés par ses participants. Dans ce cas, personne ne devrait avoir le droit de supprimer ou de modifier des documents, car cela compromettrait la finalité du système - la persistance des documents. Deuxièmement, considérons une blockchain représentant un grand livre financier partagé, qui garde la trace des soldes de ses utilisateurs. Nous ne pouvons pas permettre à un participant de gonfler arbitrairement son propre solde ou de prendre l'argent des autres.

Entrées et sorties

Nos plateformes de blockchain reposent sur deux grandes approches pour exprimer les règles de transaction. Le premier, que j'appelle le «modèle entrée-sortie», est utilisé dans MultiChain et Corda. Ici, les transactions répertorient explicitement les lignes de la base de données ou «états» qu'elles suppriment et créent, formant respectivement un ensemble «d'entrées» et de «sorties». La modification d'une ligne est exprimée comme l'opération équivalente de suppression de cette ligne et de création d'une nouvelle à sa place.

Étant donné que les lignes de la base de données ne sont supprimées que dans les entrées et uniquement créées dans les sorties, chaque entrée doit «dépenser» la sortie d'une transaction précédente. L'état actuel de la base de données est défini comme l'ensemble des «sorties de transaction non dépensées» ou «UTXO», c'est-à-dire les sorties des transactions précédentes qui n'ont pas encore été utilisées. Les transactions peuvent également contenir des informations supplémentaires, appelées «métadonnées», «commandes» ou «pièces jointes», qui ne font pas partie de la base de données mais aident à définir leur signification ou leur objectif.

Compte tenu de ces trois ensembles d'entrées, de sorties et de métadonnées, la validité d'une transaction dans MultiChain ou Corda est définie par un code qui peut effectuer des calculs arbitraires sur ces ensembles. Ce code peut valider la transaction, ou bien renvoyer une erreur avec une explication correspondante. Vous pouvez considérer le modèle d'entrées-sorties comme un «inspecteur» automatisé tenant une liste de contrôle qui garantit que les transactions suivent chaque règle. Si la transaction échoue à l'un de ces contrôles, elle sera automatiquement rejetée par tous les nœuds du réseau.

Il convient de noter que, malgré le partage du modèle d'entrée-sortie, MultiChain et Corda l'implémentent très différemment. Dans MultiChain, les sorties peuvent contenir des actifs et / ou des données au format JSON, texte ou binaire. Les règles sont définies dans des «filtres de transaction» ou des «filtres de flux», qui peuvent être définis pour vérifier toutes les transactions, ou uniquement celles impliquant des actifs ou des groupes de données particuliers. En revanche, un «état» de sortie Corda est représenté par un objet dans le langage de programmation Java ou Kotlin, avec des champs de données définis. Les règles de Corda sont définies dans des «contrats» qui sont attachés à des États spécifiques, et le contrat d'un État n'est appliqué qu'aux transactions qui contiennent cet État dans ses entrées ou sorties. Cela concerne Corda modèle de visibilité inhabituel, dans lequel les transactions ne peuvent être vues que par leurs contreparties ou celles dont elles affectent les transactions ultérieures.

Contrats et messages

La deuxième approche, que j'appelle le «modèle de contrat-message», est utilisée dans Hyperledger Fabric et Ethereum. Ici, plusieurs «contrats intelligents» ou «chaincodes» peuvent être créés sur la blockchain, et chacun a sa propre base de données et le code associé. La base de données d'un contrat ne peut être modifiée que par son code, plutôt que directement par des transactions blockchain. Ce modèle de conception est similaire à «l'encapsulation» du code et des données dans la programmation orientée objet.

Avec ce modèle, une transaction blockchain commence comme un message envoyé à un contrat, avec certains paramètres ou données facultatifs. Le code du contrat est exécuté en réaction au message et aux paramètres, et est libre de lire et d'écrire sa propre base de données dans le cadre de cette réaction. Les contrats peuvent également envoyer des messages à d'autres contrats, mais ne peuvent pas accéder directement aux bases de données des autres. Dans le langage des bases de données relationnelles, les contrats agissent comme forcée «Procédures stockées», où tout accès à la base de données passe par un code prédéfini.

Fabric et Quorum, une variante d'Ethereum, compliquent cette image en permettant à un réseau de définir plusieurs «canaux» ou «états privés». L'objectif est d'atténuer le problème de la confidentialité de la blockchain en créant des environnements séparés, dont chacun n'est visible que pour un sous-groupe particulier de participants. Bien que cela semble prometteur en théorie, en réalité, les contrats et les données de chaque canal ou État privé sont isolés de ceux des autres. Par conséquent, en termes de contrats intelligents, ces environnements sont équivalents à des chaînes de blocs distinctes.

Exemples de règles

Voyons comment mettre en œuvre les règles de transaction pour un grand livre financier à actif unique avec ces deux modèles. Chaque ligne de la base de données de notre grand livre comporte deux colonnes, contenant l'adresse du propriétaire et la quantité de l'actif détenu. Dans le modèle entrée-sortie, les transactions doivent remplir deux conditions:

  1. La quantité totale d'actifs dans les sorties d'une transaction doit correspondre au total dans ses entrées. Cela empêche les utilisateurs de créer ou de supprimer de l'argent arbitrairement.
  2. Chaque transaction doit être signée par le propriétaire de chacune de ses entrées. Cela empêche les utilisateurs de dépenser leur argent sans autorisation.

Ensemble, ces deux conditions suffisent pour créer un système financier simple mais viable.

Dans le modèle de contrat-message, le contrat de l'actif prend en charge un message «envoyer le paiement», qui prend trois paramètres: l'adresse de l'expéditeur, l'adresse du destinataire et la quantité à envoyer. En réponse, le contrat exécute les quatre étapes suivantes:

  1. Vérifiez que la transaction a été signée par l'expéditeur.
  2. Vérifiez que l'expéditeur dispose de fonds suffisants.
  3. Déduisez la quantité demandée de la ligne de l'expéditeur.
  4. Ajoutez cette quantité à la ligne du destinataire.

Si l'un des chèques des deux premières étapes échoue, le contrat sera annulé et aucun paiement ne sera effectué.

Les modèles d'entrée-sortie et de contrat-message sont donc des moyens efficaces de définir des règles de transaction et de sécuriser une base de données partagée. En effet, sur un plan théorique, chacun de ces modèles peut être utilisé pour simuler l'autre. En pratique cependant, le modèle le plus approprié dépendra de l'application en cours de construction. Chaque transaction affecte-t-elle peu ou beaucoup d'informations? Avons-nous besoin de garantir l'indépendance des transactions? Chaque élément de données a-t-il un propriétaire clair ou existe-t-il un état global à partager?

Il est hors de notre portée ici d'explorer comment les réponses devraient influencer un choix entre ces deux modèles. Mais en règle générale, lors du développement d'une nouvelle application blockchain, cela vaut la peine d'essayer d'exprimer ses règles de transaction sous les deux formes, et de voir ce qui convient plus naturellement. La différence s'exprimera en termes de: (a) facilité de programmation, (b) exigences de stockage et débit, et (c) vitesse de détection des conflits. Nous parlerons plus en détail de ce dernier numéro plus tard.

Règles intégrées

En ce qui concerne les règles de transaction, MultiChain diffère spécifiquement de Fabric, Ethereum et Corda. Contrairement à ces autres plates-formes, MultiChain a plusieurs abstractions intégrées qui fournissent des blocs de construction de base pour les applications pilotées par la chaîne de blocs, sans exigeant les développeurs d'écrire leur propre code. Ces abstractions couvrent trois domaines qui sont généralement nécessaires: (a) les autorisations dynamiques, (b) les actifs transférables et (c) le stockage des données.

Par exemple, MultiChain gère les autorisations pour se connecter au réseau, envoyer et recevoir des transactions, créer des actifs ou des flux ou contrôler les autorisations d'autres utilisateurs. De multiples actifs fongibles peuvent être émis, transférés, mis hors service ou échangés de manière sûre et atomique. Un nombre illimité de «flux» peut être créé sur une chaîne, pour la publication, l'indexation et la récupération de données en chaîne ou hors chaîne au format JSON, texte ou binaire. Toutes les règles de transaction pour ces abstractions sont disponibles immédiatement.

Lors du développement d'une application sur MultiChain, il est possible d'ignorer cette fonctionnalité intégrée et d'exprimer les règles de transaction à l'aide de filtres intelligents uniquement. Cependant, les filtres intelligents sont conçus pour fonctionner avec ses abstractions intégrées, en permettant à leur comportement par défaut d'être limité de manière personnalisée. Par exemple, l'autorisation pour certaines activités peut être contrôlée par des administrateurs spécifiques, plutôt que par le comportement par défaut que n'importe quel administrateur fera. Le transfert de certains actifs peut être limité dans le temps ou nécessiter une approbation supplémentaire au-dessus d'un certain montant. Les données d'un flux particulier peuvent être validées pour garantir qu'elles ne sont constituées que de structures JSON avec des champs et des valeurs obligatoires.

Dans tous ces cas, les filtres intelligents créent des exigences supplémentaires pour les transactions à valider, mais ne supprimez les règles simples qui sont intégrées. Cela peut aider à résoudre l'un des principaux défis des applications blockchain: le fait qu'un bogue dans du code en chaîne peut entraîner des conséquences désastreuses. Nous avons vu d'innombrables exemples de ce problème dans la blockchain Ethereum publique, le plus célèbre dans le Décès du DAO et par Bogues multisignatures de parité. Enquêtes plus larges ont trouvé un grand nombre de vulnérabilités courantes dans les contrats intelligents Ethereum qui permettent aux attaquants de voler ou de geler les fonds d'autres personnes.

Bien sûr, les filtres intelligents MultiChain peuvent également contenir des bogues, mais leurs conséquences ont une portée plus limitée. Par exemple, les règles d'actif intégrées empêchent un utilisateur de dépenser l'argent d'un autre ou de faire disparaître accidentellement son propre argent, quelle que soit la logique d'un filtre intelligent. Si un bug est trouvé dans un filtre intelligent, il peut être désactivé et remplacé par une version corrigée, tandis que l'intégrité de base du registre est protégée. Philosophiquement, MultiChain est plus proche des architectures de base de données traditionnelles, où la plate-forme de base de données fournit un certain nombre d'abstractions intégrées, telles que des colonnes, des tables, des index et des contraintes. Des fonctionnalités plus puissantes telles que les déclencheurs et les procédures stockées peuvent éventuellement être codées par les développeurs d'applications, dans les cas où elles sont réellement nécessaires.

Règles de transaction Tissu MultiChain Ethereum Corde
Modèle Contrat – message Entrée sortie Contrat – message Entrée sortie
Intégrés Aucun Autorisations +
actifs + flux
Aucun Aucun

Déterminisme

Passons à la prochaine partie de notre confrontation. Quelle que soit l'approche que nous choisissons, les règles de transaction personnalisées d'une application blockchain sont exprimées sous forme de code informatique écrit par les développeurs d'applications. Et contrairement aux applications centralisées, ce code va être exécuté plus d'une fois et à plus d'un endroit pour chaque transaction. En effet, plusieurs nœuds de chaîne de blocs appartenant à différents participants doivent chacun vérifier et / ou exécuter cette transaction pour eux-mêmes.

Cette exécution répétée et redondante du code introduit une nouvelle exigence que l'on trouve rarement dans les applications centralisées: le déterminisme. Dans le contexte du calcul, le déterminisme signifie qu'un morceau de code donnera toujours la même réponse pour les mêmes paramètres, peu importe où et quand il est exécuté. Ceci est absolument crucial pour le code qui interagit avec une blockchain car, sans déterminisme, le consensus entre les nœuds de cette chaîne peut briser de manière catastrophique.

Voyons à quoi cela ressemble dans la pratique, d'abord dans le modèle d'entrée-sortie. Si deux nœuds ont une opinion différente sur la validité d'une transaction, l'un acceptera un bloc contenant cette transaction et l'autre non. Étant donné que chaque bloc renvoie explicitement à un bloc précédent, cela créera une «fourchette» permanente dans le réseau, avec un ou plusieurs nœuds n'acceptant pas l'opinion majoritaire sur le contenu de la blockchain à partir de ce moment. Les nœuds de la minorité seront coupés de l'état évolutif de la base de données et ne pourront plus utiliser efficacement l'application.

Voyons maintenant ce qui se passe si le consensus tombe en panne dans le modèle de contrat-message. Si deux nœuds ont une opinion différente sur la façon dont un contrat doit répondre à un message particulier, cela peut entraîner une différence dans le contenu de leurs bases de données. Cela peut à son tour affecter la réponse du contrat aux futurs messages, y compris les messages qu'il envoie à d'autres contrats. Le résultat final est une divergence croissante entre la vue des différents nœuds sur l'état de la base de données. (Le champ «racine de l'État» dans les blocs Ethereum garantit que toute différence dans les réponses des contrats conduit immédiatement à une fourche de chaîne de blocs totalement catastrophique, plutôt que de risquer de rester caché pendant une période de temps.)

Sources de non-déterminisme

Le non-déterminisme dans le code de la blockchain est donc clairement un problème. Mais si les éléments de base du calcul, tels que l'arithmétique, sont déterministes, de quoi devons-nous nous inquiéter? Eh bien, il s'avère que plusieurs choses:

  • De toute évidence, les générateurs de nombres aléatoires, car par définition, ils sont conçus pour produire un résultat différent à chaque fois.
  • Vérification de l'heure actuelle, car les nœuds ne traiteront pas les transactions exactement en même temps et, en tout état de cause, leurs horloges peuvent ne pas être synchronisées. (Il est toujours possible d'implémenter des règles dépendantes du temps en faisant référence aux horodatages dans la blockchain elle-même.)
  • Interroger des ressources externes telles qu'Internet, des fichiers disque ou d'autres programmes exécutés sur un ordinateur. Ces ressources ne peuvent pas être garanties pour toujours donner la même réponse et peuvent devenir indisponibles.
  • Exécuter plusieurs morceaux de code dans des «threads» parallèles, car cela conduit à une «condition de concurrence critique» où l'ordre dans lequel ces processus se terminent ne peut pas être prévu.
  • Effectuer des calculs en virgule flottante qui peuvent donner des réponses même très différentes sur différentes architectures de processeur d'ordinateur.

Nos quatre plateformes de blockchain utilisent plusieurs approches différentes pour éviter ces pièges.

Exécution déterministe

Commençons par Ethereum, car son approche est la plus «pure». Les contrats Ethereum sont exprimés dans un format spécial appelé «Ethereum bytecode», qui est exécuté par la machine virtuelle Ethereum («EVM»). Les programmeurs n'écrivent pas directement le bytecode, mais le génèrent ou le «compilent» à partir d'un langage de programmation de type JavaScript appelé Solidity. (D'autres langues étaient disponibles mais ont depuis été dépréciées.) Le déterminisme est garanti par le fait que le bytecode Solidity et Ethereum ne peut coder aucune opération non déterministe - c'est aussi simple que cela.

Les filtres MultiChain et les contrats Corda choisissent une approche différente, en adaptant les langages de programmation et les environnements d'exécution existants. MultiChain utilise JavaScript exécuté dans Google V8 , qui constitue également le cœur du navigateur Chrome et de la plateforme Node.js, mais avec des sources de non-déterminisme désactivées. De même, Corda utilise Java ou Kotlin, tous deux compilés en «Java bytecode» qui s'exécute dans une machine virtuelle Java («JVM»). Pour l'instant, Corda utilise la machine virtuelle Java non déterministe standard d'Oracle, mais des travaux sont en cours pour intégrer un version déterministe. En attendant, les développeurs de contrats Corda doivent veiller à ne pas autoriser le non-déterminisme dans leur code.

Comment le purisme d'Ethereum se compare-t-il à l'approche évolutive adoptée par MultiChain et Corda? Le principal avantage pour Ethereum est la minimisation des risques - une machine virtuelle conçue à cet effet est moins susceptible de contenir une source involontaire de non-déterminisme. Bien qu'une telle omission puisse être corrigée par une mise à jour logicielle, elle perturberait toute chaîne qui aurait eu la malchance de la rencontrer. Le problème d'Ethereum, cependant, est que Solidity et l'EVM constituent un écosystème minuscule et naissant dans le contexte plus large des langages de programmation et des environnements d'exécution. En comparaison, JavaScript et Java sont les deux principales langues sur Github, s'exécutent sur des milliards d'appareils numériques et ont des durées d'exécution optimisées au fil des décennies. Vraisemblablement, c'est pourquoi la blockchain publique Ethereum envisage une transition vers eWASM, un fork déterministe de la nouvelle norme WebAssembly.

Déterminisme par endossement

En matière de déterminisme, Hyperledger Fabric adopte une approche complètement différente. Dans Fabric, lorsqu'un nœud «client» souhaite envoyer un message à un code de chaîne, il envoie d'abord ce message à certains nœuds «endosseurs». Chacun de ces nœuds exécute le code de chaîne indépendamment, formant une opinion sur le message effet sur la base de données de ce chaincode. Ces avis sont renvoyés au client accompagnés d'une signature numérique qui constitue une «approbation» formelle. Si le client reçoit suffisamment de recommandations du résultat escompté, il crée une transaction contenant ces recommandations et la diffuse pour inclusion dans la chaîne.

Afin de garantir le déterminisme, chaque élément de code à barres possède une «politique d'approbation» qui définit exactement le niveau d'approbation requis pour rendre ses transactions valides. Par exemple, la politique d'un code de chaîne peut indiquer que des recommandations sont requises d'au moins la moitié des nœuds de la chaîne de blocs. Un autre pourrait nécessiter l'approbation de l'une des trois parties de confiance. Dans tous les cas, chaque nœud peut vérifier indépendamment si les avenants nécessaires ont été reçus.

Pour clarifier la différence, le déterminisme dans la plupart des plateformes de blockchain est basé sur la question: "Quel est le résultat de l'exécution de ce code sur ces données?" - et nous devons être absolument sûrs que chaque nœud répondra à cette question de manière identique. En revanche, le déterminisme dans Fabric est basé sur une question différente: «Y a-t-il suffisamment d'endosseurs d'accord sur le résultat de l'exécution de ce code sur ces données?» Répondre à cela est une question de comptage assez simple, et il n'y a pas de place pour le non-déterminisme.

Le déterminisme du tissu par approbation a un certain nombre de conséquences intéressantes. Premièrement, le code de chaîne peut être écrit dans de nombreux langages de programmation différents, car ceux-ci n'ont pas besoin d'être adaptés au déterminisme (Go, Java et JavaScript sont actuellement pris en charge). Deuxièmement, le code de chaîne peut être caché à certains des participants d'une blockchain, car il n'a besoin d'être exécuté que par les clients et les endosseurs (la base de données elle-même est globalement visible). Enfin et surtout, le code de chaîne Fabric peut faire des choses interdites dans d'autres environnements de blockchain, comme vérifier la météo à l'aide d'une API Web en ligne. Dans le pire des cas, lorsque chaque endosseur obtient une réponse différente de cette API, le client ne parviendra pas à obtenir suffisamment de recommandations pour un résultat particulier, et aucune transaction n'aura lieu. (Il convient de noter que les membres de l'équipe Fabric recommander en utilisant une logique déterministe à l'intérieur du code de chaîne, afin d'éviter les surprises.)

Quel prix Fabric paie-t-il pour cette flexibilité? Si le but d'une blockchain est de supprimer les intermédiaires d'une application basée sur une base de données partagée, la dépendance de Fabric à l'égard des endosseurs éloigne considérablement cet objectif. Pour les participants de la chaîne, il ne suffit plus de suivre les règles du code de chaîne - ils ont également besoin de certains autres nœuds pour convenir qu'ils l'ont fait. Pire encore, un sous-ensemble malveillant d'endosseurs pourrait approuver les modifications de base de données qui ne suivent pas du tout le code de chaîne. Cela donne aux endosseurs beaucoup plus de pouvoir que les validateurs dans les blockchains régulières, qui peuvent censurer les transactions mais ne peuvent pas violer les règles de la blockchain. Les développeurs d'applications Blockchain doivent décider si ce compromis est logique dans leur cas particulier.

Déterminisme Tissu MultiChain Ethereum Corde
Modèle Endossements Runtime adapté VM spécialement conçue Runtime adapté
Langues Aller + Java + JavaScript JavaScript Solidité Java + Kotlin
Visibilité du code Contreparties +
endosseurs
Blockchain Blockchain Contreparties +
dépendants
Forcées Non Oui Oui Non (pour l'instant)

Prévention des conflits

Jusqu'à présent, nous avons discuté de la façon dont les différentes plateformes de blockchain expriment les règles de transaction dans le code, et comment elles garantissent de manière déterministe que chaque nœud applique ces règles de manière identique. Il est maintenant temps de parler d'un troisième aspect de notre confrontation: comment chaque plateforme gère-t-elle la possibilité que deux transactions, qui sont valides en elles-mêmes, entrent en conflit? Dans l'exemple le plus simple, imaginez qu'Alice a 10 $ dans un grand livre financier et diffuse deux transactions - l'une envoyant 8 $ à Bob et l'autre 7 $ à Charlie. De toute évidence, une seule de ces transactions peut être autorisée à réussir.

Deux modèles

Nous pouvons commencer par regrouper l'approche de MultiChain et Corda à ce problème. Comme décrit précédemment, les deux utilisent un modèle d'entrée-sortie pour représenter les transactions et leurs règles, dans lequel chaque entrée de transaction dépense une sortie de transaction précédente. Cela conduit à un principe simple de prévention des conflits: chaque sortie ne peut être dépensée qu'une seule fois. Les filtres MultiChain et les contrats Corda peuvent compter sur leurs plateformes respectives pour appliquer cette restriction de manière absolue. Étant donné que les 10 $ d'Alice sont représentés par une sortie de transaction précédente, cette règle de dépense unique l'empêche automatiquement de l'envoyer à la fois à Bob et Charlie.

Malgré cette similitude, il est important de souligner une différence clé dans la façon dont MultiChain et Corda empêchent les conflits. Dans MultiChain, chaque nœud voit chaque transaction et peut donc vérifier indépendamment que chaque sortie n'est dépensée qu'une seule fois. Toute transaction qui effectue une double dépense par rapport à une transaction précédemment confirmée sera instantanément et automatiquement rejetée. En revanche, à Corda, il n'y a pas de blockchain mondiale, donc des «notaires» sont nécessaires pour éviter ces doubles dépenses. Chaque état de sortie Corda est attribué à un notaire, qui doit signer toute transaction dépensant cette sortie, confirmant qu'elle n'a pas été dépensée auparavant. Les participants d'une blockchain doivent faire confiance aux notaires pour suivre cette règle honnêtement, et les notaires malveillants peuvent causer des ravages à volonté. Comme pour les mentions dans Fabric, ce "dépense unique en tant que service»Le design présente des avantages en termes de confidentialité mais réintroduit des intermédiaires, allant à l'encontre du grain de la blockchain. (Il est important de préciser que les notaires Corda peuvent être gérés par des groupes de participants à l'aide d'un algorithme de consensus, de sorte que l'intégrité du registre peut toujours être protégée contre les mauvais acteurs individuels).

Passons à Ethereum. Pour rappel, Ethereum utilise des contrats et des messages plutôt que des entrées et des sorties. En conséquence, les conflits de transaction tels que les deux paiements d'Alice ne sont pas immédiatement visibles pour le moteur de la chaîne de blocs. Au lieu de cela, ils sont détectés et bloqués par le contrat qui traite les transactions, une fois leur commande confirmée sur la chaîne. Lors du traitement de chacun des paiements d'Alice, le contrat vérifie si son solde est suffisant. Si la transaction payant 8 $ à Bob vient en premier, elle sera traitée comme d'habitude, laissant Alice avec 2 $ sur son compte. Par conséquent, lorsque le contrat traite la deuxième transaction payant 7 $ à Charlie, il constate qu'Alice n'a pas les fonds nécessaires et la transaction est annulée.

Résultats vs contrats

Jusqu'à présent, nous avons vu deux techniques différentes pour empêcher les transactions conflictuelles - les sorties à dépenses uniques dans MultiChain et Corda, et la vérification basée sur les contrats dans Ethereum. Alors quoi de mieux?

Afin d'aider à répondre à cette question, considérons un exemple de compte «multisignature 1 sur 2» qui détient 100 $ au nom de Gavin et Helen, et permet à l'un ou l'autre de dépenser cet argent de manière indépendante. Gavin demande à sa demande de payer 80 $ à Donna, et quelques secondes plus tard, Helen veut envoyer 40 $ à Edward. Comme les fonds sont insuffisants pour les deux paiements, ces transactions seraient inévitablement en conflit. Dans le cas où les deux transactions sont diffusées, le résultat sera déterminé par celui qui le fera en premier dans la chaîne. Notez que contrairement à l'exemple d'Alice, ce conflit est accidentellement, puisque personne n'essaie d'enfreindre les règles de l'application - ils ont simplement eu un mauvais timing.

En considérant la probabilité que ce conflit se produise, la question clé est la suivante: après que Gavin ait envoyé sa transaction, combien de temps faudra-t-il au nœud d'Helen pour savoir que son paiement pourrait échouer? Plus cette période est courte, plus il est probable qu'Helen soit empêchée d'essayer ce paiement, lui épargnant ainsi que sa demande d'une surprise ultérieure.

Avec le modèle d'entrée-sortie, tout conflit entre les transactions est directement visible pour la plate-forme blockchain, car les deux transactions tenteront explicitement de dépenser la même sortie précédente. Dans MultiChain, cela se produit dès que la transaction de Gavin s'est propagée au nœud d'Helen, généralement en une seconde ou moins. À Corda, le notaire de la sortie refusera la demande de signature de la transaction d'Helen, car il a déjà signé celle de Gavin, donc Helen saura instantanément que son paiement échouera. (Bien que si le notaire Corda est lui-même distribué, il se peut qu'elle doive attendre quelques secondes pour une réponse.) Quoi qu'il en soit, il n'est pas nécessaire d'attendre qu'une transaction soit confirmée et commandée dans la blockchain.

Et le modèle d'Ethereum? Dans ce cas, il n'y a aucun moyen immédiat pour la plate-forme blockchain de savoir qu'un conflit va se produire. Bien que le nœud d'Helen puisse voir la transaction de Gavin sur le réseau, il ne peut pas savoir comment cela affectera la propre transaction d'Helen, car de son point de vue, il s'agit simplement de deux messages envoyés au même contrat. Peut-être dix secondes plus tard, une fois que l'ordre final des transactions en conflit est confirmé sur la blockchain, le nœud d'Helen recalculera le résultat réel au lieu du résultat attendu, et son application mettra à jour son affichage en conséquence. En attendant, Gavin et Helen seront laissés dans le noir.

Mais il ne faut pas en conclure que le modèle entrée-sortie fonctionne toujours mieux. Considérez une variante de notre exemple de scénario, où Gavin et Helen demandent à la fois des paiements plus petits de 40 $ sur le solde initial de 100 $. Dans le modèle d'entrée-sortie, ces transactions entreraient en conflit, car elles dépensent toutes les deux la même ligne de base de données contenant ces 100 $, et un seul des paiements réussirait. Mais dans Ethereum, les deux transactions seraient traitées avec succès, quelle que soit leur commande finale, car le compte contient suffisamment de fonds pour les deux. Dans ce cas, Ethereum remplit plus fidèlement les intentions de Gavin et Helen.

Ensembles de lecture-écriture

Enfin, parlons de Fabric, dont l'approche basée sur l'approbation est un hybride de ces deux techniques. Comme expliqué précédemment, lorsqu'un nœud «client» Fabric souhaite envoyer un message à un contrat, il demande d'abord à certains nœuds d'approbation d'exécuter ce message en son nom. Les nœuds d'approbation le font de manière similaire à Ethereum - exécutant le contrat sur leur base de données locale - mais ce processus est observé plutôt qu'appliqué immédiatement. Chaque endosseur enregistre l'ensemble des lignes qui seraient lues et écrites, notant également la version exacte de ces lignes à ce moment-là. Cet «ensemble lecture-écriture» de lignes versionnées est explicitement référencé dans l'endossement et inclus dans la transaction que le client diffuse.

Les conflits entre les transactions Fabric sont résolus une fois leur commande finalisée dans la chaîne. Chaque nœud traite chaque transaction indépendamment, vérifiant les politiques d'approbation et appliquant les modifications de base de données spécifiées. Toutefois, si une transaction lit ou écrit une version de ligne de base de données qui a déjà été modifiée par une transaction précédente, cette deuxième transaction est ignorée. Pour revenir aux paiements conflictuels d'Alice à Bob et Charlie, ces deux transactions liront et modifieront la même version de ligne, contenant les 10 $ avec lesquels Alice a commencé. Ainsi, la deuxième transaction sera abandonnée en toute sécurité et automatiquement.

L'approche de Fabric pour la résolution des conflits fonctionne très bien, mais en termes de performances et de flexibilité, elle combine le pire des deux modèles précédents. Parce que les avenants convertissent les transactions en ensembles de lecture-écriture spécifiques, les paiements simultanés mais compatibles de 40 $ de Gavin et Helen entraîneraient un conflit qu'Ethereum évite. Cependant, Fabric n'obtient pas l'avantage de vitesse du modèle d'entrée-sortie, car les endosseurs exécutent des contrats par rapport à la version la plus récente de la base de données confirmée par la blockchain, ignorant les transactions non confirmées. Donc, si Helen initie son paiement quelques secondes après Gavin, mais avant que Gavin n'ait été confirmé sur la blockchain, Fabric créera des transactions conflictuelles qu'un pur modèle d'entrée-sortie évite.

Prévention des conflits Tissu MultiChain Ethereum Corde
Modèle Ensembles de lecture-écriture Dépense unique Contrôles de contrat Dépense unique
Vérification Independent Independent Independent Notaires de confiance
Vitesse ~ 10s (confirmation) ~ 1s (propagation) ~ 10s (confirmation) 0 ~ 5s (notaire)

Un choix complexe

Dans cet article, nous avons passé en revue plusieurs des différentes façons dont Corda, Ethereum, Fabric et MultiChain répondent aux principaux défis des «contrats intelligents», ou du code d'application qui est intégré dans une blockchain. Et chaque plate-forme a des réponses différentes à nos trois questions fondamentales: Comment les règles de transaction sont-elles représentées? Comment le code est-il exécuté de façon déterministe? Et comment prévenir les conflits?

Alors, qui est le gagnant de notre confrontation de contrat intelligent? Il devrait maintenant être évident qu'il n'y a pas de réponse simple. Chaque plate-forme représente un compromis multidirectionnel complexe entre flexibilité, simplicité, performances, désintermédiation, sécurité et confidentialité. Ainsi, le choix de la plate-forme pour une application particulière doit commencer par une compréhension détaillée du modèle de confiance de cette application, des types de transactions qu'elle implique et de leurs tendances probables de conflit. Si vous trouvez quelqu'un qui propose une solution de contrat intelligent spécifique avant de connaître les réponses à ces questions, je suggère d'insister poliment mais fermement pour qu'il adopte une approche «plus intelligente».

Veuillez poster vos commentaires sur LinkedIn.

Horodatage:

Plus de Multichain