Autor: Tia, Techub News
Blockchain-ul, datorită designului său descentralizat, a sacrificat eficiența, astfel că îmbunătățirea vitezei de execuție a fost întotdeauna una dintre problemele urgente de rezolvat. „Stratul de execuție” al blockchain-ului este partea esențială care procesează fiecare tranzacție și o adaugă în lanț. Pentru a accelera capacitatea de procesare, îmbunătățirea stratului de execuție a devenit una dintre strategiile principale, iar execuția paralelă este o descoperire importantă în acest sens.
Blockchain-urile tradiționale tratează tranzacțiile în mod secvențial, ceea ce limitează foarte mult viteza tranzacțiilor, în special în rețelele cu trafic intens, ceea ce poate duce la congestionare. Totuși, prin execuția paralelă, mai multe tranzacții pot fi procesate simultan, sporind astfel semnificativ eficiența execuției și reducând presiunea pe lanț.
Pentru a înțelege mai bine ce este paralelismul, vom începe cu execuția și vom folosi Ethereum în modul PBS după Merge ca exemplu pentru a explica ce este execuția, în timp ce vom arăta locul execuției în întregul ciclu de viață al tranzacției.
Etapele specifice ale execuției tranzacției
Tranzacțiile intră în pool-ul de memorie și sunt filtrate și sortate: aceasta este etapa de preprocesare după ce tranzacția a fost trimisă, care include interacțiunea dintre Mempool, Searcher și Builder, completând filtrarea și sortarea tranzacțiilor.
Builder-ul construiește blocul (dar nu îl execută): Builder-ul aranjează tranzacțiile profitabile într-un bloc, pentru a finaliza ambalarea și sortarea tranzacțiilor.
Propunătorul verifică și trimite blocul: după finalizarea construcției blocului, Builder-ul trimite propunerea blocului către Propunător. Propunătorul verifică structura blocului și conținutul tranzacțiilor, apoi trimite oficial blocul în rețea pentru a începe execuția.
Execuția tranzacției: după ce blocul este trimis, nodurile execută tranzacțiile din interiorul blocului una câte una. Aceasta este etapa cheie a actualizării stării, fiecare tranzacție declanșând apeluri către contracte inteligente, modificări ale soldurilor conturilor sau schimbări de stare.
Martorii mărturisesc: validatorii mărturisesc rezultatul execuției blocului și rădăcina stării și o folosesc ca confirmare finală. Aceasta asigură autenticitatea și validitatea blocului în stratul de execuție și previne inconsecvențele.
Sincronizarea stării: fiecare nod va sincroniza rezultatul execuției blocului (cum ar fi soldurile conturilor, actualizările stării contractelor etc.) în starea sa locală, după execuția fiecărei tranzacții, nodul calculează și stochează o nouă rădăcină de stare, care va fi folosită ca stare inițială în următorul bloc.
Desigur, aceasta este doar sincronizarea stării tranzacțiilor pe unități de bloc, pentru a menține starea actualizată pe lanț, de obicei, nodurile sincronizează datele bloc cu bloc și verifică continuu blocurile și starea. Dar pentru a atinge finalitatea sub mecanismul POS, este necesar ca agregatorul să adune semnăturile martorilor din fiecare Slot într-o semnătură completă și să o transmită la propunătorul următorului Slot, iar validatorul trebuie, după un Epoch, să confirme starea tuturor blocurilor din acel Epoch pe baza numărului de voturi, formând un punct de control al stării consensuale temporare. Atunci când două Epoch-uri consecutive obțin suportul majorității validatorilor, blocul și tranzacțiile vor atinge finalitatea.
Din perspectiva întregului ciclu de viață al tranzacției, execuția are loc după ce Propunătorul verifică structura blocului și conținutul tranzacțiilor trimise de Builder. Procesul efectiv de execuție necesită tratarea fiecărei tranzacții individual și actualizarea stării corespunzătoare a contului sau contractului. După finalizarea execuției tuturor tranzacțiilor, Propunătorul va calcula o nouă rădăcină de stare (rădăcina Merkle), care este un rezumat al rezultatelor execuției tuturor tranzacțiilor curente și al stării globale finale. Pe scurt, procesul complet de execuție a blocului include o serie de calcule necesare pentru a transforma Ethereum de la o stare anterioară la o stare ulterioară, de la execuția fiecărei tranzacții la calculul rădăcinii Merkle.
Execuție secvențială
În contrast cu paralelismul, execuția secvențială este metoda de execuție mai comună în prezent pe blockchain. De obicei, tranzacțiile sunt executate pas cu pas în ordinea lor. După ce o tranzacție este complet executată, Ethereum actualizează starea contului și informațiile aferente (de exemplu, soldul, datele de stocare ale contractului) în arborele de stare al contului, generând un nou hash de stare al contului. După ce toate arborile de stare ale contului sunt actualizate, se formează un nod rădăcină al arborelui de stare cunoscut sub numele de rădăcină Merkle a stării. După finalizarea rădăcinii Merkle a stării, rădăcinii Merkle a tranzacției și rădăcinii Merkle a chitanței, capul blocului va fi supus calculului hash, generând hash-ul blocului.
Și în acest context, ordinea de execuție a tranzacției este crucială. Deoarece arborele Merkle este un arbore binar de hash-uri, valorile rădăcinii Merkle formate în ordini diferite vor fi diferite.
Executare paralelă
În mediu de execuție paralelă, nodurile vor încerca să proceseze tranzacțiile din bloc în mod paralel. Nu este vorba despre executarea tranzacțiilor pas cu pas în ordinea lor, ci despre alocarea tranzacțiilor pe diferite „căi de execuție” pentru a putea fi executate simultan. Prin execuția paralelă, sistemul poate procesa tranzacțiile din blocuri mai eficient, sporind throughput-ul.
După finalizarea execuției tuturor tranzacțiilor, nodul va rezuma rezultatele execuției (adică actualizările de stare afectate de tranzacții) pentru a forma o nouă stare a blocului. Această stare va fi adăugată la blockchain, reprezentând cea mai recentă stare globală pe lanț.
Conflicte de stare
Deoarece paralelismul va trata tranzacțiile simultan pe căi diferite, o mare dificultate a paralelismului este conflictul de stare. Acesta apare atunci când mai multe tranzacții încearcă să citească sau să scrie aceleași date (stare) pe blockchain în aceeași perioadă de timp. Dacă această situație nu este gestionată corect, rezultatele execuției vor fi incerte. Deoarece ordinea actualizărilor stării este diferită, rezultatul final al calculului va fi, de asemenea, diferit. De exemplu,
Să presupunem că există două tranzacții, tranzacția A și tranzacția B, care încearcă să actualizeze soldul aceluiași cont:
Tranzacția A: crește soldul contului cu 10.
Tranzacția B: crește soldul contului cu 20.
Soldul inițial al contului este 100.
Dacă executăm în serie, rezultatul ordinii de execuție este determinat:
1. Executați mai întâi tranzacția A, apoi tranzacția B:
Soldul contului crește mai întâi cu 10, ajungând la 110.
Adăugați încă 20, ajungând în final la 130.
2. Executați mai întâi tranzacția B, apoi tranzacția A:
Soldul contului crește mai întâi cu 20, ajungând la 120.
Adăugați încă 10, ajungând în final la 130.
În ambele ordine, soldul final este 130, deoarece sistemul asigură consistența ordinii de execuție a tranzacțiilor.
Dar în mediu de execuție paralelă, tranzacția A și tranzacția B pot citi simultan soldul inițial de 100 și efectua calculele proprii:
Tranzacția A citește soldul de 100, calculează și actualizează soldul la 110.
Tranzacția B citește de asemenea soldul de 100, calculează și actualizează soldul la 120.
În această situație, din cauza executării simultane a tranzacțiilor, soldul final este actualizat doar la 120, și nu la 130, deoarece operațiile tranzacției A și B 'se suprapun' asupra rezultatului celuilalt, generând un conflict de stare.
Aceste probleme de conflict de stare sunt adesea denumite 'suprapunere de date', adică atunci când tranzacțiile încearcă simultan să modifice aceleași date, rezultatele calculului pot fi suprapuse, ducând la o stare finală incorectă. O altă problemă posibilă legată de conflictele de stare este imposibilitatea de a garanta ordinea execuției. Deoarece mai multe tranzacții completează operațiile la momente diferite, ordinea diferită poate duce la rezultate diferite ale calculului, făcând rezultatul inexact.
Pentru a evita această incertitudine, sistemele de execuție paralelă pe blockchain introduc adesea mecanisme de detectare a conflictelor și de revenire, sau analizează dependențele tranzacțiilor din timp pentru a se asigura că acestea sunt executate în paralel fără a afecta consistența stării finale.
Paralelism optimist și paralelism determinist
Există două metode de a aborda problemele posibile de conflict de stare: paralelismul determinist și paralelismul optimist. Aceste două modele au compromisuri în ceea ce privește eficiență și complexitate de design.
Paralelismul determinist necesită declararea prealabilă a accesului la stare, validatorul sau secvențierul va verifica accesul declarat la stare în timpul ordonării tranzacțiilor. Dacă mai multe tranzacții încearcă să scrie aceeași stare, acestea vor fi marcate ca fiind în conflict, evitând astfel executarea simultană. Implementările specifice ale diferitelor lanțuri pentru a declara anticipat accesul la stare variază, dar în general includ următoarele forme:
Prin constrângerea specificațiilor contractului: dezvoltatorii definesc direct domeniul de acces la starea în contractele inteligente. De exemplu, transferurile de tokeni ERC-20 necesită acces la câmpurile de sold ale expeditorului și beneficiarului.
Prin declarația de date structurate în tranzacție: adăugarea de câmpuri speciale în tranzacție pentru a marca accesul la stare.
Prin analiza compilatorului: compilatoarele pentru limbaje de nivel înalt pot analiza static codul contractului, generând automat un set de acces la stare.
Prin declarații forțate de cadrul: anumite cadre cer dezvoltatorilor să declare explicit starea la care se dorește accesul atunci când apelează funcții.
Paralelismul optimist va procesa mai întâi tranzacțiile optimist, iar când apare un conflict, va re-executa tranzacțiile afectate în ordine. Pentru a evita cât mai mult posibil apariția conflictelor, esența designului paralelismului optimist este de a face evaluări rapide și ipoteze asupra stării prin date istorice, analize statice etc. Asta înseamnă că sistemul, fără a valida complet, presupune că anumite operații sau actualizări de stare sunt valide, încercând să evite așteptarea tuturor proceselor de validare, pentru a îmbunătăți performanța și throughput-ul.
Deși paralelismul optimist poate evita în mod optimist conflictele prin presupuneri și evaluări rapide ale stării, există totuși unele provocări inevitabile, în special în cazul execuției contractelor sau tranzacțiilor între lanțuri. Dacă conflictele apar frecvent, re-execuția poate încetini semnificativ performanța sistemului și poate crește consumul de resurse de calcul.
Paralelismul determinist evită conflictele care pot apărea în paralelismul optimist prin verificarea dependențelor de stare înainte de tranzacție, dar deoarece necesită ca dependențele de stare să fie declarate cu exactitate înainte de trimiterea tranzacției, aceasta impune cerințe mai mari dezvoltatorilor, crescând astfel complexitatea implementării.
Dilema EVM paralel
Abordarea conflictelor de stare nu se limitează doar la determinism și optimistism; în implementarea paralelismului, este necesar să se ia în considerare și arhitectura bazei de date a lanțului. Problema conflictelor de stare în paralelism este deosebit de dificilă în EVM-ul bazat pe structura arborelui Merkle. Arborele Merkle este o structură de hash în mai multe niveluri, iar la fiecare modificare a unui anumit date de stare de către o tranzacție, trebuie actualizat și hash-ul rădăcină al arborelui Merkle. Acest proces de actualizare este recursiv, calculându-se de la nodurile frunzelor până la nodul rădăcină. Deoarece hash-ul este ireversibil, adică poate fi calculat pe nivelul superior doar după ce modificările de date de la nivelurile inferioare sunt finalizate, această caracteristică face dificilă actualizarea paralelă.
Dacă două tranzacții sunt executate în paralel și accesează aceeași stare (cum ar fi soldul contului), va apărea un conflict la nivelul nodurilor arborelui Merkle. Rezolvarea acestor conflicte necesită, în general, mecanisme suplimentare de gestionare a tranzacțiilor pentru a asigura obținerea unui hash rădăcină consistent în toate ramurile. Acest lucru nu este ușor de realizat pentru EVM, deoarece necesită o alegere între paralelizare și consistența stării.
Soluții de paralelism non-EVM
Solana
Spre deosebire de arborele de stare global al Ethereum, Solana adoptă un model de conturi. Fiecare cont este un spațiu de stocare independent, stocat în registru, evitând astfel problemele de conflict de cale.
Solana este paralelism determinist. În Solana, fiecare tranzacție trebuie să declare în mod clar conturile pe care le va accesa și permisiunile necesare (doar citire sau citire/scriere) în momentul trimiterii. Acest design permite nodurilor blockchain să analizeze în avans resursele accesate de fiecare tranzacție înainte de execuție. Deoarece tranzacțiile au declarat toate relațiile de dependență ale conturilor înainte de a începe execuția, nodurile pot determina care tranzacții vor accesa aceleași conturi și care tranzacții pot fi executate în siguranță în paralel, ceea ce permite programarea inteligentă, evitând conflictele, stabilind astfel baza programării paralele.
Datorită faptului că fiecare tranzacție a fost declarată înainte de execuție cu conturile și permisiunile necesare, Solana poate verifica dacă există dependențe între conturi (modelul Sealevel). Dacă nu există conturi de citire și scriere partajate între tranzacții, sistemul poate aloca aceste tranzacții pe diferite procesoare pentru a fi executate în paralel.
Aptos
Designul execuției paralele al Aptos este foarte diferit de cel al Ethereum, aducând unele inovații cheie atât în arhitectură, cât și în mecanisme, care se reflectă în modelul de conturi și stocarea stării.
Ethereum necesită actualizarea frecventă a arborelui de stare global (MPT) în timpul executării tranzacțiilor. Toate stările conturilor și contractelor sunt stocate într-un arbore de stare partajat, iar orice tranzacție trebuie să acceseze și să actualizeze o parte din acest arbore de stare. Aptos, pe de altă parte, împarte conturile în unități de stare independente, fiecare obiect fiind o pereche cheie-valoare independentă, obiectele putând exista independent una de cealaltă, fără a se afecta reciproc, fiind asociate doar atunci când există relații de referință clare. Obiectele nu au căi comune în arbore, nu există competiție pentru blocaje și pot fi complet paralele.
Structura de date de bază a Aptos este Jellyfish Merkle Tree. Starea fiecărui obiect este stocată în final în JMT ca o pereche cheie-valoare independentă. Spre deosebire de MPT-ul Ethereum, Jellyfish Merkle Tree utilizează o structură complet binară, această formă simplificând căile de stocare și de interogare ale nodurilor, reducând semnificativ timpul de validare. De asemenea, fiecare cont are o poziție fixă în arbore, iar nodurile din arbore sunt stocate independent, permițând actualizările și căutările mai multor conturi să se desfășoare în paralel.
Aptos este optimist paralel, nu necesită furnizarea prealabilă a tuturor dependențelor conturilor declarate. Pentru aceasta, Aptos folosește Block-STM, care utilizează ordinea presetată a tranzacțiilor pentru a estima dependențele, reducând astfel numărul de anulări.
EVM paralel
Comparativ cu paralelismul non-EVM, EVM paralel se confruntă cu dificultăți tehnice mai mari în gestionarea dependențelor de stare, detectarea conflictelor, gestionarea gazului și mecanismele de revenire. Pentru a înțelege mai bine acest lucru, putem consulta cum unele proiecte EVM paralele (cum ar fi Sui, Monad, Canto) rezolvă aceste probleme.
Sui
Sui și Aptos folosesc de asemenea modelul de obiecte pentru a gestiona starea, adoptând fiecare obiect (de exemplu, conturi, starea contractului inteligent) ca resursă independentă, aceste obiecte fiind diferențiate prin identificatori unici de obiect. Când tranzacțiile implică obiecte diferite, aceste tranzacții pot fi procesate în paralel, deoarece operează asupra stărilor diferite, fără a genera conflicte directe.
Deși Sui folosește un model de obiecte pentru a gestiona starea, pentru a fi compatibil cu EVM, arhitectura Sui folosește un strat de adaptare suplimentar sau mecanisme de abstractizare pentru a conecta modelul de obiecte la modelul de conturi EVM.
În Sui, programarea tranzacțiilor folosește o strategie optimistă paralelă, presupunând că nu există conflicte între tranzacții. Dacă apare un conflict, sistemul folosește mecanisme de revenire pentru a restaura starea.
Sui a folosit modelul de obiecte și tehnologia de izolare a stării, reușind să evite eficient problemele de dependență a stării. Fiecare obiect, ca resursă independentă, permite tranzacții diferite să fie executate în paralel, îmbunătățind astfel throughput-ul și eficiența. Dar acest mod are un trade-off în complexitatea modelului de obiecte și costurile mecanismelor de revenire. Dacă apar conflicte între tranzacții, este necesar să se revină asupra unei părți din stare, ceea ce va crește sarcina sistemului și poate afecta eficiența procesării paralele. Comparativ cu sistemele paralele non-EVM (cum ar fi Solana), Sui necesită mai multe resurse de calcul și stocare pentru a menține paralelismul eficient.
Monad
La fel ca Sui, Monad adoptă de asemenea paralelism optimist. Dar paralelismul optimist al Monad, înainte de execuția specifică a tranzacției, va prezice unele tranzacții cu dependențe, prezicerea fiind realizată prin analizatorul de cod static al Monad. Prezicerea necesită acces la stare, iar modul în care Ethereum stochează starea în baza de date face ca accesul la stare să fie foarte dificil. Pentru a face procesul de citire a stării mai eficient în paralel, Monad a restructurat baza de date.
Arborele de stare al Monad este împărțit pe regiuni, fiecare regiune menținând propriul său subarbore de stare. La actualizare, este suficient să se modifice fragmentele relevante, fără a fi nevoie să se reconstruiască întregul arbore de stare. Folosind o tabelă de indexare a stării pentru a localiza rapid starea din regiune, se reduc interacțiunile între regiuni.
Concluzie
Paralelismul se concentrează pe îmbunătățirea eficienței stratului de execuție printr-o abordare de execuție pe mai multe căi, iar pentru a realiza execuția pe mai multe căi, lanțul trebuie să implementeze o serie de măsuri precum detectarea conflictelor și mecanismele de revenire pentru a se asigura că acestea sunt executate în paralel fără a afecta consistența stării finale, și să facă unele îmbunătățiri ale bazei de date.
Desigur, îmbunătățirea eficienței stratului de execuție nu se limitează la paralelism, optimizarea etapelor de execuție poate fi realizată și prin reducerea operațiunilor de citire și scriere necesare pentru fiecare tranzacție în baza de date. Îmbunătățirea vitezei întregului lanț implică o gamă mai largă, incluzând și îmbunătățirea eficienței stratului de consens.
Fiecare tehnologie are condiții specifice de limitare. Paralelismul este doar unul dintre modurile de a îmbunătăți eficiența, decizia finală de a utiliza această tehnologie trebuie să țină cont dacă este prietenoasă cu dezvoltatorii, dacă poate fi realizată fără a sacrifica descentralizarea etc. Stivuirea tehnologică nu este întotdeauna mai bună, cel puțin în cazul Ethereum, paralelismul nu este atât de atrăgător, dacă ne concentrăm doar pe îmbunătățirea eficienței, introducerea paralelismului nu este soluția optimă pentru Ethereum, fie din perspectiva simplității, fie din perspectiva foii de parcurs actuale centrate pe Rollup.