De ogen zijn bang, maar de handen jeuken!
In eerdere artikelen hebben we de technologieën behandeld waarop blockchains zijn gebouwd () en de cases die daarmee gerealiseerd kunnen worden (). Het is tijd om aan de slag te gaan! Voor het realiseren van pilots en PoC (Proof of Concept) geef ik de voorkeur aan clouds, omdat ze vanaf elke locatie ter wereld toegankelijk zijn en je vaak geen tijd hoeft te verspillen aan het vervelende installeren van omgevingen, aangezien er vooraf geïnstalleerde configuraties zijn. Laten we iets eenvoudigs doen, bijvoorbeeld een netwerk voor het overdragen van munten tussen deelnemers en het bescheiden de naam CitoCoin geven. Hiervoor gaan we de cloud van IBM en de universele blockchain Hyperledger Fabric gebruiken. Laten we eerst begrijpen waarom Hyperledger Fabric een universele blockchain wordt genoemd.

Hyperledger Fabric ā de universele blockchain
In algemene termen is een universeel informatiesysteem:
- Een set servers en een programmatische kern die de bedrijfslogica uitvoert;
- Interfaces voor interactie met het systeem;
- Middelen voor registratie, authenticatie en autorisatie van apparaten/mensen;
- Een database die operationele en archiefgegevens opslaat:

De officiƫle versie van wat Hyperledger Fabric is, kan worden gelezen op , maar kort samengevat is Hyperledger Fabric een opensource platform waarmee gesloten blockchains kunnen worden gebouwd en willekeurige smart contracts kunnen worden uitgevoerd die zijn geschreven in de programmeertalen JS en Go. Laten we de architectuur van Hyperledger Fabric gedetailleerd bekijken en ervoor zorgen dat dit een universeel systeem is, waarbij alleen de specificiteit van het opslaan en schrijven van gegevens bestaat. De specificiteit is dat gegevens, zoals in alle blockchains, in blokken worden opgeslagen, die alleen in de blockchain worden geplaatst als de deelnemers consensus hebben bereikt en na opname kunnen de gegevens niet ongemerkt worden gewijzigd of verwijderd.
Architectuur van Hyperledger Fabric
In het diagram is de architectuur van Hyperledger Fabric weergegeven:

Organisaties ā organisaties bevatten peers, zodat de blockchain bestaat dankzij de ondersteuning van organisaties. Verschillende organisaties kunnen deel uitmaken van ƩƩn channel.
Channel ā een logische structuur die peers in groepen verenigt, zodat de blockchain wordt gedefinieerd. Hyperledger Fabric kan tegelijkertijd meerdere blockchains verwerken met verschillende bedrijfslogica.
Membership Services Provider (MSP) ā dit is de CA (Certificate Authority) voor het verstrekken van identiteiten en het toewijzen van rollen. Voor het creĆ«ren van een node moet interactie plaatsvinden met de MSP.
Peer-nodes ā controleren transacties, slaan de blockchain op, voeren smart contracts uit en interageren met applicaties. Peer-nodes hebben een identiteit (digitale certificaat), dat wordt uitgegeven door MSP. In tegenstelling tot netwerken zoals Bitcoin of Ethereum, waar alle nodes gelijkwaardig zijn, spelen nodes in Hyperledger Fabric verschillende rollen:
- Een peer kan zijn endorsing peer (EP) en smart contracts uitvoeren.
- Committing peer (CP) ā slaat alleen gegevens op in de blockchain en actualiseert de "World state".
- Anchor Peer (AP) ā als er meerdere organisaties in de blockchain deelnemen, worden anchor peers gebruikt voor de communicatie tussen hen. Elke organisatie moet ƩƩn of meerdere anchor peers hebben. Met AP kan elke peer binnen een organisatie informatie krijgen over alle peers in andere organisaties. Voor de synchronisatie van informatie tussen AP's wordt .
- Leader Peer ā als een organisatie meerdere peers heeft, zal alleen de leader peer blokken ontvangen van de Ordering service en deze aan de andere peers doorgeven. De leider kan zowel statisch worden ingesteld als dynamisch worden gekozen door peers binnen de organisatie. Voor de synchronisatie van informatie over de leiders wordt ook het gossipprotocol gebruikt.
Assets ā entiteiten met waarde die worden opgeslagen in de blockchain. Meer specifiek zijn dit key-value gegevens in JSON-formaat. Deze gegevens worden vastgelegd in de blockchain "Blockchain". Ze hebben een geschiedenis, die in de blockchain wordt opgeslagen, en een huidige staat, die in de database "World state" wordt opgeslagen. De datastructuren worden willekeurig gevuld, afhankelijk van de zakelijke behoeften. Er zijn geen verplichte velden, de enige aanbeveling is dat assets een eigenaar moeten hebben en waarde moeten vertegenwoordigen.
Ledger ā bestaat uit de blockchain "Blockchain" en de database "World state", waarin de huidige staat van de assets wordt opgeslagen. World state maakt gebruik van LevelDB of CouchDB.
Slim contract ā met behulp van smart contracts wordt de bedrijfslogica van het systeem geĆÆmplementeerd. In Hyperledger Fabric worden smart contracts chaincode genoemd. Met chaincode worden assets en transacties daarop gedefinieerd. Technisch gesproken zijn smart contracts softwaremodules die zijn geĆÆmplementeerd in programmeertalen zoals JS of Go.
Endorsement policy ā voor elke chaincode kan worden vastgesteld welke en hoeveel bevestigingen voor een transactie nodig zijn van wie. Als er geen beleid is vastgesteld, geldt standaard: "de transactie moet worden goedgekeurd door elk lid (member) van elke organisatie in het kanaal". Voorbeelden van beleidsregels:
- De transactie moet worden bevestigd door een administrator van de organisatie;
- Moet bevestigd worden door een lid of klant van de organisatie;
- Moet bevestigd worden door een peer van de organisatie.
Ordering service ā verpakt transacties in blokken en verzendt deze naar de peers in het kanaal. Het garandeert de levering van berichten aan alle peers in het netwerk. Voor industriĆ«le systemen wordt gebruikt , voor ontwikkeling en testen .
CallFlow

- De applicatie communiceert met Hyperledger Fabric via Go, Node.js of Java SDK;
- De client creƫert de transactie tx en stuurt deze naar de endorsing peers;
- De peer controleert de handtekening van de client, voert de transactie uit en stuurt de endorsement signature terug naar de client. Chaincode wordt alleen uitgevoerd op de endorsing peer en het resultaat van de uitvoering wordt naar alle peers verzonden. Dit werkalgoritme wordt PBFT (Practical Byzantine Fault Tolerant) consensus genoemd. Dit verschilt van doordat het bericht wordt verzonden en een bevestiging wordt verwacht niet van alle deelnemers, maar alleen van een bepaalde set;
- Nadat de client het aantal antwoorden heeft ontvangen dat overeenkomt met de endorsement policy, stuurt hij de transactie naar de Ordering service;
- De Ordering service vormt een blok en verzendt dit naar alle committing peers. De Ordering service zorgt voor een consistente opname van blokken, waardoor zogenaamde ledger forks worden uitgesloten ();
- De peers ontvangen het blok, controleren opnieuw de endorsement policy, registreren het blok in de blockchain en wijzigen de status in de 'World state' DB.
Dat is, er is een scheiding van rollen tussen de knopen. Dit zorgt voor schaalbaarheid en veiligheid van de blockchain:
- Slimme contracten (chaincode) worden uitgevoerd door de endorsing peers. Dit waarborgt de vertrouwelijkheid van slimme contracten, omdat het niet bij alle deelnemers is opgeslagen, maar alleen op de endorsing peers.
- Ordering moet snel werken. Dit wordt mogelijk gemaakt doordat Ordering alleen blokken vormt en deze naar een vaste set van leader peers verzendt.
- Committing peers slaan alleen de blockchain op ā er kunnen er veel zijn en ze vereisen geen grote kracht of directe werking.
Meer informatie over de architectonische oplossingen van Hyperledger Fabric en waarom het op deze manier werkt, kan hier worden bekeken: of hier: .
Dus, Hyperledger Fabric is echt een veelzijdig systeem waarmee je kunt:
- Arbitraire bedrijfslogica implementeren met behulp van slimme contracten;
- Gegevens opnemen en ophalen uit een blockchain-database in JSON-formaat;
- Toegang tot de API verlenen en controleren met behulp van een Certificate Authority.
Laten we iets nuttigs gaan doen nu we een beetje begrijpen van de specificaties van Hyperledger Fabric!
Blockchain implementeren
Taakstelling
De taak is om een Citcoin-netwerk te implementeren met de volgende functies: een account aanmaken, saldo opvragen, rekening aanvullen, munten van het ene account naar het andere overmaken. Laten we een objectmodel schetsen dat we vervolgens in een smart contract zullen implementeren. We hebben dus accounts die worden geĆÆdentificeerd door namen (name) en een saldo (balance) bevatten, en een lijst van accounts. Accounts en de lijst van accounts zijn in de terminologie van Hyperledger Fabric assets. Ze hebben respectievelijk een geschiedenis en een huidige status. Ik zal proberen dit visueel weer te geven:

De bovenste figuren zijn de huidige status, die wordt opgeslagen in de 'World state' database. Onder hen zijn de figuren die de geschiedenis tonen, die in de blockchain zijn opgeslagen. De huidige status van assets verandert door transacties. Een asset wordt alleen geheel gewijzigd, daarom wordt er na het uitvoeren van een transactie een nieuw object aangemaakt, en de huidige waarde van de asset gaat naar de geschiedenis.
IBM Cloud
Laten we een account aanmaken in . Voor het gebruik van het blockchainplatform moet het worden geüpgraded naar Pay-As-You-Go. Dit proces kan niet snel zijn, omdat IBM aanvullende informatie aanvraagt en deze handmatig controleert. Positief is dat IBM goede leermaterialen heeft die het mogelijk maken om Hyperledger Fabric in hun cloud in te zetten. Ik vond de volgende cyclus van artikelen en voorbeelden leuk:
Hieronder staan schermafbeeldingen van het IBM Blockchain-platform. Dit is geen handleiding voor het maken van een blockchain, maar gewoon een demonstratie van de omvang van de taak. Dus, voor onze doeleinden maken we ƩƩn organisatie:

Daar creƫren we nodes: Orderer CA, Org1 CA, Orderer Peer:

We maken gebruikers aan:

We creƫren een kanaal en noemen het citcoin:

In wezen is een kanaal een blockchain, dus het begint met een nulblok (Genesis block):

We schrijven een 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;
IntuĆÆtief moet hier alles duidelijk zijn:
- Er zijn verschillende functies (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance) die het demo-programma zal aanroepen met behulp van de Hyperledger Fabric API.
- De functies SendFrom en RefillBalance genereren evenementen (Event) die het demo-programma zal ontvangen.
- De functie instantiate wordt eenmaal aangeroepen bij het instantiƫren van een smart contract. In werkelijkheid wordt deze niet ƩƩn keer aangeroepen, maar elke keer dat de versie van het smart contract verandert. Daarom is het initialiseren van de lijst met een lege array een slecht idee, omdat we nu de huidige lijst verliezen bij de wijziging van de versie van het smart contract. Maar goed, ik leer alleen maar).
- Accounts en de lijst van accounts (accounts) zijn JSON-gegevensstructuren. Voor gegevensmanipulaties wordt JS gebruikt.
- De huidige waarde van een asset kan worden verkregen met de functie getState, en kan worden bijgewerkt met putState.
- Bij het aanmaken van een Account wordt de functie AddAccount aangeroepen, waarin de vergelijking wordt gemaakt met het maximum aantal accounts in de blockchain (maxAccounts = 5). En hier zit een fout (opgemerkt?), die leidt tot een oneindige groei van het aantal accounts. Dit soort fouten moet je vermijden)
Laten we nu het smart contract in het Channel laden en het instantiƫren:

Laten we de transactie voor het instellen van het Smart Contract bekijken:

Laten we de details van ons Channel bekijken:

Als resultaat krijgen we het volgende schema van het blockchain-netwerk in de cloud van IBM. Ook op het schema staat een demo-applicatie die draait in de cloud van Amazon op een virtuele server (meer daarover in de volgende sectie):

GUI maken voor het aanroepen van de Hyperledger Fabric API
Hyperledger Fabric heeft een API die kan worden gebruikt voor:
- Het aanmaken van een channel;
- Het verbinden van een peer aan een channel;
- Het installeren en instantiƫren van smart contracts in het channel;
- Het aanroepen van transacties;
- Informatie opvragen in de blockchain.
Applicatieontwikkeling
In onze demo-applicatie gebruiken we de API alleen voor het aanroepen van transacties en het opvragen van informatie, aangezien we de andere stappen al hebben uitgevoerd met behulp van het blockchain-platform van IBM. We schrijven de GUI met behulp van de standaardtechnologiestack: Express.js + Vue.js + Node.js. Hoe je moderne webapplicaties kunt beginnen te maken, kan in een apart artikel worden behandeld. Hier laat ik een link achter naar een serie lezingen die ik het leukst vond: . Het resultaat is een client-serverapplicatie met een bekend grafisch interface in de stijl van Material Design van Google. REST API tussen de client en de server bestaat uit verschillende aanroepen:
- HyperledgerDemo/v1/init ā blockchain initialiseren;
- HyperledgerDemo/v1/accounts/list ā lijst van alle accounts ophalen;
- HyperledgerDemo/v1/account?name=Bob&balance=100 ā Bob account aanmaken;
- HyperledgerDemo/v1/info?account=Bob ā informatie over Bob account ophalen;
- HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 ā twee munten overmaken van Bob naar Alice;
- HyperledgerDemo/v1/disconnect ā verbindt met de blockchain.
De API-beschrijving met voorbeelden heb ik geplaatst op ā een wereldwijd bekend programma voor het testen van HTTP-API's.
Demo-applicatie in de Amazon-cloud.
Ik heb de applicatie geüpload naar Amazon, omdat IBM nog steeds mijn account niet heeft geüpgraded en ik geen virtuele servers kan aanmaken. Als kers op de taart heb ik het domein toegevoegd: . Ik houd de server een beetje aan, daarna zet ik hem uit, omdat de kosten voor de huur oplopen en de citcoin-munten nog niet op de beurs worden verhandeld) Ik voeg screenshots van de demo toe om de werklogica te verduidelijken. De demo-applicatie kan:
- De blockchain initialiseren;
- Een account aanmaken (maar op dit moment kan er geen nieuw account worden aangemaakt, omdat het maximale aantal accounts in het smart contract bereikt is);
- Een lijst van accounts opvragen;
- Citcoin-munten overdragen tussen Alice, Bob en Alex;
- Gebeurtenissen ontvangen (maar op dit moment kunnen gebeurtenissen niet worden getoond, daarom staat er voor de eenvoud in de interface dat gebeurtenissen niet worden ondersteund);
- Acties loggen.
Laten we eerst de blockchain initialiseren:

Vervolgens maken we een account aan, laten we niet zuinig zijn met het saldo:

Laten we een lijst van alle beschikbare accounts opvragen:

We kiezen een verzender en ontvanger, en bekijken hun saldi. Als de verzender en ontvanger dezelfde zijn, wordt zijn rekening aangevuld:

In het log volgen we de uitvoering van transacties:

Dat was het dan met de demo-applicatie. Laten we nu onze transactie in de blockchain bekijken:

En de algemene lijst van transacties:

Hiermee hebben we de implementatie van de PoC voor het opzetten van het Citcoin-netwerk succesvol afgerond. Wat moet er nog meer gebeuren om Citcoin een volwaardig netwerk voor het overdragen van munten te maken? Heel weinig:
- Bij het aanmaken van een account moet de generatie van een privƩ-/publieke sleutel worden gerealiseerd. De privƩsleutel moet bij de gebruiker van het account worden bewaard, de publieke sleutel in de blockchain.
- Doe een muntoverdracht waarin de identificatie van de gebruiker niet via de naam, maar via de publieke sleutel verloopt.
- Versleutel transacties die van de gebruiker naar de server gaan met zijn privƩsleutel.
Conclusie
We hebben het Citcoin-netwerk gerealiseerd met de functies: account toevoegen, saldo opvragen, rekening aanvullen, munten van de ene rekening naar de andere overdragen. Dus, wat heeft het ons gekost om de PoC te bouwen?
- We moeten de blockchain in het algemeen en Hyperledger Fabric in het bijzonder bestuderen;
- Leren om gebruik te maken van IBM- of Amazon-cloudservices;
- De programmeertaal JS leren en een webframework kiezen;
- Als bepaalde gegevens niet in de blockchain, maar in een aparte database moeten worden opgeslagen, leer dan bijvoorbeeld te integreren met PostgreSQL;
- En als laatste op de lijst, maar niet minder belangrijk - zonder kennis van Linux kom je de moderne wereld niet door!)
Natuurlijk, het is geen rocket science, maar je moet wel je best doen!
Bronbestanden op GitHub
De broncodes zijn geplaatst op . Korte beschrijving van de repository:
Catalogus «server» - Node.js server
Catalogus «client» - Node.js client
Catalogus «blockchain» (de parameterwaarden en sleutels zijn natuurlijk niet werkend en alleen ter illustratie):
- contract - broncode van het smart contract
- wallet - gebruikerssleutels voor het gebruik van de Hyperledger Fabric API.
- *.cds - gecompileerde versies van smart contracts
- *.json bestanden - voorbeelden van configuratiebestanden voor het gebruik van de Hyperledger Fabric API
Dit is pas het begin!
Bron: habr.com
