Come funziona Ethereum? (Italian ver.)

READ STORY
Special thanks to Hacktar(@inzhoop) and Matteopey(@matteopey) for translating this post into Italian

Introduzione

Probabilmente avrete sentito parlare della blockchain di Ethereum, anche se magari non sapete di cosa si tratta. Recentemente è stato pubblicato un gran numero di notizie a riguardo, e alcune importanti riviste hanno anche dedicato la copertina, ma leggere questi articoli può creare confusione se non avete le basi per capire cosa sia esattamente Ethereum. Quindi, di cosa si tratta? In sostanza, è un database pubblico che conserva una registrazione permanente delle transazioni digitali. L'aspetto importante è che questo database non richiede alcuna autorità centrale per la gestione e la protezione. Al contrario, funziona come un sistema transazionale senza terze parti fiduciarie, ossia un framework in cui gli individui possono effettuare transazioni peer-to-peer senza la necessità di fidarsi di terze parti o degli altri.

Non è ancora chiaro? È qui che torna utile questo post. Il mio obiettivo è di spiegare come funziona Ethereum a livello tecnico, senza concetti matematici complessi o formule che possono incutere timore. Spero che anche chi non si intende di programmazione riesca alla fine a comprendere un po' meglio questa tecnologia. Se alcune parti sono troppo tecniche e difficili da comprendere, non spaventatevi. Non c'è bisogno di capire ogni minimo dettaglio. Il mio suggerimento è di concentrarsi sulla comprensione a livello generale.

Molti degli argomenti trattati in questo post riprendono i concetti discussi nello Yellow Paper. Ho aggiunto le mie spiegazioni e alcuni grafici per facilitare la comprensione di Ethereum. Chi se la sente di affrontare la sfida tecnica può leggere anche lo Yellow Paper di Ethereum.

Iniziamo!

Definizione di blockchain

Una blockchain è una " macchina singleton transazionale crittograficamente sicura con stato condiviso". [1] Suona bene, vero? Analizziamo i vari concetti.

  • "Crittograficamente sicura" significa che la creazione della valuta digitale è protetta da complessi algoritmi matematici che sono incredibilmente difficili da violare. Pensate ad una sorta di firewall. Rendono quasi impossibile aggirare il sistema (ad esempio creare transazioni false, cancellare transazioni, ecc.)
  • "Macchina singleton transazionale" significa che esiste un'unica istanza canonica della macchina responsabile di tutte le transazioni create nel sistema.In altre parole, esiste una sola verità globale in cui tutti credono.
  • "Con stato condiviso" significa che lo stato archiviato su questa macchina è condiviso e aperto a tutti.

Ethereum implementa questo paradigma blockchain.

Il paradigma blockchain di Ethereum

La blockchain di Ethereum è essenzialmente una macchina a stati basata su transazioni. In informatica, una macchina a stati si riferisce a qualcosa che leggerà una serie di input e, sulla base di tali input, passerà a un nuovo stato.

La macchina a stati di Ethereum inizia con uno stato simile alla genesi, cioè analogo a una lista vuota, prima che qualsiasi transazione avvenga sulla rete. Quando vengono eseguite transazioni, questo stato di genesi passa a un determinato stato finale. In qualsiasi momento, questo stato finale rappresenta lo stato attuale di Ethereum.

Lo stato di Ethereum ha milioni di transazioni. Queste transazioni sono raggruppate in "blocchi". Un blocco contiene una serie di transazioni, e ogni blocco viene concatenato al blocco precedente.

Per passare da uno stato all'altro, la transazione deve essere valida. Affinché una transazione sia considerata valida, deve passare attraverso un processo di convalida detto mining. Mining è quando un gruppo di nodi (es. computer) utilizza le proprie risorse di calcolo per creare un blocco di transazioni valide.

Qualsiasi nodo della rete che si dichiara miner può provare a creare e convalidare un blocco. Molti miner di tutto il mondo cercano di creare e convalidare blocchi contemporaneamente. Ogni miner fornisce una "prova" matematica quando invia un blocco alla blockchain e questa prova funge da garanzia: se la prova esiste, il blocco deve essere valido.

Per aggiungere un blocco alla blockchain principale, il miner deve fornire la prova più velocemente di qualsiasi altro miner concorrente. Il processo di convalida di ciascun blocco con un miner che fornisce una prova matematica è detto "proof of work".

Un miner che convalida un nuovo blocco viene premiato con un determinato valore per il suo lavoro. Qual è questo valore? La blockchain di Ethereum utilizza un token digitale intrinseco chiamato "Ether". Ogni volta che un miner fornisce la prova per un blocco, nuovi token Ether vengono generati e assegnati.

Ci si potrebbe chiedere: quali garanzie ci sono che tutti si attengano a una sola catena di blocchi? Come possiamo essere certi che non esista un sottogruppo di miner che decidono di creare una propria catena di blocchi?

In precedenza, abbiamo definito una blockchain come macchina singleton transazionale con stato condiviso. In base a questa definizione, possiamo capire che lo stato corrente corretto è un'unica verità globale, che tutti devono accettare. Avere più stati (o catene) danneggerebbe l'intero sistema, perché sarebbe impossibile essere d'accordo su quale stato sia quello corretto. Se le catene dovessero divergere, si potrebbero possedere 10 monete su una catena, 20 su un'altra, 40 su un'altra ancora. In questo scenario, non ci sarebbe modo di determinare quale catena sia la più "valida".

Ogni volta che vengono generati più percorsi, si verifica una biforcazione. In genere vogliamo evitare biforcazioni, perché destabilizzano il sistema e costringono le persone a scegliere in quale catena “credere”.

Per determinare qual'è il percorso più valido e impedire la nascita di più catene, Ethereum utilizza un meccanismo chiamato "protocollo GHOST".

"GHOST" = "Greedy Heaviest Observed Subtree"

In termini semplici, il protocollo GHOST afferma che dobbiamo scegliere il percorso su cui si è verificato il maggior numero di calcoli. Un modo per determinare di quale percorso si tratta è utilizzare il numero di blocchi del blocco più recente (il "blocco foglia"), che rappresenta il numero totale di blocchi nel percorso corrente (senza contare il blocco genesi). Più alto è il numero di blocchi, più lungo è il percorso e maggiore è il lavoro di mining effettuato per arrivare alla foglia. Utilizzando questo ragionamento, possiamo accordarci sulla versione canonica dello stato attuale.

Ora che abbiamo fornito una panoramica molto generica di cosa sia una blockchain, approfondiamo i componenti principali del sistema Ethereum:

  • account
  • stato
  • carburante e commissioni
  • transazioni
  • blocchi
  • esecuzione delle transazioni
  • mining
  • proof of work

Una nota prima di iniziare: ogni volta che parlo di "hash" di X, mi riferisco all'hash KECCAK-256 utilizzato da Ethereum.

Account

Lo "stato condiviso" globale di Ethereum è composto da molti piccoli oggetti ("account") che sono in grado di interagire tra loro attraverso un framework che passa messaggi. A ogni account è associato uno stato e un indirizzo a 20 byte. Un indirizzo in Ethereum è un identificatore a 160 bit che viene utilizzato per identificare qualsiasi account.

Esistono due tipi di account:

  • Account esterni, che sono controllati da chiavi private e che non hanno alcun codice associato.
  • Account a contratto, che sono controllati dal codice del contratto e sono associati a codice.

Account esterni e account a contratto

È importante comprendere la differenza fondamentale tra account esterni e account a contratto. Un account esterno può inviare messaggi ad altri account esterni OPPURE ad altri account a contratto creando e firmando una transazione mediante la propria chiave privata. Un messaggio tra due account esterni è semplicemente un trasferimento di valore. Ma un messaggio da un account esterno a un account a contratto attiva il codice dell'account a contratto, consentendogli di eseguire diverse azioni (ad esempio trasferire token, scrivere nello storage interno, coniare nuovi token, eseguire calcoli, creare nuovi contratti, ecc.).

A differenza degli account esterni, gli account a contratto non possono avviare da soli nuove transazioni. Possono generare transazioni solo in risposta ad altre transazioni ricevute (da account esterni o da un altro account a contratto). Scopriremo di più sulle chiamate da contratto a contratto nella sezione "Transazioni e messaggi".

Pertanto, qualsiasi azione che si verifichi nella catena di Ethereum è sempre avviata da transazioni originate da account esterni.

Stato dell'account

Lo stato dell'account è costituito da quattro componenti, che sono presenti indipendentemente dal tipo di account:

  • nonce: se l'account è esterno, questo numero rappresenta il numero di transazioni inviate dall'indirizzo dell'account. Se l'account è a contratto, il nonce è il numero di contratti creati dall'account.
  • balance: numero di Wei di proprietà di questo indirizzo.Ci sono 1e+18 Wei per ogni Ether.
  • storageRoot: un hash del nodo radice di un albero di Merkle Patricia (spiegheremo gli alberi di Merkle più avanti). Questo albero codifica l'hash del contenuto dello storage di questo account ed è vuoto per impostazione predefinita.
  • codeHash: l'hash del codice EVM (Ethereum Virtual Machine, approfondiremo più avanti) di questo account. Per gli account a contratto, è il codice a cui viene applicato un hash e che viene archiviato come codeHash. Per gli account esterni, il campo codeHash è l'hash della stringa vuota.

Stato a livello mondiale

A questo punto sappiamo che lo stato globale di Ethereum consiste in una mappatura tra gli indirizzi degli account e gli stati degli account. Questa mappatura è memorizzata in una struttura di dati detta albero di Merkle Patricia.

Un albero di Merkle (detto anche "Merkle trie") è un tipo di albero binario composto da un insieme di nodi con:

  • un gran numero di nodi foglia nella parte inferiore dell'albero che contengono i dati sottostanti
  • un insieme di nodi intermedi, dove ciascun nodo è l'hash dei suoi due nodi figlio
  • un singolo nodo radice, anch'esso formato dall'hash del suo nodo a due figli, che rappresenta la parte più alta dell'albero

I dati nella parte inferiore dell'albero vengono generati suddividendo i dati che vogliamo archiviare in porzioni, quindi suddividendo le porzioni in bucket e quindi prendendo l'hash di ciascun bucket e ripetendo lo stesso processo fino a quando il numero totale di hash rimanenti diventa uno solo: l'hash radice.

Questo albero deve avere una chiave per ogni valore memorizzato al suo interno. A partire dal nodo radice dell'albero, la chiave deve indicare quale nodo figlio seguire per ottenere il valore corrispondente, che è memorizzato nei nodi foglia. Nel caso di Ethereum, la mappatura chiave/valore per l'albero degli stati è tra gli indirizzi e i loro account associati, inclusi saldo, nonce, codeHash e storageRoot per ciascun account (dove storageRoot è esso stesso un albero).

Fonte: white paper Ethereum La stessa struttura dell'albero è utilizzata anche per memorizzare transazioni e ricevute. Più nello specifico, ogni blocco ha un'"intestazione" che memorizza l'hash del nodo radice di tre diverse strutture di Merkle trie, tra cui:

  1. Alberto di stato
  2. Albero delle transazioni
  3. Alberto delle ricevute

La capacità di archiviare tutte queste informazioni in modo efficiente in diversi Merkle trie è incredibilmente utile in Ethereum per quelli che chiamiamo "client leggeri" o "nodi leggeri". Ricordate che una blockchain è gestita da un gruppo di nodi. In linea di massima, esistono due tipi di nodi: nodi completi e nodi leggeri.

Un nodo archivio completo sincronizza la blockchain scaricando l'intera catena, dal blocco genesi al blocco intestazione corrente, ed eseguendo tutte le transazioni contenute all'interno. In genere, i miner archiviano il nodo archivio completo, perché è necessario ai fini del processo di mining. È anche possibile scaricare un nodo completo senza eseguire ogni transazione. Indipendentemente da ciò, qualsiasi nodo completo contiene l'intera catena.

Ma a meno che un nodo non debba eseguire tutte le transazioni o eseguire facilmente query sui dati storici, non è davvero necessario archiviare l'intera catena. È qui che entra in gioco il concetto di nodo leggero. Invece di scaricare e archiviare l'intera catena ed eseguire tutte le transazioni, i nodi leggeri scaricano solo la catena di intestazioni, dal blocco genesi all'intestazione corrente, senza eseguire alcuna transazione o recuperare alcuno stato associato. Poiché i nodi leggeri hanno accesso alle intestazioni dei blocchi, che contengono hash di tre alberi, possono comunque generare e ricevere facilmente risposte verificabili su transazioni, eventi, saldi, ecc.

Tutto ciò funziona perché gli hash nell'albero di Merkle si propagano verso l'alto: se un hacker tenta di scambiare una transazione non autentica che si trova in fondo a un albero di Merkle, questo cambiamento causerà una modifica nell'hash del nodo che si trova sopra, che cambierà l'hash del nodo ancora sopra, e così via, fino a cambiare la radice dell'albero.

Qualsiasi nodo che desideri verificare un dato può utilizzare la cosiddetta "prova di Merkle".

Una prova di Merkle è composta da:

  1. Una porzione di dati da verificare e il suo hash
  2. L'hash radice dell'albero
  3. Il "ramo" (tutti gli hash partner lungo il percorso, dalla porzione fino alla radice)

Chiunque legga la prova può verificare che l'hash di quel ramo è coerente per tutto l'albero, e quindi che una data porzione si trova effettivamente in quella posizione nell'albero.

In sintesi, usando un albero di Merkle Patricia si ha il vantaggio che il nodo radice di questa struttura è crittograficamente dipendente dai dati memorizzati nell'albero, e quindi l'hash del nodo radice può essere usato come identità sicura per questi dati. Poiché l'intestazione dei blocchi include l'hash radice degli alberi dello stato, delle transazioni e delle ricevute, qualsiasi nodo può convalidare una piccola parte dello stato di Ethereum senza per forza contenere l'intero stato, che può essere potenzialmente illimitato nelle dimensioni.

Carburante e commissioni

Un concetto molto importante in Ethereum è quello delle commissioni. Ogni calcolo che si verifica a seguito di una transazione sulla rete Ethereum è soggetto a una commissione. Niente è gratis! La commissione corrisposta viene denominata "carburante". Il carburante è l'unità di misura utilizzata per le commissioni richieste per un determinato calcolo.

Il prezzo del carburante è la quantità di Ether che siete disposti a spendere per ogni unità di carburante, ed è misurato in "gwei". "Wei" è la più piccola unità di Ether, dove 1⁰¹⁸ Wei rappresenta 1 Ether. Un gwei è composto da 1.000.000 Wei.

Con ogni transazione, un mittente imposta un limite di carburante e il prezzo del carburante. Il prodotto di prezzo del carburante per limite di carburante rappresenta l'importo massimo di Wei che il mittente è disposto a pagare per l'esecuzione di una transazione.

Ad esempio, supponiamo che il mittente fissi il limite del carburante a 50.000 e un prezzo per il carburante di 20 gwei. Questo significa che il mittente è disposto a spendere al massimo 50.000 x 20 gwei = 1.000.000.000.000.000.000 Wei = 0,001 Ether per eseguire la transazione.

Ricorda che il limite di carburante rappresenta il carburante massimo per il quale il mittente è disposto a spendere denaro. Se ha Ether sufficienti nel saldo del proprio conto per coprire questo costo massimo, può partire. Il mittente viene rimborsato per l'eventuale carburante non utilizzato al termine della transazione, scambiato alla tariffa originale.

Nel caso in cui il mittente non metta a disposizione carburante sufficiente per eseguire la transazione, questa rimane "a secco" e viene considerata non valida. In questo caso, l'elaborazione della transazione si interrompe e qualsiasi cambiamento di stato che si è verificato viene annullato, in modo tale da tornare allo stato di Ethereum precedente alla transazione. Inoltre, viene registrato un record del fallimento della transazione che mostra quale transazione è stata tentata e dove ha fallito. E poiché la macchina ha già lavorato per eseguire i calcoli prima di esaurire il carburante, logicamente il carburante utilizzato non viene rimborsato al mittente.

Dove va a finire esattamente questo denaro speso per il carburante? Tutti i soldi spesi per il carburante dal mittente vengono inviati all'indirizzo "beneficiario", che in genere è l'indirizzo del miner. Poiché i miner lavorano per eseguire calcoli e convalidare le transazioni, ricevono il costo del carburante come ricompensa.

In genere, più alto è il prezzo del carburante che il mittente è disposto a pagare, maggiore sarà il valore che il miner trarrà dalla transazione, e quindi più alta sarà la probabilità che i miner la scelgano. I miner sono quindi liberi di scegliere quali transazioni convalidare o ignorare. Al fine di aiutare i mittenti a fissare il prezzo del carburante, i miner hanno la possibilità di pubblicizzare il prezzo minimo del carburante per il quale effettueranno le transazioni.

Ci sono commissioni da pagare anche per lo storage

Il carburante viene utilizzato non solo per pagare le fasi di calcolo, ma anche per l'utilizzo dello storage. Il costo totale dello storage è proporzionale al multiplo più piccolo di 32 byte utilizzato.

Le commissioni per lo storage hanno alcuni aspetti più complessi. Ad esempio, poiché l'aumento dello storage comporta un aumento delle dimensioni del database degli stati di Ethereum su tutti i nodi, viene incentivato un utilizzo minimo dello storage per i dati archiviati. Per questo motivo, se una transazione prevede un passaggio che cancella una voce nello storage, la commissione richiesta per eseguire l'operazione viene annullata e allo stesso tempo viene concesso un rimborso per aver liberato spazio nello storage.

Qual è lo scopo delle commissioni?

Un aspetto importante del funzionamento di Ethereum è che ogni operazione eseguita dalla rete viene effettuata simultaneamente da ogni nodo completo. Però i passaggi di calcolo sulla macchina virtuale Ethereum sono molto costosi. Gli smart contract di Ethereum sono utilizzati al meglio per attività semplici, come l'esecuzione di logica business semplice o la verifica di firme e altri oggetti crittografici, piuttosto che usi più complessi, come archiviazione di file, e-mail o machine learning, che possono mettere a dura prova la rete. L'imposizione di commissioni impedisce agli utenti di sovraccaricare la rete.

Ethereum è un linguaggio Turing completo. In breve, una macchina Turing è una macchina che può simulare qualsiasi algoritmo informatico (chi non ha familiarità con le macchine Turing può dare un'occhiata qui e qui). Questo permette di utilizzare i cicli e rende Ethereum vulnerabile al problema di arresto, cioè non è possibile determinare se un programma verrà eseguito all'infinito. Se non ci fossero commissioni, un utente malintenzionato potrebbe facilmente tentare di interrompere il funzionamento della rete eseguendo un ciclo infinito all'interno di una transazione, senza alcuna ripercussione negativa. Le commissioni quindi proteggono la rete da attacchi deliberati.

Si potrebbe pensare: "perché bisogna anche pagare lo storage?" Esattamente come il calcolo, anche lo storage sulla rete Ethereum è un costo che l'intera rete deve sostenere.

Transazioni e messaggi

Abbiamo fatto notare in precedenza che Ethereum è una macchina a stati basata sulle transazioni. In altre parole, le transazioni che si verificano tra diversi account sono ciò che fa muovere globalmente Ethereum da uno stato a quello successivo.

In parole semplici, una transazione è un'istruzione firmata crittograficamente che viene generata da un account esterno, serializzata e quindi inviata alla blockchain.

Esistono due tipi di transazioni: chiamate di messaggi e creazioni di contratti (cioè transazioni che creano nuovi contratti Ethereum).

Indipendentemente dal loro tipo, tutte le transazioni contengono i seguenti componenti:

  • nonce: un conteggio del numero di transazioni inviate dal mittente.
  • gasPrice: il numero di Wei che il mittente è disposto a pagare per ogni unità di carburante necessaria per eseguire la transazione.
  • gasLimit: la quantità massima di carburante che il mittente è disposto a pagare per eseguire la stessa transazione. Questo importo viene impostato e pagato in anticipo, prima che venga eseguito qualsiasi calcolo.
  • to: l'indirizzo del destinatario. In una transazione che crea contratti, l'indirizzo dell'account del contratto non esiste ancora e quindi viene utilizzato un valore vuoto.
  • value: l'importo di Wei da trasferire dal mittente al destinatario. In una transazione che crea contratti, questo valore funge da saldo iniziale all'interno dell'account a contratto appena creato.
  • v, r, s: utilizzati per generare la firma che identifica il mittente della transazione.
  • init (esiste solo per le transazioni che creano contratti): un frammento di codice EVM utilizzato per inizializzare il nuovo account a contratto.
  • init viene eseguito una sola volta e poi scartato. Quando init viene eseguito per la prima volta, restituisce il corpo del codice dell'account, cioè il codice associato in modo permanente all'account a contratto.
  • data (campo opzionale che esiste solo per le chiamate di messaggi): i dati di input (ovvero i parametri) della chiamata del messaggio. Ad esempio, se uno smart contract funge da servizio di registrazione del dominio, una chiamata a tale contratto potrebbe prevedere campi di input come il dominio e l'indirizzo IP.

Nella sezione "Account" abbiamo capito che le transazioni (sia le chiamate di messaggi che le transazioni che creano contratti) sono sempre avviate da account esterni e inviate alla blockchain. Si può anche pensare alle transazioni come al legame tra il mondo esterno e lo stato interno di Ethereum.

Ma questo non significa che i contratti non possano parlare con altri contratti. I contratti esistenti nell'ambito globale dello stato di Ethereum possono parlare con altri contratti nello stesso ambito. Lo fanno attraverso “messaggi” (o “transazioni interne”) ad altri contratti. Possiamo considerare i messaggi o le transazioni interne simili alle transazioni, con l'importante differenza che NON sono generati da account esterni. Sono generati da contratti. Sono oggetti virtuali che, a differenza delle transazioni, non sono serializzati ed esistono solo nell'ambiente di esecuzione di Ethereum.

Quando un contratto invia una transazione interna a un altro contratto, viene eseguito il codice associato presente nell'account a contratto destinatario.

Un aspetto importante da tenere a mente è che le transazioni interne o i messaggi non contengono un limite di carburante perché questo è determinato dal creatore esterno della transazione originale (cioè da un account esterno). Il limite di carburante che l'account esterno imposta deve essere sufficientemente elevato per consentire di eseguire la transazione, comprese eventuali esecuzioni secondarie attivate dalla transazione, come ad esempio i messaggi da contratto a contratto. Se, nella catena di transazioni e messaggi, una particolare esecuzione di messaggi rimane "a secco" di carburante, l'esecuzione del messaggio viene ripristinata, insieme a tutti i messaggi successivi attivati dall'esecuzione. Non è però necessario ripristinare l'esecuzione padre.

Blocchi

Tutte le transazioni sono raggruppate in "blocchi". Una blockchain contiene una serie di blocchi concatenati.

In Ethereum, un blocco è composto da:

  • intestazione del blocco
  • informazioni sul set di transazioni incluse nel blocco
  • un gruppo di altre intestazioni di blocchi per l'ommer del blocco corrente .

Spiegazione di ommer

Cosa è un "ommer"? È un blocco il cui padre corrisponde al padre del padre del blocco corrente. Vediamo rapidamente per cosa vengono utilizzati gli ommer e perché un blocco contiene le intestazioni dei blocchi degli ommer.

A causa del modo in cui è strutturato Ethereum, i tempi dei blocchi sono molto più bassi (~15 secondi) di quelli di altre blockchain, ad esempio Bitcoin (~10 minuti). Questo consente di elaborare le transazioni più velocemente. Tuttavia, uno degli aspetti negativi associati al fatto di avere tempi più brevi per i blocchi è che i miner trovano soluzioni più concorrenti per i blocchi. Questi blocchi concorrenti sono definiti anche "blocchi orfani" (cioè i blocchi sottoposti a mining che non finiscono nella catena principale).

Lo scopo degli ommer è contribuire a premiare i miner per l'inclusione di questi blocchi orfani. Gli ommer che i miner includono devono essere "validi", ovvero trovarsi non oltre la sesta generazione del blocco attuale. Dopo sei figli, i blocchi orfani non aggiornati non possono più essere referenziati (perché includere transazioni più vecchie complicherebbe le cose).

I blocchi ommer sono associati a una ricompensa inferiore rispetto a un blocco intero. Questo rimane comunque un incentivo per i miner, che ottengono una ricompensa se includono blocchi orfani.

Intestazioni dei blocchi

Torniamo per un attimo ai blocchi. In precedenza abbiamo detto che ogni blocco ha un'"intestazione". Ma di cosa si tratta esattamente?

L'intestazione di un blocco è una parte del blocco composta da:

  • parentHash: un hash dell'intestazione del blocco padre (questo fa sì che il blocco costituisca una "catena")
  • ommersHash: un hash della lista degli ommer del blocco corrente
  • beneficiary: l'indirizzo dell'account che riceve le commissioni per il mining di questo blocco
  • stateRoot: l'hash del nodo radice dell'albero di stato (abbiamo visto che l'albero di stato è contenuto nell'intestazione e rende facile ai client leggeri verificare ogni aspetto dello stato)
  • transactionsRoot: l'hash del nodo radice dell'albero che contiene tutte le transazioni elencate in questo blocco
  • receiptsRoot: l'hash del nodo radice dell'albero che contiene le ricevute di tutte le transazioni elencate in questo blocco
  • logsBloom: un filtro Bloom (struttura di dati) composto da informazioni di log
  • difficulty: il livello di difficoltà di questo blocco
  • number: il conteggio del blocco corrente (il blocco genesi ha un numero blocco uguale a zero; il numero del blocco aumenta di 1 per ogni blocco successivo)
  • gasLimit: l'attuale limite di carburante per blocco
  • gasUsed: il carburante totale utilizzato dalle transazioni in questo blocco
  • timestamp: data/ora Unix dell'inizio di questo blocco
  • extraData: dati aggiuntivi relativi a questo blocco
  • mixHash: un hash che, se combinato con il nonce, dimostra che questo blocco ha eseguito abbastanza calcoli
  • nonce: un hash che, se combinato con mixHash, dimostra che questo blocco ha effettuato calcoli sufficienti

Si noti che ogni intestazione di blocco contiene tre strutture ad albero per:

  • stato (stateRoot)
  • transazioni (transactionsRoot)
  • ricevute (receiptsRoot)

Queste strutture ad albero non sono altro che gli alberi di Merkle Patricia di cui abbiamo parlato prima.

Ci sono anche alcuni termini contenuti nella descrizione precedente che meritano di essere chiariti. Diamo un'occhiata.

Log

Ethereum permette di creare log per poter tracciare transazioni e messaggi. Un contratto può esplicitamente generare un log definendo gli "eventi" che desidera registrare.

Una voce di log contiene:

  • l'indirizzo dell'account che crea il log,
  • una serie di argomenti che rappresentano vari eventi eseguiti dalla transazione e
  • tutti i dati associati a questi eventi.

I log sono memorizzati in un filtro bloom, che contiene i dati di log infiniti in modo efficiente.

Ricevuta della transazione

I log memorizzati nell'intestazione provengono dalle informazioni di log contenute nella ricevuta della transazione. Esattamente come si ottiene una ricevuta quando si acquista qualcosa in un negozio, Ethereum genera una ricevuta per ogni transazione. Come vi aspettereste, ogni ricevuta contiene alcune informazioni sulla transazione. Questa ricevuta include voci come:

  • il numero del blocco
  • l'hash del blocco
  • l'hash della transazione
  • il carburante utilizzato nella transazione corrente
  • il carburante totale utilizzato nel blocco corrente dopo il termine dell'esecuzione della transazione corrente
  • log creati dopo l'esecuzione della transazione corrente
  • ..e così via

Difficoltà del blocco

La "difficoltà" di un blocco viene utilizzata per imporre la coerenza nel tempo necessario per convalidare i blocchi. Il blocco genesi ha una difficoltà di 131,072 e viene utilizzata una formula speciale per calcolare la difficoltà di ogni blocco successivo. Se un determinato blocco viene convalidato più velocemente rispetto a quello precedente, il protocollo Ethereum ne aumenta la difficoltà.

La difficoltà del blocco influenza il nonce, che è un hash che deve essere calcolato quando si esegue il mining di un blocco, utilizzando l'algoritmo proof of work.

La relazione tra la difficoltà del blocco e il suo nonce è espressa matematicamente come:

dove Hd è la difficoltà.

L'unico modo per trovare un nonce che soddisfi la soglia di difficoltà è utilizzare l'algoritmo proof of work per enumerare tutte le possibilità. Il tempo previsto per trovare una soluzione è proporzionale alla difficoltà: più aumenta la difficoltà, più difficile è trovare il nonce e quindi convalidare il blocco, che a sua volta aumenta il tempo necessario per convalidare un nuovo blocco. Quindi, modificando la difficoltà di un blocco, il protocollo può modificare il tempo necessario per convalidare un blocco.

Se invece i tempi di convalida si fanno più lenti, il protocollo riduce la difficoltà. In questo modo, il tempo di convalida si autoregola per mantenere un tasso costante, in media un blocco ogni 15 secondi.

Esecuzione delle transazioni

Siamo arrivati a una delle parti più complesse del protocollo Ethereum: l'esecuzione di una transazione. Immaginiamo di inviare una transazione alla rete Ethereum per l'elaborazione. Cosa avviene per modificare lo stato di Ethereum e includere questa transazione?

In primo luogo, tutte le transazioni devono soddisfare una serie iniziale di requisiti per poter essere eseguite. Tra questi vi sono:

  • La transazione deve avere un formato RLP corretto. “RLP” sta per “Recursive Length Prefix” ed è un formato di dati utilizzato per codificare array nidificati di dati binari. RLP è il formato che Ethereum usa per serializzare gli oggetti.
  • Firma di transazione valida.
  • Nonce di transazione valido. Ricordate che il nonce di un account è il numero di transazioni inviate da quell'account. Per essere valido, il nonce della transazione deve essere uguale a quello dell'account mittente.
  • Il limite di carburante della transazione deve essere uguale o maggiore del carburante intrinseco utilizzato dalla transazione. Il carburante intrinseco comprende:
  1. un costo predefinito di 21.000 unità di carburante per eseguire la transazione
  2. una commissione in carburante per i dati inviati con la transazione (4 unità di carburante per ogni byte di dati o codice che equivale a zero, e 68 unità di carburante per ogni byte non pari a zero di dati o codice)
  3. se la transazione è una transazione che crea contratti, altre 32.000 unità di carburante
  • Il saldo dell'account mittente deve disporre di abbastanza Ether per coprire a priori i costi di carburante che il mittente deve pagare. Il calcolo del costo del carburante a priori è semplice: in primo luogo il limite di carburante della transazione viene moltiplicato per il prezzo del carburante della transazione per determinare il costo massimo del carburante. Quindi questo costo massimo viene aggiunto al valore totale che viene trasferito dal mittente al destinatario.

Se la transazione soddisfa tutti i requisiti di validità appena elencati, si passa alla fase successiva.

Innanzitutto, sottraiamo il costo anticipato per l'esecuzione dal saldo del mittente e aumentiamo il nonce dell'account del mittente di 1 per tenere conto della transazione corrente. A questo punto, possiamo calcolare il carburante rimanente come limite di carburante totale per la transazione meno il carburante intrinseco utilizzato.

Quindi inizia l'esecuzione della transazione. Durante l'esecuzione di una transazione, Ethereum tiene traccia dello "stato secondario". È un modo per registrare le informazioni accumulate durante la transazione che saranno necessarie immediatamente dopo il completamento della transazione. Nello specifico, contiene:

  • Set di autodistruzione: un set di account (se presenti) che verrà eliminato dopo il completamento della transazione.
  • Serie di registri: punti di controllo archiviati e indicizzabili dell'esecuzione del codice della macchina virtuale.
  • Saldo rimborso: l'importo da rimborsare all'account mittente dopo la transazione. Ricordate che abbiamo detto che lo storage in Ethereum costa e che un mittente viene rimborsato se libera spazio di storage? Ethereum tiene traccia di questo con un contatore di rimborsi. Il contatore rimborsi inizia da zero e viene incrementato ogni volta che il contratto elimina qualcosa nello storage.

Successivamente, vengono elaborati i vari calcoli richiesti dalla transazione.

Una volta che tutti i passaggi richiesti dalla transazione sono stati elaborati e supponendo che non vi sia uno stato non valido, lo stato viene finalizzato determinando la quantità di carburante inutilizzato da rimborsare al mittente. Oltre al carburante inutilizzato, al mittente vengono rimborsate anche alcune quote dal "saldo di rimborso" che abbiamo descritto sopra.

Una volta rimborsato il mittente:

  • l'Ether per il carburante viene trasferito al miner
  • il carburante utilizzato per la transazione viene aggiunto al contatore del carburante per il blocco (che tiene traccia del carburante totale utilizzato per tutte le transazioni nel blocco ed è utile per la convalida di un blocco)
  • tutti gli account nel set di autodistruzione (se presenti) vengono eliminati

Infine, ci restano da vedere il nuovo stato e una serie di log creata dalla transazione.

Ora che abbiamo trattato i concetti di base dell'esecuzione delle transazioni, diamo un'occhiata ad alcune differenze tra transazioni che creano contratti e chiamate di messaggi.

Creazione di contratti

Non dimentichiamo che in Ethereum esistono due tipi di account: account a contratto e account esterni. Quando diciamo che una transazione "crea un contratto", intendiamo che lo scopo della transazione è creare un nuovo account a contratto.

Per creare un nuovo account a contratto, dichiariamo innanzitutto l'indirizzo del nuovo account utilizzando una formula speciale. Quindi inizializziamo il nuovo account:

  • Il nonce viene impostato a zero
  • Se il mittente ha inviato una certa quantità di Ether come valore con la transazione, il saldo dell'account viene impostato su quel valore
  • Il valore aggiunto al saldo del nuovo account viene sottratto dal saldo del mittente
  • La memoria viene impostata come vuota
  • il valore codeHash del contratto viene impostato come hash di una stringa vuota

Una volta inizializzato l'account, possiamo effettivamente creare l'account, utilizzando il codice di inizializzazione inviato con la transazione (vedere la sezione "Transazione e messaggi" per un ripasso del codice di inizializzazione). Ciò che accade durante l'esecuzione di questo codice di inizializzazione non sempre è uguale. A seconda del costruttore del contratto, potrebbe avvenire l'aggiornamento dello storage dell'account, la creazione di altri account a contratto, la chiamata di altri messaggi, ecc.

L'esecuzione del codice per inizializzare un contratto utilizza carburante. La transazione non può utilizzare più carburante di quanto ne rimane. Se il carburante non basta, l'esecuzione genera un'eccezione out-of-gas (OOG) e viene interrotta. Se la transazione viene interrotta a causa di un'eccezione di carburante esaurito, lo stato viene ripristinato al punto immediatamente precedente la transazione. Al mittente non viene rimborsato il carburante speso prima dell'esaurimento. Se però il mittente invia Ether con la transazione, il valore in Ether viene rimborsato anche se la creazione del contratto non riesce.

Meno male.

Se il codice di inizializzazione viene eseguito correttamente, viene versato un costo finale per la creazione del contratto.

Si tratta di un costo per lo storage ed è proporzionale alla dimensione del codice del contratto creato (di nuovo, niente è gratis!). Se non rimane abbastanza carburante per pagare questo costo finale, la transazione dichiara un'eccezione di carburante esaurito e si interrompe.

Se tutto va bene e si procede senza eccezioni, il carburante inutilizzato viene rimborsato al mittente originale della transazione e lo stato alterato può rimanere tale.

Evviva.

Chiamate di messaggi

L'esecuzione di una chiamata di messaggio è simile a quella per la creazione di un contratto, con alcune piccole differenze.

L'esecuzione di una chiamata di messaggio non include alcun codice di inizializzazione, poiché non vengono creati nuovi account. Può però contenere dati di input, se questi dati sono stati forniti dal mittente della transazione. Una volta eseguite, le chiamate ai messaggi hanno anche un componente aggiuntivo contenente i dati di output, che viene utilizzato se un'esecuzione successiva richiede questi dati.

Come avviene per la creazione del contratto, se l'esecuzione di una chiamata di messaggio viene interrotta perché si esaurisce il carburante o perché la transazione non è valida (ad esempio overflow dello stack, destinazione di salto non valida o istruzione non valida), il carburante utilizzato non viene rimborsato al chiamante originale. Viene cioè utilizzato tutto il carburante inutilizzato rimanente e lo stato viene riportato al punto immediatamente precedente al trasferimento del saldo.

Fino all'aggiornamento più recente di Ethereum, non c'era modo di interrompere o ripristinare l'esecuzione di una transazione senza che il sistema consumasse tutto il carburante fornito. Ad esempio, supponiamo che abbiate creato un contratto che genera un errore quando un chiamante non è stato autorizzato a eseguire alcune transazioni. Nelle versioni precedenti di Ethereum, il carburante rimanente verrebbe comunque consumato e niente verrebbe rimborsato al mittente. L'aggiornamento a Bisanzio invece include un nuovo codice di "ripristino" che consente a un contratto di interrompere l'esecuzione e ripristinare i cambiamenti di stato, senza utilizzare il carburante rimanente e con la possibilità di restituire un motivo per la transazione non riuscita. Se una transazione viene interrotta a causa di un ripristino, il carburante non utilizzato viene restituito al mittente.

Modello di esecuzione

Finora abbiamo visto i passaggi necessari affinché una transazione venga eseguita dall'inizio alla fine. Ora vedremo come viene effettivamente eseguita la transazione all'interno della VM.

La parte del protocollo che gestisce effettivamente l'elaborazione delle transazioni è la macchina virtuale di Ethereum, detta Ethereum Virtual Machine (EVM). L'EVM è una macchina virtuale completa in Turing, come definito in precedenza.

L'unica limitazione che l'EVM ha, al contrario di una tipica macchina completa in Turing, è quella di essere legata intrinsecamente al carburante. Pertanto, la quantità totale di calcolo che può essere eseguita è intrinsecamente limitata dalla quantità di carburante fornita.

Fonte: CMU Inoltre, l'EVM ha un'architettura basata su stack. Una macchina a stack è un computer che utilizza uno stack last-in, first-out (LIFO) per mantenere valori temporanei.

La dimensione di ciascun elemento dello stack nell'EVM è di 256 bit e lo stack ha una dimensione massima di 1024.

L'EVM ha una memoria che archivia gli elementi come array di byte indirizzati a parole. La memoria è volatile, cioè non è permanente.

L'EVM dispone anche di spazio di storage. A differenza della memoria, lo storage non è volatile e viene mantenuto come parte dello stato del sistema. L'EVM archivia il codice del programma separatamente, in una ROM virtuale a cui è possibile accedere solo tramite istruzioni speciali. In questo senso, c'è una differenza rispetto alla tipica architettura von Neumann, in cui il codice del programma è contenuto nella memoria o nello storage.

L'EVM ha anche un suo linguaggio: "bytecode EVM". Quando un programmatore come me o voi scrive smart contract che funzionano in Ethereum, in genere scrive codice in un linguaggio di livello superiore come Solidity. Può quindi compilarlo in bytecode EVM che EVM può comprendere.

Ok, ora passiamo all'esecuzione.

Prima di eseguire un determinato calcolo, il processore si accerta che le seguenti informazioni siano disponibili e valide:

  • Stato del sistema
  • Carburante rimanente per il calcolo
  • Indirizzo dell'account proprietario del codice in esecuzione
  • Indirizzo del mittente della transazione che ha originato l'esecuzione
  • Indirizzo dell'account che ha causato l'esecuzione del codice (potrebbe essere diverso dal mittente originale)
  • Prezzo del carburante della transazione che ha originato l'esecuzione
  • Dati di input per l'esecuzione
  • Valore (in Wei) trasferito a questo account come parte dell'attuale esecuzione
  • Codice macchina da eseguire
  • Intestazione del blocco corrente
  • Profondità dell'attuale chiamata di messaggio o dello stack di creazione del contratto

All'inizio dell'esecuzione, la memoria e lo stack sono vuoti e il contatore del programma è zero.

PC: 0 STACK: [] MEM: [], STORAGE: {}


L'EVM esegue la transazione in modo ricorsivo, calcolando lo stato del sistema e lo stato della macchina per ogni ciclo. Lo stato del sistema è semplicemente lo stato globale di Ethereum. Lo stato della macchina comprende:

  • carburante disponibile
  • contatore del programma
  • contenuto della memoria
  • numero attivo di parole in memoria
  • contenuto nello stack.

Gli elementi dello stack sono aggiunti o rimossi dalla porzione più a sinistra della serie.

A ogni ciclo, la quantità appropriata di carburante viene sottratta dal carburante restante e il contatore del programma viene incrementato.

Alla fine di ogni ciclo, ci sono tre possibilità:

  1. La macchina raggiunge uno stato di eccezione (ad esempio carburante insufficiente, istruzioni non valide, elementi di stack insufficienti, gli elementi dello stack supererebbero 1024, destinazione JUMP/JUMPI non valida, ecc.) e quindi deve essere arrestata, e le eventuali modifiche annullate
  2. La sequenza continua fino a elaborare il ciclo successivo
  3. La macchina raggiunge uno stop controllato (la fine del processo di esecuzione)

Supponendo che l'esecuzione non raggiunga uno stato di eccezione ma un arresto "controllato" o normale, la macchina genera lo stato risultante, il carburante rimanente dopo l'esecuzione, lo stato secondario ottenuto e l'output risultante.

Bene. Abbiamo trattato una delle parti più complesse di Ethereum. Anche se non avete capito proprio tutto, non importa. Non è necessario comprendere tutti i dettagli dell'esecuzione, a meno che non stiate lavorando a un livello molto complesso.

Finalizzazione di un blocco

Infine, vediamo come viene finalizzato un blocco di molte transazioni.

Il termine "finalizzato", può significare due cose diverse, a seconda che il blocco sia nuovo o esistente. Se si tratta di un blocco nuovo, ci riferiamo al processo necessario per il mining del blocco. Se si tratta di un blocco esistente, allora stiamo parlando del processo di convalida del blocco. In entrambi i casi, i requisiti per "finalizzare" un blocco sono quattro:

1) Convalida (o, in caso di mining, determinazione) degli ommer

Ogni blocco ommer all'interno dell'intestazione di un blocco deve essere un'intestazione valida e trovarsi entro la sesta generazione del blocco corrente.

2) Convalida (o, in caso di mining, determinazione) delle transazioni

Il valore di gasUsed sul blocco deve essere uguale al carburante totale utilizzato dalle transazioni elencate nel blocco. Tenete a mente che quando eseguiamo una transazione, teniamo traccia del contatore di carburante del blocco, che a sua volta tiene traccia del carburante totale utilizzato da tutte le transazioni del blocco.

3) Applicazione della ricompensa (solo in caso di mining)

L'indirizzo del beneficiario riceve 5 Ether per il mining del blocco. (Secondo la proposta Ethereum EIP-649, questa ricompensa di 5 ETH sarà presto ridotta a 3 ETH). Inoltre, per ogni ommer, il beneficiario corrente del blocco riceve un ulteriore 1/32 della ricompensa per il blocco corrente. Infine, anche al beneficiario del blocco ommer viene assegnato un certo importo (c'è una formula speciale per il calcolo).

4) Verifica di stato e nonce (o, se mining, calcolo di uno valido)

Tutte le transazioni e le modifiche di stato risultanti devono essere state applicate. Il nuovo blocco viene quindi definito come stato dopo che la ricompensa per il blocco è stata applicata allo stato risultante della transazione finale. La verifica avviene controllando questo stato finale rispetto all'albero dello stato contenuto nell'intestazione.

Proof of work del mining

Nella sezione “Blocchi” è stato brevemente affrontato il concetto di difficoltà dei blocchi. L'algoritmo che dà senso alla difficoltà del blocco è chiamato Proof of Work (PoW).

L'algoritmo proof-of-work di Ethereum si chiama “Ethash” (precedentemente Dagger-Hashimoto).

L'algoritmo è definito formalmente come:

dove m è mixHash , n è  nonce,  Hn è l'intestazione del nuovo blocco (esclusi i componenti nonce  e mixHash  che devono essere calcolati), Hn è il nonce dell'intestazione del blocco e d è il DAG , che è un set di dati di grandi dimensioni. Nella sezione " Blocchi *", abbiamo parlato dei vari elementi presenti nell'intestazione di un blocco.

Due di questi componenti erano stati chiamati **mixHash e nonce.

Come ricorderete:

  • mixHash è un hash che, se combinato con il nonce, dimostra che il blocco ha effettuato un calcolo sufficiente
  • nonce è un hash che, combinato con mixHash, dimostra che questo blocco ha eseguito un calcolo sufficiente

La funzione PoW è utilizzata per valutare questi due elementi.

Come vengono calcolati esattamente mixHash e nonce usando la funzione PoW è un po' complesso, e andrebbe approfondito in un post separato. Ma a un livello alto funziona così:

per ogni blocco viene calcolato un "seed". Questo seed è diverso per ogni “epoca”, dove ogni epoca dura 30.000 blocchi. Per la prima epoca, il seed è l'hash di una serie di 32 byte di zeri. Per ogni epoca successiva, è l'hash dell'hash del seme precedente. Usando questo seed, un nodo può calcolare una cache pseudo-casuale.

Questa cache è incredibilmente utile perché rende possibile il concetto di "nodi leggeri", di cui abbiamo discusso in precedenza in questo post. Lo scopo dei nodi leggeri è quello di permettere ad alcuni nodi di verificare in modo efficiente una transazione senza dover archiviare l'intero set di dati della blockchain. Un nodo leggero può verificare la validità di una transazione basandosi esclusivamente su questa cache, perché la cache può rigenerare il blocco specifico necessario per la verifica.

Utilizzando la cache, un nodo può generare il "set di dati" del DAG, dove ogni elemento nel set di dati dipende da un piccolo numero di elementi selezionati pseudo-casualmente dalla cache. Per essere un miner, è necessario generare questo set di dati completo; tutti i client e i miner completi archiviano questo set di dati, che cresce in modo lineare con il tempo.

I miner possono quindi prendere porzioni casuali del set di dati e attraverso una funzione matematica riunirli in un “mixHash". Un miner genererà ripetutamente un mixHash finché l'output non sarà inferiore al nonce che si desidera raggiungere. Quando l'output soddisferà questo requisito, il nonce sarà considerato valido e il blocco potrà essere aggiunto alla catena.

Mining come meccanismo di sicurezza

Nel complesso, lo scopo del PoW è di dimostrare, in modo crittograficamente sicuro, che una particolare quantità di calcolo è stata impiegata per generare un output (cioè il nonce). Questo perché non esiste un modo migliore per trovare un nonce inferiore alla soglia richiesta se non quello di elencare tutte le possibilità. Gli output dell'applicazione ripetuta della funzione hash hanno una distribuzione uniforme, e quindi possiamo essere certi che, in media, il tempo necessario per trovare tale nonce dipende dalla soglia di difficoltà. Maggiore è la difficoltà, maggiore è il tempo necessario per risolvere il nonce. In questo modo, l'algoritmo PoW dà un senso al concetto di difficoltà, che viene utilizzato per garantire la sicurezza della blockchain.

Cosa intendiamo per sicurezza della blockchain? È semplice: vogliamo creare una blockchain che TUTTI possano ritenere attendibile. Come abbiamo già spiegato in questo post, se esistesse più di una catena, gli utenti perderebbero fiducia, perché non sarebbero in grado di determinare in modo ragionevole quale catena sia quella “valida”. Affinché un gruppo di utenti accetti lo stato sottostante che è memorizzato su una blockchain, abbiamo bisogno di una singola blockchain canonica in cui un gruppo di persone creda.

Questo è esattamente ciò che fa l'algoritmo PoW: garantisce che una particolare blockchain rimanga canonica in futuro, rende incredibilmente difficile per un hacker creare nuovi blocchi che sovrascrivano una determinata parte della cronologia (ad esempio cancellando le transazioni o creando transazioni false) o gestire una biforcazione. Per ottenere la prima convalida del blocco, un hacker dovrebbe sempre risolvere il nonce in modo più veloce di chiunque altro nella rete, in modo tale che la rete ritenga che la sua catena sia la più pesante (in base ai principi del protocollo GHOST di cui abbiamo parlato prima). Questo sarebbe impossibile a meno che l’hacker non abbia più della metà della potenza di mining della rete, uno scenario noto come attacco del 51%.

Mining come meccanismo di distribuzione della ricchezza

Oltre a fornire una blockchain sicura, PoW è anche un modo per distribuire ricchezza a coloro che utilizzano le proprie capacità di calcolo per fornire questa sicurezza.

Ricordate che un miner riceve una ricompensa per il mining di un blocco, tra cui:

  • una ricompensa per blocco statico di 5 Ether per il blocco "vincente" (presto verrà portato a 3 Ether)
  • il costo del carburante utilizzato all'interno del blocco dalle transazioni incluse nel blocco
  • una ricompensa extra per l'inserimento degli ommer come parte del blocco

Per garantire che l'utilizzo del meccanismo di consenso PoW per la distribuzione della sicurezza e della ricchezza sia sostenibile a lungo termine, Ethereum fa il possibile per implementare queste due proprietà:

  • Renderlo accessibile al maggior numero possibile di persone. In altre parole, la gente non deve avere bisogno di hardware specializzato o non comune per eseguire l'algoritmo. Lo scopo è rendere il modello di distribuzione della ricchezza il più aperto possibile, in modo che chiunque possa fornire una quantità di potenza di calcolo in cambio di Ether.
  • Ridurre la possibilità che un singolo nodo (o un gruppo ridotto di nodi) realizzi una quantità sproporzionata di profitto. Se un nodo è in grado di ottenere una quantità sproporzionata di profitto, significa che ha una grande influenza sulla determinazione della blockchain canonica. Questo è un problema perché riduce la sicurezza della rete.

Nella rete blockchain Bitcoin, un problema che si presenta in relazione alle due proprietà appena descritte è che l'algoritmo PoW è una funzione hash SHA256. La debolezza di questo tipo di funzione è che può essere risolta in modo molto più efficiente utilizzando hardware specializzato, detto anche ASIC.

Per mitigare questo problema, Ethereum ha scelto di richiedere sequenzialmente un uso molto intensivo della memoria per il suo algoritmo PoW (Ethhash). Significa che l'algoritmo è progettato in modo che il calcolo del nonce richieda molta memoria e larghezza di banda. Gli elevati requisiti di memoria rendono difficile l'utilizzo della memoria in parallelo da parte di un computer per scoprire diversi nonce contemporaneamente, e gli elevati requisiti di larghezza di banda rendono difficile scoprire simultaneamente più nonce anche per un computer super veloce. Questo riduce il rischio di centralizzazione e crea condizioni più eque per i nodi che effettuano la verifica.

Una cosa da notare è che Ethereum sta passando da un meccanismo di consenso PoW al cosiddetto "proof-of-stake". Si tratta di un argomento molto impegnativo che speriamo di poter eviscerare in un post futuro.

☺️

Conclusioni

Eccoci qui. Siete arrivati fino alla fine. O almeno lo spero.

C'è molto da assimilare in questo post, lo so. Se vi servono più letture per comprendere appieno cosa sta succedendo, è normale. Anche io ho letto lo yellow paper, il white papter di Ethereum e varie parti della base di codice molte volte prima di capire bene quello che stava accadendo.

Spero comunque che abbiate trovato utile questa panoramica. Se avete notato errori, vi invito a scrivermi privatamente o a pubblicare un commento direttamente qui sotto. Leggero tutto, prometto ;)

E ricordate, sono umano anche io (ebbene sì) e commetto errori. Ho scritto questo post a beneficio della comunità, gratuitamente. Quindi vi pregherei di essere costruttivi nel vostro feedback, ed evitare attacchi inutili.

☺️

[1] https://github.com/ethereum/yellowpaper

Story tags:
More Stories from Archive

Why am I sharing my travel stories?

Founder & CEO of TruStory. I have a passion for understanding things at a fundamental level and sharing it as clearly as possible.

Preethi Kasireddy
LEARN MORE