paint-brush
Déballage de la mise à niveau Starknet Boltpar@2077research
Nouvelle histoire

Déballage de la mise à niveau Starknet Bolt

par 2077 Research17m2024/12/26
Read on Terminal Reader

Trop long; Pour lire

La mise à niveau de Starknet Bolt a introduit deux fonctionnalités majeures : l'exécution parallèle et les performances des blocs. Cet article explique comment ces nouvelles fonctionnalités améliorent les performances de Starknet et améliorent l'expérience de transaction pour les utilisateurs de la couche 2 (L2).
featured image - Déballage de la mise à niveau Starknet Bolt
2077 Research HackerNoon profile picture


La dernière mise à jour de Starknet (v0.13.2) appelée Bolt apporte deux changements majeurs : l'exécution parallèle et le block-packing . Bien qu'indépendantes l'une de l'autre, ces deux fonctionnalités soutiennent l'objectif d'un espace de blocs rapide et bon marché, sécurisé cryptographiquement par Ethereum.


L'exécution parallèle permet aux transactions non litigieuses (c'est-à-dire aux transactions qui ne touchent pas au même état) de s'exécuter simultanément. En implémentant l'exécution parallèle, les L2 comme Starknet peuvent réduire le temps d'exécution sans augmenter l'utilisation des ressources. Cela signifie des frais de transaction inférieurs pour les utilisateurs et des délais de confirmation des transactions considérablement améliorés.


Le block packaging optimise l'utilisation de l'espace blob par Starknet sur Ethereum L1 : avec le block packaging, les séquenceurs peuvent générer une preuve pour vérifier simultanément plusieurs blocs Starknet L2. Cela dissocie l'utilisation de l'espace blob de la fréquence de production des blocs L2 et amortit les coûts de vérification des preuves. Ces deux éléments réduisent les coûts d'exploitation du séquenceur Starknet, ce qui signifie que les utilisateurs paient moins par transaction.


Comme nous l'avons dit, Bolt rend Starknet moins cher et plus rapide ! Ce rapport fournira une analyse détaillée de la mise à niveau de Bolt, en se concentrant sur l'exécution parallèle et le regroupement de blocs, et explorera les implications pour les performances de Starknet.

Un petit rappel sur les rollups

Les rollups sont des solutions de mise à l'échelle de couche 2 (L2) qui visent à faire évoluer la blockchain de couche 1 (L1) sous-jacente en déplaçant le calcul hors chaîne. En déplaçant l'exécution hors chaîne, les rollups peuvent optimiser l'évolutivité (transactions bon marché et rapides), tandis que la couche 1 assure la sécurité des transactions de couche 2.


On dit souvent que les rollups « héritent de la sécurité du L1 ». Cela signifie essentiellement qu’ils héritent des garanties de consensus et de disponibilité des données fournies par le L1. En outre, le L1 fournit également une garantie de sécurité sous la forme d’un pont sécurisé entre lui et le rollup.


Lorsque les séquenceurs publient des blocs L2 vers le L1, ce dernier fournit des garanties de disponibilité ainsi que de classement de ces informations. À partir de là, les nœuds L2 peuvent calculer en toute confiance la chaîne L2 canonique avec ces informations ainsi que les règles de cumul autour de la dérivation de la chaîne et de la transition d'état décrites par l'implémentation du nœud.


Afin de faciliter la mise en place d'un pont sécurisé entre les niveaux L1 et L2, le niveau L1 requiert la preuve que la chaîne L2 qu'il suit actuellement est correcte et n'inclut pas de changements d'état illégaux (par exemple, une double dépense). Ce besoin de cumuls pour prouver la validité des changements d'état garantit que le niveau L1 n'autorise pas les retraits du cumul sur la base d'un état illégal.


Les cumuls diffèrent selon la manière dont ils prouvent la validité des modifications d'état apportées au L1 :

  • Les cumuls de validité s'appuient sur des preuves de validité pour vérifier objectivement l'exactitude de l'exécution. Les proposants sont autorisés à proposer un nouvel état de cumul s'ils soumettent une preuve de validité au contrat de cumul.
  • Les cumuls optimistes s'appuient sur l'absence de preuve de fraude pour vérifier subjectivement l'exactitude de l'exécution. Les proposants soumettent des mises à jour d'état sans preuves, mais le contrat de cumul peut annuler toute mise à jour d'état dont la validité est contestée avec succès par une preuve de fraude.


Les cumuls fournissent également à la couche de base suffisamment de données pour que les parties intéressées puissent reconstruire l'état L2. Alors que les cumuls optimistes doivent publier des données de transaction complètes pour permettre aux challengers de calculer les preuves de fraude, les cumuls de validité n'ont pas de telles exigences (les preuves de validité garantissent une exécution correcte). Mais la publication de données de transaction complètes sur L1 est toujours utile du point de vue de la minimisation de la confiance (reconstruction sans confiance de l'état et retraits sans autorisation).


Starknet est un cumul de validité qui utilise des arguments de connaissances scalables et transparents (STARK) pour prouver la validité des changements d'état. La dernière mise à niveau de Starknet, nommée Bolt, ajoute l'exécution parallèle et le regroupement de blocs. Dans les sections suivantes, nous expliquerons comment fonctionnent les deux fonctionnalités et quelles améliorations elles apportent aux utilisateurs de Starknet.

Qu'est-ce que la mise à niveau Starknet Bolt a changé ?

À un niveau élevé, la mise à niveau de Bolt a modifié les mécanismes d'exécution, de preuve et de disponibilité des données de Starknet.

Optimisation de l'exécution

Avant la mise à niveau de Bolt, les transactions Starknet étaient exécutées séquentiellement (l'une après l'autre) par le séquenceur. L'exécution séquentielle est simple mais également très inefficace. Elle est inefficace car elle ne tire pas parti des multiples unités de traitement indépendantes qu'offrent les ordinateurs modernes et de la parallélisabilité d'un ensemble de transactions.


Exécution séquentielle


Exécution parallèle

La parallélisabilité est une mesure du degré d'indépendance des transactions dans un ensemble donné. Par exemple, considérons l'ensemble de trois transactions ci-dessous :

  • Transaction 1 : Alice veut envoyer 1 STRK à Bob

  • Transaction 2 : Caitlyn veut envoyer 100 ETH à Danny

  • Transaction 3 : Caitlyn veut envoyer 100 ETH à Ella


La transaction 1 est complètement indépendante des transactions 2 et 3, car elle accède à une partie différente de l'état (le solde d'Alice) et peut être exécutée simultanément. Cependant, les transactions 2 et 3 sont en conflit car elles veulent accéder au même état, le solde ETH de Caitlyn. Ces transactions ne peuvent pas être exécutées simultanément, sinon nous obtiendrons des résultats contradictoires.


Pour illustrer :

  • Supposons que le solde de Caitlyn soit de 300 ETH et que les transactions 2 et 3 démarrent en même temps. Les deux transactions liront le solde initial du compte de Caitlyn comme étant de 300 ETH, en déduiront le montant du transfert (300 - 100 = 200) et écriront 200 ETH à l'emplacement de la mémoire où le solde du compte de Caitlyn est stocké.
  • Les transactions 2 et 3 liront ensuite les soldes de Danny et d'Ella respectivement et ajouteront 100 ETH aux soldes des deux utilisateurs. Le solde de Caitlyn diminuerait de 100 ETH, mais 200 ETH seraient crédités, ce qui reviendrait à imprimer 100 ETH à partir de rien.


C'est pour éviter ce type de conflits (et la nature complexe des mécanismes d'atténuation) qu'Ethereum a choisi l'exécution séquentielle. Cependant, si l'exécution séquentielle réduit la complexité et améliore la sécurité, elle entraîne une utilisation inefficace du matériel. Pire encore, la tendance de la conception du matériel suggère que l'exécution séquentielle deviendra de plus en plus inefficace dans les années à venir.


La figure 4 montre l'évolution de la conception matérielle au cours des 50 dernières années. Le point important à retenir ? Les performances monothread (cercles violets) stagnent depuis le milieu des années 2000, alors que le nombre de cœurs logiques a augmenté à peu près au même moment. Nous pouvons tirer deux conclusions sur la base de ces données :

  • Les concepteurs de matériel informatique font évoluer les puces informatiques en ajoutant des unités de traitement indépendantes plutôt qu’en améliorant les performances d’une seule unité.

  • Tout système qui continue à s’appuyer sur les performances accrues d’une seule unité de traitement verra ses gains de performances stagner, même sur du matériel plus récent.


Figure 4 : Tendances des microprocesseurs


Ces dernières années, des algorithmes sophistiqués permettant de gérer les conflits de transactions et de garantir l'exactitude de l'exécution parallèle sont apparus. Block-STM (basé sur un article de Fikunmi et al*) est l'un de ces algorithmes et constitue la partie centrale du nouveau moteur d'exécution parallèle de Starknet. Nous analysons l'algorithme Block-STM dans les sections suivantes.

Optimisation de la preuve et de la disponibilité des données

Le SHARP (abréviation de Shared Prover) de Starknet a toujours tiré parti des preuves récursives pour réduire autant que possible les coûts de vérification. Une preuve récursive est essentiellement une « preuve de preuve » où une preuve vérifie qu'une ou plusieurs preuves sont correctes. Vous trouverez ci-dessous un schéma de la manière dont SHARP génère une preuve récursive :

  • Le système SHARP prend en entrée un ensemble de programmes à exécuter (un « job ») et génère une preuve d'exécution pour le job. Ces « programmes » sont des blocs L2 et la preuve atteste de l'exactitude des transactions.

  • La preuve est envoyée à un autre programme qui vérifie la preuve et convertit le programme de vérification de preuve en tâche. SHARP prend la nouvelle tâche en entrée et génère une autre preuve (cette preuve confirme la validité de la preuve précédente).

  • Le processus (preuve → tâche → preuve) redémarre et continue jusqu'à ce qu'une cible soit atteinte, moment auquel la preuve finale (qui est maintenant une version hautement compressée de la preuve originale) est publiée sur le L1


Figure 5 : Génération de preuves récursives


Cette conception amortit considérablement les coûts pour deux raisons principales :

  • Les tâches suivantes* ne sont pas des programmes ou des transactions individuels et les coûts de preuve augmentent de manière sous-linéaire. Cela signifie que plus le nombre de programmes/transactions dans une tâche est élevé, plus les économies sont importantes. En créant des preuves par bloc plutôt que par transaction, les frais de transaction peuvent être beaucoup moins élevés.
  • La récursivité compresse considérablement les preuves, ce qui donne lieu à une « preuve de preuve » qui est nettement moins coûteuse à vérifier sur le L1 que la preuve initiale ou l’une des preuves intermédiaires.


Bien que le système de validation soit efficace, des opportunités de réduction des coûts supplémentaires ont été manquées. Par exemple, chaque tâche était un seul bloc Starknet et chacun de ces blocs était conçu pour occuper un blob sur le L1. Cela a entraîné certaines inefficacités, comme décrit ci-dessous :

  • Avant Bolt, Starknet n'avait pas (et n'a toujours pas) de durée de blocage régulière ; à la place, un bloc L2 était publié sur le L1 sous deux conditions : (1) L'équivalent d'un blob de données était exécuté (2) Six minutes s'étaient écoulées depuis le bloc précédent. Malheureusement, en raison de la demande, la plupart des blocs ont été envoyés sur le L1 en raison de la limite de six minutes (et non des limites DA).
  • Ce qui précède signifiait que les blobs (et non les blocs) étaient souvent (gravement) sous-utilisés, ce qui entraînait des coûts de gaz inutilement élevés. Les blocs Starknet avaient également un coût fixe , qui pouvait théoriquement être réduit en appliquant les mêmes techniques de récursivité décrites ci-dessus pour produire des preuves de plusieurs blocs.


Le block-packing s'attaque à ces problèmes en utilisant un arbre binaire de preuves récursives. Nous aborderons le block-packing dans une section ultérieure de l'article.

Bolt Partie 1 : Exécution parallèle

Comme nous l'avons vu précédemment, l'exécution séquentielle est inefficace (et le sera encore plus avec le temps) et l'exécution parallèle naïve produit des résultats non valides. Les moteurs d'exécution parallèle de production veillent toutefois à éviter les résultats incohérents.


Il existe deux approches pour gérer l'exécution parallèle : le contrôle de concurrence pessimiste (PCC) et le contrôle de concurrence optimiste (OCC) . Le PCC et l'OCC sont des unités de traitement de transaction (TPU). Vous trouverez ci-dessous une définition d'une unité de traitement de transaction de Block-STM vs. SVM : Une comparaison des moteurs d'exécution parallèle :


Le TPU est généralement couplé à la machine virtuelle (VM), mais en est distinct. Les machines virtuelles blockchain comme l'EVM, la SVM et la MoveVM sont des machines virtuelles à langage de haut niveau… Le TPU, qui fait généralement l'objet d'intérêt, englobe la VM. Il est chargé de la gestion de l'ensemble du pipeline d'exécution des transactions, y compris la création et la gestion des instances de la VM.


Le contrôle de concurrence pessimiste est conçu sur la base de l'hypothèse selon laquelle de nombreuses transactions au sein de l'ensemble de transactions à exécuter seront en conflit, c'est-à-dire qu'elles toucheront le même état. Le contrôle de concurrence pessimiste empêche ces conflits.


Pour éviter les conflits, PCC exige qu'une transaction déclare à l'avance à quelles parties de l'état elle accédera pendant les opérations de lecture/écriture. L'unité de traitement des transactions peut utiliser ces informations pour planifier les transactions de manière à garantir que les transactions en conflit sont exécutées de manière séquentielle (au lieu de simultanément). Certains TPU utilisent également des verrous pour appliquer ce comportement (un verrou (également appelé mutex) est un mécanisme utilisé pour empêcher l'accès simultané à un emplacement de mémoire).


Cela dit, l’exécution basée sur PCC implique certains compromis. Tout d’abord, l’obligation de fournir des listes d’accès (qui identifient l’emplacement mémoire touché par une transaction) dégrade l’expérience du développeur et réduit la gamme d’applications possibles. Ensuite, la planification des transactions peut entraîner des frais généraux inutiles, en particulier lorsqu’il n’y a pas de conflits.


Le contrôle de concurrence optimiste est conçu en supposant que de nombreuses transactions au sein de l'ensemble donné ne seront pas en conflit, c'est-à-dire qu'elles n'écriront pas dans le même état. Ainsi, les TPU OCC exécutent l'ensemble des transactions avec toutes les ressources disponibles et tentent uniquement de détecter les conflits. Si un conflit est détecté, les transactions en conflit sont exécutées et revérifiées jusqu'à ce que l'ensemble soit validé.


Les unités de traitement de transactions OCC n'entraînent pas de surcharge liée à la planification, elles ont donc tendance à être plus performantes lorsqu'il y a peu de conflits. Les unités de traitement de transactions basées sur OCC offrent également une meilleure expérience de développement et une plus large gamme de cas d'utilisation, car les dépendances d'état n'ont pas besoin d'être connues à l'avance.


Cependant, lorsque l'ensemble des transactions est très controversé, l'OCC est moins performant que le PCC. Nous abordons les conceptions TPU (de manière beaucoup plus détaillée) et comparons les approches OCC et PCC dans notre article sur l'exécution parallèle.


Le nouveau TPU de Starknet utilise l'approche OCC. Plus précisément, il s'agit d'une implémentation de l'algorithme Block-STM. Block-STM exécute les transactions de manière optimiste avec toutes les ressources disponibles en supposant qu'aucune d'entre elles n'entrera en conflit et vérifie après l'exécution qu'aucune transaction conflictuelle n'est exécutée simultanément. Avant de nous plonger dans la nouvelle architecture de Starknet, il est important de passer en revue certaines définitions clés :

  1. État : L'état est l'état d'un objet à un instant donné. Dans le contexte de la blockchain, il fait généralement référence à la valeur d'une partie de la mémoire, par exemple, le solde d'une adresse est (une partie de) son état.
  2. Sérialisabilité : On dit que l'exécution parallèle a conservé la propriété de sérialisabilité si l'exécution d'un ensemble de transactions en série et simultanément produit les mêmes résultats.
  3. Conflit : on dit que deux transactions sont en conflit si et seulement si au moins l'une d'entre elles veut écrire dans une partie de l'état à laquelle les deux veulent accéder (en lecture ou en écriture). Si les deux transactions ne lisent qu'une partie de l'état, il n'y a pas de conflit, mais si au moins l'une d'entre elles écrit dans cette partie de l'état, les transactions ne peuvent pas être exécutées simultanément sans rompre la sérialisabilité. Nous avons couvert un exemple de cas ci-dessus dans l'exemple de Caitlyn, Danny et Ella.
  4. Dépendance : Une transaction txj est dite dépendante (ou dépendante) d'une transaction txi si et seulement si les deux transactions écrivent dans le même emplacement mémoire et que txj vient après txi dans l'ordre séquentiel. Si txi venait après txj , txi serait dépendant de txj .
  5. Structure de données multiversion : une structure de données multiversion est une structure dans laquelle une nouvelle version de la structure de données est créée pour chaque écriture dans la structure de données. Au lieu de modifier la valeur en place, une nouvelle version spécifique à l'écriture de l'emplacement à modifier est créée. L'avantage des structures de données multiversion est qu'elles permettent des lectures et des écritures hautement simultanées dans la même région de la mémoire. Nous verrons plus tard comment cela est utile.

Maintenant que nous avons défini ces définitions, nous pouvons passer à la description du fonctionnement de Block-STM.

Comment fonctionne Block-STM

L'entrée de Block-STM est une file d'attente (une liste ordonnée) de transactions, cette liste est souvent appelée BLOC. Cette liste peut être ordonnée de n'importe quelle manière ; la seule exigence est qu'il y ait un ordre clairement défini. Ainsi, étant donné un ensemble de transactions T contenant des transactions {t0…tn} , les transactions sont triées de telle sorte que {t0 > t1 > t2 … > tn} (lire comme si t0 était de priorité supérieure à t1 , t1 était de priorité supérieure à t2 etc.)


Au début du processus d'exécution, deux ensembles sont créés : un ensemble d'exécution E et un ensemble de validation V. E suit les transactions qui doivent encore être exécutées tandis que V suit les transactions qui ont été exécutées mais qui doivent encore être validées. Chaque transaction est également associée à un numéro d'incarnation n pour suivre le nombre de fois qu'elle a été exécutée (et réexécutée). L'état initial des ensembles est que E contient toutes les transactions et V est vide, c'est-à-dire que E = {t0,1 > t1,1 > t2,1 > … > tn,1} et V = {} .


Avec ces ensembles ordonnés de transactions, chaque thread utilisé pour l'exécution parcourt une boucle en trois étapes :

  1. Vérification effectuée
  2. Trouver la tâche suivante
  3. Effectuer une tâche

Vérification effectuée

Au cours de cette étape, le thread vérifie à la fois V et E. Si les deux sont vides et qu'aucune transaction n'est en cours d'exécution, le lot actuel de transactions a été entièrement exécuté et les résultats peuvent être enregistrés dans le stockage.

Trouver la tâche suivante

Si V ou E contient des transactions, Block-STM sélectionne la transaction avec l'index le plus bas (et non le numéro d'incarnation) parmi les deux ensembles de transactions, c'est-à-dire que si E contient {t1,3 , t3,1 and t5,2} et V contient {t0,1, t2,4, t4,3} , la tâche de validation pour la transaction t0 sera sélectionnée comme tâche suivante.

Effectuer une tâche

Une fois la tâche suivante identifiée et sélectionnée, elle est exécutée. À la fin de cette étape, l'algorithme revient à Check Done. Ce processus se poursuit jusqu'à ce que les deux ensembles de transactions soient vides.


Regardons ce qui se passe pendant l’exécution et la validation :


Lors de l'exécution d'une transaction, l'algorithme Block-STM remplit deux ensembles (par transaction) : un ensemble de lecture ( Ri,n ) et un ensemble d'écriture ( Wn,i ). L'ensemble de lecture contient tous les emplacements mémoire à partir desquels une transaction a lu pendant son exécution tandis que l'ensemble d'écriture contient tous les emplacements mémoire dans lesquels elle a écrit. Pendant l'exécution, les transactions appliquent leurs écritures à la structure de données multiversion, mais la lecture est un peu nuancée.


Dans Block-STM, lorsqu'une transaction souhaite lire la structure de données, elle recherche la valeur écrite par la transaction de priorité la plus basse qui a la priorité la plus élevée. Par exemple, si tx1 , tx2 et tx7 ont tous écrit dans un emplacement mémoire et tx5 souhaite lire à partir de cet emplacement, il lit la version de la structure de données correspondant à tx2 .


Ceci est fait pour renforcer la sérialisation ; comme tx5 doit être exécuté après tx2 et avant tx7 , il doit utiliser les valeurs écrites par tx2 et non par tx7 . Dans cet exemple, tx7 devra être réexécuté car il aurait dû lire les valeurs écrites par tx5 , et non par tx2 ou toute autre transaction de priorité supérieure. Si une structure de données à version unique était utilisée, la valeur écrite par tx2 ne serait pas disponible et un conflit se produirait certainement.


Pour une tâche de validation, l'ensemble de lecture de la transaction est comparé aux valeurs actuelles des emplacements de mémoire à partir desquels elle a lu pendant l'exécution. Par exemple, si tx2 lit le compte B pendant l'exécution, pendant la validation, l'emplacement de mémoire du compte B est lu (en gardant à l'esprit la définition de lecture que nous avons établie précédemment). Si les deux valeurs sont identiques, cela signifie qu'aucune transaction de priorité supérieure (par exemple tx0 ou tx1 ) n'a écrit à cet emplacement pendant l'exécution de tx2 . Cela entraîne que tx2 est marqué comme validé mais qu'il n'est pas sûr de le valider.


La transaction n'est pas considérée comme sûre à valider car une transaction de priorité inférieure pourrait, pour un certain nombre de raisons, être exécutée après la validation de la transaction. Dans notre exemple, si tx1 touche le compte B et ne le touche qu'après, tx2 passe la validation, alors tx2 doit être réexécuté.


Pour ce faire, à chaque fois qu'une transaction termine son exécution, toutes les transactions de priorité inférieure qui ont passé la validation sont revalidées pour garantir qu'elles n'entrent pas en conflit avec la transaction. Par exemple, si tx1 , tx3 et tx4 ont été validées et que tx2 termine son exécution, tx3 et tx4 doivent être revalidés pour garantir qu'ils n'entrent pas en conflit avec tx2 (et ne sont donc pas des dépendances de celui-ci).


Si une transaction échoue à la validation, c'est-à-dire si une transaction de priorité supérieure qui écrit dans le même état a été exécutée en même temps qu'elle, alors les écritures effectuées par la transaction sont sales (car les valeurs sont erronées). Mais au lieu de supprimer complètement ces valeurs de la base de données, elles sont marquées ESTIMATE.


L'indicateur ESTIMATE indique à toute transaction lisant cet emplacement mémoire que les valeurs qui y sont présentes ne sont pas correctes et les transactions suspendent leur exécution. Cette opération remplace la suppression, car la réexécution de la transaction dont la validation a échoué entraînerait probablement l'écriture dans les mêmes emplacements mémoire que l'exécution précédente.


En marquant l'emplacement mémoire comme une estimation au lieu de le supprimer, les dépendances (de la transaction dont la validation a échoué) peuvent être détectées avant même la réexécution, évitant ainsi les réexécutions inutiles. Cette heuristique réduit considérablement le travail inutile.

Mettre tout cela ensemble

Un aperçu complet de la manière dont Block-STM aborde la parallélisation peut être résumé comme suit :

  • Un BLOCK de transactions commence par une liste ordonnée avec un ordre sériel clairement défini. Ces transactions sont exécutées sur toutes les ressources disponibles par ordre de priorité.
  • Lors de l'exécution, les ensembles de lecture et d'écriture des transactions sont suivis et les lectures et écritures sont effectuées depuis/vers une structure de données multiversion. Lorsqu'une transaction termine son exécution, elle est validée pour garantir qu'elle n'a pas été exécutée en même temps que des transactions en conflit.
  • Si une transaction passe la validation, elle est supprimée de E et V. Et lorsqu'une transaction est validée, toutes les transactions de priorité inférieure à celle-ci qui ont passé la validation sont reprogrammées pour validation.
  • Si une transaction échoue à la validation, elle est reprogrammée pour exécution. Lorsque l'ensemble des transactions a été exécuté et validé, le BLOC entier peut être validé en toute sécurité et les résultats peuvent être écrits dans la mémoire permanente.


Un exemple est présenté ci-dessous :


Figure 6 : Exemple de Block-STM


Voici un aperçu du fonctionnement de Block-STM. Plus de détails peuvent être trouvés dans notre rapport ici et dans le document original de Block-STM ici .

Comment Block-STM améliore-t-il les performances de Starknet ?

Pour quantifier l’importance de l’ajout de Block-STM, nous avons effectué quelques tests pour évaluer les améliorations de performances qu’il apporte par rapport à l’exécution séquentielle et les résultats sont présentés ci-dessous.


Figure 7 : Performances Block-STM pour une taille de bloc de 1 k


Figure 8 : Performances Block-STM pour une taille de bloc de 10 k


Les résultats montrent que lorsque le nombre de threads (analogues à des unités de traitement indépendantes) utilisés augmente, les performances augmentent également. Les améliorations sont plus prononcées avec des blocs plus grands, ce qui donne des améliorations de performances jusqu'à 9X par rapport à une exécution séquentielle avec seulement 16 threads. Nous avons constaté que les résultats sont plus prononcés avec des blocs plus grands.


Nos tests montrent que les performances de Block-STM se dégradent considérablement sous des charges très conflictuelles, mais la pratique courante dans le secteur consiste à revenir à l'exécution séquentielle pendant de telles périodes. Nous recommandons le même mécanisme à Starknet pour préserver le débit sous des charges de travail très conflictuelles. Mais, dans l'ensemble, l'ajout de Block-STM améliorera considérablement et pérennisera Starknet.


Le deuxième changement majeur intégré dans la mise à niveau v0.13.2 est le regroupement de blocs et nous en parlerons plus en détail ci-dessous.

Boulon Partie 2 : Emballage de bloc

Comme nous l'avons vu précédemment, avant Bolt, chaque bloc Starknet était une tâche distincte, ce qui entraînait un coût fixe par bloc pour chaque bloc. De plus, le système a été conçu de telle sorte que chaque bloc nécessitait son propre blob, quelle que soit la quantité de données réellement consommée par le bloc.


Dans un monde où la demande était toujours élevée, cela ne poserait pas de problème, mais Starknet offre actuellement plus d'espace de bloc que la demande et il y a donc beaucoup de ressources gaspillées qui pourraient entraîner la perte de centaines d'ETH au cours d'un mois. Pour mettre davantage en contexte la gravité de la situation avant Bolt, voici les coûts associés à la publication d'un bloc sur L1 :


  1. 23 000 $ d'essence par enregistrement - partie de la vérification de la preuve et de l'enregistrement
  2. 56K gaz par page de mémoire SHARP de registre
  3. 136 000 gaz par État Mise à jour
  4. 50K gas pour la précompilation KZG pour échantillonner un blob,
  5. 86 000 $ de gaz pour exécuter la fonction de mise à jour de l'état.


Cela représente un total de 215 000 gaz par bloc et ce coût est fixe, c'est-à-dire qu'il est le même quelle que soit la quantité de données contenues dans chaque bloc et qu'il est lié au nombre de blocs par $Cost = num blocks * 215000$. La solution idéale à ce problème serait que les coûts soient liés à la quantité de données publiées plutôt qu'à la quantité de blocs. Et c'est exactement ce que le regroupement de blocs permet d'accomplir via les arbres SNAR.

Essais du SNAR

Les arbres Starknet Applicative Recursive (SNAR) sont un nouveau type d'arbre binaire introduit dans Bolt pour résoudre les problèmes mis en évidence ci-dessus. Un arbre SNAR a la structure suivante : chaque feuille est un bloc Starknet et les nœuds de tous les autres niveaux sont des preuves récursives de leurs enfants. Le nœud racine qui est une preuve récursive de toutes les autres preuves est le travail final qui est envoyé au SHARed Prover (SHARP).


Figure 9 : Arbre SNAR


Figure 10 : arborescence SNAR dans le flux de travail de conditionnement de blocs

Que fait l’arbre SNAR ?

Le principal avantage de l'arbre SNAR est que plutôt que de publier un bloc par preuve, de nombreux blocs Starknet peuvent être amortis dans la même mise à jour L1. Les racines de l'arbre SNAR sont désormais publiées sur le L1 uniquement lorsque l'une des deux limites configurables est atteinte : soit la limite DA (6 blobs de données), soit après qu'un certain nombre de feuilles ont été ajoutées à l'arbre (où une feuille est un bloc).


Cette conception dissocie le coût des transactions du nombre de blocs. Il existe toujours un coût fixe pour chaque bloc résultant de l'exécution du système d'exploitation StarkNet (SNOS) dans chaque bloc, mais dans l'ensemble, les coûts sont dissociés. Voici les chiffres actuels :


  1. Enregistrement de mémoire SHARP par tâche : 23 000 gaz (comme avant)
  2. Page mémoire SHARP par tâche : 36 K gas (réduit de 56 K grâce à l'optimisation SHARP),
  3. Mise à jour de l'état par tâche égale à :
  4. 86K gaz (comme avant) +
  5. 50 000 gaz × nombre de blobs utilisés. (Lorsqu'un blob était utilisé par bloc, cela représentait 50 000 x 1, ce qui donnait le nombre de gaz de 136 000 indiqué ci-dessus).


Le graphique de la figure 11 ci-dessous montre comment les coûts du gaz varient en fonction du numéro de bloc dans la conception précédente et maintenant (sous Bolt) :


Figure 11 : Coûts de vérification avec et sans conditionnement en bloc


Il est assez évident que le regroupement de blocs réduit considérablement les coûts de vérification sur le L1, ce qui entraînera sans aucun doute une baisse des prix du gaz pour les utilisateurs de Starknet.

Conclusion

L'effet des changements apportés à Bolt : exécution parallèle optimiste via Block-STM et packaging de blocs via le SNAR propriétaire peut être résumé comme suit : plus rapide et moins cher.


L'exécution parallèle réduit le temps d'exécution et, par extension, la congestion, ce qui réduira les frais de gaz pendant les périodes de trafic élevé, tandis que les arbres SNAR s'attaquent aux coûts associés de DA et de preuve. Il est intéressant de noter que cette mise à niveau fait de Starknet le premier L2 avec exécution parallèle et le prépare à devenir un concurrent majeur dans l'espace L2. Il est important de noter qu'il est peu probable que l'effet de ces changements soit immédiatement évident, en particulier celui de l'exécution parallèle, mais ils sont essentiels pour assurer la pérennité de Starknet et de l'ensemble de l'écosystème Ethereum dans son ensemble.


Note de l'auteur : Une version de cet article a déjà été publiée ici .