Auteur : Tia, Techub News

La blockchain sacrifie l'efficacité en raison de sa conception décentralisée, ce qui rend l'accélération de la vitesse d'exécution l'un des problèmes urgents à résoudre. La « couche d'exécution » de la blockchain est la partie clé qui traite chaque transaction et l'ajoute à la chaîne. Pour accélérer la capacité de traitement, améliorer la couche d'exécution devient l'une des stratégies centrales, et l'exécution parallèle est une percée importante dans ce domaine.

Les blockchains traditionnelles traitent généralement les transactions de manière sérielle, ce qui limite considérablement la vitesse des transactions, en particulier dans les réseaux à fort trafic qui peuvent provoquer des congestions. Cependant, grâce à l'exécution parallèle, plusieurs transactions peuvent être traitées simultanément, ce qui augmente considérablement l'efficacité d'exécution et réduit la pression sur la chaîne.

Pour mieux comprendre ce qu'est la parallélisation, nous commencerons par introduire l'exécution et utiliserons l'exemple d'Ethereum dans le modèle PBS après la fusion pour expliquer ce qu'est l'exécution, tout en montrant la place de l'exécution dans l'ensemble du cycle de vie de la transaction.

Les étapes spécifiques de l'exécution des transactions

  1. Les transactions entrent dans le pool de mémoire et sont filtrées et triées : c'est la phase de prétraitement après la soumission des transactions, qui implique l'interaction entre le Mempool, le Searcher et le Builder pour finaliser le filtrage et le tri des transactions.

  2. Le Builder construit le bloc (mais ne l'exécute pas) : le Builder organise les transactions rentables en un bloc pour finaliser le regroupement et le tri des transactions.

  3. Le Proposeur vérifie et soumet le bloc : une fois le bloc construit, le Builder envoie la proposition de bloc au Proposeur. Le Proposeur vérifie la structure du bloc et le contenu des transactions, puis soumet officiellement le bloc au réseau pour commencer l'exécution.

  4. Exécution des transactions : après la soumission du bloc, les nœuds exécutent les transactions dans le bloc une par une. C'est la phase clé de la mise à jour de l'état, chaque transaction déclenchant un appel de contrat intelligent, un changement de solde de compte ou une modification d'état.

  5. Le témoin atteste : le validateur témoigne des résultats d'exécution du bloc et de la racine d'état, et les considère comme une confirmation finale. Cela garantit l'authenticité et la validité du bloc au niveau de la couche d'exécution et empêche les incohérences.

  6. Synchronisation de l'état : chaque nœud synchronise les résultats d'exécution du bloc (comme les soldes des comptes, les mises à jour de l'état des contrats, etc.) à son état local. Après chaque transaction, le nœud calcule et stocke une nouvelle racine d'état pour l'utiliser comme état initial dans le prochain bloc.

Bien sûr, ceci n'est qu'une synchronisation d'état des transactions au niveau du bloc. Pour maintenir l'état le plus à jour sur la chaîne, les nœuds synchronisent généralement les données bloc par bloc et vérifient continuellement les blocs et les états. Cependant, pour atteindre la finalité sous le mécanisme POS, il est également nécessaire que les agrégateurs rassemblent les signatures des témoins de chaque slot en une signature complète et les transmettent au proposeur du slot suivant. Les validateurs doivent, après un epoch, confirmer l'état de tous les blocs dans cet epoch sur la base du nombre de votes, formant un point de contrôle de l'état de consensus temporaire. Une fois que deux epochs consécutifs ont reçu le soutien de la majorité des témoins, les blocs et les transactions atteignent la finalité.

Du point de vue du cycle de vie complet d'une transaction, l'exécution se produit après que le Proposeur a vérifié la structure du bloc et le contenu des transactions envoyés par le Builder. Le processus d'exécution réel nécessite de traiter les transactions une par une et de mettre à jour l'état des comptes ou des contrats correspondants. Une fois que toutes les transactions ont été exécutées, le Proposeur calculera une nouvelle racine d'état (racine de Merkle), qui résume les résultats d'exécution de toutes les transactions du bloc actuel et l'état global final. En termes simples, l'ensemble du processus d'exécution du bloc comprend une série de calculs nécessaires pour transformer Ethereum d'un état précédent à un état suivant, depuis l'exécution de chaque transaction jusqu'au calcul de la racine de Merkle.

Exécution séquentielle

Contrairement à la parallélisation, l'exécution séquentielle est la méthode d'exécution actuellement plus courante dans les blockchains. En général, les transactions sont exécutées progressivement dans l'ordre. Une fois qu'une transaction a été exécutée, Ethereum met à jour l'état du compte et les informations associées (comme le solde, les données de stockage du contrat) dans l'arbre d'état du compte, générant un nouveau hachage d'état de compte. Une fois que tous les arbres d'état des comptes ont été mis à jour, cela forme le hachage du nœud racine de l'arbre d'état, appelé racine de Merkle d'état. Après l'achèvement des racines de Merkle d'état, de Merkle de transaction et de Merkle de reçu, l'en-tête du bloc est haché pour générer le hachage du bloc.

Dans ce contexte, l'ordre d'exécution des transactions est crucial. Comme l'arbre de Merkle est un arbre binaire de valeurs de hachage, les racines de Merkle formées dans des ordres différents seront différentes.

Exécution parallèle

Dans un environnement d'exécution parallèle, les nœuds tenteront de traiter les transactions dans le bloc de manière parallèle. Les transactions ne sont pas exécutées une par une dans l'ordre, mais sont attribuées à différents « chemins d'exécution » afin qu'elles puissent s'exécuter simultanément. Grâce à l'exécution parallèle, le système peut traiter les transactions dans le bloc plus efficacement, augmentant ainsi le débit.

Une fois que toutes les transactions ont été exécutées, les nœuds résument les résultats d'exécution (c'est-à-dire les mises à jour d'état affectées par les transactions) pour former un nouvel état de bloc. Cet état sera ajouté à la blockchain, représentant le dernier état global sur la chaîne.

Conflit d'état

Étant donné que la parallélisation traite des transactions en même temps sur différents chemins, l'un des principaux défis de la parallélisation est le conflit d'état. Il peut y avoir plusieurs transactions qui lisent ou écrivent sur la même partie des données (état) de la blockchain au même moment. Si cette situation n'est pas gérée correctement, elle peut entraîner des résultats d'exécution incertains. Puisque l'ordre des mises à jour d'état diffère, les résultats de calcul finaux varieront. Par exemple,

Supposons qu'il y ait deux transactions, la transaction A et la transaction B, qui tentent toutes deux de mettre à jour le solde du même compte :

  • Transaction A : ajouter 10 au solde du compte.

  • Transaction B : ajouter 20 au solde du compte.

Le solde initial du compte est de 100.

Si nous exécutons de manière sérielle, le résultat de l'ordre d'exécution est déterminé :

1. D'abord exécuter la transaction A, puis exécuter la transaction B :

  • Le solde du compte augmente d'abord de 10, atteignant 110.

  • Puis il augmente de 20, atteignant finalement 130.

2. D'abord exécuter la transaction B, puis exécuter la transaction A :

  • Le solde du compte augmente d'abord de 20, atteignant 120.

  • Puis il augmente de 10, atteignant finalement 130.

Dans ces deux ordres, le solde final est toujours de 130, car le système garantit la cohérence de l'ordre d'exécution des transactions.

Mais dans un environnement d'exécution parallèle, les transactions A et B peuvent lire simultanément le solde initial de 100 et effectuer leurs propres calculs :

  1. La transaction A lit un solde de 100 et l'actualise à 110 après calcul.

  2. La transaction B lit également un solde de 100 et l'actualise à 120 après calcul.

Dans ce cas, en raison de l'exécution simultanée des transactions, le solde final n'est mis à jour qu'à 120, et non à 130, car les opérations des transactions A et B ont « couvert » les résultats de l'autre, entraînant un conflit d'état.

Ces problèmes de conflit d'état sont souvent appelés « écrasement de données », c'est-à-dire que lorsque des transactions tentent de modifier simultanément les mêmes données, elles peuvent se recouvrir mutuellement, entraînant un état final incorrect. Un autre type de conflit d'état peut également provoquer des problèmes en rendant impossible la garantie de l'ordre d'exécution. Comme plusieurs transactions complètent leurs opérations à différents moments, cela peut entraîner un ordre d'exécution différent. Des ordres différents peuvent produire des résultats de calcul différents, rendant ainsi le résultat incertain.

Pour éviter cette incertitude, les systèmes d'exécution parallèle de blockchain introduisent généralement des mécanismes de détection de conflits et de rollback, ou effectuent une analyse de dépendance préalable des transactions pour s'assurer qu'elles s'exécutent en parallèle sans affecter la cohérence finale de l'état.

Exécution parallèle optimiste et déterministe

Il existe deux façons de traiter les conflits d'état potentiels : l'exécution parallèle déterministe et l'exécution parallèle optimiste. Ces deux modèles présentent des compromis en termes d'efficacité et de complexité de conception.

L'exécution parallèle déterministe nécessite une déclaration préalable de l'accès à l'état, le validateur ou le séquenceur vérifiant les déclarations d'accès à l'état lors du tri des transactions. Si plusieurs transactions tentent d'écrire dans le même état, elles seront marquées comme conflictuelles pour éviter une exécution simultanée. Les formes de déclaration d'accès à l'état peuvent varier d'une chaîne à l'autre, mais incluent généralement les méthodes suivantes :

  • Par la contrainte des spécifications du contrat : les développeurs définissent directement le champ d'accès à l'état dans le contrat intelligent. Par exemple, le transfert de jetons ERC-20 nécessite l'accès aux champs de solde de l'expéditeur et du destinataire.

  • Par la déclaration de données structurées dans la transaction : ajout de champs spéciaux dans la transaction pour annoter l'accès à l'état.

  • Par l'analyse du compilateur : les compilateurs de langages de haut niveau peuvent analyser statiquement le code du contrat pour générer automatiquement un ensemble d'accès à l'état.

  • Déclaration forcée par le cadre : certains cadres exigent que les développeurs spécifient explicitement l'état à accéder lors de l'appel de fonctions.

L'exécution parallèle optimiste traite d'abord les transactions de manière optimiste, et lorsque des conflits se produisent, les transactions concernées sont réexécutées dans l'ordre. Pour éviter autant que possible la survenance de conflits, le cœur de la conception de l'exécution parallèle optimiste est de faire des préjugés et des hypothèses rapides sur l'état à partir de données historiques et d'analyses statiques. Cela signifie que le système suppose que certaines opérations ou mises à jour d'état sont valides sans vérification complète, évitant ainsi d'attendre tous les processus de vérification, afin d'améliorer les performances et le débit.

Bien que l'exécution parallèle optimiste puisse éviter autant que possible les conflits grâce à des préjugés rapides et des hypothèses sur l'état, il existe encore des défis inévitables, en particulier pour l'exécution de contrats ou les transactions inter-chaînes. Si les conflits se produisent fréquemment, la réexécution peut ralentir considérablement les performances du système et augmenter la consommation des ressources de calcul.

L'exécution parallèle déterministe évite les conflits potentiels en effectuant des vérifications de dépendance d'état avant la transaction, mais exige que les développeurs déclarent précisément les dépendances d'état avant la soumission de la transaction, ce qui augmente la complexité de mise en œuvre.

Dilemme de la parallélisation EVM

Le traitement des conflits d'état ne se limite pas à une distinction entre déterministe et optimiste. Dans le processus d'implémentation parallèle, il est également nécessaire de considérer la perspective de l'architecture de la chaîne de blocs. Le problème des conflits d'état en parallèle est particulièrement difficile dans l'EVM sous l'architecture de l'arbre de Merkle. Un arbre de Merkle est une structure de hachage hiérarchique, où la valeur de hachage racine de l'arbre de Merkle doit également être mise à jour chaque fois qu'une transaction modifie des données d'état. Ce processus de mise à jour est récursif, calculé couche par couche à partir des nœuds feuille jusqu'à la racine. Étant donné que le hachage est irréversible, il est difficile de mettre à jour en parallèle, car on ne peut calculer le niveau supérieur qu'après avoir terminé les modifications des données au niveau inférieur.

Si deux transactions s'exécutent en parallèle et accèdent au même état (comme le solde d'un compte), cela entraînera des conflits au niveau des nœuds de l'arbre de Merkle. Résoudre ce type de conflit nécessite souvent des mécanismes de gestion des transactions supplémentaires pour garantir une valeur de hachage racine cohérente dans plusieurs branches. Cela n'est pas facile à réaliser pour l'EVM, car il doit faire un compromis entre la parallélisation et la cohérence de l'état.

Solutions parallèles non-EVM

Solana

Contrairement à l'arbre d'état global d'Ethereum, Solana utilise un modèle de compte. Chaque compte est un espace de stockage indépendant, stocké dans le registre, évitant ainsi les problèmes de conflit de chemin.

Solana est une parallélisation déterministe. Dans Solana, chaque transaction doit déclarer explicitement les comptes qu'elle va accéder et les autorisations nécessaires (lecture seule ou lecture/écriture) au moment de la soumission. Ce design permet aux nœuds de la blockchain d'analyser à l'avance les ressources que chaque transaction doit accéder avant son exécution. Puisque les dépendances entre comptes sont clairement déclarées avant le début de l'exécution, les nœuds peuvent déterminer quelles transactions accéderont aux mêmes comptes et quelles transactions peuvent être exécutées en parallèle sans risque de conflit, ce qui permet une planification intelligente et constitue la base de la planification parallèle.

Comme chaque transaction a déjà déclaré les comptes et les permissions nécessaires avant l'exécution, Solana peut vérifier s'il existe des relations de dépendance entre les transactions (modèle Sealevel). Si les transactions n'ont pas de comptes partagés en lecture/écriture, le système peut les attribuer à différents processeurs pour une exécution parallèle.

Aptos

La conception de l'exécution parallèle d'Aptos est très différente de celle d'Ethereum, avec des innovations clés dans l'architecture et les mécanismes, notamment en ce qui concerne le modèle de compte et le stockage d'état.

Ethereum nécessite de mettre à jour fréquemment l'arbre d'état global (MPT) lors de l'exécution des transactions. Tous les comptes et l'état des contrats sont stockés dans un arbre d'état partagé, et chaque transaction doit accéder et mettre à jour une partie de cet arbre d'état. Aptos, quant à lui, divise les comptes en unités d'état indépendantes, chaque objet étant une paire clé-valeur indépendante, pouvant exister indépendamment les uns des autres sans impact mutuel, et ne se liant que lorsque des relations de référence explicites sont définies. Il n'y a pas de chemin d'arbre commun entre les objets, ce qui évite les conflits de verrouillage et permet une exécution complètement parallèle.

La structure de données sous-jacente d'Aptos est l'arbre de Merkle Jellyfish. L'état de chaque objet est finalement stocké dans le JMT, en tant que paire clé-valeur indépendante. Contrairement à l'MPT d'Ethereum, l'arbre de Merkle Jellyfish adopte une structure d'arbre binaire complète, simplifiant considérablement les chemins de stockage et de requête des nœuds, réduisant ainsi le temps de vérification. De plus, la position de chaque compte dans l'arbre est fixe, et les nœuds de l'arbre sont stockés indépendamment, permettant à plusieurs comptes d'être mis à jour et consultés en parallèle.

Aptos utilise une parallélisation optimiste, sans exiger la déclaration préalable de toutes les dépendances des comptes. Pour ce faire, Aptos utilise le Block-STM, qui utilise un ordre de transaction prédéfini pour estimer les dépendances, réduisant ainsi le nombre d'interruptions.

EVM parallèle

Comparé aux systèmes parallèles non-EVM, l'EVM parallèle fait face à des difficultés techniques plus importantes lors du traitement des dépendances d'état, de la détection des conflits, de la gestion du gaz et des mécanismes de rollback. Pour mieux comprendre cela, nous pouvons consulter comment certains projets EVM parallèles (comme Sui, Monad, Canto) abordent ces problèmes.

Sui

Tout comme Aptos, Sui utilise également un modèle d'objet pour traiter l'état, utilisant chaque objet (comme un compte ou l'état d'un contrat intelligent) comme une ressource indépendante, ces objets étant différenciés par des identifiants uniques. Lorsque des transactions impliquent différents objets, elles peuvent être traitées en parallèle, car elles opèrent sur différents états sans générer de conflits directs.

Bien que Sui utilise un modèle d'objet pour gérer l'état, pour être compatible avec l'EVM, l'architecture de Sui utilise une couche d'adaptation ou un mécanisme abstrait supplémentaire pour faire le lien entre le modèle d'objet et le modèle de comptes de l'EVM.

Dans Sui, la planification des transactions utilise une stratégie d'exécution parallèle optimiste, supposant qu'il n'y a pas de conflits entre les transactions. Si des conflits surviennent, le système utilise un mécanisme de rollback pour restaurer l'état.

Sui utilise un modèle d'objet et des techniques d'isolation d'état, ce qui lui permet d'éviter efficacement les problèmes de dépendance d'état. Chaque objet est une ressource indépendante, et différentes transactions peuvent être exécutées en parallèle, augmentant ainsi le débit et l'efficacité. Cependant, le compromis de cette approche est la complexité du modèle d'objet et le coût des mécanismes de rollback. Si des conflits se produisent entre les transactions, il faudra rollback une partie de l'état, ce qui augmentera la charge du système et pourrait affecter l'efficacité du traitement parallèle. Comparé aux systèmes parallèles non-EVM (comme Solana), Sui nécessite plus de ressources de calcul et de stockage pour maintenir une parallélisation efficace.

Monad

Comme Sui, Monad utilise également une parallélisation optimiste. Cependant, la parallélisation optimiste de Monad fait des prévisions sur certaines transactions ayant des relations de dépendance avant leur exécution. Les prévisions sont principalement réalisées via l'analyse statique du code de Monad. Les prévisions nécessitent un accès à l'état, et la façon dont l'état est stocké dans la base de données d'Ethereum rend cet accès très difficile. Pour rendre la lecture d'état plus efficace lors de l'exécution parallèle, Monad a également reconstruit la base de données.

L'arbre d'état Monad est partitionné, chaque partition maintenant son propre sous-arbre d'état. Lors de la mise à jour, seules les partitions concernées doivent être modifiées, sans avoir à reconstruire l'ensemble de l'arbre d'état. Un tableau d'index d'état permet de localiser rapidement l'état dans la partition, réduisant les interactions entre partitions.

并行区块链全解:执行原理、代表项目及所处周期

Résumé

Le cœur de la parallélisation est d'améliorer l'efficacité d'exécution de la couche d'exécution par l'exécution multi-chemins. Pour réaliser l'exécution multi-chemins, la chaîne doit mettre en place une série de mécanismes de détection de conflits et de rollback pour garantir qu'elles s'exécutent en parallèle sans affecter la cohérence finale de l'état, et apporter certaines améliorations à la base de données.

Bien sûr, l'amélioration de l'efficacité de la couche d'exécution ne se limite pas à la parallélisation. L'optimisation de l'exécution peut également être réalisée en réduisant les opérations de lecture/écriture nécessaires à une transaction dans la base de données. L'ensemble du processus d'accélération de la chaîne implique un champ encore plus large, y compris l'amélioration de l'efficacité de la couche de consensus.

Chaque technologie a ses propres conditions de limitation. La parallélisation n'est qu'un moyen d'améliorer l'efficacité, et la décision finale d'utiliser cette technologie doit également tenir compte de sa convivialité pour les développeurs et de la possibilité de la réaliser sans sacrifier la décentralisation, etc. L'accumulation de technologies n'est pas toujours bénéfique, surtout pour Ethereum, où la parallélisation n'est pas si attrayante. D'un point de vue purement axé sur l'efficacité, l'ajout de la parallélisation n'est pas la solution optimale pour Ethereum, que ce soit en termes de simplicité ou en regard de la feuille de route actuelle centrée sur Rollup.