Blockchain: cosa ci costerebbe costruire un PoC?

Gli occhi hanno paura, ma le mani prudono!

Negli articoli precedenti, abbiamo esaminato le tecnologie su cui si basano le blockchain (Cosa ci vuole per costruire una blockchain?) e i casi d'uso che possono essere realizzati con esse (Cosa ci costa costruire un caso?). È tempo di mettersi al lavoro! Per realizzare progetti pilota e PoC (Proof of Concept), preferisco utilizzare i cloud, poiché sono accessibili da qualsiasi parte del mondo e, spesso, non è necessario perdere tempo con l'installazione noiosa dell'ambiente, poiché ci sono configurazioni preinstallate. Quindi, diamo vita a qualcosa di semplice, ad esempio, una rete per trasferire monete tra partecipanti e la chiameremo modestamente Citcoin. Per questo utilizzeremo il cloud IBM e il blockchain universale Hyperledger Fabric. Prima di tutto, analizziamo perché Hyperledger Fabric è chiamato blockchain universale?

Blockchain: cosa ci costerebbe costruire un PoC?

Hyperledger Fabric — blockchain universale

Parlando in generale, un sistema informatico universale consiste in:

  • Un insieme di server e un nucleo software che esegue la logica aziendale;
  • Interfacce per interagire con il sistema;
  • Strumenti per la registrazione, l'autenticazione e l'autorizzazione di dispositivi/persone;
  • Un database che memorizza dati operativi e di archivio:

Blockchain: cosa ci costerebbe costruire un PoC?

La versione ufficiale di cosa sia Hyperledger Fabric può essere letta su sito, e in breve, Hyperledger Fabric è una piattaforma open source che consente di costruire blockchain private e di eseguire smart contract arbitrari scritti nei linguaggi di programmazione JS e Go. Esaminiamo nel dettaglio l'architettura di Hyperledger Fabric e assicuriamoci che sia un sistema universale, in cui ci sono solo specificità riguardo la memorizzazione e la registrazione dei dati. La specificità consiste nel fatto che i dati, come in tutte le blockchain, sono memorizzati in blocchi, che vengono inseriti nella blockchain solo se i partecipanti raggiungono un consenso e dopo la registrazione, i dati non possono essere facilmente modificati o eliminati.

Architettura di Hyperledger Fabric

Nello schema è rappresentata l'architettura di Hyperledger Fabric:

Blockchain: cosa ci costerebbe costruire un PoC?

Organizations — le organizzazioni contengono peer, quindi la blockchain esiste grazie al supporto delle organizzazioni. Diverse organizzazioni possono far parte di un unico channel.

Canale — una struttura logica che unisce peer in gruppi, determinando così la blockchain. Hyperledger Fabric può gestire simultaneamente più blockchain con logiche aziendali diverse.

Membership Services Provider (MSP) — è l'CA (Certificate Authority) per il rilascio di identità e l'assegnazione di ruoli. Per creare un nodo è necessario interagire con l'MSP.

Peer nodes — verificano le transazioni, memorizzano la blockchain, eseguono smart contract e interagiscono con le applicazioni. I peer hanno un'identità (certificato digitale) rilasciata dall'MSP. A differenza delle reti Bitcoin o Ethereum, dove tutti i nodi sono uguali, in Hyperledger Fabric i nodi svolgono ruoli diversi:

  • Un peer può essere endorsing peer (EP) e eseguire smart contract.
  • Committing peer (CP) — conserva solo i dati nella blockchain e aggiorna lo stato del 'World state'.
  • Anchor Peer (AP) — se più organizzazioni partecipano alla blockchain, gli anchor peer vengono utilizzati per comunicare tra di loro. Ogni organizzazione deve avere uno o più anchor peer. Con l'AP, qualsiasi peer di un'organizzazione può ottenere informazioni su tutti i peer delle altre organizzazioni. Per sincronizzare le informazioni tra gli AP viene utilizzato il protocollo gossip.
  • Leader Peer — se un'organizzazione ha più peer, solo il leader peer riceverà i blocchi dal servizio di ordinamento e li fornirà agli altri peer. Il leader può essere assegnato staticamente o selezionato dinamicamente dai peer dell'organizzazione. Per sincronizzare le informazioni sui leader viene anch'esso utilizzato il protocollo gossip.

Assets — entità di valore che sono memorizzate nella blockchain. Più specificamente, si tratta di dati chiave-valore in formato JSON. Sono questi dati a essere registrati nella blockchain 'Blockchain'. Hanno una storia, che è memorizzata nella blockchain, e uno stato attuale, che è memorizzato nel database 'World state'. Le strutture dei dati possono variare a seconda delle esigenze aziendali. Non ci sono campi obbligatori, l'unica raccomandazione è che gli asset devono avere un proprietario e avere un valore.

Ledger — consiste nella blockchain 'Blockchain' e nel database 'World state', dove è memorizzato lo stato attuale degli asset. Il World state utilizza LevelDB o CouchDB.

Smart contract — tramite smart contract viene implementata la logica aziendale del sistema. In Hyperledger Fabric, gli smart contract sono chiamati chaincode. Attraverso il chaincode vengono definiti asset e transazioni ad essi associate. Parlando tecnicamente, gli smart contract sono moduli software implementati in linguaggi di programmazione JS o Go.

Endorsement policy — per ogni chaincode è possibile definire politiche su quante e quali conferme sono necessarie per una transazione. Se la politica non è definita, per impostazione predefinita si utilizza: “la transazione deve essere confermata da qualsiasi membro di qualsiasi organizzazione nel channel”. Esempi di politiche:

  • La transazione deve essere confermata da un amministratore dell'organizzazione;
  • Deve essere confermata da qualsiasi membro o cliente dell'organizzazione;
  • Deve essere confermata da qualsiasi peer dell'organizzazione.

Servizio di ordinazione — imballa le transazioni in blocchi e le invia ai peer nel canale. Garantisce la consegna dei messaggi a tutti i peer nella rete. Per i sistemi industriali viene utilizzato il broker di messaggi Kafka, per sviluppo e test Solo.

CallFlow

Blockchain: cosa ci costerebbe costruire un PoC?

  • L'applicazione interagisce con Hyperledger Fabric utilizzando Go, Node.js o Java SDK;
  • Il cliente crea una transazione tx e la invia ai peer di endorsement;
  • Il peer verifica la firma del cliente, esegue la transazione e invia la firma di endorsement indietro al cliente. Il chaincode viene eseguito solo sui peer di endorsement e il risultato della sua esecuzione viene distribuito a tutti i peer. Questo algoritmo di lavoro è chiamato consenso PBFT (Practical Byzantine Fault Tolerant). Si distingue dalla classica BFT per il fatto che il messaggio viene inviato e si attende la conferma non da tutti i partecipanti, ma solo da un insieme specifico;
  • Dopo che il cliente ha ricevuto un numero di risposte che soddisfa la policy di endorsement, invia la transazione al servizio di ordinazione;
  • Il servizio di ordinazione forma un blocco e lo invia a tutti i peer di committing. Il servizio di ordinazione garantisce la registrazione sequenziale dei blocchi, escludendo così il cosiddetto ledger fork (vedi sezione 'Forks');
  • I peer ricevono il blocco, verificano di nuovo la policy di endorsement, registrano il blocco nella blockchain e aggiornano lo stato nel database 'World state'.

Si ottiene quindi una divisione dei ruoli tra i nodi. Questo assicura la scalabilità e la sicurezza della blockchain:

  • I contratti intelligenti (chaincode) vengono eseguiti dai peer di endorsement. Questo garantisce la riservatezza dei contratti intelligenti, poiché non è conservato da tutti i partecipanti, ma solo sui peer di endorsement.
  • Il servizio di ordinazione deve funzionare rapidamente. Questo è garantito dal fatto che il servizio di ordinazione si occupa solo di formare il blocco e inviarlo a un insieme fisso di peer leader.
  • I peer di committing semplicemente archiviano la blockchain—possono essere numerosi e non richiedono grande potenza o funzionamento immediato.

Per ulteriori dettagli sulle soluzioni architetturali di Hyperledger Fabric e sul perché funzioni in un certo modo, si può consultare qui: Architecture Origins o qui: Hyperledger Fabric: A Distributed Operating System for Permissioned Blockchains.

Quindi, Hyperledger Fabric è realmente un sistema versatile, che consente di:

  • Implementare logiche aziendali arbitrarie utilizzando un meccanismo di contratti intelligenti;
  • Registrare e recuperare dati da un database blockchain in formato JSON;
  • Fornire e verificare l'accesso alle API utilizzando l'Autorità Certificatrice.

Ora che abbiamo un po' compreso la specificità di Hyperledger Fabric, facciamo finalmente qualcosa di utile!

Distribuiamo la blockchain

Definizione del compito

L'obiettivo è implementare una rete Citcoin con le seguenti funzionalità: creare un account, ottenere un saldo, ricaricare il conto, trasferire monete da un conto all'altro. Disegneremo un modello di oggetti che poi implementeremo nel contratto intelligente. Quindi, avremo account che si identificano attraverso nomi e contengono saldi, e una lista di account. Gli account e la lista di account sono asset in termini di Hyperledger Fabric. Di conseguenza, hanno una storia e uno stato attuale. Proverò a rappresentarlo visivamente:

Blockchain: cosa ci costerebbe costruire un PoC?

Le figure superiori rappresentano lo stato attuale, che è conservato nel database 'World state'. Sotto di esse ci sono figure che mostrano la storia, che è conservata nella blockchain. Lo stato attuale degli asset viene modificato dalle transazioni. L'asset viene modificato solo nella sua interezza, quindi al termine di una transazione viene creato un nuovo oggetto e il valore attuale dell'asset va nella storia.

Cloud IBM

Creiamo un account nel cloud IBM. Per utilizzare la piattaforma blockchain, deve essere aggiornato a Pay-As-You-Go. Questo processo potrebbe non essere rapido, poiché IBM richiede ulteriori informazioni e le verifica manualmente. Posso dire positivamente che IBM ha buoni materiali didattici che consentono di distribuire Hyperledger Fabric nel loro cloud. Mi è piaciuto il seguente ciclo di articoli e esempi:

Di seguito sono presentati screenshot della Blockchain platform di IBM. Questa non è un'istruzione per creare blockchain, ma solo una dimostrazione della portata della task. Quindi, per i nostri scopi, creiamo un'organizzazione:

Blockchain: cosa ci costerebbe costruire un PoC?

In essa creiamo nodi: Orderer CA, Org1 CA, Orderer Peer:

Blockchain: cosa ci costerebbe costruire un PoC?

Creiamo utenti:

Blockchain: cosa ci costerebbe costruire un PoC?

Creiamo un canale e lo chiamiamo citcoin:

Blockchain: cosa ci costerebbe costruire un PoC?

In sostanza, il canale è una blockchain, quindi inizia con il blocco zero (Genesis block):

Blockchain: cosa ci costerebbe costruire un PoC?

Scriviamo il contratto intelligente

/*
 * Citcoin smart-contract v1.5 for Hyperledger Fabric
 * (c) Alexey Sushkov, 2019
 */
 
'use strict';
 
const { Contract } = require('fabric-contract-api');
const maxAccounts = 5;
 
class CitcoinEvents extends Contract {
 
    async instantiate(ctx) {
        console.info('instantiate');
        let emptyList = [];
        await ctx.stub.putState('accounts', Buffer.from(JSON.stringify(emptyList)));
    }
    // Get all accounts
    async GetAccounts(ctx) {
        // Get account list:
        let accounts = '{}'
        let accountsData = await ctx.stub.getState('accounts');
        if (accountsData) {
            accounts = JSON.parse(accountsData.toString());
        } else {
            throw new Error('accounts not found');
        }
        return accountsData.toString()
    }
     // add a account object to the blockchain state identifited by their name
    async AddAccount(ctx, name, balance) {
        // this is account data:
        let account = {
            name: name,
            balance: Number(balance),       
            type: 'account',
        };
        // create account:
        await ctx.stub.putState(name, Buffer.from(JSON.stringify(account)));
 
        // Add account to list:
        let accountsData = await ctx.stub.getState('accounts');
        if (accountsData) {
            let accounts = JSON.parse(accountsData.toString());
            if (accounts.length < maxAccounts)
            {
                accounts.push(name);
                await ctx.stub.putState('accounts', Buffer.from(JSON.stringify(accounts)));
            } else {
                throw new Error('Max accounts number reached');
            }
        } else {
            throw new Error('accounts not found');
        }
        // return  object
        return JSON.stringify(account);
    }
    // Sends money from Account to Account
    async SendFrom(ctx, fromAccount, toAccount, value) {
        // get Account from
        let fromData = await ctx.stub.getState(fromAccount);
        let from;
        if (fromData) {
            from = JSON.parse(fromData.toString());
            if (from.type !== 'account') {
                throw new Error('wrong from type');
            }   
        } else {
            throw new Error('Accout from not found');
        }
        // get Account to
        let toData = await ctx.stub.getState(toAccount);
        let to;
        if (toData) {
            to = JSON.parse(toData.toString());
            if (to.type !== 'account') {
                throw new Error('wrong to type');
            }  
        } else {
            throw new Error('Accout to not found');
        }
 
        // update the balances
        if ((from.balance - Number(value)) >= 0 ) {
            from.balance -= Number(value);
            to.balance += Number(value);
        } else {
            throw new Error('From Account: not enought balance');          
        }
 
        await ctx.stub.putState(from.name, Buffer.from(JSON.stringify(from)));
        await ctx.stub.putState(to.name, Buffer.from(JSON.stringify(to)));
                 
        // define and set Event
        let Event = {
            type: "SendFrom",
            from: from.name,
            to: to.name,
            balanceFrom: from.balance,
            balanceTo: to.balance,
            value: value
        };
        await ctx.stub.setEvent('SendFrom', Buffer.from(JSON.stringify(Event)));
 
        // return to object
        return JSON.stringify(from);
    }
 
    // get the state from key
    async GetState(ctx, key) {
        let data = await ctx.stub.getState(key);
        let jsonData = JSON.parse(data.toString());
        return JSON.stringify(jsonData);
    }
    // GetBalance   
    async GetBalance(ctx, accountName) {
        let data = await ctx.stub.getState(accountName);
        let jsonData = JSON.parse(data.toString());
        return JSON.stringify(jsonData);
    }
     
    // Refill own balance
    async RefillBalance(ctx, toAccount, value) {
        // get Account to
        let toData = await ctx.stub.getState(toAccount);
        let to;
        if (toData) {
            to = JSON.parse(toData.toString());
            if (to.type !== 'account') {
                throw new Error('wrong to type');
            }  
        } else {
            throw new Error('Accout to not found');
        }
 
        // update the balance
        to.balance += Number(value);
        await ctx.stub.putState(to.name, Buffer.from(JSON.stringify(to)));
                 
        // define and set Event
        let Event = {
            type: "RefillBalance",
            to: to.name,
            balanceTo: to.balance,
            value: value
        };
        await ctx.stub.setEvent('RefillBalance', Buffer.from(JSON.stringify(Event)));
 
        // return to object
        return JSON.stringify(from);
    }
}
module.exports = CitcoinEvents;

Intuitivamente, qui dovrebbe essere tutto chiaro:

  • Ci sono diverse funzioni (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance) che saranno chiamate dal programma demo tramite l'API di Hyperledger Fabric.
  • Le funzioni SendFrom e RefillBalance generano eventi (Event) che saranno ricevuti dal programma demo.
  • La funzione instantiate viene chiamata una sola volta durante l'istanza del contratto intelligente. In realtà, viene chiamata non una sola volta, ma ogni volta che viene modificata la versione del contratto intelligente. Pertanto, inizializzare l'elenco con un array vuoto è una cattiva idea, poiché ora, con il cambio della versione del contratto intelligente, perderemo l'elenco attuale. Ma niente, sto solo imparando).
  • Gli account e l'elenco degli account (accounts) sono strutture di dati JSON. Per le manipolazioni dei dati si utilizza JS.
  • Il valore attuale dell'asset può essere ottenuto tramite la chiamata alla funzione getState, e può essere aggiornato con putState.
  • Quando si crea un Account, viene chiamata la funzione AddAccount, nella quale si confronta il numero massimo di account nella blockchain (maxAccounts = 5). Qui c'è un problema (l'hai notato?), che porta a una crescita infinita del numero di account. Errori come questo devono essere evitati).

Successivamente, carichiamo il contratto intelligente nel Channel e lo istanziamo:

Blockchain: cosa ci costerebbe costruire un PoC?

Visualizziamo la transazione per l'installazione del Smart Contract:

Blockchain: cosa ci costerebbe costruire un PoC?

Controlliamo i dettagli del nostro Channel:

Blockchain: cosa ci costerebbe costruire un PoC?

Di conseguenza, otteniamo il seguente schema della rete blockchain nel cloud IBM. Inoltre, nello schema è presente un programma demo, eseguito nel cloud Amazon su un server virtuale (ne parlerò nel prossimo capitolo):

Blockchain: cosa ci costerebbe costruire un PoC?

Creazione di un GUI per invocare le API di Hyperledger Fabric

Hyperledger Fabric ha un'API che può essere utilizzata per:

  • Creare un channel;
  • Collegare il peer al channel;
  • Installare e istanziare contratti intelligenti nel channel;
  • Eseguire transazioni;
  • Richiedere informazioni nella blockchain.

Sviluppo dell'applicazione

Nella nostra applicazione demo utilizzeremo l'API solo per invocare transazioni e richiedere informazioni, poiché gli altri passaggi sono già stati effettuati utilizzando la piattaforma blockchain IBM. Creiamo un GUI utilizzando il classico stack di tecnologie: Express.js + Vue.js + Node.js. Per iniziare a creare applicazioni web moderne, potrei scrivere un articolo separato. Qui lascio un link su una serie di lezioni che mi sono piaciute di più: Full Stack Web App using Vue.js & Express.js. Il risultato è un'applicazione client-server con un'interfaccia grafica familiare in stile Material Design di Google. L'API REST tra client e server consiste in varie invocazioni:

  • HyperledgerDemo/v1/init — inizializzare la blockchain;
  • HyperledgerDemo/v1/accounts/list — ottenere l'elenco di tutti gli account;
  • HyperledgerDemo/v1/account?name=Bob&balance=100 — creare l'account Bob;
  • HyperledgerDemo/v1/info?account=Bob — ottenere informazioni sull'account Bob;
  • HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — trasferire due monete da Bob ad Alice;
  • HyperledgerDemo/v1/disconnect — chiudere la connessione con la blockchain.

Ho posizionato la descrizione dell'API con degli esempi sul sito ‘Postman’ — un programma ben conosciuto per il testing delle API HTTP.

App demo nel cloud Amazon

Ho caricato l'app su Amazon, poiché IBM non è ancora riuscita ad aggiornare il mio account e a consentirmi di creare server virtuali. Come ciliegina sulla torta, ho aggiunto un dominio: www.citcoin.info. Terrò il server acceso un po', poi lo spegnerò, poiché i centesimi di affitto iniziano ad accumularsi, e le monete citcoin non sono ancora quotate in borsa). Nella mia pubblicazione ho incluso screenshot della demo per chiarire la logica di funzionamento. L'app demo può:

  • Inizializzare la blockchain;
  • Creare un Account (ma attualmente non è possibile creare un nuovo Account, poiché nella blockchain è stato raggiunto il numero massimo di account specificato nel contratto intelligente);
  • Ottenere l'elenco degli Account;
  • Trasferire monete citcoin tra Alice, Bob e Alex;
  • Ottenere eventi (ma attualmente non è possibile visualizzare eventi, quindi per semplicità l'interfaccia indica che gli eventi non sono supportati);
  • Registrare le azioni.

Prima di tutto, inizializziamo la blockchain:

Blockchain: cosa ci costerebbe costruire un PoC?

Successivamente, creiamo il nostro account, senza risparmiare sul bilancio:

Blockchain: cosa ci costerebbe costruire un PoC?

Ottenere l'elenco di tutti gli account disponibili:

Blockchain: cosa ci costerebbe costruire un PoC?

Scegliamo il mittente e il destinatario, controlliamo i loro saldi. Se mittente e destinatario sono la stessa persona, il suo saldo verrà ricaricato:

Blockchain: cosa ci costerebbe costruire un PoC?

Nel registro seguiamo l'esecuzione delle transazioni:

Blockchain: cosa ci costerebbe costruire un PoC?

In effetti, con il programma demo è tutto. Ora possiamo visualizzare la nostra transazione nella blockchain:

Blockchain: cosa ci costerebbe costruire un PoC?

E l'elenco generale delle transazioni:

Blockchain: cosa ci costerebbe costruire un PoC?

Con questo abbiamo concluso con successo l'implementazione del PoC per la creazione della rete Citcoin. Cosa resta da fare affinché Citcoin diventi una rete completa per il trasferimento di monete? Davvero poco:

  • In fase di creazione dell'account, implementare la generazione della chiave privata/pubblica. La chiave privata deve essere conservata dall'utente dell'account, quella pubblica nella blockchain.
  • Effettuare il trasferimento di monete, in cui per l'identificazione dell'utente viene utilizzata non il nome, ma la chiave pubblica.
  • Cifrare le transazioni provenienti dall'utente al server con la sua chiave privata.

Conclusione

Abbiamo implementato la rete Citcoin con funzionalità per: aggiungere account, ottenere saldo, ricaricare il proprio conto, trasferire monete da un conto all'altro. Quindi, cosa ci è costato costruire il PoC?

  • Occorre studiare la blockchain in generale e Hyperledger Fabric in particolare;
  • Imparare a usare i servizi cloud di IBM o Amazon;
  • Apprendere il linguaggio di programmazione JS e qualche framework web;
  • Se alcuni dati devono essere archiviati non nella blockchain, ma in un database separato, è necessario imparare a integrarsi, ad esempio, con PostgreSQL;
  • E l'ultimo della lista, ma non meno importante — senza conoscenze di Linux nel mondo moderno non si va da nessuna parte!)

Certamente, non è rocket science, ma ci sarà da sudare!

Codice sorgente su GitHub

Ho caricato i sorgenti su GitHub. Breve descrizione del repository:
La cartella «server» — server Node.js
La cartella «client» — client Node.js
La cartella «blockchain» (i valori dei parametri e le chiavi, ovviamente, non sono funzionanti e sono forniti solo a titolo esemplificativo):

  • contract — sorgente del contratto smart
  • wallet — chiavi dell'utente per usare l'API di Hyperledger Fabric.
  • *.cds — versioni compilate dei contratti smart
  • *.json file — esempi di file di configurazione per usare l'API di Hyperledger Fabric

È solo l'inizio!

Fonte: habr.com

Acquista un hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista un hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster