Die Augen fürchten sich, doch die Hände jucken!
In den vorherigen Artikeln haben wir uns mit den Technologien beschäftigt, auf denen Blockchains basieren () und mit den Anwendungsfällen, die wir damit realisieren können (). Jetzt ist es an der Zeit, selbst Hand anzulegen! Für die Umsetzung von Piloten und PoC (Proof of Concept) bevorzuge ich die Nutzung von Clouds, da man von überall auf der Welt darauf zugreifen kann und oft keine Zeit mit dem mühsamen Einrichten von Umgebungen verbringen muss, da bereits vorkonfigurierte Setups vorhanden sind. Lassen Sie uns also etwas Einfaches machen, zum Beispiel ein Netzwerk, um Münzen zwischen Teilnehmern zu übertragen, und nennen wir es bescheiden Citcoin. Dafür verwenden wir die IBM-Cloud und die universelle Blockchain Hyperledger Fabric. Zunächst klären wir, warum Hyperledger Fabric als universelle Blockchain bezeichnet wird?

Hyperledger Fabric — die universelle Blockchain
Allgemein gesagt ist ein universelles Informationssystem:
- Ein Satz von Servern und eine Software, die die Geschäftslogik ausführt;
- Schnittstellen zur Interaktion mit dem System;
- Mittel zur Registrierung, Authentifizierung und Autorisierung von Geräten / Personen;
- Eine Datenbank, die operative und archivierte Daten speichert:

Die offizielle Version, was Hyperledger Fabric ist, kann man lesen auf , kurz gesagt, Hyperledger Fabric ist eine Open-Source-Plattform, die es ermöglicht, private Blockchains zu erstellen und arbiträre Smart Contracts in den Programmiersprachen JS und Go auszuführen. Lassen Sie uns die Architektur von Hyperledger Fabric im Detail betrachten und sicherstellen, dass es sich um ein universelles System handelt, das spezielle Anforderungen an die Speicherung und Aufzeichnung von Daten hat. Diese Besonderheit besteht darin, dass die Daten, wie in allen Blockchains, in Blöcken gespeichert werden, die nur dann in die Blockchain eingefügt werden, wenn die Teilnehmer einen Konsens erzielt haben, und nach der Aufzeichnung sind die Daten nicht unbemerkt änderbar oder löschbar.
Architektur von Hyperledger Fabric
Die Architektur von Hyperledger Fabric ist in folgendem Diagramm dargestellt:

Organisationen – Organisationen enthalten Peers, das heißt, die Blockchain existiert durch die Unterstützung der Organisationen. Verschiedene Organisationen können einem Kanal beitreten.
Kanal – eine logische Struktur, die Peers in Gruppen zusammenfasst, wodurch die Blockchain definiert wird. Hyperledger Fabric kann gleichzeitig mehrere Blockchains mit unterschiedlicher Geschäftslogik verarbeiten.
Membership Services Provider (MSP) — ist eine CA (Zertifizierungsstelle) zur Erstellung von Identitäten und Rollenverteilungen. Um einen Knoten zu erstellen, muss mit dem MSP interagiert werden.
Peer-Knoten — prüfen Transaktionen, speichern die Blockchain, führen Smart Contracts aus und interagieren mit Anwendungen. Peer-Knoten besitzen eine Identität (digitales Zertifikat), das von MSP ausgegeben wird. Im Gegensatz zu Netzwerken wie Bitcoin oder Ethereum, wo alle Knoten gleichberechtigt sind, übernehmen Knoten in Hyperledger Fabric unterschiedliche Rollen:
- Ein Peer kann sein endorsing peer (EP) und Smart Contracts ausführen.
- Committing peer (CP) — speichert nur Daten in der Blockchain und aktualisiert den „World State“.
- Anchor Peer (AP) — wenn mehrere Organisationen an der Blockchain beteiligt sind, werden Anchor Peer verwendet, um Verbindungen zwischen ihnen herzustellen. Jede Organisation muss einen oder mehrere Anchor Peer haben. Mit einem AP kann jeder Peer in der Organisation Informationen über alle Peers in anderen Organisationen abrufen. Zur Synchronisierung von Informationen zwischen AP wird das .
- Leader Peer — Wenn eine Organisation mehrere Peers hat, wird nur der führende Peer Blöcke vom Ordering-Service empfangen und an die anderen Peers weitergeben. Der Führende kann sowohl statisch festgelegt als auch dynamisch von den Peers innerhalb der Organisation ausgewählt werden. Zur Synchronisierung der Informationen über die Führenden wird ebenfalls das Gossip-Protokoll verwendet.
Assets — sind Entitäten von Wert, die in der Blockchain gespeichert werden. Genauer gesagt handelt es sich um Key-Value-Daten im JSON-Format. Diese Daten werden in die Blockchain „Blockchain“ geschrieben. Sie haben eine Historie, die in der Blockchain gespeichert wird, und einen aktuellen Zustand, der in der Datenbank „World state“ gespeichert ist. Die Datenstrukturen werden je nach Geschäftszweck beliebig befüllt. Es gibt keine verpflichtenden Felder, die einzige Empfehlung ist, dass Assets einen Eigentümer haben und einen Wert darstellen.
Ledger — besteht aus der Blockchain „Blockchain“ und der Datenbank „World state“, in der der aktuelle Zustand der Assets gespeichert ist. Der World state verwendet LevelDB oder CouchDB.
Smart Contract — Die Geschäftslogik des Systems wird durch Smart Contracts umgesetzt. In Hyperledger Fabric werden Smart Contracts als Chaincode bezeichnet. Mit Chaincode werden Assets und die Transaktionen über sie definiert. Technisch gesehen sind Smart Contracts Programmmodule, die in den Programmiersprachen JS oder Go implementiert sind.
Genehmigungspolitik — Für jeden Chaincode können Politiken festgelegt werden, wie viele und von wem Bestätigungen für die Transaktion benötigt werden. Wenn keine Politik festgelegt ist, gilt standardmäßig: „Die Transaktion muss von jedem Mitglied (Member) jeder Organisation im Channel bestätigt werden“. Beispiele für Politiken:
- Die Transaktion muss von einem Administrator der Organisation bestätigt werden;
- Es muss von einem Mitglied (Member) oder einem Kunden der Organisation bestätigt werden;
- Es muss von einem Peer der Organisation bestätigt werden.
Bestellservice — Verpackt Transaktionen in Blöcke und sendet sie an die Peers im Channel. Garantiert die Zustellung von Nachrichten an alle Peers im Netzwerk. Für industrielle Systeme wird , für Entwicklung und Test .
CallFlow

- Die Anwendung interagiert mit Hyperledger Fabric über das Go-, Node.js- oder Java-SDK;
- Der Client erstellt die Transaktion tx und sendet sie an die bestätigenden Peers;
- Der Peer überprüft die Signatur des Clients, führt die Transaktion aus und sendet die Endorsement-Signatur zurück an den Client. Chaincode wird nur auf dem endorsierenden Peer ausgeführt, und das Ergebnis seiner Ausführung wird an alle Peers verteilt. Dieses Arbeitsalgorithmus wird als PBFT (Practical Byzantine Fault Tolerant) Konsens bezeichnet. Es unterscheidet sich von dadurch, dass die Nachricht gesendet wird und eine Bestätigung nicht von allen Teilnehmern, sondern nur von einer bestimmten Gruppe erwartet wird;
- Nachdem der Client die Anzahl der Antworten erhalten hat, die der Endorsement-Policy entspricht, sendet er die Transaktion an den Ordering-Service;
- Der Ordering-Service bildet den Block und sendet ihn an alle commitierenden Peers. Der Ordering-Service gewährleistet eine konsistente Aufzeichnung von Blöcken, wodurch das sogenannte Ledger-Fork ausgeschlossen wird ();
- Die Peers erhalten den Block, überprüfen erneut die Endorsement-Policy, schreiben den Block in die Blockchain und ändern den Zustand in der „World state“ DB.
Das bedeutet, dass eine Rollentrennung zwischen den Knoten erfolgt. Dies gewährleistet die Skalierbarkeit und Sicherheit der Blockchain:
- Smart Contracts (Chaincode) werden von den endorsierenden Peers ausgeführt. Dies gewährleistet die Vertraulichkeit der Smart Contracts, da sie nicht bei allen Teilnehmern, sondern nur bei den endorsierenden Peers gespeichert werden.
- Die Bestellung muss schnell funktionieren. Das wird erreicht, indem die Bestellung nur einen Block erstellt und ihn an eine feste Gruppe von Leader-Peers sendet.
- Die Commit-Peers speichern lediglich die Blockchain — es kann viele davon geben, und sie benötigen keine große Leistung und sofortige Reaktionszeiten.
Weitere architektonische Lösungen von Hyperledger Fabric und warum es so funktioniert, kann hier angesehen werden: oder hier: .
Also, Hyperledger Fabric ist wirklich ein vielseitiges System, mit dem man folgende Dinge tun kann:
- Willkürliche Geschäftslogik umsetzen, indem man den Mechanismus der Smart Contracts verwendet;
- Daten in der Blockchain-Datenbank im JSON-Format aufzeichnen und abrufen;
- Zugriff auf APIs bereitstellen und überprüfen, indem man die Zertifizierungsstelle nutzt.
Jetzt, da wir ein wenig über die Besonderheiten von Hyperledger Fabric Klarheit haben, lassen Sie uns endlich etwas Nützliches tun!
Blockchain bereitstellen
Problemstellung
Die Aufgabe besteht darin, ein Citcoin-Netzwerk mit folgenden Funktionen zu implementieren: ein Konto erstellen, den Kontostand abrufen, das Konto aufladen und Münzen von einem Konto auf ein anderes überweisen. Lassen Sie uns ein Objektmodell skizzieren, das wir später in einem Smart Contract umsetzen werden. Wir werden also Konten haben, die durch Namen (name) identifiziert werden und einen Kontostand (balance) enthalten, sowie eine Liste der Konten. Konten und die Liste der Konten sind in den Begriffen von Hyperledger Fabric Assets. Daher haben sie eine Historie und einen aktuellen Status. Ich werde versuchen, dies anschaulich darzustellen:

Die oberen Figuren zeigen den aktuellen Zustand, der im „World State“ gespeichert ist. Darunter befinden sich die Figuren, die die Historie zeigen, die in der Blockchain gespeichert wird. Der aktuelle Zustand der Assets verändert sich durch Transaktionen. Ein Asset wird nur vollständig geändert, weshalb bei der Ausführung einer Transaktion ein neues Objekt erstellt wird, während der aktuelle Wert des Assets in die Historie übergeht.
IBM Cloud
Erstellen Sie ein Konto in der . Um die Blockchain-Plattform nutzen zu können, muss sie auf Pay-As-You-Go aktualisiert werden. Dieser Prozess kann zeitaufwendig sein, da IBM zusätzliche Informationen anfordert und diese manuell überprüft. Positiv ist, dass IBM gute Schulungsmaterialien bietet, die helfen, Hyperledger Fabric in ihrer Cloud zu implementieren. Mir haben die folgende Artikelreihe und die Beispiele gefallen:
Im Folgenden sind Screenshots der IBM Blockchain-Plattform zu sehen. Dies ist keine Anleitung zur Erstellung einer Blockchain, sondern lediglich eine Demonstration des Umfangs der Aufgabe. Für unsere Zwecke erstellen wir eine Organisation:

In dieser Organisation erstellen wir die Nodes: Orderer CA, Org1 CA, Orderer Peer:

Wir legen Benutzer an:

Wir erstellen einen Channel und nennen ihn citcoin:

Im Grunde ist ein Channel eine Blockchain, daher beginnt er mit dem Genesis-Block:

Wir schreiben einen Smart Contract
/*
* 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;
Hier sollte alles intuitiv verständlich sein:
- Es gibt mehrere Funktionen (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), die das Demo-Programm über die Hyperledger Fabric API aufruft.
- Die Funktionen SendFrom und RefillBalance erzeugen Ereignisse (Event), die das Demo-Programm empfangen wird.
- Die Funktion instantiate wird einmal aufgerufen, wenn der Smart Contract instanziiert wird. Tatsächlich wird sie jedoch nicht nur einmal aufgerufen, sondern jedes Mal, wenn die Version des Smart Contracts geändert wird. Daher ist die Initialisierung der Liste mit einem leeren Array eine schlechte Idee, da wir bei einer Versionsänderung die aktuelle Liste verlieren würden. Aber egal, ich lerne ja gerade).
- Accounts und die Liste der Accounts sind JSON-Datenstrukturen. Für die Manipulation der Daten wird JS verwendet.
- Der aktuelle Wert des Assets kann durch den Aufruf der Funktion getState abgerufen und mit putState aktualisiert werden.
- Bei der Erstellung des Accounts wird die Funktion AddAccount aufgerufen, die die maximale Anzahl der Accounts in der Blockchain (maxAccounts = 5) vergleicht. Hier gibt es einen Fehler (haben Sie es bemerkt?), der zu einem endlosen Wachstum der Anzahl der Accounts führt. Solche Fehler sollten vermieden werden).
Dann laden wir den Smart Contract in den Channel und instanziieren ihn:

Wir sehen die Transaktion zur Einrichtung des Smart Contracts:

Wir sehen Einzelheiten zu unserem Channel:

Das Ergebnis ist das folgende Schema des Blockchain-Netzwerks in der IBM Cloud. Auch in dem Diagramm ist ein Demo-Programm zu sehen, das in der Amazon Cloud auf einem virtuellen Server läuft (nähere Informationen dazu finden Sie im nächsten Abschnitt):

Erstellung einer GUI für Aufrufe der Hyperledger Fabric API
Hyperledger Fabric bietet eine API, die für folgende Zwecke genutzt werden kann:
- Erstellung von Channels;
- Anschluss eines Peers an einen Channel;
- Installation und Instanziierung von Smart Contracts im Channel;
- Aufruf von Transaktionen;
- Abfrage von Informationen in der Blockchain.
Anwendungsentwicklung
In unserem Demo-Programm werden wir die API nur für den Aufruf von Transaktionen und die Abfrage von Informationen verwenden, da wir die anderen Schritte bereits unter Verwendung der IBM Blockchain-Plattform durchgeführt haben. Wir schreiben die GUI unter Verwendung des Standardtechnologiestacks: Express.js + Vue.js + Node.js. Ein separater Artikel könnte sich mit der Erstellung moderner Webanwendungen befassen. Hier lasse ich einen Link zu einer Vorlesungsreihe, die mir am besten gefallen hat: . Daraus entstand eine Client-Server-Anwendung mit einer vertrauten grafischen Benutzeroberfläche im Material Design-Stil von Google. Die REST API zwischen Client und Server besteht aus mehreren Aufrufen:
- HyperledgerDemo/v1/init — Blockchain initialisieren;
- HyperledgerDemo/v1/accounts/list — eine Liste aller Accounts abrufen;
- HyperledgerDemo/v1/account?name=Bob&balance=100 — einen Account für Bob erstellen;
- HyperledgerDemo/v1/info?account=Bob — Informationen über den Account von Bob abrufen;
- HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — zwei Münzen von Bob an Alice überweisen;
- HyperledgerDemo/v1/disconnect — die Verbindung zur Blockchain schließen.
Die API-Beschreibung mit Beispielen habe ich auf — einem weithin bekannten Programm zum Testen von HTTP-APIs, bereitgestellt.
Die Demo-Anwendung läuft in der Cloud von Amazon.
Ich habe die Anwendung auf Amazon hochgeladen, da IBM es bis jetzt nicht geschafft hat, mein Konto zu aktualisieren und mir die Erstellung virtueller Server zu ermöglichen. Als Sahnehäubchen habe ich die Domain hinzugefügt: . Ich werde den Server etwas länger laufen lassen, danach abschalten, da die Mietkosten anfallen und die Citcoin-Münzen an der Börse noch nicht gehandelt werden.) In den Artikel füge ich Screenshots der Demo ein, um die Funktionsweise zu verdeutlichen. Die Demo-Anwendung kann:
- die Blockchain initialisieren;
- Accounts erstellen (aber aktuell kann kein neuer Account erstellt werden, da in der Blockchain die maximale Anzahl der Accounts, die im Smart Contract definiert ist, erreicht wurde);
- eine Liste von Accounts abrufen;
- Citcoin-Münzen zwischen Alice, Bob und Alex überweisen;
- Ereignisse empfangen (aber aktuell können keine Ereignisse angezeigt werden, daher steht zur Vereinfachung im Interface, dass Ereignisse nicht unterstützt werden);
- Aktionen protokollieren.
Zuerst initialisieren wir die Blockchain:

Danach erstellen wir unser Konto und lassen uns mit dem Guthaben nicht lumpen:

Wir erhalten eine Liste aller verfügbaren Konten:

Wir wählen den Absender und den Empfänger aus und prüfen deren Guthaben. Wenn Absender und Empfänger identisch sind, wird dessen Konto aufgeladen:

Im Protokoll verfolgen wir die Ausführung von Transaktionen:

Das wäre alles zur Demoversion. Als Nächstes können wir unsere Transaktion in der Blockchain betrachten:

Und die Gesamtliste der Transaktionen:

Damit haben wir die Umsetzung des PoC zur Schaffung des Citcoin-Netzwerks erfolgreich abgeschlossen. Was muss noch getan werden, damit Citcoin ein vollwertiges Netzwerk für den Münztransfer wird? Nur wenig:
- Bei der Erstellung des Kontos sollte die Generierung des privaten / öffentlichen Schlüssels implementiert werden. Der private Schlüssel sollte beim Benutzer des Kontos aufbewahrt werden, der öffentliche Schlüssel in der Blockchain.
- Durchführung von Geldtransfers, bei denen zur Identifizierung des Benutzers nicht der Name, sondern der öffentliche Schlüssel verwendet wird.
- Transaktionen, die vom Benutzer an den Server gesendet werden, mit seinem privaten Schlüssel verschlüsseln.
Fazit
Wir haben das Citcoin-Netzwerk mit Funktionen realisiert: Konto hinzufügen, Guthaben abrufen, Ihr Konto aufladen, Münzen von einem Konto auf ein anderes übertragen. Was hat uns also der Aufbau des PoC gekostet?
- Es ist notwendig, die Blockchain im Allgemeinen und Hyperledger Fabric im Besonderen zu studieren;
- Lerne, die Cloud-Dienste von IBM oder Amazon zu nutzen;
- Lerne die Programmiersprache JS und ein beliebiges Web-Framework;
- Wenn einige Daten nicht in der Blockchain, sondern in einer separaten Datenbank gespeichert werden müssen, lerne, dich beispielsweise mit PostgreSQL zu integrieren;
- Und last but not least – ohne Kenntnisse in Linux kommt man in der modernen Welt nicht weit!)
Natürlich ist es nicht die Raketenwissenschaft, aber es wird ein gewisses Maß an Anstrengung erforden!
Quellcodes auf GitHub
Die Quellcodes habe ich auf . Kurze Beschreibung des Repositories:
Katalog „server“ – Node.js-Server
Katalog „client“ – Node.js-Client
Katalog „Blockchain“ (Werte der Parameter und Schlüssel sind natürlich nicht funktional und dienen nur als Beispiel):
- contract – Quellcode des Smart Contracts
- wallet – Benutzerschlüssel zur Nutzung der Hyperledger Fabric API.
- *.cds – kompilierte Versionen von Smart Contracts
- *.json-Dateien – Beispiele für Konfigurationsdateien zur Nutzung der Hyperledger Fabric API.
Es ist erst der Anfang!
Quelle: habr.com
