Come costruire una semplice blockchain di criptovaluta in Node.js
Pubblicato: 2022-03-10smashingCoin
, usando i concetti delle classi JavaScript e Node.js. Provalo: è più semplice di quanto pensi!L'aumento senza precedenti delle criptovalute e la loro tecnologia blockchain alla base, hanno preso d'assalto il mondo, dagli umili inizi di essere un concetto accademico oltre un decennio fa all'attuale crescente adozione in vari settori.
La tecnologia blockchain sta ricevendo molta attenzione a causa della sua capacità di migliorare la sicurezza in ambienti trustless, imporre il decentramento e rendere i processi efficienti.
Tradizionalmente, Python è stato di fatto il linguaggio di programmazione per lo sviluppo di blockchain. Tuttavia, con la proliferazione di questa straordinaria tecnologia, anche le opzioni di sviluppo sono aumentate e Node.js non è stato lasciato indietro.
In questo tutorial parlerò di come costruire una semplice blockchain di criptovaluta in Node.js. Non sarà troppo elegante, ma sufficiente per aiutarti a capire come funziona una blockchain.
Chiamerò questa semplice criptovaluta smashingCoin
.
Se sei uno sviluppatore JavaScript che vuole fare un salto nel fiorente campo delle criptovalute, questo articolo ti fornirà le competenze necessarie per iniziare. Oppure, se sei curioso di sapere come funzionano le cose nel mondo delle criptovalute, allora questo tutorial può aiutarti a rispondere ad alcune delle tue domande.
Letture consigliate : Capire l'integrità delle sottorisorse di Drew McLellan
Prerequisiti
Per seguire con successo questo tutorial, avrai bisogno di quanto segue:
- Node.js installato sulla tua macchina. Puoi scaricarlo da qui;
- Un editor di codice, come Visual Studio Code, Sublime Text o qualsiasi altro.
Iniziamo…
Che cos'è una blockchain?
Blockchain è la tecnologia che alimenta le valute digitali, come Bitcoin ed Ethereum. Si tratta di un'innovativa tecnologia di contabilità pubblica distribuita che mantiene un elenco in continua crescita di record, denominati blocchi, che sono collegati in modo sicuro tramite crittografia.
Il termine blockchain si è guadagnato il nome per il modo in cui conserva i dati delle transazioni, ovvero in blocchi che sono collegati tra loro per creare una catena . La dimensione della blockchain cresce con un aumento del numero di transazioni intraprese.
Tutti i dati di transazione validi vengono registrati nella rete blockchain, che è regolata dalle regole peer-to-peer stabilite dai partecipanti. Ad esempio, questi dati potrebbero contenere il "valore" del blocco come nelle valute digitali, un record di transazioni (come quando le parti si scambiano beni e servizi) o privilegi di diritto come quando la catena registra le informazioni sulla proprietà.
Oltre ai dati della transazione, ogni blocco può contenere il proprio hash crittografico (un identificatore univoco o impronta digitale), il proprio valore nonce (un numero casuale arbitrario utilizzato una volta nei calcoli crittografici), l'hash del blocco precedente e un timestamp di transazioni autenticate.
Poiché ogni nuovo blocco dovrebbe puntare al blocco precedente, se un blocco viene incorporato nella catena senza contenere l'hash corretto dell'ultimo blocco, potrebbe rendere non valida l'intera blockchain. Questa proprietà di immutabilità è fondamentale per la sicurezza delle blockchain.
Inoltre, vengono spesso applicati vari tipi di protocolli di consenso per mantenere l'autenticità della blockchain. Il consenso garantisce che tutti i partecipanti accettino le transazioni convalidate dalla rete.
Ad esempio, un protocollo di consenso comunemente usato è proof of work, che mira a identificare un numero che trova una soluzione a un complicato problema matematico dopo aver completato una certa quantità di lavoro di calcolo.
L'idea principale del lavoro di prova è che qualsiasi partecipante alla rete blockchain dovrebbe trovare questo numero difficile da identificare ma facilmente verificabile. Di conseguenza, scoraggia lo spamming e la manomissione della struttura della blockchain.
Nel caso della maggior parte delle criptovalute, l'aggiunta di un nuovo blocco alla blockchain richiede la risoluzione di una complessa equazione matematica, che aumenta di difficoltà nel tempo man mano che la blockchain cresce. Di conseguenza, qualsiasi persona che dimostri di aver svolto un lavoro risolvendo questo problema viene compensata con una valuta digitale, in un processo denominato "mining".
Come creare un blocco
Ora, dopo aver introdotto la tecnologia blockchain e come funziona, vediamo come possiamo applicare i concetti nella creazione di un blocco. Come accennato in precedenza, i blocchi sono ciò che si collegano tra loro per formare una blockchain.
Per creare la valuta smashingCoin
, userò le classi JavaScript, che sono state introdotte in ES6.
Pronto?
Sporciamoci le mani...
Ecco il codice per la classe CryptoBlock
:
const SHA256 = require('crypto-js/sha256'); class CryptoBlock{ constructor(index, timestamp, data, precedingHash=" "){ this.index = index; this.timestamp = timestamp; this.data = data; this.precedingHash = precedingHash; this.hash = this.computeHash(); } computeHash(){ return SHA256(this.index + this.precedingHash + this.timestamp + JSON.stringify(this.data)).toString(); } }
Come puoi vedere nel codice sopra, ho creato la classe CryptoBlock
e ho aggiunto il metodo constructor()
, proprio come è stato fatto in qualsiasi altra classe JavaScript. Quindi, per inizializzare le sue proprietà, ho assegnato i seguenti parametri al metodo del constructor
:
index | È un numero univoco che tiene traccia della posizione di ogni blocco nell'intera blockchain. |
timestamp | Tiene traccia del momento in cui si è verificata ogni transazione completata. |
data | Fornisce i dati sulle transazioni completate, come i dettagli del mittente, i dettagli del destinatario e la quantità negoziata. |
precedingHash | Indica l'hash del blocco precedente nella blockchain, qualcosa di importante per mantenere l'integrità della blockchain. |
Inoltre, ho utilizzato il metodo computeHash
per calcolare l'hash del blocco in base alle sue proprietà, come indicato nei dati sopra.
Come puoi vedere, ho importato la libreria JavaScript crypto-js e ho usato il suo modulo crypto-js/sha256
per calcolare l'hash di ogni blocco. Poiché il modulo restituisce un oggetto numero, ho usato il metodo toString()
per convertirlo in una stringa.
Per aggiungere la libreria crypto-js al tuo progetto, vai sul terminale ed esegui il seguente comando per installarlo usando npm
:
npm install --save crypto-js
Dopo aver eseguito il comando precedente, la directory dei moduli del nodo, che contiene la libreria e altri file essenziali, verrà aggiunta alla cartella del progetto.
Come creare una blockchain
Come spiegato in precedenza, la tecnologia blockchain si basa sul concetto che tutti i blocchi sono incatenati l'uno all'altro. Quindi, creiamo una classe CryptoBlockchain
che sarà responsabile della gestione delle operazioni dell'intera catena. È qui che la gomma incontrerà la strada.
La classe CryptoBlockchain
manterrà le operazioni della blockchain utilizzando metodi di supporto che svolgono diverse attività, come la creazione di nuovi blocchi e l'aggiunta alla catena.
Ecco il codice per la classe CryptoBlockchain
:
class CryptoBlockchain{ constructor(){ this.blockchain = [this.startGenesisBlock()]; } startGenesisBlock(){ return new CryptoBlock(0, "01/01/2020", "Initial Block in the Chain", "0"); } obtainLatestBlock(){ return this.blockchain[this.blockchain.length - 1]; } addNewBlock(newBlock){ newBlock.precedingHash = this.obtainLatestBlock().hash; newBlock.hash = newBlock.computeHash(); this.blockchain.push(newBlock); } }
Consentitemi di parlare dei ruoli di ciascuno dei metodi di supporto che costituiscono la classe CryptoBlockchain
.
1. Metodo del costruttore
Questo metodo istanzia la blockchain. All'interno del costruttore, ho creato la proprietà blockchain
, che fa riferimento a un array di blocchi. Si noti che gli ho passato il metodo startGenesisBlock()
, che crea il blocco iniziale nella catena.
2. Creazione del blocco Genesi
In una blockchain, il blocco di genesi si riferisce al primo blocco in assoluto creato sulla rete. Ogni volta che un blocco è integrato con il resto della catena, dovrebbe fare riferimento al blocco precedente.
Al contrario, nel caso di questo blocco iniziale, non ha alcun blocco precedente a cui puntare. Pertanto, un blocco di genesi è solitamente codificato nella blockchain. In questo modo è possibile creare blocchi successivi su di esso. Di solito ha un indice di 0.
Ho usato il metodo startGenesisBlock()
per creare il blocco di genesi. Si noti che l'ho creato utilizzando la classe CryptoBlock
creata in precedingHash
e ho passato i parametri index
, timestamp
, data
e previousHash.
3. Ottenere l'ultimo blocco
Ottenere l'ultimo blocco nella blockchain aiuta a garantire che l'hash del blocco corrente punti all'hash del blocco precedente, mantenendo così l'integrità della catena.
Ho usato il metodo obtainLatestBlock()
per recuperarlo.
4. Aggiunta di nuovi blocchi
Ho usato il metodo addNewBlock()
per aggiungere un nuovo blocco alla catena. Per fare ciò, ho impostato l'hash precedente del nuovo blocco in modo che sia uguale all'hash dell'ultimo blocco della catena, assicurandomi così che la catena sia a prova di manomissione.
Poiché le proprietà del nuovo blocco vengono modificate ad ogni nuovo calcolo, è importante calcolare nuovamente il relativo hash crittografico. Dopo aver aggiornato il suo hash, il nuovo blocco viene inserito nell'array blockchain.
In realtà, aggiungere un nuovo blocco a una blockchain non è così semplice a causa dei numerosi controlli che sono stati piazzati. Tuttavia, per questa semplice criptovaluta, è sufficiente dimostrare come funziona effettivamente una blockchain.
Testare la Blockchain
Ora, testiamo la nostra semplice blockchain e vediamo se funziona.
Ecco il codice:
let smashingCoin = new CryptoBlockchain(); smashingCoin.addNewBlock(new CryptoBlock(1, "01/06/2020", {sender: "Iris Ljesnjanin", recipient: "Cosima Mielke", quantity: 50})); smashingCoin.addNewBlock(new CryptoBlock(2, "01/07/2020", {sender: "Vitaly Friedman", recipient: "Ricardo Gimenes", quantity: 100}) ); console.log(JSON.stringify(smashingCoin, null, 4));
Come puoi vedere nel codice sopra, ho creato una nuova istanza della classe CryptoBlockchain
e l'ho chiamata smashingCoin
. Quindi, ho aggiunto due blocchi nella blockchain utilizzando alcuni valori arbitrari. Nel parametro data
, ho utilizzato un oggetto e ho aggiunto i dettagli del mittente, i dettagli del destinatario e la quantità oggetto di transazione.
Se eseguo il codice sul terminale, ecco l'output che ottengo:
Ecco come appare lo smashingCoin
! È un oggetto che contiene la proprietà blockchain
, che è un array contenente tutti i blocchi della catena. Come puoi vedere nell'immagine sopra, ogni blocco fa riferimento all'hash del blocco precedente. Ad esempio, il secondo blocco fa riferimento all'hash del primo blocco. Dopo aver testato e visto che la nostra blockchain funziona, aggiungiamo alcune funzionalità in più per migliorare le caratteristiche di smashingCoin
.
Come verificare l'integrità della blockchain
Come accennato in precedenza, una caratteristica chiave di una blockchain è che una volta che un blocco è stato aggiunto alla catena, non può essere modificato senza invalidare l'integrità del resto della catena.
Pertanto, per verificare l'integrità della blockchain, aggiungerò un metodo checkChainValidity()
alla classe CryptoBlockchain
.
Gli hash sono fondamentali per garantire la validità e la sicurezza di una blockchain perché qualsiasi modifica nel contenuto di un blocco comporterà la produzione di un hash completamente nuovo e invaliderà la blockchain.
In quanto tale, il metodo checkChainValidity()
utilizzerà le istruzioni if
per verificare se l'hash di ogni blocco è stato manomesso. A partire dal primo blocco creato, scorrerà l'intera blockchain e ne verificherà la validità. Nota che poiché il blocco di genesi è stato codificato, non verrà verificato.
Inoltre, il metodo verificherà se gli hash di ogni due blocchi consecutivi puntano l'uno all'altro. Se l'integrità della blockchain non è stata compromessa, restituisce true; in caso contrario, in caso di eventuali anomalie, restituisce falso.
Ecco il codice:
checkChainValidity(){ for(let i = 1; i < this.blockchain.length; i++){ const currentBlock = this.blockchain[i]; const precedingBlock= this.blockchain[i-1]; if(currentBlock.hash !== currentBlock.computeHash()){ return false; } if(currentBlock.precedingHash !== precedingBlock.hash) return false; } return true; }
Come aggiungere una prova di lavoro
Come accennato in precedenza, proof of work è il concetto applicato per aumentare la difficoltà che comporta il mining o l'aggiunta di nuovi blocchi alla blockchain.
Nel caso di smashingCoin
, utilizzerò un semplice algoritmo che dissuade le persone dal generare facilmente nuovi blocchi o dallo spammare la blockchain.
Quindi, nella classe CryptoBlock
, aggiungerò un altro metodo chiamato proofOfWork().
In sostanza, questo semplice algoritmo identifica un numero, passato come proprietà di difficulty
, in modo tale che l'hash di ogni blocco contenga zeri iniziali che corrispondono a questo livello di difficulty
.
Garantire che l'hash di ogni blocco inizi con il numero di zeri impostato nel livello di difficulty
richiede molta potenza di calcolo. Maggiore è il livello di difficoltà, maggiore è il tempo necessario per estrarre nuovi blocchi.
Inoltre, aggiungerò un valore nonce
casuale a ogni blocco con hash in modo tale che, quando ha luogo il rehashing, le restrizioni del livello di difficoltà possano ancora essere soddisfatte.
Ecco il codice:
proofOfWork(difficulty){ while(this.hash.substring(0, difficulty) !==Array(difficulty + 1).join("0")){ this.nonce++; this.hash = this.computeHash(); } }
Ed ecco il metodo computeHash()
aggiornato con la variabile nonce
inclusa:
computeHash(){ return SHA256(this.index + this.precedingHash + this.timestamp + JSON.stringify(this.data)+this.nonce).toString(); }
Inoltre, per implementare il meccanismo di prova del lavoro nella generazione di nuovi blocchi, lo includerò nel metodo addNewBlock()
:
addNewBlock(newBlock){ newBlock.precedingHash = this.obtainLatestBlock().hash; //newBlock.hash = newBlock.computeHash(); newBlock.proofOfWork(this.difficulty); this.blockchain.push(newBlock); }
Avvolgendo
Ecco l'intero codice per costruire la criptovaluta smashingCoin
usando Node.js:
const SHA256 = require("crypto-js/sha256"); class CryptoBlock { constructor(index, timestamp, data, precedingHash = " ") { this.index = index; this.timestamp = timestamp; this.data = data; this.precedingHash = precedingHash; this.hash = this.computeHash(); this.nonce = 0; } computeHash() { return SHA256( this.index + this.precedingHash + this.timestamp + JSON.stringify(this.data) + this.nonce ).toString(); } proofOfWork(difficulty) { while ( this.hash.substring(0, difficulty) !== Array(difficulty + 1).join("0") ) { this.nonce++; this.hash = this.computeHash(); } } } class CryptoBlockchain { constructor() { this.blockchain = [this.startGenesisBlock()]; this.difficulty = 4; } startGenesisBlock() { return new CryptoBlock(0, "01/01/2020", "Initial Block in the Chain", "0"); } obtainLatestBlock() { return this.blockchain[this.blockchain.length - 1]; } addNewBlock(newBlock) { newBlock.precedingHash = this.obtainLatestBlock().hash; //newBlock.hash = newBlock.computeHash(); newBlock.proofOfWork(this.difficulty); this.blockchain.push(newBlock); } checkChainValidity() { for (let i = 1; i < this.blockchain.length; i++) { const currentBlock = this.blockchain[i]; const precedingBlock = this.blockchain[i - 1]; if (currentBlock.hash !== currentBlock.computeHash()) { return false; } if (currentBlock.precedingHash !== precedingBlock.hash) return false; } return true; } } let smashingCoin = new CryptoBlockchain(); console.log("smashingCoin mining in progress...."); smashingCoin.addNewBlock( new CryptoBlock(1, "01/06/2020", { sender: "Iris Ljesnjanin", recipient: "Cosima Mielke", quantity: 50 }) ); smashingCoin.addNewBlock( new CryptoBlock(2, "01/07/2020", { sender: "Vitaly Friedman", recipient: "Ricardo Gimenes", quantity: 100 }) ); console.log(JSON.stringify(smashingCoin, null, 4));
Se eseguo il codice sul terminale, ecco l'output che ottengo:
Come puoi vedere nell'immagine sopra, gli hash ora iniziano con quattro zeri, che corrispondono al livello di difficoltà impostato nel meccanismo di proof of work.
Conclusione
Questo è tutto! È così che puoi costruire una semplice blockchain di criptovaluta usando Node.js.
Naturalmente, la criptovaluta smashingCoin
è tutt'altro che completa. In effetti, se lo rilasci senza apportare ulteriori miglioramenti, è improbabile che soddisfi le attuali richieste del mercato di una valuta digitale sicura, affidabile e intuitiva, rendendoti l'unico a utilizzarla!
Tuttavia, spero che questo tutorial ti abbia dotato di alcune abilità di base per bagnarti i piedi nell'elettrizzante mondo delle criptovalute.
Se hai commenti o domande, pubblicali qui sotto.
Ulteriori risorse
- "Blockchain 101", CoinDesk
- "Bitcoin: un sistema di cassa elettronico peer-to-peer", Satoshi Nakamoto, Bitcoin.org