paint-brush
Disimballaggio dell'aggiornamento del bullone Starknetdi@2077research
Nuova storia

Disimballaggio dell'aggiornamento del bullone Starknet

di 2077 Research17m2024/12/26
Read on Terminal Reader

Troppo lungo; Leggere

L'aggiornamento Starknet Bolt ha introdotto due funzionalità principali: esecuzione parallela e prestazioni a blocchi. Questo articolo illustra come queste funzionalità appena introdotte migliorino le prestazioni di Starknet e l'esperienza di transazione per gli utenti Layer 2 (L2).
featured image - Disimballaggio dell'aggiornamento del bullone Starknet
2077 Research HackerNoon profile picture


L'ultimo aggiornamento di Starknet (v0.13.2) denominato Bolt apporta due cambiamenti importanti: esecuzione parallela e block-packing . Sebbene indipendenti l'una dall'altra, entrambe le funzionalità supportano la spinta verso l'obiettivo di uno spazio di blocco veloce ed economico, crittograficamente protetto da Ethereum.


L'esecuzione parallela consente alle transazioni non contenziose (ovvero, transazioni che non toccano lo stesso stato) di essere eseguite contemporaneamente. Implementando l'esecuzione parallela, L2 come Starknet possono ridurre il tempo di esecuzione senza aumentare l'utilizzo delle risorse. Ciò significa commissioni di transazione inferiori per gli utenti e tempi di conferma delle transazioni notevolmente migliorati.


Il block packing ottimizza l'utilizzo di Starknet del blobspace su Ethereum L1: con il block packing, i sequencer possono generare una prova per verificare più blocchi Starknet L2 contemporaneamente. Ciò separa l'utilizzo del blobspace dalla frequenza di produzione dei blocchi L2 e ammortizza i costi di verifica della prova. Entrambi riducono i costi operativi per il sequencer Starknet, il che significa che gli utenti pagano meno per transazione.


Come abbiamo detto, Bolt rende Starknet più economico e veloce! Questo report fornirà un'analisi dettagliata dell'aggiornamento di Bolt, concentrandosi sull'esecuzione parallela e sul block packing, ed esplorerà le implicazioni per le prestazioni di Starknet.

Un rapido ripasso sui rollup

I rollup sono soluzioni di scaling di livello due (L2) che mirano a scalare la blockchain di livello uno (L1) sottostante spostando il calcolo fuori dalla catena. Spostando l'esecuzione fuori dalla catena, i rollup possono ottimizzare la scalabilità (transazioni economiche e veloci), mentre L1 fornisce sicurezza per le transazioni L2.


Si dice spesso che i rollup "ereditino la sicurezza dall'L1". Ciò significa essenzialmente che ereditano il consenso e le garanzie di disponibilità dei dati fornite dall'L1. Oltre a ciò, l'L1 fornisce anche una garanzia di sicurezza sotto forma di bridging sicuro tra sé e il rollup.


Quando i sequencer pubblicano blocchi L2 su L1, L1 fornisce garanzie di disponibilità e ordinamento di queste informazioni. Da qui, i nodi L2 possono calcolare in modo affidabile la catena L2 canonica con queste informazioni insieme alle regole del rollup sulla derivazione della catena e sulla transizione di stato descritte dall'implementazione del nodo.


Per facilitare il bridging sicuro tra L1 e L2, L1 richiede la prova che la catena L2 che sta seguendo al momento sia corretta e non includa modifiche di stato illegali (ad esempio doppia spesa). Questa necessità di rollup per dimostrare la validità delle modifiche di stato, assicura che L1 non autorizzi prelievi dal rollup in base allo stato illegale.


I rollup differiscono in base al modo in cui dimostrano la validità delle modifiche di stato alla L1:

  • I rollup di validità si basano su prove di validità per verificare oggettivamente la correttezza dell'esecuzione. I proponenti possono proporre un nuovo stato di rollup se inviano una prova di validità al contratto di rollup.
  • I rollup ottimistici si basano sull'assenza di una prova di frode per verificare soggettivamente la correttezza dell'esecuzione. I proponenti inviano aggiornamenti di stato senza prove, ma il contratto di rollup può annullare qualsiasi aggiornamento di stato la cui validità sia contestata con successo da una prova di frode.


I rollup forniscono inoltre al livello di base dati sufficienti per le parti interessate a ricostruire lo stato L2. Mentre i rollup ottimistici devono pubblicare dati completi sulle transazioni per consentire ai contestatori di calcolare le prove di frode, i rollup di validità non hanno tali requisiti (le prove di validità garantiscono l'esecuzione corretta). Tuttavia, pubblicare dati completi sulle transazioni su L1 è comunque utile da una prospettiva di minimizzazione della fiducia (ricostruzione dello stato senza fiducia e prelievi senza autorizzazione).


Starknet è un rollup di validità che usa S calable, T rasparent AR gument of K nowledge (STARK) per dimostrare la validità delle modifiche di stato. L'ultimo aggiornamento di Starknet, nome in codice Bolt, aggiunge l'esecuzione parallela e il block packing. Nelle sezioni successive, spiegheremo come funzionano le due funzionalità e quali miglioramenti apportano agli utenti di Starknet.

Cosa ha cambiato l'aggiornamento Starknet Bolt?

Ad alto livello, l'aggiornamento di Bolt ha modificato i meccanismi di esecuzione, verifica e disponibilità dei dati di Starknet.

Ottimizzazione dell'esecuzione

Prima dell'aggiornamento di Bolt, le transazioni Starknet venivano eseguite in sequenza, una dopo l'altra, dal sequencer. L'esecuzione sequenziale è semplice ma anche molto inefficiente. È inefficiente perché non sfrutta le molteplici unità di elaborazione indipendenti che i computer moderni offrono e la parallelizzabilità di un set di transazioni.


Esecuzione sequenziale


Esecuzione parallela

La parallelizzabilità è una misura di quanto siano indipendenti le transazioni in un dato set. Ad esempio, considera il set di tre transazioni qui sotto:

  • Transazione 1: Alice vuole inviare a Bob 1 STRK

  • Transazione 2: Caitlyn vuole inviare a Danny 100 ETH

  • Transazione 3: Caitlyn vuole inviare a Ella 100 ETH


La transazione 1 è completamente indipendente dalle transazioni 2 e 3, perché accede a una parte diversa dello stato (il saldo di Alice) e può essere eseguita contemporaneamente. Tuttavia, le transazioni 2 e 3 sono in conflitto perché vogliono accedere allo stesso stato, il saldo ETH di Caitlyn. Queste transazioni non possono essere eseguite contemporaneamente o finiremo con risultati conflittuali.


Per fare un esempio:

  • Diciamo che il saldo di Caitlyn è di 300 ETH e le transazioni 2 e 3 iniziano contemporaneamente. Entrambe le transazioni leggeranno il saldo iniziale del conto di Caitlyn come 300 ETH, ne dedurranno l'importo del trasferimento (300 - 100 = 200) e scriveranno 200 ETH nella posizione in memoria in cui è archiviato il saldo del conto di Caitlyn.
  • Le transazioni 2 e 3 leggeranno quindi rispettivamente i saldi di Danny ed Ella e aggiungeranno 100 ETH ai saldi di entrambi gli utenti. Il saldo di Caitlyn si ridurrebbe di 100 ETH, ma verrebbero accreditati 200 ETH, stampando di fatto 100 ETH dal nulla.


Evitare questi tipi di conflitti (e la natura complessa dei meccanismi di mitigazione) è il motivo per cui Ethereum ha scelto l'esecuzione sequenziale. Tuttavia, mentre l'esecuzione sequenziale riduce la complessità e migliora la sicurezza, si traduce in un uso inefficiente dell'hardware. Peggio ancora, la tendenza della progettazione hardware suggerisce che l'esecuzione sequenziale diventerà sempre più inefficiente nei prossimi anni.


La figura 4 mostra l'andamento della progettazione hardware negli ultimi 50 anni. La conclusione rilevante? Le prestazioni single-thread (cerchi viola) hanno raggiunto un plateau dalla metà degli anni 2000, mentre il numero di core logici è aumentato più o meno nello stesso periodo. Possiamo trarre due conclusioni sulla base di questi dati:

  • I progettisti hardware stanno ampliando i chip dei computer aggiungendo più unità di elaborazione indipendenti anziché migliorare le prestazioni di una singola unità.

  • Qualsiasi sistema che continui a fare affidamento sulle prestazioni migliorate di una singola unità di elaborazione subirà una battuta d'arresto nei guadagni di prestazioni, anche con hardware più recente.


Figura 4: Tendenze dei microprocessori


Negli ultimi anni sono comparsi algoritmi sofisticati per gestire i conflitti di transazione e garantire la correttezza dell'esecuzione parallela. Block-STM (basato su un articolo di Fikunmi et al*) è uno di questi algoritmi e costituisce la parte centrale del nuovo motore di esecuzione parallela di Starknet. Analizzeremo l'algoritmo Block-STM nelle sezioni successive.

Ottimizzazione della dimostrazione e della disponibilità dei dati

SHARP (abbreviazione di Shared Prover) di Starknet ha sempre sfruttato le dimostrazioni ricorsive per ridurre il più possibile i costi di verifica. Una dimostrazione ricorsiva è essenzialmente una "prova di dimostrazione" in cui una dimostrazione verifica che una o più dimostrazioni siano corrette. Di seguito è riportato uno schizzo di come SHARP genera una dimostrazione ricorsiva:

  • Il sistema SHARP prende un set di programmi da eseguire (un "lavoro") come input e genera una prova di esecuzione per il lavoro. Questi "programmi" sono blocchi L2 e la prova attesta la correttezza delle transazioni.

  • La prova viene inviata a un altro programma che verifica la prova e converte il programma di verifica della prova in un lavoro. SHARP prende il nuovo lavoro come input e genera un'altra prova (questa prova conferma la validità della prova precedente).

  • Il processo (bozza → lavoro → bozza) si riavvia e continua fino al raggiungimento di un obiettivo, a quel punto la bozza finale (che ora è una versione altamente compressa della bozza originale) viene pubblicata su L1


Figura 5: Generazione di prove ricorsive


Questo design ammortizza notevolmente i costi per due motivi principali:

  • I lavori successivi* non sono programmi o transazioni individuali e i costi di verifica crescono in modo sub-lineare. Ciò significa che più è grande il numero di programmi/transazioni all'interno di un lavoro, maggiore è il risparmio. Creando prove per blocco anziché per transazione, le commissioni di transazione possono essere molto più economiche.
  • La ricorsione comprime notevolmente le prove, dando luogo a una "prova della prova" che è significativamente più economica da verificare sulla L1 rispetto alla prova iniziale o a una qualsiasi delle prove intermedie.


Sebbene il sistema di verifica fosse valido, sono state perse delle occasioni per risparmiare ulteriormente sui costi. Ad esempio, ogni lavoro era un singolo blocco Starknet e ognuno di questi blocchi era progettato per occupare un blob sulla L1. Ciò ha comportato alcune inefficienze come descritto di seguito:

  • Prima di Bolt, Starknet non aveva (e non ha ancora) tempi di blocco regolari; invece un blocco L2 veniva pubblicato su L1 a due condizioni: (1) Veniva eseguito un blob di dati (2) Erano trascorsi sei minuti dal blocco precedente. Sfortunatamente, a causa della domanda, la maggior parte dei blocchi veniva inviata a L1 a causa del limite di sei minuti (non dei limiti DA).
  • Quanto sopra significava che i blob (non i blocchi) erano spesso (gravemente) sottoutilizzati, con conseguenti costi del gas inutilmente elevati. Anche i blocchi Starknet avevano un costo fisso , che teoricamente poteva essere ridotto applicando le stesse tecniche di ricorsione discusse sopra per produrre prove di più blocchi.


Il block packing affronta questi problemi utilizzando un albero binario di dimostrazioni ricorsive. Discuteremo del block packing in una sezione successiva dell'articolo.

Bolt Parte 1: Esecuzione parallela

Come discusso in precedenza, l'esecuzione sequenziale è inefficiente (e diventerà sempre più inefficiente con il passare del tempo) e l'esecuzione parallela ingenua produce risultati non validi. Tuttavia, i motori di esecuzione parallela di produzione si prendono cura di evitare risultati incoerenti.


Esistono due approcci per affrontare l'esecuzione parallela: Pessimistic Concurrency Control (PCC) e Optimistic Concurrency Control (OCC) . PCC e OCC sono unità di elaborazione delle transazioni (TPU). Di seguito è riportata una definizione di unità di elaborazione delle transazioni da Block-STM vs. SVM: un confronto di motori di esecuzione parallela:


La TPU è solitamente accoppiata con, ma distinta dalla Virtual Machine (VM). Le VM Blockchain come EVM, SVM e MoveVM sono VM di linguaggio di alto livello... La TPU, che è solitamente l'oggetto di interesse, subordina la VM. È incaricata della gestione dell'intera pipeline di esecuzione delle transazioni, inclusa la creazione e la gestione di istanze della VM.


Il controllo della concorrenza pessimistica è progettato in base al presupposto che molte delle transazioni all'interno del set di transazioni da eseguire saranno in conflitto, ovvero toccheranno lo stesso stato. PCC impedisce questi conflitti.


Per evitare conflitti, PCC richiede che una transazione dichiari in anticipo a quali parti dello stato accederà durante le operazioni di lettura/scrittura. L'unità di elaborazione delle transazioni può utilizzare queste informazioni per pianificare le transazioni in modo da garantire che le transazioni in conflitto vengano eseguite in sequenza (anziché contemporaneamente). Alcune TPU utilizzano anche blocchi per imporre questo comportamento (un blocco (noto anche come mutex) è un meccanismo utilizzato per impedire l'accesso concorrente a una posizione di memoria).


Detto questo, l'esecuzione basata su PCC comporta alcuni compromessi. Innanzitutto, il requisito di fornire elenchi di accesso (che identificano lo slot di memoria toccato da una transazione) degrada l'esperienza dello sviluppatore e riduce la gamma di possibili applicazioni. In secondo luogo, la pianificazione delle transazioni può comportare un overhead non necessario, soprattutto quando non ci sono conflitti.


Il controllo della concorrenza ottimistica è progettato con l'ipotesi che molte delle transazioni all'interno del set dato non saranno in conflitto, ovvero non scriveranno nello stesso stato. Pertanto, le TPU OCC eseguono il set di transazioni con tutte le risorse disponibili e provano solo a rilevare i conflitti. Se viene rilevato un conflitto, le transazioni in conflitto vengono eseguite e verificate di nuovo finché l'intero set non passa e può essere eseguito il commit.


Le TPU OCC non subiscono overhead dalla pianificazione, quindi tendono a funzionare meglio quando ci sono pochi conflitti. Le unità di elaborazione delle transazioni basate su OCC hanno anche una migliore esperienza di sviluppo e una gamma più ampia di casi d'uso perché le dipendenze di stato non devono essere note in anticipo.


Tuttavia, quando l'insieme delle transazioni è altamente controverso, OCC funziona peggio di PCC. Trattiamo i progetti TPU (in modo molto più dettagliato) e confrontiamo gli approcci OCC e PCC nel nostro articolo sull'esecuzione parallela.


La nuova TPU di Starknet utilizza l'approccio OCC. Più specificamente, è un'implementazione dell'algoritmo Block-STM. Block-STM esegue le transazioni in modo ottimistico con tutte le risorse disponibili, supponendo che nessuna di esse entri in conflitto e verifica dopo l'esecuzione che nessuna transazione in conflitto venga eseguita contemporaneamente. Prima di immergerci nella nuova architettura di Starknet, è importante esaminare alcune definizioni chiave:

  1. Stato : lo stato è la condizione di un oggetto in un'istanza nel tempo. Nel contesto della blockchain di solito si riferisce al valore di una porzione di memoria, ad esempio, il saldo di un indirizzo è (parte del) suo stato.
  2. Serializzabilità : si dice che l'esecuzione parallela ha preservato la proprietà di serializzabilità se l'esecuzione di un set di transazioni in serie e contemporaneamente produce gli stessi risultati.
  3. Conflitto : due transazioni sono considerate in conflitto se e solo se almeno una di esse desidera scrivere su una porzione di stato a cui entrambe desiderano accedere (può essere letta o scritta). Se entrambe le transazioni leggono solo da una porzione di stato, allora non c'è conflitto, ma se almeno una di esse scrive su quella porzione di stato, allora le transazioni non possono essere eseguite contemporaneamente senza interrompere la serializzabilità. Abbiamo trattato un caso di esempio sopra nell'esempio di Caitlyn, Danny ed Ella.
  4. Dipendenza : una transazione txj si dice dipendente da (o una dipendenza di) una transazione txi se e solo se entrambe le transazioni scrivono nella stessa posizione di memoria e txj viene dopo txi nell'ordinamento seriale. Se txi venisse dopo txj , txi sarebbe dipendente da txj .
  5. Struttura dati multi-versione : una struttura dati multi-versione è una struttura in cui viene creata una nuova versione della struttura dati per ogni scrittura sulla struttura dati. Invece di modificare il valore in loco, viene creata una nuova versione specifica della scrittura della posizione da modificare. Il valore prop delle strutture dati multi-versione è che consentono letture e scritture altamente simultanee dalla stessa regione in memoria. Esploreremo in seguito come ciò sia utile.

Dopo aver chiarito le definizioni, possiamo passare a spiegare il funzionamento di Block-STM.

Come funziona Block-STM

L'input per Block-STM è una coda (un elenco ordinato) di transazioni, questo elenco è spesso chiamato BLOCK. Questo elenco può essere ordinato in qualsiasi modo; l'unico requisito è che ci sia un ordine chiaramente definito. Quindi, dato un set di transazioni T contenente transazioni {t0…tn} , le transazioni sono ordinate in modo tale che {t0 > t1 > t2 … > tn} (letto come t0 ha una priorità maggiore di t1 , t1 ha una priorità maggiore di t2 ecc.)


All'inizio del processo di esecuzione, vengono creati due set: un set di esecuzione E e un set di convalida V. E tiene traccia delle transazioni che devono ancora essere eseguite, mentre V tiene traccia delle transazioni che sono state eseguite ma devono ancora essere convalidate. Ogni transazione è anche associata a un numero di incarnazione n per tenere traccia di quante volte è stata eseguita (e rieseguita). Lo stato iniziale dei set è che E contiene tutte le transazioni e V è vuoto, ovvero E = {t0,1 > t1,1 > t2,1 > … > tn,1} e V = {} .


Con questi insiemi ordinati di transazioni, ogni thread utilizzato per l'esecuzione esegue un ciclo in tre fasi:

  1. Controllo completato
  2. Trova attività successiva
  3. Eseguire l'attività

Controllo completato

Durante questa fase, il thread controlla sia V che E. Se entrambi sono vuoti e non viene eseguita alcuna transazione, il batch corrente di transazioni è stato eseguito completamente e i risultati possono essere salvati nell'archivio.

Trova attività successiva

Se V o E contengono transazioni, Block-STM seleziona la transazione con l'indice più basso (non il numero di incarnazione) da entrambi i set di transazioni, ovvero se E contiene {t1,3 , t3,1 and t5,2} e V contiene {t0,1, t2,4, t4,3} , l'attività di convalida per la transazione t0 verrà selezionata come attività successiva.

Eseguire l'attività

Una volta identificato e selezionato il task successivo, questo viene eseguito. Alla fine di questo passaggio, l'algoritmo torna a Check Done. Questo processo continua finché entrambi i set di transazioni non sono vuoti.


Diamo un'occhiata a cosa succede durante l'esecuzione e la convalida:


Durante l'esecuzione di una transazione, l'algoritmo Block-STM popola due set (per transazione); un set di lettura ( Ri,n ) e un set di scrittura ( Wn,i ). Il set di lettura contiene tutte le posizioni di memoria da cui una transazione ha letto durante la sua esecuzione, mentre il set di scrittura contiene tutte le posizioni di memoria in cui ha scritto. Durante l'esecuzione, le transazioni applicano le loro scritture alla struttura dati multi-versione, ma la lettura è un po' sfumata.


In Block-STM quando una transazione vuole leggere dalla struttura dati, controlla il valore scritto dalla transazione con priorità più bassa che ha priorità più alta. Ad esempio, se tx1 , tx2 e tx7 hanno scritto tutti in una posizione di memoria e tx5 vuole leggere da questa posizione, legge la versione della struttura dati corrispondente a tx2 .


Questo viene fatto per imporre la serializzabilità; poiché tx5 dovrebbe essere eseguito dopo tx2 e prima di tx7 , dovrebbe usare i valori scritti da tx2 non tx7 . In questo esempio, tx7 dovrà essere rieseguito perché avrebbe dovuto leggere i valori scritti da tx5 , non da tx2 o da transazioni con priorità più alta. Se fosse stata utilizzata una struttura dati a versione singola, il valore scritto da tx2 non sarebbe disponibile e si verificherebbe sicuramente un conflitto.


Per un'attività di convalida, il set di lettura della transazione viene confrontato con i valori correnti nelle posizioni di memoria da cui legge durante l'esecuzione. Ad esempio, se tx2 legge l'account B durante l'esecuzione, durante la convalida, la posizione di memoria per l'account B viene letta (tenendo a mente la definizione di lettura che abbiamo stabilito in precedenza). Se i due valori sono uguali, significa che nessuna transazione con priorità più alta (ad esempio tx0 o tx1 ) ha scritto in quella posizione durante l'esecuzione di tx2 . Ciò comporta che tx2 venga contrassegnato come convalidato ma non sicuro per il commit.


La transazione non è considerata sicura da eseguire perché una transazione con priorità inferiore potrebbe, per un numero qualsiasi di ragioni, essere eseguita dopo che la transazione è stata convalidata. Nel nostro esempio in esecuzione, se tx1 tocca l'account B e lo tocca solo dopo, tx2 supera la convalida, quindi tx2 deve essere rieseguito.


Per provvedere a ciò, ogni volta che una transazione completa l'esecuzione, tutte le transazioni di priorità inferiore che hanno superato la convalida vengono riconvalidate per garantire che non siano in conflitto con la transazione. Ad esempio, se tx1 , tx3 e tx4 sono stati convalidati e tx2 completa l'esecuzione, tx3 e tx4 devono essere riconvalidati per garantire che non siano in conflitto con (e quindi non siano dipendenze di) tx2 .


Se una transazione non supera la convalida, ovvero se contemporaneamente è stata eseguita una transazione con priorità più alta che scrive nello stesso stato, le scritture effettuate dalla transazione risultano sporche (perché i valori sono errati). Tuttavia, anziché eliminare completamente questi valori dal database, vengono contrassegnati come ESTIMATE.


Il flag ESTIMATE indica a qualsiasi transazione che legge quella posizione di memoria che i valori non sono corretti e le transazioni mettono in pausa la loro esecuzione. Questo avviene al posto dell'eliminazione perché la riesecuzione della transazione che non ha superato la convalida probabilmente comporterebbe la scrittura nelle stesse posizioni di memoria dell'esecuzione precedente.


Contrassegnando la posizione di memoria come stima anziché eliminarla, le dipendenze (della transazione che non ha superato la convalida) possono essere intercettate anche prima della riesecuzione, impedendo ri-esecuzioni non necessarie. Questa euristica riduce notevolmente lo spreco di lavoro.

Mettere tutto insieme

Una panoramica completa di come Block-STM affronta la parallelizzazione può essere riassunta come:

  • Un BLOCK di transazioni inizia come un elenco ordinato con un ordine seriale chiaramente definito. Queste transazioni vengono eseguite su tutte le risorse disponibili in ordine di priorità.
  • Durante l'esecuzione, i set di lettura e scrittura delle transazioni vengono tracciati e le letture e le scritture vengono eseguite da/verso una struttura dati multi-versione. Quando una transazione termina l'esecuzione, viene convalidata per garantire che non sia stata eseguita contemporaneamente a transazioni in conflitto.
  • Se una transazione supera la convalida, viene rimossa da E e V. Quando una transazione viene convalidata, tutte le transazioni con priorità inferiore alla sua che hanno superato la convalida vengono riprogrammate per la convalida.
  • Se una transazione non supera la convalida, viene riprogrammata per l'esecuzione. Quando l'intero set di transazioni è stato eseguito e convalidato, l'intero BLOCK è sicuro da impegnare e i risultati possono essere scritti in un archivio permanente.


Di seguito è riportato un esempio:


Figura 6: Esempio Block-STM


Questa è una panoramica del funzionamento di Block-STM; maggiori dettagli sono disponibili nel nostro rapporto qui e nel documento originale di Block-STM qui .

In che modo Block-STM migliora le prestazioni di Starknet?

Per quantificare l'importanza dell'aggiunta di Block-STM, abbiamo eseguito alcuni benchmark per valutare i miglioramenti delle prestazioni che offre rispetto all'esecuzione sequenziale; i risultati sono riportati di seguito.


Figura 7: Prestazioni Block-STM a blocchi di 1k


Figura 8: Prestazioni Block-STM a blocchi da 10k


I risultati mostrano che all'aumentare del numero di thread (analoghi alle unità di elaborazione indipendenti) utilizzati, aumentano anche le prestazioni. I miglioramenti sono più pronunciati con blocchi più grandi che offrono miglioramenti delle prestazioni fino a 9 volte superiori rispetto all'esecuzione sequenziale con soli 16 thread. Abbiamo scoperto che i risultati sono più pronunciati con blocchi più grandi.


I nostri test dimostrano che le prestazioni di Block-STM si degradano in modo significativo sotto carichi altamente controversi, ma la prassi standard del settore è quella di ricorrere all'esecuzione sequenziale durante tali periodi. Raccomandiamo la stessa meccanica a Starknet per preservare la produttività sotto carichi di lavoro altamente controversi. Ma, in generale, l'aggiunta di Block-STM migliorerà in modo significativo e renderà Starknet a prova di futuro.


La seconda modifica importante inclusa nell'aggiornamento v0.13.2 è il block packing, di cui parleremo più avanti.

Bullone Parte 2: Blocco di imballaggio

Come discusso in precedenza, prima di Bolt, ogni blocco Starknet era un lavoro a sé stante, con un conseguente costo fisso per blocco per ogni blocco. Inoltre, il sistema era progettato in modo che ogni blocco richiedesse il proprio blob indipendentemente dalla quantità di dati effettivamente consumata dal blocco.


In un mondo in cui la domanda è sempre stata alta, questo non sarebbe un problema, ma Starknet attualmente offre più blockspace di quanto ci sia domanda e quindi ci sono molte risorse sprecate che potrebbero causare la perdita di centinaia di ETH nel corso di un mese. Per contestualizzare ulteriormente la gravità della situazione prima di Bolt, questi sono i costi associati alla pubblicazione di un blocco su L1:


  1. 23K gas per registrazione dei fatti – parte di Verifica prova e registrazione
  2. 56K gas per registro Pagina di memoria SHARP
  3. 136K gas per aggiornamento dello Stato
  4. 50K di gas per la precompilazione KZG per campionare un blob,
  5. 86K di carburante per l'esecuzione della funzione di aggiornamento dello stato.


Ciò equivale a 215k gas per blocco e questo costo è fisso, ovvero è lo stesso indipendentemente dalla quantità di dati contenuta in ogni blocco e correlato al numero di blocchi da $Cost = num blocks * 215000$. La soluzione ideale a questo problema sarebbe che i costi fossero correlati alla quantità di dati pubblicati anziché alla quantità di blocchi. Ed è esattamente ciò che il block packing ottiene tramite alberi SNAR.

Tentativi SNAR

Gli alberi Starknet Applicative Recursive (SNAR) sono un nuovo tipo di albero binario introdotto in Bolt per risolvere i problemi evidenziati sopra. Un albero SNAR ha la seguente struttura: ogni foglia è un blocco Starknet e i nodi in tutti gli altri livelli sono prove ricorsive dei loro figli. Il nodo radice che è una prova ricorsiva di tutte le altre prove è il lavoro finale che viene inviato allo SHARed Prover (SHARP).


Figura 9: Albero SNAR


Figura 10: Albero SNAR nel flusso di lavoro di confezionamento dei blocchi

A cosa serve l'albero SNAR?

Il vantaggio principale di SNAR Tree è che anziché pubblicare un blocco per prova, molti blocchi Starknet possono essere ammortizzati nello stesso aggiornamento L1. Le radici dell'albero SNAR vengono ora pubblicate su L1 solo quando viene raggiunto uno dei due limiti configurabili: il limite DA (6 blob di dati) o dopo che un certo numero di foglie sono state aggiunte all'albero (dove una foglia è un blocco).


Questo design disaccoppia il costo delle transazioni dal numero di blocchi. Ora, c'è ancora un costo fisso per ogni blocco che deriva dall'esecuzione di StarkNet OS (SNOS) in ogni blocco, ma in generale i costi sono disaccoppiati. Questi sono i numeri ora:


  1. Registrazione della memoria SHARP per lavoro: 23K gas, (come prima)
  2. Pagina di memoria SHARP per lavoro: 36K di gas (ridotto da 56K grazie all'ottimizzazione SHARP),
  3. Aggiornamento dello stato per lavoro pari a:
  4. 86K benzina (come prima) +
  5. 50K gas × numero di blob utilizzati. (Quando veniva utilizzato un blob per blocco, questo era 50K x 1, ottenendo il numero di gas 136K indicato sopra).


Il grafico nella Figura 11 sottostante mostra come i costi del gas variano in base al numero di blocchi nel progetto precedente e ora (sotto Bolt):


Figura 11: Costi di verifica con e senza imballaggio a blocchi


È abbastanza ovvio che il block packing riduce notevolmente i costi di verifica sulla L1, il che si tradurrà senza dubbio in prezzi del gas più bassi per gli utenti Starknet.

Conclusione

L'effetto delle modifiche apportate in Bolt: esecuzione parallela ottimistica tramite Block-STM e block-packing tramite SNAR proprietario può essere riassunto come: più veloce ed economico.


L'esecuzione parallela riduce i tempi di esecuzione e, per estensione, la congestione, il che ridurrà le tariffe del gas durante i periodi di traffico elevato, mentre gli alberi SNAR affrontano i costi DA e di verifica associati. È interessante notare che questo aggiornamento rende Starknet il primo L2 con esecuzione parallela e lo prepara a essere un contendente importante nello spazio L2. È importante notare che è improbabile che l'effetto di queste modifiche sarà immediatamente evidente, in particolare quello dell'esecuzione parallela, ma sono fondamentali per rendere Starknet e l'intero ecosistema Ethereum a prova di futuro.


Nota dell'autore: una versione di questo articolo è stata precedentemente pubblicata qui .