Oči sa bojažia, ale ruky svrbia!
V predchádzajúcich článkoch sme sa zaoberali technológiami, na ktorých sú postavené blockchainy () a prípadmi, ktoré je možné s ich pomocou realizovať (). Prišiel čas zamerať sa na praktickú prácu! Na realizáciu pilotných projektov a PoC (Proof of Concept) uprednostňujem používanie cloudových služieb, pretože k nim je prístup z ktorejkoľvek časti sveta a často nemusím tráviť čas nudnou inštaláciou prostredia, pretože existujú predkonfigurované nastavenia. Takže, poďme spraviť niečo jednoduché, napríklad sieť na prevod mincí medzi účastníkmi, a skromne ju nazveme CitiCoin. Na to budeme používať cloud od IBM a univerzálny blockchain Hyperledger Fabric. Na začiatok sa pozrime, prečo sa Hyperledger Fabric nazýva univerzálnym blockchainom?

Hyperledger Fabric — univerzálny blockchain
Vo všeobecnosti je univerzálna informačná sústava:
- Súbor serverov a programové jadro, ktoré vykonáva biznis logiku;
- Rozhrania na interakciu so systémom;
- Prostriedky na registráciu, autentifikáciu a autorizáciu zariadení / ľudí;
- Dátová báza, ktorá uchováva prevádzkové a archívne dáta:

Oficiálnu verziu toho, čo je Hyperledger Fabric, si môžete prečítať na , a ak to zhrnieme, Hyperledger Fabric je opensource platforma, ktorá umožňuje vytvárať uzavreté blockchainy a vykonávať libovolné smart kontrakty napísané v programovacích jazykoch JS a Go. Pozrime sa podrobne na architektúru Hyperledger Fabric a presvedčme sa, že ide o univerzálny systém, ktorý má len špecifiku v ukladaní a zapisovaní dát. Špecifikum spočíva v tom, že dáta, podobne ako vo všetkých blockchainoch, sú uložené v blokoch, ktoré sú vložené do blockchainu len v prípade, že účastníci dosiahli konsenzus, a po zapísaní nie je možné tieto dáta nenápadne upraviť alebo odstrániť.
Architektúra Hyperledger Fabric
Na schéme je zobrazená architektúra Hyperledger Fabric:

Organizácie — organizácie obsahujú peer-ov, pričom blockchain existuje vďaka podpore organizácií. Rôzne organizácie môžu byť súčasťou jedného kanála.
Channel — logická štruktúra, ktorá spája peer-ov do skupín, čím sa určuje blockchain. Hyperledger Fabric môže súčasne spracovávať viacero blockchainov s rôznou biznis logikou.
Membership Services Provider (MSP) — je to CA (Certificate Authority) na vydávanie identities a prideľovanie rolí. Na vytvorenie uzla je potrebné interagovať s MSP.
Peer uzly — kontrolujú transakcie, ukladajú blockchain, vykonávajú smart kontrakty a komunikujú s aplikáciami. Peer uzly majú identitu (digitálny certifikát), ktorý vydáva MSP. Na rozdiel od sietí Bitcoin alebo Ethereum, kde sú všetky uzly rovnaké, v Hyperledger Fabric majú uzly rôzne úlohy:
- Peer môže byť endorzujúci peer (EP) a môže vykonávať smart kontrakty.
- Zachovávajúci peer (CP) — len ukladajú dáta do blockchainu a aktualizujú "World state".
- Anchor Peer (AP) — ak sa do blockchainu zapája niekoľko organizácií, tak sa anchor peer využívajú na spojenie medzi nimi. Každá organizácia musí mať jeden alebo niekoľko anchor peer. Pomocou AP môže akýkoľvek peer v organizácii získať informácie o všetkých peer-och v iných organizáciách. Na synchronizáciu informácií medzi AP sa používa .
- Líder Peer — ak organizácia má niekoľko peer-ov, len líder peer bude prijímať bloky z Ordering service a distribuovať ich ostatným peer-om. Líder môže byť nastavený staticky, alebo vybraný dynamicky peer-ami v organizácii. Na synchronizáciu informácií o lídroch sa tiež používa gossip protokol.
Aktíva — entity, ktoré majú hodnotu a sú uložené v blockchainu. Presnejšie ide o key-value dáta vo formáte JSON. Práve tieto dáta sú zapisované do blockchainu „Blockchain“. Majú históriu, ktorá je uložená v blockchainu, a aktuálny stav, ktorý je uložený v databáze „World state“. Štruktúry dát sa napĺňajú libovoľne v závislosti od obchodných úloh. Nie sú žiadne povinné polia, jedinou odporúčanou podmienkou je, že aktíva by mali mať vlastníka a predstavovať hodnotu.
Ledger — pozostáva z blockchainu „Blockchain“ a databázy „World state“, v ktorej sa uchováva aktuálny stav aktív. World state využíva LevelDB alebo CouchDB.
Smart kontrakt — pomocou smart kontraktov sa realizuje obchodná logika systému. V Hyperledger Fabric sa smart kontrakty nazývajú chaincode. Pomocou chaincode sa definujú aktíva a transakcie s nimi. Ak hovoríme technicky, tak smart kontrakty sú programové moduly implementované v programovacích jazykoch JS alebo Go.
Politika schválenia — pre každý chaincode je možné nastaviť politiky, koľko a od koho je potrebné očakávať potvrdenia pre transakciu. Ak politika nie je nastavená, predvolene sa používa: “transakciu musí potvrdiť akýkoľvek člen (member) akejkoľvek organizácie v channel”. Príklady politík:
- Transakciu musí potvrdiť ktorýkoľvek administrátor organizácie;
- Musí potvrdiť ktorýkoľvek člen (member) alebo klient organizácie;
- Musí potvrdiť ktorýkoľvek peer organizácie.
Služba Ordering — balí transakcie do blokov a posiela ich peer-om v kanáli. Zabezpečuje doručenie správ všetkým peer-om v sieti. Pre priemyselné systémy sa používa , pre vývoj a testovanie .
CallFlow

- Aplikácia interaguje s Hyperledger Fabric, používajúc Go, Node.js alebo Java SDK;
- Klient vytvára transakciu tx a posiela ju na endorsing peer-ov;
- Peer kontroluje podpis klienta, vykonáva transakciu a posiela endorsement signature späť klientovi. Chaincode sa vykonáva len na endorsing peer, a výsledok jeho vykonania sa rozosiela na všetky peer-y. Takýto algoritmus práce sa nazýva — PBFT (Practical Byzantine Fault Tolerant) konsenzus. Rozdiel oproti spočíva v tom, že správa sa rozosiela a očakáva potvrdenie nie od všetkých účastníkov, ale iba od konkrétneho súboru;
- Keď klient dostane počet odpovedí zodpovedajúci endorsement policy, posiela transakciu na službu Ordering;
- Služba Ordering vytvára blok a posiela ho všetkým committing peer-om. Služba Ordering zabezpečuje sekvenčné zapisovanie blokov, čím sa vylučuje takzvané ledger fork ();
- Peer-om príde blok, opäť overia endorsement policy, zapíšu blok do blockchainu a zmenia stav v „World state“ DB.
To znamená, že dochádza k rozdeleniu rolí medzi nódami. To zabezpečuje škálovateľnosť a bezpečnosť blockchainu:
- Smart kontrakty (chaincode) vykonávajú endorsing peer-ov. To zabezpečuje dôvernosť smart kontraktov, keďže sú uchovávané nie u všetkých účastníkov, ale len na endorsing peer-och.
- Ordering musí fungovať rýchlo. To sa zabezpečuje tým, že Ordering iba vytvára blok a posiela ho na pevný súbor leader peer-ov.
- Committing peers iba uchovávajú blockchain — ich môže byť veľa a nevyžadujú veľkú výkonovú kapacitu a okamžitú prácu.
Podrobnejšie architektonické riešenia Hyperledger Fabric a prečo funguje tak, a nie inak, si môžete pozrieť tu: alebo tu: .
Takže, Hyperledger Fabric je naozaj univerzálny systém, pomocou ktorého môžete:
- Realizovať ľubovoľnú obchodnú logiku, používajúc mechanizmus smart kontraktov;
- Zaznamenávať a získavať údaje z blockchain databázy vo formáte JSON;
- Poskytovať a overovať prístup k API pomocou certifikačnej autority.
Teraz, keď sme si trochu objasnili špecifiká Hyperledger Fabric, poďme konečne spraviť niečo užitočné!
Rozvíjame blockchain
Stanovenie úlohy
Úloha — realizovať sieť Citcoin s nasledujúcimi funkciami: vytvoriť účet, získať zostatok, doplniť účet, previesť mince z jedného účtu na druhý. Vykreslíme objektový model, ktorý neskôr implementujeme v smart kontrakte. Takže budeme mať účty, ktoré sú identifikované menami (name) a obsahujú zostatok (balance), a zoznam účtov. Účty a zoznam účtov — to sú v termínoch Hyperledger Fabric aktíva. Zodpovedajúcim spôsobom majú históriu a aktuálny stav. Pokúsim sa to názorne znázorniť:

Horné postavy — to je aktuálny stav, ktorý sa uchováva v databáze „World state“. Pod nimi postavy, ktoré ukazujú históriu, ktorá sa uchováva v blockchain. Aktuálny stav aktív sa mení transakciami. Aktívum sa mení iba celé, preto sa v dôsledku vykonania transakcie vytvára nový objekt a aktuálna hodnota aktíva prechádza do histórie.
IBM Cloud
Zakladáme účet v . Na používanie blockchain platformy ju treba upgradovať na Pay-As-You-Go. Tento proces nemusí byť rýchly, pretože IBM požaduje ďalšie informácie a kontroluje ich ručne. Z pozitívneho hľadiska môžem povedať, že IBM má skvelé vzdelávacie materiály, ktoré umožňujú rozvinúť Hyperledger Fabric v ich cloude. Páčil sa mi nasledujúci cyklus článkov a príkladov:
Nasledujú obrazovky Blockchain platformy IBM. Toto nie je návod na vytváranie blockchainu, ale jednoducho ukážka rozsahu úlohy. Takže pre naše účely vytvárame jednu Organizáciu:

V nej vytvárame uzly: Orderer CA, Org1 CA, Orderer Peer:

Zakladáme používateľov:

Vytvárame Channel a nazývame ho citcoin:

V podstate Channel — to je blockchain, preto začína s nulovým blokom (Genesis block):

Píšeme 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;
Intuitívne by to malo byť všetko jasné:
- Existuje niekoľko funkcií (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), ktoré bude vyžadovať demo program pomocou Hyperledger Fabric API.
- Funkcie SendFrom a RefillBalance generujú udalosti (Event), ktoré dostane demo program.
- Funkcia instantiate – sa volá len raz pri inštancii smart kontraktu. V skutočnosti sa volá nie jedenkrát, ale zakaždým pri zmene verzie smart kontraktu. Preto inicializácia zoznamu prázdnym poľom nie je dobrý nápad, pretože pri zmene verzie smart kontraktu prídeme o aktuálny zoznam. Ale nič, len sa učím).
- Účty a zoznam účtov (accounts) – to sú JSON štruktúry údajov. Na manipuláciu s údajmi sa používa JS.
- Aktuálnu hodnotu assetu môžeme získať pomocou volania funkcie getState, a aktualizovať pomocou putState.
- Pri vytváraní účtu sa volá funkcia AddAccount, v ktorej sa porovnáva maximálny počet účtov v blockchaine (maxAccounts = 5). A tu je problém (ste si všimli?), ktorý vedie k nekonečnému rastu počtu účtov. Takýmto chybám je potrebné sa vyhýbať).
Ďalej nahráme smart kontrakt do Channel a inštancujeme ho:

Pozrime sa na transakciu na nastavenie Smart Contract:

Pozrime sa na podrobnosti o našom Channel:

V dôsledku získavame nasledujúcu schému blockchain siete v cloude IBM. Na schéme je tiež demoprogram, ktorý je spustený v cloude Amazon na virtuálnom serveri (podrobnosti o ňom budú v ďalšej časti):

Vytvorenie GUI pre volania Hyperledger Fabric API
Hyperledger Fabric má API, ktoré sa môže použiť na:
- Vytvorenie channel;
- Pripojenie peer k channel;
- Inštaláciu a inštancovanie smart kontraktov v channel;
- Volanie transakcií;
- Žiadosť o informácie v blockchaine.
Vývoj aplikácie
V našej demoprogramu budeme používať API len na volanie transakcií a žiadosť o informácie, pretože ostatné kroky sme už uskutočnili pomocou blockchain platformy IBM. Píšeme GUI s použitím štandardného technologického stacku: Express.js + Vue.js + Node.js. O tom, ako začať vytvárať moderné webové aplikácie, by sa mohla napísať samostatná článok. Tu nechám odkaz na sériu prednášok, ktorá sa mi najviac páčila: . V dôsledku toho vzniklo klient-serverové aplikácie so známym grafickým rozhraním v štýle Material Design od Google. REST API medzi klientom a serverom pozostáva z niekoľkých volaní:
- HyperledgerDemo/v1/init – inicializovať blockchain;
- HyperledgerDemo/v1/accounts/list – získať zoznam všetkých účtov;
- HyperledgerDemo/v1/account?name=Bob&balance=100 – vytvoriť účet Bob;
- HyperledgerDemo/v1/info?account=Bob – získať informácie o účte Bob;
- HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — previesť dve mince od Bob k Alice;
- HyperledgerDemo/v1/disconnect — uzavrieť spojenie s blokchainom.
Popis API s príkladmi som dal na — široko známy program na testovanie HTTP API.
Demo aplikácia v cloude Amazon
Aplikáciu som nahral na Amazon, pretože IBM doteraz nemohol aktualizovať môj účet a povoliť mi vytvárať virtuálne servery. Ako pomyselnú čerešničku som pridal doménu: . Trochu podporím server zapnutý, potom ho vypnem, pretože centy za prenájom sa kumulujú, a mince citcoin na burze ešte nie sú obchodované) Do článku vkladám screenshoty demoa, aby bola zrozumiteľná logika fungovania. Demo aplikácia môže:
- Inicializovať blockchain;
- Vytvárať účet (ale teraz nie je možné vytvoriť nový účet, pretože v blockchaine bolo dosiahnuté maximálne číslo účtov, uvedené v smart kontrakte);
- Získať zoznam účtov;
- Prevádzať mince citcoin medzi Alice, Bobom a Alexom;
- Získavať udalosti (ale teraz sa žiadne udalosti nemôžu zobraziť, preto je v rozhraní zjednodušene napísané, že udalosti nie sú podporované);
- Registrovať akcie.
Najprv inicializujeme blockchain:

Potom si zakladáme svoj účet, nešetriac s bilanciou:

Získavame zoznam všetkých dostupných účtov:

Vyberáme odosielateľa a príjemcu, a získavame ich zostatky. Ak je odosielateľ a príjemca ten istý, dojde k navýšeniu jeho zostatku:

V logu sledujeme vykonávanie transakcií:

Vlastne s demo programom je to všetko. Potom si môžeme pozrieť našu transakciu v blockchaine:

A celkový zoznam transakcií:

Týmto sme úspešne ukončili implementáciu PoC na vytvorenie siete Citcoin. Čo ešte potrebujeme urobiť, aby sa Citcoin stal plnohodnotnou sieťou na prevod mincí? Veľmi málo:
- V etape vytvárania účtu realizovať generáciu súkromného / verejného kľúča. Súkromný kľúč by mal byť uložený u užívateľa účtu, verejný v blockchaine.
- Urobiť prevod mincí, pri ktorom sa na identifikáciu užívateľa používa nie meno, ale verejný kľúč.
- Šifrovať transakcie, ktoré idú od užívateľa na server jeho súkromným kľúčom.
Záver
Implementovali sme sieť Citcoin s funkciami: pridať účet, získať zostatok, doplniť svoj účet, previesť mince z jedného účtu na iný. Takže, čo nás stálo postaviť PoC?
- Je potrebné študovať blockchain všeobecne a Hyperledger Fabric konkrétne;
- Naučiť sa používať cloudy IBM alebo Amazon;
- Naučiť sa programovací jazyk JS a nejaký webový framework;
- Ak je potrebné uchovávať niektoré údaje mimo blockchainu, naučiť sa integráciu, napríklad, s PostgreSQL;
- A posledné, ale nie menej dôležité — bez znalosti Linuxu sa v modernom svete nikam nepohneme!)
Samozrejme, nie je to raketová veda, ale bude treba zapotiť sa!
Zdrojové kódy na GitHub
Súbory sú uložené na . Stručný popis repozitára:
Adresár „server“ — Node.js server
Adresár „client“ — Node.js klient
Adresár „blockchain“ (hodnoty parametrov a kľúče sú, samozrejme, nefunkčné a uvedené iba ako príklad):
- contract — zdrojový kód smart kontraktu
- wallet — kľúče používateľa pre použitie Hyperledger Fabric API.
- *.cds — skompilované verzie smart kontraktov
- *.json súbory — príklady konfiguračných súborov pre použitie Hyperledger Fabric API
Je to len začiatok!
Zdroj: habr.com
