190214_Hyperledger - Lesson 05

Avviso – Queste lezioni sono il frutto del MOOC che ho svolto per conseguire il relativo certificato
( link )

PS: l’uso di tecnologie nuove porta con se nuovi termini. Al sopraggiungere di essi ho provato a tradurli in italiano per una migliore comprensione. Successivamente ho usato il termine in inglese per assecondarne l’introduzione nell’uso abitudinario.

Per la fine della Lezione 5, capiremo:

  • Comprendere le basi di Hyperledger Fabric

  • Utilizzare la dimostrazione di uno scenario per evidenziare gli aspetti di Hyperledger Fabric

  • Discutere dei componenti cruciali dell’architettura di Hyperledger Fabric, incluso clients, peers, ordering service e membership service provider

  • Configurare un esempio di network ed un esempio di applicazione con un Javascript SDK

  • Discutere di Chaincode (lo smart contract di Hyperledger Fabric) e recensirne un esempio

Introduzione

Hyperledger Fabric è stata la prima proposta al progetto Hyperledger della Linux Foundation, in parte contribuito da IBM.

La versione 1.0 è stata rilasciata solo di recente, a luglio del 2017.

Questo framework è modulare, scalabile, sicuro.

È specificamente formulato per settori come la produzione, l’agricoltura, la sanità e i mercati dei capitali.

Hyperledger Fabric è rivoluzionario nella sua capacità di consentire alle entità di condurre transazioni confidenziali senza passare attraverso un’autorità centrale.

Una dimostrazione di scenario

Secondo il World Economic Forum:

“La pesca illegale, non dichiarata e non regolamentata rappresenta una perdita di circa 26 milioni di tonnellate per un valore di circa 24 miliardi di $ di pescato all’anno”

Di seguito useremo lo stesso esempio usato per Hyperledger Sawtooth

Ogni anno nel mondo vengono spesi tre trilioni di $ in risorse costiere marine e industrie.

La pesca marina impiega oltre 200 milioni di persone, dalla pesca, alla lavorazione, alla spedizione, alle vendite.

Fino al 40% dei nostri oceani sono pesantemente colpiti dalla pesca illegale.

Ogni anno vengono venduti cinque milioni di tonnellate di tonno, con un valore stimato di 40 miliardi di dollari.

Si tratta di un settore enorme, che potrebbe beneficiare enormemente dell’innovazione e della trasparenza.

Con la dichiarazione di tracciabilità del tonno del 2020 ben in mente, il nostro obiettivo è eliminare la pesca illegale, non dichiarata e non regolamentata.

Useremo Hyperledger Fabric per portare trasparenza e chiarezza ad un esempio reale reale del mondo: la filiera della pesca del tonno.

Descriveremo come migliorare la pesca del tonno, partendo dalla fonte, la pescatrice Sarah, e il processo con cui il suo tonno finisce nel ristorante di Miriam.

Nel frattempo, avremo altre parti coinvolte, come il regolatore che verifica la validità dei dati e la sostenibilità delle catture di tonno.

Utilizzeremo il framework di Hyperledger Fabric per tenere traccia di ogni parte di questo processo.

Ora, prima di introdurre la sezione dello scenario dimostrativo, ci sono due idee principali su cui prestare attenzione:

  1. Ci sono molti attori all’interno della rete, e si vedrà come questi attori interagiscono e come viene condotta una transazione;
  2. I canali privati consentiranno a Sarah e Miriam di concordare privatamente i termini della loro interazione, pur mantenendo la trasparenza, in modo che altri attori possano corroborare e confermare la loro transazione.

Utilizzando canali privati, i regolatori e i ristoratori possono confermare se una particolare spedizione di tonno ha una fonte sostenibile e legale, senza la necessità di vedere i dettagli dell’intero viaggio.

Solo il pescatore e il ristoratore sono a conoscenza di dettagli specifici.

Definizione degli Attori

  • Sarah è la pescatrice che pesca in modo sostenibile e legalmente il tonno.

  • I regolatori verificano che il tonno sia stato catturato legalmente e in modo sostenibile.

  • Miriam è la proprietaria del ristorante che fungerà da utente finale, in questa situazione.

  • Carl è un altro proprietario di ristorante, cui la pescatrice Sarah può vendere il tonno.

190214_Hyperledger - Lesson 05-02 - Fabric_demonstrated_scenario_actors

Utilizzando Hyperledger Fabric, mostreremo come migliorare la pesca del tonno a partire dalla fonte, la pescatrice Sarah, e il processo con cui vende il suo tonno al ristorante di Miriam.

Elementi principali di Hyperledger Fabric

I canali sono meccanismi di partizionamento dei dati che consentono la visibilità delle transazioni solo per le parti interessate. Ogni canale è una catena indipendente di blocchi di transazione contenenti solo transazioni per quel particolare canale.

Il chaincode (Smart Contracts) incapsula sia le definizioni degli asset che la logica aziendale (o le transazioni) per modificare tali asset. Le chiamate di transazione generano modifiche al registro.

Il registro contiene lo stato del mondo attuale della rete e una catena di invocazioni delle transazioni. Un registro condiviso e autorizzato è un sistema di record in append-only e funge da unica fonte di verità.

Il network è la raccolta di peer di elaborazione dati che formano una rete blockchain. Il network è responsabile del mantenimento di un registro costantemente replicato.

Il servizio di ordinamento è una raccolta di nodi che ordinano le transazioni in un blocco.

Lo stato del mondo riflette i dati correnti su tutte le risorse nella rete. Questi dati sono memorizzati in un database per un accesso efficiente. I database attualmente supportati sono LevelDB e CouchDB.

Il provider del servizio di appartenenza (Membership Service Provider – MSP) gestisce l’identità e l’accesso autorizzato per clienti e colleghi.

La Pesca

Inizieremo con Sarah, la nostra pescatore di tonno con licenza, che si guadagna da vivere vendendo il suo tonno a più ristoranti. Sarah opera come un’impresa privata, in cui la sua azienda fa spesso affari internazionali. Attraverso un’applicazione client, Sarah è in grado di ottenere l’accesso a una rete di blockchain di Hyperledger Fabric composta da altri pescatori, oltre che da regolatori e proprietari di ristoranti. Sarah ha la possibilità di aggiungere e aggiornare le informazioni nel registro della rete blockchain mentre il tonno passa attraverso la catena di approvvigionamento e mentre i regolatori e i ristoranti hanno accesso in lettura al registro.

Dopo ogni pesca, Sarah registra informazioni su ogni singolo tonno, tra cui: un numero identificativo univoco, la posizione e l’ora della pesca, il suo peso, il tipo di imbarcazione e chi ha catturato il pesce. Per semplicità, continueremo con questi sei attributi di dati. Tuttavia, in un’applicazione reale, molti altri dettagli sarebbero registrati, dalla tossicologia, ad altre caratteristiche fisiche.

Questi dettagli vengono salvati nello stato del mondo come coppia chiave/valore in base alle specifiche di un contratto di chaincode, consentendo all’applicazione di Sarah di creare effettivamente una transazione sul registro. Di seguito un esempio:

$ var tuna = { id: ‘0001’,
holder: ‘Sarah’,
location: { latitude: ‘41.40238’, longitude: ‘2.170328’},
when: ‘20170630123546’,
weight: ‘58lbs’,
vessel : ‘9548E’ }

Gli Incentivi

Miriam è proprietaria di un ristorante che cerca pescatori di tonno di alta qualità e che siano stati catturati in modo responsabile, al prezzo più basso. Ogni volta che Miriam compra il tonno, è sempre incerta se può fidarsi del fatto che il tonno che sta acquistando sia stato catturato legalmente e in modo sostenibile, data l’importanza della pesca al tonno illegale e non dichiarata.

Allo stesso tempo, come pescatrice legittima ed esperta, Sarah si sforza di guadagnarsi da vivere vendendo il suo tonno ad un prezzo ragionevole. Vorrebbe anche l’autonomia a chi vendere e a quale prezzo.

Fortunatamente Hyperledger Fabric può aiutare sia Sarah che Miriam!

La Vendita

Normalmente, Sarah vende il suo tonno ai ristoratori, come Carl, per 80 $ a libbra. Tuttavia, Sarah accetta di fare a Miriam un prezzo speciale di 50 $ per libbra di tonno, piuttosto che il suo solito prezzo. In una blockchain pubblica tradizionale, una volta che Sarah e Miriam hanno completato la loro transazione, l’intero network è in grado di visualizzare i dettagli di questo accordo, in particolare il fatto che Sarah abbia fatto a Miriam un prezzo speciale. Ovviamente, avere altri ristoratori, come Carl, consapevoli di questo accordo non è economicamente vantaggioso per Sarah.

190214_Hyperledger - Lesson 05-03 - Fabric_sale_scenario

Per rimediare a questo, Sarah vuole che le specifiche del suo accordo non siano disponibili per tutti sul network, ma vuole comunque che tutti gli attori del network siano in grado di visualizzare i dettagli del pesce che sta vendendo. Usando la funzione dei canali di Hyperledger Fabric, Sarah può in privato concordare i termini con Miriam, in modo che solo loro possano vederli, senza che nessuno sappia le specifiche.

Inoltre, altri pescatori, che non fanno parte della transazione di Sarah e Miriam, non vedranno questa transazione sul loro libro mastro. Ciò garantisce che un altro pescatore non possa deprezzare l’offerta avendo informazioni sui prezzi che Sarah addebita ai diversi ristoratori.

I Regolatori

I regolatori potranno inoltre accedere al network blockchain di Hyperledger Fabric per confermare, verificare e visualizzare i dettagli dal registro. La loro applicazione permetterà a questi attori di interrogare il registro e vedere i dettagli di ciascuna delle catture di Sarah per confermare che sta pescando legalmente il suo pesce. I regolatori devono solo avere accesso alla query e non è necessario aggiungere voci al registro. Con ciò detto, possono essere in grado di regolare chi può ottenere l’accesso alla rete e/o essere in grado di rimuovere i pescatori dal network, se si scopre che stanno partecipando ad attività illegali.

Diventare Membri del Network

Hyperledger Fabric è un network con permesso, il che significa che solo i partecipanti che sono stati approvati possono accedere al network. Per gestire l’appartenenza e l’identità della rete, il fornitore del servizio di appartenenza (Membership Service Providers – MSP) gestiscono gli ID utente e autenticano tutti i partecipanti al network. Un network blockchain di Hyperledger Fabric può essere governato da uno o più MSP. Ciò fornisce la modularità delle operazioni di appartenenza e l’interoperabilità tra diversi standard e architetture di appartenenza.

Nel nostro scenario, il regolatore, i pescatori approvati e i ristoratori autorizzati dovrebbero essere gli unici autorizzati a entrare nel network. Per raggiungere questo obiettivo, viene definito un fornitore di servizio di appartenenza (MSP) per soddisfare l’appartenenza a tutti i membri di questa catena di approvvigionamento. Nella configurazione di questo MSP, vengono creati i certificati e le identità dei membri. Le politiche sono quindi definite per dettare le politiche di lettura/scrittura di un canale, o le politiche di approvazione di un chaincode.

Il nostro scenario ha due chaincode separati, che vengono eseguiti su tre canali separati. I due chaincode sono: uno per l’accordo sui prezzi tra il pescatore e il ristoratore e uno per il trasferimento del tonno. I tre canali sono: uno per l’accordo sui prezzi tra Sarah e Miriam; uno per l’accordo sui prezzi tra Sarah e Carl; e uno per il trasferimento del tonno. Ogni membro di questa rete conosce l’un l’altro e la loro identità. I canali forniscono la privacy e la riservatezza delle transazioni.

In Hyperledger Fabric, gli MSP consentono inoltre un’appartenenza dinamica per aggiungere o rimuovere membri per mantenere l’integrità e il funzionamento della catena di approvvigionamento. Ad esempio, se si scopre che Sarah sta catturando il suo pesce illegalmente, può essere revocata la sua iscrizione, senza compromettere il resto della rete. Questa funzione è fondamentale, specialmente per le applicazioni aziendali, in cui i rapporti commerciali cambiano nel tempo.

Riepilogo dello Scenario Dimostrativo

Di seguito è riportato un riepilogo dello scenario di cattura del tonno presentato in questa lezione:

  1. Sarah cattura un tonno e utilizza l’interfaccia utente dell’applicazione della catena di approvvigionamento per registrare tutti i dettagli sul pescato. Prima che raggiunga il registro, la transazione viene passata ai peer di supporto sulla rete, dove viene quindi approvata. La transazione approvata viene inviata al servizio di ordinamento, per essere ordinato in un blocco. Questo blocco viene quindi inviato ai peer che impegnano nella rete; l’impegno viene eseguito dopo essere stato convalidato.
  2. Mentre il tonno passa lungo la catena di approvvigionamento, i regolatori possono utilizzare la propria applicazione per interrogare il registro per i dettagli sulle specifiche catture (ad eccezione del prezzo, poiché non hanno accesso al chaincode relativo al prezzo).
  3. Sarah può stipulare un accordo col ristoratore Carl e concordare un prezzo di 80 $ per libbra. Usano il canale “blu” per il contratto di chaincode che stipula 80 $/lb. Il registro del canale “blu” viene aggiornato con un blocco contenente questa transazione.
  4. In un accordo commerciale separato, Sarah e Miriam concordano un prezzo speciale di 50 $ per libbra. Usano il contratto di chaincode del canale “rosso” che stipula 50 $/lb. Il registro del canale “rosso” viene aggiornato con un blocco contenente questa transazione.

190214_Hyperledger - Lesson 05-04 - Demonstrated_Tuna_Fishing_Scenario

Componenti chiave e Flusso della Transazione

I ruoli all’interno di un network Hyperledger Fabric

Esistono tre diversi tipi di ruoli all’interno di una rete Hyperledger Fabric:

  • I Client
    Sono applicazioni che agiscono per conto di una persona per proporre transazioni sul network.
  • I Peer
    Mantengono lo stato del network e una copia del registro. Esistono due tipi diversi di peer: endorsing peers (peer che approvano) e committing peers (peer che impegnano). Tuttavia, vi è una sovrapposizione tra endorsing e committing peer, nel senso che gli endorsing sono un tipo speciale di committing peer. Tutti i peer impegnano blocchi nel registro distribuito.
    • Gli Endorser simulano e approvano le transazioni
    • I Committer verificano le approvazioni e convalidano i risultati delle transazioni, prima di eseguire le transazioni sulla blockchain.
  • Servizio di ordinamento
    Accetta transazioni approvate, le ordina in un blocco e consegna i blocchi ai peer che impegnano.

Come raggiungere il Consenso

In un sistema di registro distribuito, il consenso è il processo per raggiungere un accordo sulla successiva serie di transazioni da aggiungere al registro. In Hyperledger Fabric, il consenso è costituito da tre passaggi distinti:

  • Approvazione della transazione
  • Ordinamento
  • Convalida e impegno.

Questi tre passaggi garantiscono che le politiche di un network siano rispettate. Vedremo come questi passaggi sono implementati esplorando il flusso della transazione.

Flusso della Transazione (Passo 1)

All’interno di un network Hyperledger Fabric, le transazioni iniziano con le applicazioni client che inviano proposte di transazione o, in altre parole, propongono una transazione per approvare i peer.

190214_Hyperledger - Lesson 05-05 - Key_Components_-_Transaction_Proposal

Le applicazioni client sono comunemente chiamate applicazioni o client e consentono alle persone di comunicare col network blockchain. Gli sviluppatori di applicazioni possono sfruttare il network Hyperledger Fabric attraverso l’SDK dell’applicazione.

Flusso della Transazione (Passo 2)

Ogni peer di approvazione simula la transazione proposta, senza aggiornare il registro. I peer di approvazione acquisiranno il set di dati Read (Letti) e Written (Scritti), chiamati RW Set.

Questi RW set catturano ciò che è stato letto dallo stato del mondo corrente durante la simulazione della transazione, così come ciò che sarebbe stato scritto nello stato mondiale se la transazione fosse stata eseguita. Questi RW set vengono quindi firmati dal peer di approvazione e restituiti all’applicazione client per essere utilizzati nelle fasi future del flusso di transazione.

190214_Hyperledger - Lesson 05-06 - Transaction_flow_step_2

I peer di approvazione devono avere contratti intelligenti per simulare le proposte di transazione.

Approvazione della transazione

Una approvazione della transazione è una risposta firmata ai risultati della transazione simulata. Il metodo di approvazione delle transazioni dipende dal criterio di approvazione che viene specificato quando viene distribuito il codice di attivazione.

Un esempio di politica di approvazione sarebbe “la maggior parte dei peer che approvano devono approvare la transazione”. Poiché una politica di approvazione è specificata per uno specifico codice, i diversi canali possono avere politiche di approvazione diverse.

Flusso della Transazione (Passo 3)

L’applicazione invia quindi la transazione approvata e i RW set al servizio di ordinamento. L’ordinamento avviene attraverso il network, in parallelo con le transazioni approvate e i RW set inviati da altre applicazioni.

190214_Hyperledger - Lesson 05-07 - Transaction_flow_step_3

Flusso della Transazione (Passo 4)

Il servizio di ordinamento prende le transazioni approvate e i RW sets, ordina queste informazioni in un blocco e consegna il blocco a tutti i committing peers (peer che impegnano).

190214_Hyperledger - Lesson 05-08 - Transaction_Flow_Step_4

Il servizio di ordinamento, che è costituito da un gruppo di ordinatori, non elabora le transazioni, i contratti intelligenti o mantiene il registro condiviso. Il servizio di ordinamento accetta le transazioni approvate e specifica l’ordine in cui tali transazioni saranno impegnate nel libro mastro. L’architettura Fabric v1.0 è stata progettata in modo tale che l’implementazione specifica di “ordering” (Solo, Kafka, BFT) diventa un componente collegabile. Il servizio di ordinamento predefinito per Hyperledger Fabric è Kafka. Pertanto, il servizio di ordinamento è un componente modulare di Hyperledger Fabric.

Ordinamento (Parte I)

Le transazioni all’interno di un intervallo di tempo vengono ordinate in un blocco e vengono eseguite in ordine sequenziale.

In un network blockchain, le transazioni devono essere scritte nel registro condiviso in un ordine coerente. L’ordine delle transazioni deve essere stabilito per garantire che gli aggiornamenti dello stato del mondo siano validi quando sono impegnati nella rete. A differenza della blockchain Bitcoin, dove l’ordinamento avviene attraverso la risoluzione di un enigma crittografico detto anche mining, Hyperledger Fabric consente alle organizzazioni che eseguono il network di scegliere il meccanismo di ordinamento che meglio si adatta al network. Questa modularità e flessibilità rendono Hyperledger Fabric incredibilmente vantaggioso per le applicazioni aziendali.

Ordinamento (Parte II)

Hyperledger Fabric fornisce tre meccanismi di ordinamento: SOLO, Kafka e Simplified Byzantine Fault Tolerance (SBFT).

  • SOLO è il meccanismo di ordinamento di Hyperledger Fabric più comunemente usato dagli sviluppatori che sperimentano il network Hyperledger Fabric. SOLO implica un singolo nodo di ordinamento.
  • Kafka è il meccanismo di ordinamento di Fabric Hyperledger consigliato per l’uso in produzione. Questo meccanismo di ordinamento utilizza Apache Kafka, una piattaforma di elaborazione del flusso open source che fornisce una piattaforma unificata, ad alto throughput e a bassa latenza per gestire i feed di dati in tempo reale. In questo caso, i dati sono costituiti da transazioni approvate e RW Set. Il meccanismo di Kafka fornisce una soluzione ai guasti “fault-tolerant” dell’ordinamento.
  • SBFT è sinonimo di Simplified Byzantine Fault Tolerance. Questo meccanismo di ordinamento è sia resistente ai guasti “fault-tolerant” sia ai guasti “byzantine fault-tolerant”, il che significa che può raggiungere un accordo anche in presenza di nodi dannosi o difettosi.

Questi tre meccanismi di ordinamento forniscono metodologie alternative per concordare l’ordine delle transazioni.

Flusso della Transazione (Passo 5)

Il committing peer (peer che impegna) convalida la transazione controllando che i RW Set corrispondano ancora allo stato del mondo corrente. In particolare, che i dati di lettura esistenti quando gli endorser hanno simulato la transazione sono identici allo stato del mondo corrente. Quando il committing peer convalida la transazione, essa viene scritta nel registro e lo stato del mondo viene aggiornato con i dati di scrittura dal RW Set.

190214_Hyperledger - Lesson 05-09 - Transaction_Flow_Step_5

Se la transazione fallisce, cioè se il committing peer scopre che l’RW Set non corrisponde allo stato del mondo attuale, la transazione ordinata in un blocco sarà comunque inclusa in quel blocco, ma sarà contrassegnata come non valida, e lo stato del mondo non verrà aggiornato.

I committing peer sono responsabili dell’aggiunta di blocchi di transazioni al registro condiviso e dell’aggiornamento dello stato del mondo. Possono tenere contratti intelligenti, ma non è un requisito.

Flusso della Transazione (Passo 6)

Infine, i committing peer notificano in modo asincrono all’applicazione client l’esito positivo o negativo della transazione. Le domande saranno comunicate da ciascun committing peer.

190214_Hyperledger - Lesson 05-10 - Transaction_Flow_Step_6

Verifica dell’Identità

Oltre alle innumerevoli verifiche di approvazione, validità e controllo delle versioni che si verificano, sono inoltre in corso verifiche di identità che accadono durante ogni fase del flusso di transazione. Gli elenchi di controllo di accesso sono implementati nei livelli gerarchici della rete (dal servizio di ordinamento fino ai canali) e i carichi utili (payload) vengono ripetutamente firmati, verificati e autenticati mentre una proposta di transazione passa attraverso i diversi componenti dell’architettura.

Riassunto del Flusso della Transazione

È importante notare che lo stato del network è gestito dai peer e non dal servizio di ordinamento o dal client. Normalmente, si può progettare il sistema in modo tale che diverse macchine nel network svolgano ruoli diversi. Ovvero, le macchine che fanno parte del servizio di ordinamento non dovrebbero essere configurate per supportare o proporre transazioni e viceversa. Tuttavia, vi è una sovrapposizione tra gli endorsing peer e i committing peer sul sistema. Gli endorsing peer devono avere accesso e mantenere i contratti intelligenti, oltre a svolgere il ruolo di un committing peer. Gli endorsing peer impegnano i blocchi, ma i committing peer non approvano le transazioni.

Gli endorsing peer verificano la firma del client ed eseguono una funzione di chaincode per simulare la transazione. L’output è il risultato chaincode, un insieme di versioni chiave/valore che sono state lette nel chaincode (Read set) e l’insieme di chiavi/valori che sono stati scritti dal chaincode. La risposta proposta viene inviata al client, insieme a una firma di approvazione. Queste risposte proposte vengono inviate all’ordinante per essere ordinate. L’ordinante ordina quindi le transazioni in un blocco, che inoltra agli endorsing peer e ai committing peer. Gli RW Set vengono utilizzati per verificare che le transazioni siano ancora valide prima che il contenuto del registro e dello stato del mondo vengano aggiornati. Infine, i peer comunicano asincronicamente all’applicazione client il successo o il fallimento della transazione.

I canali

I canali consentono alle organizzazioni di utilizzare lo stesso network, mantenendo al contempo la separazione tra più blockchain. Solo i membri del canale su cui è stata eseguita la transazione possono vedere le specifiche della transazione. In altre parole, i canali suddividono il network per consentire la visibilità delle transazioni solo per le parti interessate. Questo meccanismo funziona delegando le transazioni a diversi registri. Solo i membri del canale sono coinvolti nel consenso, mentre altri membri del network non vedono le transazioni sul canale.

190214_Hyperledger - Lesson 05-11 - Key_Components_Channels

Lo schema sopra mostra tre canali distinti: “blu”, “arancione” e “grigio”. Ogni canale ha un’applicazione, un registro e i peer propri.

I peer possono appartenere a più network o canali. I peer che partecipano a più canali simulano e propongono transazioni su diversi registri. Il servizio di ordinamento è lo stesso fra qualsiasi rete o canale.

Alcune cose da ricordare:

  • L’impostazione di network consente la creazione di canali.
  • La stessa logica di chaincode può essere applicata a più canali.
  • Un determinato utente può partecipare a più canali.

Stato del database

I dati dello stato corrente rappresentano gli ultimi valori per tutte le risorse nel registro. Poiché lo stato corrente rappresenta tutte le transazioni impegnate sul canale, a volte viene indicato come stato del mondo.

Le chiamate Chaincode eseguono transazioni rispetto allo stato corrente dei dati. Per rendere queste interazioni chaincode estremamente efficienti, le ultime coppie chiave/valore per ogni risorsa sono memorizzate in un database di stato. Il database di stato è semplicemente una vista indicizzata nelle transazioni impegnate della catena. Può quindi essere rigenerato dalla catena in qualsiasi momento. Lo stato del database verrà automaticamente recuperato (o generato, se necessario) all’avvio di peer, prima che vengano accettate nuove transazioni. Lo stato del database predefinito, LevelDB, può essere sostituito con CouchDB.

  • LevelDB è lo stato del database predefinito chiave/valore per Hyperledger Fabric e memorizza semplicemente coppie chiave/valore.
  • CouchDB è un’alternativa a LevelDB. A differenza di LevelDB, CouchDB memorizza oggetti JSON. CouchDB è unico in quanto supporta query con chiave, composito, intervallo chiave e query complete di dati.

LevelDB e CouchDB di Hyperledger Fabric sono molto simili nella loro struttura e funzione. Sia LevelDB che CouchDB supportano le operazioni core chaincode, come ottenere e impostare risorse chiave e query basate su queste chiavi. Con entrambi, le chiavi possono essere interrogate in base all’intervallo e le chiavi composite possono essere modellate per abilitare query di equivalenza su più parametri. Ma, come archivio di documenti JSON, CouchDB abilita inoltre query complesse sui dati chaincode, quando i valori chaincode (ad es. Asset) sono modellati come dati JSON.

190214_Hyperledger - Lesson 05-12 - State_Database

Smart Contracts

Come promemoria, i contratti intelligenti sono programmi per computer che contengono la logica per eseguire transazioni e modificare lo stato delle risorse memorizzate all’interno del registro. I contratti intelligenti di Hyperledger Fabric sono chiamati chaincode e sono scritti in Go. Il chaincode funge da logica di business per un network Hyperledger Fabric, in quanto il chaincode dirige il modo in cui si manipolano le risorse all’interno del network. Discuteremo di più su chaincode nella sezione Capire Chaincode.

Fornitore del Servizio di Appartenenza (Membership Service Providers - MSP)

Il fornitore del servizio di appartenenza, o MSP, è un componente che definisce le regole in cui le identità sono convalidate, autenticate e consente l’accesso a una rete. MSP gestisce gli ID utente e autentica i client che desiderano unirsi al network. Ciò include fornire credenziali per questi clienti per proporre transazioni.

L’MSP utilizza un’Autorità di Certificazione, che è un’interfaccia collegabile che verifica e revoca i certificati utente all’identità confermata.

L’interfaccia predefinita utilizzata per MSP è il Fabric-CA API, tuttavia, le organizzazioni possono implementare un’autorità di certificazione esterna a loro scelta. Questa è un’altra caratteristica di Hyperledger Fabric che è modulare. Hyperledger Fabric supporta molte architetture di credenziali, il che consente l’utilizzo di molti tipi di interfacce External Certificate Authority. Di conseguenza, un singolo network Hyperledger Fabric può essere controllato da più MSP, in cui ciascuna organizzazione porta il proprio preferito.

Cosa fa l’MSP?

Per iniziare, gli utenti sono autenticati utilizzando un’autorità di certificazione. L’autorità di certificazione identifica l’applicazione, il peer, l’endorser, l’ordinatore di identità e la verifica di tali credenziali. Una firma viene generata mediante l’utilizzo di un Algoritmo della firma e un Algoritmo di verifica della firma.

In particolare, la generazione di una firma inizia con un Algoritmo della firma, che utilizza le credenziali delle entità associate con le rispettive identità e genera un avallo. Viene generata una firma, che è una matrice di byte associata a un’identità specifica. Successivamente, l’Algoritmo di verifica della firma prende l’identità, l’approvazione e la firma come input, e l’output ‘accetta’ se la matrice di byte della firma corrisponde a una firma valida per l’approvazione immessa, o restituisce ‘rifiuta’ se non lo fa. Se l’output è ‘accept’, l’utente può vedere le transazioni nella rete ed eseguire transazioni con altri attori nella rete. Se l’output è “rifiutato”, l’utente non è stato autenticato correttamente e non è in grado di inviare transazioni alla rete o visualizzare transazioni precedenti.

190214_Hyperledger - Lesson 05-13 - The_role_of_membership_service_provider

Autorità Fabric-Certificate

In generale, le Autorità di Certificazione gestiscono i certificati di iscrizione per una blockchain autorizzata. Fabric-CA è l’autorità di certificazione predefinita per Hyperledger Fabric e gestisce la registrazione delle identità dell’utente. L’autorità di certificazione Fabric-CA è responsabile dell’emissione e della revoca dei certificati di iscrizione (E-Certs). L’attuale implementazione di Fabric-CA rilascia solo E-Certs, che fornisce certificati di identità a lungo termine. Gli e-certs, emessi dall’autorità di certificazione delle iscrizioni (E-CA), assegnano ai colleghi la loro identità e danno loro il permesso di aderire alla rete e inviare le transazioni.

Installare Hyperledger Fabric

Prerequisiti tecnici

Per installare correttamente Hyperledger Fabric, si dovrebbe avere familiarità con i linguaggi di programmazione Go e Node.js e avere le seguenti funzionalità installate sul proprio computer: cURL, Node.js, gestore pacchetti npm, linguaggio Go, Docker e Docker Compose.

Installazione di Images and Binaries di Hyperledger Fabric Docker

Successivamente, bisogna scaricare le ultime immagini Docker rilasciate per Hyperledger Fabric contrassegnate con il tag latest. Eseguire il comando dalla directory in cui sono stati estratti i binari specifici della piattaforma:

$ curl -sSL https://goo.gl/6wtTN5 | bash -s 1.1.0

NOTA: Controllare http://hyperledger-fabric.readthedocs.io/en/release-1.1/samples.html#binaries per l’URL più recente (l’indirizzo dopo il precedente comando curl) per estrarre i binari.

Questo comando scarica i binari per cryptogen, configtxgen, configxlator, configxlator E scarica le immagini di Docker Fabric Hyperledger. Queste risorse sono collocate in una sottodirectory bin della directory di lavoro corrente. Per confermare e visualizzare l’elenco delle immagini Docker appena scaricate, esegui:

$ docker images

La risposta attesa è:

190214_Hyperledger - Lesson 05-14 - Fabric_installation_1

Nota i tag per ciascuno dei repository nel riquadro rosso. Se le immagini del Docker non sono già etichettate con il tag latest, eseguire il seguente comando per ciascuna delle immagini Docker:

$ docker tag hyperledger/fabric-tools:x86_64-1.0.2
hyperledger/fabric-tools:latest

Modificare “x86_64-1.0.2” con i tag della propria lista di repository. Inoltre, modificare la parte con “fabric-tools” con il nome dell’immagine di Docker di cui stai cambiando il tag (ad es .: fabric-tools, fabric-ccenv, fabric-orderer, ecc.). Ripetere questo passaggio per tutte le immagini Docker che visualizzate nell’elenco.

Nello screenshot in alto, le immagini Docker sono già taggate. Se questo è il proprio caso, non è necessario eseguire questo passaggio aggiuntivo.

Installazione di Hyperledger Fabric

Come misura aggiuntiva, è possibile aggiungere la sottodirectory bin alla variabile di ambiente PATH, in modo che possano essere raccolti senza la necessità di qualificare il PATH per ogni binario. È possibile farlo eseguendo il seguente comando:

$ export PATH=$PWD/bin:$PATH

Per installare il codice di esempio Hyperledger Fabric che verrà utilizzato nelle esercitazioni, eseguire:

$ git clone https://github.com/hyperledger/fabric-samples.git

$ cd fabric-samples/first-network

Avviare un test su network Hyperledger Fabric

Una volta installato con successo Hyperledger Fabric, si può procedere alla configurazione di un semplice network con due membri. Per fare riferimento al nostro scenario dimostrativo, il network include la gestione di ogni “asset” tonno verificato, trasferito e acquistato tra Sarah, la pescatrice e Miriam, la ristoratrice. Creeremo, quindi, un semplice network con due membri composta da due organizzazioni (in effetti solo Sarah e Miriam), ognuna delle quali mantiene due peer e un servizio di ordinazione.

Utilizzeremo Docker images per avviare il nostro primo network Hyperledger Fabric. Avvierà inoltre un container per eseguire un’esecuzione basata su script che unirà i peer a un canale, implementerà e istanzierà il chaincode ed eseguirà transazioni contro il chaincode.

Avviare il nostro primo network

Eseguire questo comando (all’interno della cartella first-network):

$ ./byfn.sh -m generate

Apparirà una breve descrizione, insieme a una riga di comando Y/N nel prompt. Scrivere una Y <Invio> per continuare.

Questo passaggio genera tutti i certificati e le chiavi per tutte le nostre varie entità di network, incluso il blocco di genesi utilizzato per eseguire il bootstrap del servizio di ordinamento e una raccolta di configurazioni di transazioni necessarie per creare un canale. Successivamente, è possibile avviare il network con il seguente comando:

$ ./byfn.sh -m up

Apparirà un’altra riga di comando, scrivere Y <Invio> per continuare.

I registri appariranno nella riga di comando, mostrando i container che vengono lanciati, i canali creati e uniti, il chaincode installato, istanziato e invocato su tutti i peer, oltre a vari registri delle transazioni.

Nota sulla risoluzione dei problemi:
Se si riscontrano difficoltà con i due comandi precedenti e si sospetta che le Docker images possano essere errate, è possibile ricominciare da capo, eliminando e annullando la selezione del Docker images.

$ docker rmi -f $(docker images -q)

Una volta eseguito questo comando, tornare alla sezione vista precedentemente Installazione di Images and Binaries di Hyperledger Fabric Docker.

Chiudere e Terminare il Network

Infine, proviamo a mettere giù questa rete. All’interno dello stesso terminale, eseguire Control+C per uscire dall’esecuzione corrente.

Quindi, esegui il seguente comando:

$ ./byfn.sh -m down

Apparirà un’altra riga di comando, scrivere Y <Invio> per continuare.

Questo comando terminerà i container, rimuoverà il materiale crittografico e quattro artefatti ed eliminerà le immagini del codice dal registro Docker.

Questa è stata una semplice dimostrazione!

Questi semplici passaggi mostrano come possiamo facilmente avviare e terminare una rete Hyperledger Fabric, dato il codice che abbiamo. Nella prossima sezione, impareremo di più sul chaincode.

Di seguito un video esplicativo per l’installazione di Hyperledger Fabric

Capire Chaincode

Chaincode

In Hyperledger Fabric, chaincode è il “contratto intelligente” che viene eseguito sui peer e crea transazioni. Più in generale, consente agli utenti di creare transazioni nel registro condiviso del network di Hyperledger Fabric e aggiornare lo stato mondiale delle risorse.

Chaincode è un codice programmabile, scritto in Go e istanziato su un canale. Gli sviluppatori utilizzano il chaincode per sviluppare contratti commerciali, definizioni degli “asset” e applicazioni decentralizzate gestite collettivamente. Il chaincode gestisce lo stato del registro attraverso le transazioni invocate dalle applicazioni. Gli “asset” sono creati e aggiornati da uno specifico chaincode e non sono accessibili da un altro chaincode.

Le applicazioni interagiscono con il registro blockchain attraverso il chaincode. Pertanto, il chaincode deve essere installato su ogni peer che avalla una transazione e istanziato sul canale.

Esistono due modi per sviluppare contratti intelligenti con Hyperledger Fabric:

  • Contrassegnare i singoli contratti in istanze indipendenti di chaincode
  • (Modalità più efficiente) Utilizzare il chaincode per creare applicazioni decentralizzate che gestiscono il ciclo di vita di uno o più tipi di contratti commerciali e consentire agli utenti finali di creare istanze di contratti all’interno di queste applicazioni.

Chaincode Key APIs

Un’interfaccia importante che si può usare quando si scrive il proprio chaincode è definita da ChaincodeStub e ChaincodeStubInterface di Hyperledger Fabric.

ChaincodeStub fornisce le funzioni che consentono di interagire con il registro sottostante per interrogare, aggiornare ed eliminare risorse. Le principali API per il chaincode includono:

  • func (stub *ChaincodeStub) GetState(key string) ([]byte, error)
    Restituisce il valore della chiave specificata dal registro. Si noti che GetState non legge i dati dal Write set, che non sono stato impegnati nel registro. In altre parole, GetState non considera i dati modificati da PutState che non sono stati impegnati. Se la chiave non esiste nel database di stato, viene restituito (nil, nil).
  • func (stub *ChaincodeStub) PutState(key string, value []byte) error
    Inserisce la key e il value specificati nel Write set della transazione come proposta di scrittura dati. PutState non influisce sul registro finché la transazione non viene convalidata e impegnata correttamente.
  • func (stub *ChaincodeStub) DelState(key string) error
    Registra la key specificata da eliminare nel Write set della proposta di transazione. La key e il relativo value verranno eliminati dal registro quando la transazione viene convalidata e impegnata correttamente.

Panoramica di un Programma Chaincode

Quando si crea un chaincode, ci sono due metodi che bisogna implementare:

  • Init
    Chiamato quando un chaincode riceve una transazione di instantiate o di upgrade. Questo è dove si inizializzerà qualsiasi stato dell’applicazione.
  • Invoke
    Chiamato quando viene ricevuta la transazione di invoke per elaborare eventuali proposte di transazione.

Come sviluppatore, bisogna creare sia un metodo Init che un metodo Invoke all’interno del proprio chaincode. Il chaincode deve essere installato utilizzando il comando peer chaincode install e istanziato utilizzando il comando peer chaincode instantiate prima che il chaincode possa essere invocato. Quindi, è possibile creare transazioni utilizzando i comandi peer chaincode invoke o peer chaincode query.

Esempio di struttura di Chaincode – Dependencies

Passiamo ora a un esempio di chaincode scritto in Go, passo dopo passo:

package main import (
__“fmt”
__“github.com/hyperledger/fabric/core/chaincode/shim”
__“github.com/hyperledger/fabric/protos/peer”
)

La dichiarazione import elenca alcune dipendenze necessarie per il corretto sviluppo del codice.

  • fmt – contiene Println per il debug/logging
  • github.com/hyperledger/fabric/core/chaincode/shim – contiene la definizione per chaincode interface e lo chaincode stub, che sarà necessario far interagire con il registro, come descritto nella sezione Chaincode Key APIs
  • github.com/hyperledger/fabric/protos/peer – contiene il pacchetto peer protobuf.

Esempio di struttura di Chaincode – Struct

type SampleChaincode struct {
}

Questo potrebbe non sembrare molto, ma questa è la dichiarazione che inizia la definizione di un oggetto/classe in Go. SampleChaincode implementa un semplice chaincode per gestire un “asset”.

Esempio di struttura di Chaincode - Metodo Init

Successivamente, bisogna implementare il metodo Init. Init viene chiamato durante l’istanza di chaincode per inizializzare i dati richiesti dall’applicazione. In questo esempio, verrà creata la coppia chiave/valore iniziale per un “asset”, come specificato nella riga di comando:

func (t *SampleChaincode) Init(stub shim.ChainCodeStubInterface) peer.Response {
__// Get the args from the transaction proposal
__args := stub.GetStringArgs()
__if len(args) != 2 {
____return shim.Error(“Incorrect arguments. Expecting a key and a value”)
__}
__// We store the key and the value on the ledger
__err := stub.PutState(args[0], []byte(args[1]))
__if err != nil {
____return shim.Error(fmt.Sprintf(“Failed to create asset: %s”, args[0]))
__}
__return shim.Success(nil)
}

L’implementazione Init accetta due parametri come input e propone di scrivere una coppia chiave/valore nel registro utilizzando la funzione stub.PutState. GetStringArgs recupera e verifica la validità degli argomenti che si prevede siano una coppia chiave/valore. Pertanto, bisogna controllare che ci siano due argomenti specificati. In caso contrario, verrà restituito un errore dal metodo Init, per indicare che qualcosa è andato storto. Una volta verificato il numero corretto di argomenti, è possibile memorizzare lo stato iniziale nel registro. Per ottenere ciò, verrà chiamata la funzione stub.PutState, specificando il primo argomento come chiave e il secondo argomento come valore per quella chiave. Se non vengono restituiti errori, il metodo Init è stato eseguito con successo.

Esempio di struttura di Chaincode - Metodo Invoke

Ora esploreremo il metodo Invoke, che viene chiamato quando una transazione viene proposta da un’applicazione client. In questo esempio, si otterrà il valore per un determinato “asset” o verrà proposto di aggiornare il valore per una risorsa specifica.

func (t *SampleChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
__// Extract the function and args from the transaction proposal
__fn, args := stub.GetFunctionAndParameters()
__var result string
__var err error
__if fn == “set” {
____result, err = set(stub, args)
__} else { // assume ‘get’ even if fn is nil
____result, err = get(stub, args)
__}
__if err != nil { //Failed to get function and/or arguments from transaction proposal
____return shim.Error(err.Error())
__}
__// Return the result as success payload
__return shim.Success([]byte(result))
}

Ci sono due azioni di base che un cliente può invocare: get e set.

  • Il metodo get verrà utilizzato per interrogare e restituire il valore di un “asset” esistente.
  • Il metodo set verrà utilizzato per creare un nuovo “asset” o aggiornare il valore di un “asset” esistente.

Per iniziare, verrà chiamato GetFunctionandParameters per isolare il nome della funzione e le variabili dei parametri. Ogni transazione o è set o è get. Diamo prima un’occhiata a come viene implementato il metodo set:

func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
__if len(args) != 2 {
____return “”, fmt.Errorf(“Incorrect arguments. Expecting a key and a value”)
__}
__err := stub.PutState(args[0], []byte(args[1]))
__if err != nil {
____return “”, fmt.Errorf(“Failed to set asset: %s”, args[0])
__}
__return args[1], nil
}

Il metodo set creerà o modificherà un “asset” identificato da una chiave con il valore specificato. Il metodo set modificherà lo stato del mondo per includere la coppia chiave/valore specificata. Se la chiave esiste, sovrascriverà il valore con quello nuovo, utilizzando il metodo PutState; in caso contrario, verrà creata un nuovo “asset” con il valore specificato.

Di seguito, vediamo come viene implementato il metodo get:

func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
__if len(args) != 1 {
____return “”, fmt.Errorf(“Incorrect arguments. Expecting a key”)
__}
__value, err := stub.GetState(args[0])
__if err != nil {
____return “”, fmt.Errorf(“Failed to get asset: %s with error: %s”, args[0], err)
__}
__if value == nil {
____return “”, fmt.Errorf(“Asset not found: %s”, args[0])
__}
__return string(value), nil
}

Il metodo get tenterà di recuperare il valore per la chiave specificata. Se l’applicazione non passa in una singola chiave, verrà restituito un errore; in caso contrario, verrà utilizzato il metodo GetState per interrogare lo stato del mondo per la chiave specificata. Se la chiave non è stata ancora aggiunta al registro (e allo stato del mondo), verrà restituito un errore; in caso contrario, il valore impostato per la chiave specificata viene restituito dal metodo.

Esempio di struttura di Chaincode - Main Function

L’ultimo pezzo di codice in questo esempio è la funzione main, che chiamerà la funzione Start. La funzione main avvia il chaincode nel container durante l’istanziazione.

func main() {
__err := shim.Start(new(SampleChaincode))
__if err != nil {
____fmt.Println(“Could not start SampleChaincode”)
__} else {
____fmt.Println(“SampleChaincode successfully started”)
__}
}

Procedura dettagliata Chaincode
(Scenario Dimostrato)

Porre le basi

Ora che abbiamo un’idea generale di come è codificato chaincode, vedremo attraverso un esempio di chaincode che crea “asset” su un registro, basato sul nostro scenario dimostrativo per creare dei record per il tonno.

Il chaincode che esamineremo in questa sezione registrerà una cattura di tonno memorizzandola nel registro, oltre a consentire le query e gli aggiornamenti dei record di cattura del tonno.

Definizione degli attributi dell’Asset

Ecco i quattro attributi del tonno, che come esempio, registreremo sul registro:

  • Vessel [Nave] (stringa)
  • Date and Time (datetime)
  • Location [Posizione] (stringa)
  • Holder [Titolare] (stringa)

Creeremo una Struttura Tonno che ha quattro proprietà. I tag della struttura sono usati dalla libreria encoding/json.

type Tuna struct {
__Vessel string ‘json:”vessel”’
__Datetime string ‘json:”datetime”’
__Location string ‘json:”location”’
__Holder string ‘json:”holder”’
)

Metodo Invoke (Part I)

Come descritto in precedenza, il metodo Invoke è quello che viene chiamato quando una transazione viene proposta da un’applicazione client. All’interno di questo metodo, abbiamo tre diversi tipi di transazioni: recordTuna, queryTuna e changeTunaHolder , che esamineremo un po’ più tardi.

Come un promemoria, Sarah, la pescatrice, invocherà il recordTuna quando cattura ogni tonno.

190214_Hyperledger - Lesson 05-15 - Invoke_method_recordTuna

changeTunaHolder può essere invocato da Miriam, la ristoratrice, quando conferma la ricezione e il passaggio di un particolare tonno mentre passa attraverso la catena di approvvigionamento. queryTuna può essere invocato da Miriam, la ristoratrice, per visualizzare lo stato di un particolare tonno.

190214_Hyperledger - Lesson 05-16 - Invoke_method_queryTuna_and_changeTuna

I Regolatori invocheranno queryTuna e queryAllTuna in base alla loro necessità di verificare e controllare la sostenibilità della catena di approvvigionamento.

190214_Hyperledger - Lesson 05-17 - Invoke_method_queryTuna_and_queryAllTuna

Metodo Invoke (Part II)

Di seguito i diversi metodi tuna chaincode. Per primo il metodo Invoke. Come si può vedere, questo metodo analizzerà il primo parametro per determinare quale funzione dovrebbe essere chiamata e invocherà l’appropriato metodo tuna chaincode.

func (s *SmartContract) Invoke(APIstub shim.ChaincodeStubInterface) sc.Response {
__// Retrieve the requested Smart Contract function and arguments
__function, args := APIstub.GetFunctionAndParameters()
__// Route to the appropriate handler function to interact with the ledger appropriately
__if function == “queryTuna” {
____return s.queryTuna(APIstub, args)
__} else if function == “initLedger” {
____return s.initLedger(APIstub)
__} else if function == “recordTuna” {
____return s.recordTuna(APIstub, args)
__} else if function == “queryAllTuna” {
____return s.queryAllTuna(APIstub)
__} else if function == “changeTunaHolder” {
____return s.changeTunaHolder(APIstub, args)
__}
__return shim.Error(“Invalid Smart Contract function name.”)
}

Metodi Chaincode – queryTuna

Il metodo queryTuna può essere utilizzato da un pescatore, un regolatore o un ristoratore per visualizzare il record di un particolare tonno. Prende un argomento – la chiave per il tonno in questione.

func (s *SmartContract) queryTuna(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
__if len(args) != 1 {
____return shim.Error(“Incorrect number of arguments. Expecting 1”)
__}
__tunaAsBytes, _ := APIstub.GetState(args[0])
__if tunaAsBytes == nil {
____return shim.Error(“Could not locate tuna”)
__}
__return shim.Success(tunaAsBytes)
}

Metodi Chaincode – initLedger

Il metodo initLedger aggiungerà i dati di test alla nostra rete.

func (s *SmartContract) initLedger(APIstub shim.ChaincodeStubInterface) sc.Response {
__tuna := []Tuna{
____Tuna{Vessel: “923F”, Location: “67.0006, -70.5476”, Timestamp: “1504054225”, Holder: “Miriam”},
____Tuna{Vessel: “M83T”, Location: “91.2395, -49.4594”, Timestamp: “1504057825”, Holder: “Dave”},
____Tuna{Vessel: “T012”, Location: “58.0148, 59.01391”, Timestamp: “1493517025”, Holder: “Igor”},
____Tuna{Vessel: “P490”, Location: “-45.0945, 0.7949”, Timestamp: “1496105425”, Holder: “Amalea”},
____Tuna{Vessel: “S439”, Location: “-107.6043, 19.5003”, Timestamp: “1493512301”, Holder: “Rafa”},
____Tuna{Vessel: “J205”, Location: “-155.2304, -15.8723”, Timestamp: “1494117101”, Holder: “Shen”},
____Tuna{Vessel: “S22L”, Location: “103.8842, 22.1277”, Timestamp: “1496104301”, Holder: “Leila”},
____Tuna{Vessel: “EI89”, Location: “-132.3207, -34.0983”, Timestamp: “1485066691”, Holder: “Yuan”},
____Tuna{Vessel: “129R”, Location: “153.0054, 12.6429”, Timestamp: “1485153091”, Holder: “Carlo”},
____Tuna{Vessel: “49W4”, Location: “51.9435, 8.2735”, Timestamp: “1487745091”, Holder: “Fatima”},
__}
__i := 0
__for i < len(tuna) {
____fmt.Println(“i is “, i)
____tunaAsBytes, _ := json.Marshal(tuna[i])v
____APIstub.PutState(strconv.Itoa(i+1), tunaAsBytes)
____fmt.Println(“Added”, tuna[i])
____i = i + 1
__}
__return shim.Success(nil)
}

Metodi Chaincode – recordTuna

Il metodo recordTuna è il metodo che una pescatrice come Sarah userebbe per registrare ciascuna delle sue catture di tonno. Questo metodo accetta cinque argomenti (gli attributi da salvare nel registro).

func (s *SmartContract) recordTuna(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
__if len(args) != 5 {
____return shim.Error(“Incorrect number of arguments. Expecting 5”)
__}
__var tuna = Tuna{ Vessel: args[1], Location: args[2], Timestamp: args[3], Holder: args[4]}
__tunaAsBytes, _ := json.Marshal(tuna)
__err := APIstub.PutState(args[0], tunaAsBytes)
__if err != nil {
____return shim.Error(fmt.Sprintf(“Failed to record tuna catch: %s”, args[0]))
__}
__return shim.Success(nil)
}

Metodi Chaincode – queryAllTuna

Il metodo queryAllTuna consente di valutare tutti i record; in questo caso, tutti i record di Tonno aggiunti al registro. Questo metodo non accetta argomenti. Restituirà una stringa JSON contenente i risultati.

func (s *SmartContract) queryAllTuna(APIstub shim.ChaincodeStubInterface) sc.Response {
__startKey := “0”
__endKey := “999”
__resultsIterator, err := APIstub.GetStateByRange(startKey, endKey)
__if err != nil {
____return shim.Error(err.Error())
__}
__defer resultsIterator.Close()
__// buffer is a JSON array containing QueryResults
__var buffer bytes.Buffer
__buffer.WriteString(“[“)
__bArrayMemberAlreadyWritten := false
__for resultsIterator.HasNext() {
____queryResponse, err := resultsIterator.Next()
____if err != nil {
______return shim.Error(err.Error())
____}
____// Add a comma before array members, suppress it for the first array member
____if bArrayMemberAlreadyWritten == true {
______buffer.WriteString(“,”)
____}
____buffer.WriteString(“{\”Key\”:”)
____buffer.WriteString(“\””)
____buffer.WriteString(queryResponse.Key)
____buffer.WriteString(“\””)
____buffer.WriteString(“, \”Record\”:”)
____// Record is a JSON object, so we write as-is
____buffer.WriteString(string(queryResponse.Value))
____buffer.WriteString(“}”)
____bArrayMemberAlreadyWritten = true
__}
__buffer.WriteString(“]”)
__fmt.Printf(“- queryAllTuna:\n%s\n”, buffer.String())
__return shim.Success(buffer.Bytes())
}

Metodi Chaincode – changeTunaHolder

Dato che il tonno viene passato fra le diverse parti della catena di approvvigionamento, i dati nello stato del mondo possono essere aggiornati in base a chi ne ha il possesso. Il metodo changeTunaHolder accetta 2 argomenti, tuna id e il new holder name.

func (s *SmartContract) changeTunaHolder(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
__if len(args) != 2 {
____return shim.Error(“Incorrect number of arguments. Expecting 2”)
__}
__tunaAsBytes, _ := APIstub.GetState(args[0])
__if tunaAsBytes != nil {
____return shim.Error(“Could not locate tuna”)
__}
__tuna := Tuna{}
__json.Unmarshal(tunaAsBytes, &tuna)
__// Normally check that the specified argument is a valid holder of tuna
__// but here we are skipping this check for this example.
__tuna.Holder = args[1]
__tunaAsBytes, _ = json.Marshal(tuna)
__err := APIstub.PutState(args[0], tunaAsBytes)
__if err != nil {
____return shim.Error(fmt.Sprintf(“Failed to change tuna holder: %s”, args[0]))
__}
__return shim.Success(nil)
}

Conclusioni

Questo è un semplice esempio di come viene costruito e scritto il chaincode, specialmente se applicato a un semplice esempio. Per vedere tutti i frammenti di codice, si può visitare il repository educativo su GitHub

Scrivere un'Applicazione

Cos'è un'Applicazione Blockchain?

In un’applicazione blockchain, la blockchain memorizzerà lo stato del sistema, oltre al record immutabile di transazioni che hanno creato quello stato.
Un’applicazione client verrà utilizzata per inviare transazioni alla blockchain.
I contratti intelligenti codificheranno alcuni (se non tutti) della logica aziendale.

Come le Applicazioni interagiscono con il Network

Le applicazioni utilizzano le API per eseguire contratti intelligenti.
In Hyperledger Fabric, questi contratti intelligenti sono chiamati chaincode. Questi contratti sono ospitati sul network e identificati per nome e versione.
Le API sono accessibili con un software development kit (kit di sviluppo software) o SDK. Attualmente, Hyperledger Fabric ha tre opzioni per gli sviluppatori: Node.js SDK, Java SDK e CLI.

Fabric Node.js SDK

In questo esercizio, utilizzeremo il Node.js SDK per interagire con il network e, di conseguenza, con il registro.
L’Hyperledger Fabric Client SDK semplifica l’utilizzo delle API per interagire con una blockchain Hyperledger Fabric. Questa sezione aiuterà a scrivere una prima applicazione, iniziando con un network test Hyperledger Fabric, quindi imparando i parametri del contratto smart di esempio e infine sviluppando l’applicazione per interrogare e aggiornare i record del registro.

Per ulteriori informazioni, consultare la documentazione di Hyperledger Fabric Node SDK.

Finora, in questo capitolo, abbiamo trattato i componenti del framework di Hyperledger Fabric, inclusi i diversi tipi di nodi nella rete, i canali privati e le funzionalità del database.

Abbiamo anche installato e attivato la nostra rete di test, approfondendo la programmazione dei contatti intelligenti di chaincodes e analizzato un esempio dimostrativo, descrivendo in dettaglio come Fabric sia così unico.

Così, ora, siamo arrivati alla parte davvero eccitante, in cui combiniamo tutti questi concetti in un’applicazione di esempio funzionante.

In questo esercizio vedremo come un utente può interagire con una rete attraverso un’applicazione che consente agli utenti di interrogare e aggiornare un registro.

La nostra applicazione gestisce l’interfaccia utente e invia le transazioni alla rete, che quindi chiama chaincode.

Fabric ha attualmente tre opzioni per gli sviluppatori: un SDK del nodo, un SDK Java e un’interfaccia della riga di comando o CLI.

Oggi utilizzeremo l’SDK del nodo di Fabric, che semplifica l’utilizzo delle API per interagire con la blockchain di Hyperledger Fabric.

In poche parole, leggere o scrivere il registro è noto come una proposta.

Questa proposta viene creata dalla nostra applicazione tramite l’SDK e quindi inviata a un blockchain peer.

Il peer comunicherà al suo container di codice specifico dell’applicazione. Il chaincode eseguirà la transazione.

Se non ci sono problemi, confermerà la transazione e la rinvierà alla nostra applicazione. La nostra applicazione, tramite l’SDK, invierà quindi la proposta approvata al servizio di ordinamento.

L’ordinamento impacchetterà molte proposte dell’intera rete in un blocco, che verrà poi trasmesso ai peer della rete.

Infine, il peer convaliderà il blocco e lo scriverà nel suo registro.

La transazione è ora “viva”.

Entro la fine di questo esercizio, avremo familiarità con l’utilizzo dell’SDK Node.js per interagire con la rete e, di conseguenza, con un registro, e comprendere in che modo una rete e un registro dei codici a barre dell’applicazione interagiscono l’uno con l’altro.

Inizio (Parte I)

Nel caso non lo si abbia ancora fatto si scarichi il repository educational per questo corso, seguendo le successive direzioni nel proprio terminale:

$ git clone https://github.com/hyperledger/education.git

$ cd education/LFS171x/fabric-material/tuna-app

Assicurarsi di avere Docker in esecuzione sul proprio computer prima di eseguire il comando successivo. Se non si ha installato Docker, torna alla sezione: Requisiti tecnici.

Inoltre, assicurarsi di aver completato la sezione Installazione del fabric Hyperledger in questo capitolo prima di passare a questa sezione dell’applicazione, poiché è probabile che si verifichino degli errori. Innanzitutto, rimuovere eventuali contenitori preesistenti, poiché potrebbero entrare in conflitto con i comandi di questo tutorial:

$ docker rm -f $(docker ps -aq)

Quindi, avviare la rete Hyperledger Fabric con il seguente comando:

$ ./startFabric.sh

Risoluzione dei problemi: se, dopo aver eseguito quanto sopra, si verifica un errore simile al seguente:

ERROR: failed to register layer: rename

/var/lib/docker/image/overlay2/layerdb/tmp/write-set-091347846
/var/lib/docker/image/overlay2/layerdb/sha256/
9d3227c1793b7494e598caafd0a5013900e17dcdf1d7bdd31d39c82be04fcf28:
file exists

provare ad eseguire il seguente comando:

$ rm -rf ~/Library/Containers/com.docker.docker/Data/*

Inizio (Parte II)

Installare le librerie richieste dal file package.json, registrare i componenti Admin e User del nostro network e avviare l’applicazione client con i seguenti comandi:

$ npm install
$ node registerAdmin.js
$ node registerUser.js
$ node server.js

Caricare il client semplicemente aprendo localhost:8000 in qualsiasi finestra del browser di propria scelta, Si dovrebbe vedere l’interfaccia utente per la nostra semplice applicazione a questo URL (come nella schermata qui sotto).

190214_Hyperledger - Lesson 05-18 - Fabric-application1

Risoluzione dei problemi: se si verifica un errore simile a quello riportato di seguito mentre si tenta di eseguire una delle funzioni dell’applicazione:

Error: [client-utils.js]: sendPeersProposal – Promise is rejected: Error: Connect Failed
error from query = { Error: Connect Failed
at /Desktop/prj/education/LFS171x/fabric-material/tuna-app/node_modules/grpc/
src/node/src/client.js:554:15 code: 14, metadata: Metadata { _internal_repr: {} } }

Provare a far eseguire il seguente comando:

$ cd ~
$ rm -rf .hfc-key-store/

Quindi eseguire i comandi precedenti partendo con:

$ node registerAdmin.js

I File della Struttura dell’Application

Qui si può vedere i file della struttura dell’applicazione Fabric:

190214_Hyperledger - Lesson 05-19 - Fabric-filestructure

Interrogazione di tutto il Tonno registrato

// queryAllTuna – requires no arguments
const request = {
__chaincodeId:’tuna-app’,
__txId: tx_id,
__fcn: ‘queryAllTuna’,
__args: [”]
__};
return channel.queryByChaincode(request);

(Riferimento: il codice proviene da ..src / queryAllTuna.js)

Ora, interroghiamo il nostro database, dove ci dovrebbero essere già alcune voci di esempio, dal momento che il nostro contratto intelligente di chaincode ha avviato il registro con 10 catture precedenti. Questa funzione non accetta argomenti, come vediamo sulla riga 6. Invece, prende una matrice vuota.

La risposta alla query che si dovrebbe vedere nell’interfaccia utente è 10 voci pre-compilate con gli attributi per ciascuna cattura.

190214_Hyperledger - Lesson 05-20 - Fabric-queryAll

Interrogazione di uno specifico Tonno registrato

// queryTuna – requires 1 argument
const request = {
__chaincodeId:’tuna-app’,
__txId: tx_id,
__fcn: ‘queryTuna’,
__}args: [‘1’]
__};
return channel.queryByChaincode(request);

(Riferimento: il codice proviene da ..src / queryTuna.js)

Ora, interroghiamo una specifica cattura di tonno. Questa funzione richiede 1 argomento, come si può vedere nella riga 6, un esempio potrebbe essere [‘1’]. In questo esempio, usiamo la chiave per interrogare le catture.

Si dovrebbe visualizzare la seguente risposta alla query che descrive in dettaglio gli attributi registrati per una determinata cattura.

190214_Hyperledger - Lesson 05-21 - Fabric-query

Modificare il proprietario del Tonno

// changeTunaHolder – requires 2 argument
var request = {
__chaincodeId:’tuna-app’,
__fcn: ‘changeTunaHolder’,
__args: [‘1’, ‘Alex’],
__chainId: ‘mychannel’,
__txId: tx_id
__};
return channel.sendTransactionProposal(request);

(Riferimento: il codice proviene da ..src / changeHolder.js) Ora, cambieremo il nome della persona in possesso di un dato tonno. Questa funzione richiede 2 argomenti: la chiave per la particolare cattura e il nuovo titolare, come possiamo vedere nella riga 5 dell’esempio sopra. Es: args: [‘1’, ‘Alex’].

Potrebbe essere possibile visualizzare una risposta di successo simile nella finestra del terminale:

The transaction has been committed on peer localhost:7053
event promise all complete and testing complete

Successfully sent transaction to the orderer.
Successfully sent Proposal and received ProposalResponse: Status – 200,
message – “OK”, metadata – “”, endorsement signature: 0D 9

Ciò indica che è stata inviata una proposta dalla nostra applicazione tramite l’SDK e il peer ha approvato, impegnato e il registro è stato aggiornato.

190214_Hyperledger - Lesson 05-22 - Fabric-changeTunaHolder

Si può vedere che il titolare è stato effettivamente cambiato interrogando di nuovo per la chiave [‘1’]. Ora, nell’esempio, l’attributo holder è stato modificato da Miriam ad Alex.

190214_Hyperledger - Lesson 05-23 - Fabric-changedRecord

Registrare una cattura di Tonno

// recordTuna – requires 5 argument
var request = {
__chaincodeId:’tuna-app’,
__fcn: ‘recordTuna’,
__args: [’11’, ‘239482392’, ‘28.012, 150.225’, ‘0923T’, “Hansel”],
__chainId: ‘mychannel’,
__txId: tx_id
__};
return channel.sendTransactionProposal(request);

(Riferimento: il codice proviene da ..src / recordTuna.js)

Infine, praticheremo la registrazione di una nuova cattura di tonno e la aggiungeremo al registro invocando la funzione recordTuna.

Questa funzione accetta 5 argomenti, elencando ciascuno degli attributi di una nuova cattura. Si può vedere un esempio di proposta nella riga 5: args: [’11 ‘,’ 239482392 ‘, ’28 .012, 150.225’, ‘0923T’, “Hansel”].

190214_Hyperledger - Lesson 05-24 - Fabric-createTunaRecord

Tramite un controllo, interrogando tutte le catture di tonno, si dovrebbe vedere che il titolare è stato effettivamente cambiato. Ora si dovrebbe vedere una voce aggiuntiva in fondo alla tabella:

190214_Hyperledger - Lesson 05-25 - Fabric-queryAfterCreate

Chiudendo

Rimuovere tutti i contenitori Docker e images che si sono create in questo tutorial con il seguente comando nella cartella tuna-app:

$ docker rm -f $(docker ps -aq)
$ docker rmi -f $(docker images -a -q)

Le basi del flusso dell’Applicazione

190214_Hyperledger - Lesson 05-26 - Fabric-application-flowbasics
  1. Uno sviluppatore crea un’applicazione e uno smart contract.

  2. L’applicazione invocherà le chiamate all’interno del contratto intelligente tramite l’SDK Client Fabric Hyperledger.

  3. Queste chiamate vengono elaborate dalla logica di business all’interno del chaincode smart contract.

  4. Un comando put o delete passerà attraverso il processo di consenso e verrà aggiunto alla blockchain all’interno del registro.

  5. Un comando get può solo leggere dallo stato del mondo, ma non è registrato sulla blockchain.

  6. L’applicazione può accedere alle informazioni blockchain tramite le API.

Esempio di flusso dell’Applicazione

190214_Hyperledger - Lesson 05-27 - Fabric-application-flow
  1. Vari utenti (pescatore, regolatori, ristoratori, ecc.) interagiranno con l’applicazione Node.js.

  2. Il client JS invierà messaggi al backend quando l’utente interagisce con l’applicazione.

  3. La lettura o la scrittura del registro è nota come proposta (ad esempio, interrogando una specifica pesca di Tonno – queryTuna – o registrando una pesca di Tonno – recordTuna). Questa proposta viene creata dalla nostra applicazione tramite l’SDK e quindi inviata ai peer di approvazione.

  4. Gli endorsing peer utilizzeranno lo specifico chaincode smart contract dell’applicazione per simulare la transazione. Se non ci sono problemi, la transazione sarà approvata e inviata alla nostra applicazione.

  5. La nostra applicazione invierà quindi la proposta approvata al servizio di ordinamento tramite l’SDK. Il servizio di ordinamento impacchetterà molte proposte dell’intero network in un blocco. Quindi, trasmetterà il nuovo blocco ai committing peer nel network.

  6. Infine, ogni committing peer convaliderà il blocco e lo scriverà nel suo registro (mostrato in verde acqua sopra). La transazione è stata ora impegnata e tutte le letture rifletteranno questo cambiamento.