A szemek félnek, de a kezek viszketnek!
A korábbi cikkekben foglalkoztunk a blokkláncok alapját képező technológiákkal () és azokra az esetekre, amelyeket ezek segítségével meg lehet valósítani (). Itt az idő, hogy kézbe vegyük a dolgokat! A pilotok és PoC (Proof of Concept) megvalósításához általában felhőket használok, mivel ezekhez a világ bármely pontjáról hozzáférhetünk, és gyakran nem kell időt pazarolni a környezet unalmas telepítésére, mivel vannak előre telepített konfigurációk. Tehát csináljunk valami egyszerűt, például egy hálózatot, amely lehetővé teszi a pénz átutalását a résztvevők között, és nevezzük el szerényen Cointcoin-nak. Ehhez az IBM felhőt és a Hyperledger Fabric egyetemes blokkláncot fogjuk használni. Először nézzük meg, miért nevezik a Hyperledger Fabric-ot egyetemes blokkláncnak?

Hyperledger Fabric — egyetemes blokklánc
Általánosságban elmondható, hogy az egyetemes információs rendszer a következőkből áll:
- Szerverek és egy programás alap, amely végrehajtja az üzleti logikát;
- Felületek a rendszerrel való interakcióhoz;
- Eszközök és személyek regisztrációjának, azonosításának és jogosultságának biztosítására;
- Adatbázis, amely működési és archív adatokat tárol:

A Hyperledger Fabric hivatalos verzióját elolvashatja a , röviden pedig a Hyperledger Fabric egy nyílt forráskódú platform, amely lehetővé teszi zárt blokkláncok létrehozását és tetszőleges okosszerződések végrehajtását, amelyek JavaScript és Go programozási nyelveken íródtak. Nézzük meg részletesen a Hyperledger Fabric architektúráját, és győződjünk meg arról, hogy ez egy egyetemes rendszer, amelyben csak az adatok tárolásának és rögzítésének sajátosságai vannak. Az a sajátosság, hogy az adatok, mint minden blokkláncban, blokkokban kerülnek tárolásra, amelyeket csak akkor helyeznek el a blokkláncon, ha a résztvevők konszenzusra jutottak, és a rögzített adatokat nem lehet észrevétlenül módosítani vagy törölni.
Hyperledger Fabric architektúrája
A diagramban a Hyperledger Fabric architektúrája látható:

Szervezetek — a szervezetek peer-eket tartalmaznak, így a blokklánc a szervezetek támogatásának köszönhetően létezik. Különböző szervezetek egy channelbe léphetnek be.
Csatorna — logikai struktúra, amely a peer-eket csoportokba tömöríti, így létrejön a blokklánc. A Hyperledger Fabric egyidejűleg több blokkláncot is képes kezelni, eltérő üzleti logikával.
Tagsági Szolgáltatások Szolgáltatója (MSP) — ez a CA (Tanúsítványhatóság) az identitások kiadására és szerepek kiosztására. Egy node létrehozásához kapcsolatba kell lépni az MSP-vel.
Peer node-ok — ellenőrzik a tranzakciókat, tárolják a blokkláncot, végrehajtják az okos szerződéseket és kapcsolatba lépnek az alkalmazásokkal. A peer-ek rendelkeznek egy identitással (digitális tanúsítvány), amelyet az MSP ad ki. A Bitcoin vagy Ethereum hálózatokkal ellentétben, ahol minden csomópont egyenlő, a Hyperledger Fabric csomópontjai különböző szerepeket töltenek be:
- A Peer lehet endorseoló peer (EP), és végrehajtják az okos szerződéseket.
- Követelő peer (CP) — csak az adatokat tárolják a blokkláncban, és frissítik a „World state”-et.
- Horgony Peer (AP) — ha több szervezet vesz részt a blokkláncban, akkor a horgony peer-eket használják a közötti kapcsolatra. Minden szervezetnek rendelkeznie kell egy vagy több horgony peer-rel. Az AP segítségével bármely peer a szervezeten belül információt kaphat az összes peer-ről más szervezetekben. Az AP-k közötti információszinkronizáláshoz .
- Vezető Peer — ha a szervezetnek több peer-je van, akkor csak a vezető peer fog blokkokat kapni az Ordering service-től, és átadni azokat a többi peer-nek. A vezető statikusan beállítható vagy dinamikusan választható a szervezet peer-jei által. A vezetők közötti információszinkronizáláshoz szintén gossip protokollt használnak.
Eszközök — értékes entitások, amelyek a blokkláncban tárolódnak. Pontosabban — ezek kulcs-érték adatok JSON formátumban. Ezek az adatok kerülnek rögzítésre a „Blokklánc”-ban. Történetük van, amely a blokkláncban van tárolva, és aktuális állapotuk, amely az „World state” adatbázisban található. Az adatszerkezetek véletlenszerűen vannak kitöltve az üzleti feladatoknak megfelelően. Nincsenek kötelező mezők, az egyetlen ajánlás — az eszközöknek rendelkezniük kell tulajdonossal és értéket kell képviselniük.
Könyvelés — a „Blokkláncból” és a „World state” adatbázisból áll, ahol az eszközök aktuális állapota található. A World state a LevelDB-t vagy CouchDB-t használja.
Okos szerződés — az okos szerződéseken keresztül valósítják meg a rendszer üzleti logikáját. A Hyperledger Fabricben az okos szerződések chaincode-nak nevezik. A chaincode segítségével definiálják az eszközöket és azokkal kapcsolatos tranzakciókat. Technikai nyelven az okos szerződések olyan programmodulok, amelyek JS vagy Go programozási nyelveken vannak megvalósítva.
Jóváhagyási politika — minden chaincode-hoz megadhatók politikák, hogy mennyit és kitől kell várni a tranzakció jóváhagyására. Ha a politika nincs megadva, akkor alapértelmezetten a következő használatos: “a tranzakciót bármely tag (member) bármely szervezettől a channel-ben meg kell hogy erősítse”. Példák politikákra:
- A tranzakciót bármely szervezet adminisztrátora meg kell, hogy erősítse;
- Bármely szervezeti tag vagy ügyfél meg kell, hogy erősítse;
- Bármely szervezeti peernek meg kell, hogy erősítse.
Rendelkezési szolgáltatás — a tranzakciókat blokkokba csomagolja és elküldi a peer-eknek a csatornában. Garantálja a üzenetek kézbesítését az összes peer-hez a hálózatban. Ipari rendszerekhez használatos , fejlesztéshez és teszteléshez .
CallFlow

- Az alkalmazás a Hyperledger Fabric-el kommunikál a Go, Node.js vagy Java SDK használatával;
- A kliens létrehozza a tx tranzakciót, és elküldi azt az endorsáló peer-eknek;
- A peer ellenőrzi a kliens aláírását, végrehajtja a tranzakciót, és visszaküldi az endorsement aláírást a kliensnek. A chaincode csak az endorsáló peer-en kerül végrehajtásra, és a végrehajtás eredményét minden peer-hez eljuttatják. Ez a munkamenet algoritmus — PBFT (Practical Byzantine Fault Tolerant) konszenzus. Különbözik a azzal, hogy az üzenetet nem az összes résztvevőtől küldik el és várják meg a megerősítést, hanem csak egy meghatározott halmaztól;
- Miután a kliens megkapta a megerősítés politikának megfelelő válaszok számát, elküldi a tranzakciót a Rendelkezési szolgáltatásnak;
- A Rendelkezési szolgáltatás blokkot képez, és elküldi azt az összes elkötelezett peer-nek. A Rendelkezési szolgáltatás biztosítja a blokkok folyamatos rögzítését, ami kizárja a ledger fork-ot ();
- A peer-ek megkapják a blokkot, újra ellenőrzik az endorsement politikát, rögzítik a blokkot a blokkláncon és módosítják az állapotot a „World state” DB-ben.
Tehát a node-ok között szerepkülönbség alakul ki. Ez biztosítja a blokklánc skálázhatóságát és biztonságát:
- Az endorsáló peer-ek hajtják végre a okos szerződéseket (chaincode). Ez biztosítja a okos szerződések titkosságát, mivel ezek nem minden résztvevőnél tárolódnak, hanem csak az endorsáló peer-eken.
- A Rendelkezési szolgáltatásnak gyorsan kell működnie. Ezt biztosítja, hogy a Rendelkezés csak a blokkot képezi és elküldi egy fix vezető peer halmaz számára.
- Az elkötelezett peer-ek csak a blokkláncot tárolják — sokan létezhetnek, és nem igényelnek nagy teljesítményt és azonnali működést.
További információkat a Hyperledger Fabric architekturális megoldásairól, és hogy miért működik így, itt talál. vagy itt: .
Tehát a Hyperledger Fabric valóban egy sokoldalú rendszer, amellyel az alábbiakat lehet megvalósítani:
- Tetszőleges üzleti logika megvalósítása az okos szerződések mechanizmusának használatával;
- Az adatok rögzítése és lekérdezése JSON formátumban a blokklánc adatbázisból;
- Hozzáférés biztosítása és ellenőrzése az API-hoz, a Tanúsító Hatóság használatával.
Most, hogy egy kicsit tisztában vagyunk a Hyperledger Fabric sajátosságaival, nézzünk végre valamit, ami hasznos!
Blokklánc telepítése
Lépjünk át a kitűzött feladatra: írjunk egy XDP mechanizmust SYN cookie-kkal.
A feladat — egy Citcoin hálózat megvalósítása a következő funkciókkal: fiók létrehozása, egyenleg lekérdezése, egyenleg feltöltése, érmék átutalása egyik fiókról a másikra. Rajzoljunk meg egy objektum modellt, amelyet később megvalósítunk a okos szerződésben. Tehát lesznek fiókok, amelyek nevekkel (name) azonosíthatók és egyenleget (balance) tartalmaznak, és egy fióklista. A fiókok és a fióklista a Hyperledger Fabric terminológiájában eszközök (assets). Ennek megfelelően van történelmük és aktuális állapotuk. Megpróbálom szemléletesen ábrázolni:

A felső figurák az aktuális állapotot jelzik, amely az „World state” adatbázisban tárolódik. Az alattuk lévő figurák a blokkláncban tárolt történelmet mutatják. Az eszközök aktuális állapota tranzakciók alapján változik. Az eszköz csak egészben változik, így egy tranzakció végrehajtása új objektumot hoz létre, míg az eszköz aktuális értéke a történetbe kerül.
IBM Felhő
Fiókot hozunk létre az . A blokklánc platform használatához azt frissíteni kell Pay-As-You-Go-ra. Ez a folyamat nem biztos, hogy gyors, mivel az IBM további információt kér és azt manuálisan ellenőrzi. Pozitívumként elmondható, hogy az IBM-nek jó tanulmányi anyagai vannak, amelyek lehetővé teszik a Hyperledger Fabric telepítését a felhőjükben. Tetszett a következő ciklus cikk és példa:
Az alábbiakban az IBM Blokklánc platformjának képernyőképei láthatók. Ez nem egy blokklánc létrehozására vonatkozó útmutató, hanem a feladat terjedelmét bemutató démonstráció. Tehát a céljaink érdekében létrehozunk egy Szervezetet:

Ezen belül csomópontokat hozunk létre: Orderer CA, Org1 CA, Orderer Peer:

Felhasználókat hozunk létre:

Channel-t hozunk létre, és elnevezzük citcoin:

Lényegében a Channel — ez a blokklánc, ezért nulladik blokkal (Genesis block) kezdődik:

Okos Szerződést írunk
/*
* 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;
Itt intuitívan mindennek világosnak kell lennie:
- Több funkciónk van (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), amelyeket a demo program a Hyperledger Fabric API segítségével fog hívni.
- A SendFrom és RefillBalance funkciók eseményeket (Event) generálnak, amelyeket a demo program fog fogadni.
- Az instantiate funkciót egyszer hívják meg, amikor a okos szerződés példányosítása történik. Valójában nem egyszer hívják meg, hanem minden alkalommal, amikor a okos szerződés verziója megváltozik. Ezért a lista üres tömbként való inicializálása rossz ötlet, mivel így a okos szerződés verzióváltásakor elveszítjük az aktuális listát. De semmi baj, csak tanulok).
- A fiókok (accounts) és a fiókok listája (accounts) JSON adatszerkezetek. Az adatokkal való manipulációhoz JS-t használunk.
- A jelenlegi asset értékét a getState függvény hívásával lehet lekérni, frissíteni pedig a putState segítségével.
- Fiók létrehozásakor az AddAccount függvény hívódik meg, ahol összehasonlítás történik a blokkláncon lévő maximális fiókok számával (maxAccounts = 5). Itt van egy hiba (észrevetted?), amely végtelen növekedést okoz a fiókok számában. Az ilyen hibákat el kell kerülni)
Ezután betöltjük a okos szerződést a Channel-be, és példányosítjuk:

Nézzük meg a Smart Contract telepítési tranzakciót:

Nézzük meg a Channel részleteit:

Ennek eredményeként a következő blokklánc-hálózati sémát kapjuk az IBM felhőjében. A sémán egy demóprogram is látható, amely az Amazon felhőjében egy virtuális szerveren fut (erről a következő részben részletesebben lesz szó):

GUI létrehozása a Hyperledger Fabric API hívásaihoz
A Hyperledger Fabric-nek van egy API-ja, amely a következőkre használható:
- Channel létrehozására;
- Peer csatlakoztatása a channelhez;
- Okos szerződések telepítése és példányosítása a channel-en;
- Tranzakciók hívása;
- Információ lekérése a blokkláncból.
Alkalmazás fejlesztése
A demóprogramunkban az API-t csak tranzakciók hívására és információk lekérésére használjuk, mivel a többi lépést már elvégeztük az IBM blokklánc platformján. GUI-t írunk a standard technológiai stack használatával: Express.js + Vue.js + Node.js. Arról, hogy hogyan kezdjünk modern webalkalmazásokat készíteni, külön cikket lehetne írni. Itt hagyok egy linket egy olyan előadássorozathoz, amely nekem legjobban tetszett: . Ennek eredményeként egy kliens-szerver alkalmazás lett, ismerős grafikus felhasználói felülettel, a Google Material Design stílusában. A kliens és a szerver közötti REST API több hívásból áll:
- HyperledgerDemo/v1/init — blokklánc inicializálása;
- HyperledgerDemo/v1/accounts/list — az összes fiók listájának lekérése;
- HyperledgerDemo/v1/account?name=Bob&balance=100 — Bob fiók létrehozása;
- HyperledgerDemo/v1/info?account=Bob — információk lekérése Bob fiókról;
- HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — két érme átutalása Bobtól Alice-hoz;
- HyperledgerDemo/v1/disconnect — a kapcsolat lezárása a blokklánccal.
API leírását példákkal feltettem a — a HTTP API tesztelésére széles körben ismert program.
Demó alkalmazás az Amazon felhőben
Az alkalmazást az Amazonra töltöttem fel, mivel az IBM még mindig nem tudta frissíteni a fiókómat és engedélyezni a virtuális szerverek létrehozását. Mint egy cseresznye a tortán, hozzátettem a domaint: . Kicsit fenntartom a szervert, majd kikapcsolom, mivel a bérleti díj költségei szaladnak, a citcoin érmék pedig még nem jegyzettek a tőzsdén) A cikkbe képernyőképeket helyezek el a demóról, hogy érthető legyen a működés logikája. A demó alkalmazás képes:
- Blokklánc inicializálása;
- Fiók létrehozása (de jelenleg új fiókot nem lehet létrehozni, mivel a blokkláncban elértük a maximális fiókszámot, amelyet a okos szerződés meghatározott);
- Fiókok listájának lekérdezése;
- Citcoin érmék átvitele Alice, Bob és Alex között;
- Események lekérdezése (de jelenleg az események nem jeleníthetők meg, ezért a felület egyszerűségének érdekében azt írja, hogy az események nem támogatottak);
- Műveletek naplózása.
Először inicializáljuk a blokkláncot:

Ezután létrehozzuk a saját fiókunkat, nem spórolunk a egyenleggel:

Lekérjük az összes elérhető fiókot:

Kiválasztjuk a küldőt és a címzettet, megkapjuk az egyenlegüket. Ha a küldő és a címzett ugyanaz, akkor a számlát feltöltjük:

Áttekintjük a tranzakciók végrehajtását a naplóban:

A demó programmal ennyi. Most megnézhetjük a tranzakciónkat a blokkláncon:

És az összes tranzakció listáját:

Ezzel sikeresen befejeztük a Citcoin hálózat PoC megvalósítását. Mit kell még tenni ahhoz, hogy a Citcoin teljes értékű hálózattá váljon az érmék átvitelére? Csak egy kicsit:
- A fiók létrehozásakor meg kell valósítani a privát/publikus kulcs generálását. A privát kulcsnak a fiók felhasználójánál kell tárolódnia, a publikusnak a blokkláncon.
- Tranzakciókat kell végrehajtani, melyeknél a felhasználó azonosítása nem névvel, hanem publikus kulccsal történik.
- Titkosítani kell a felhasználótól a szerver felé haladó tranzakciókat a privát kulccsal.
Zárás
A Citcoin hálózatot valósítottuk meg olyan funkciókkal, mint: fiók hozzáadása, egyenleg lekérdezése, számla feltöltés, érmék átvitele egyik számláról a másikra. Szóval mit is állítottunk elő a PoC keretében?
- Meg kell ismerkedni a blokklánccal általában és különösen a Hyperledger Fabric-el;
- Meg kell tanulni használni az IBM vagy az Amazon felhőit;
- Meg kell tanulni a JS programozási nyelvet és egy webes keretrendszert;
- Ha bármilyen adatot a blokkláncon kívül szeretnél tárolni, akkor meg kell tanulnod például integrálni a PostgreSQL-t.
- És végül, de nem utolsósorban — a Linux ismerete nélkül manapság nem megy sehová!)
Természetesen nem űrhajózás, de lesz vele munka!
🥇DoubleContact 0.2.0 | ProHoster
A forráskódokat elhelyeztem a . A repository rövid leírása:
A „server” — Node.js szerver
A „client” — Node.js kliens
A „blockchain” (a paraméterek értékei és a kulcsok természetesen nem működnek és csak példa kedvéért lettek megadva):
- contract — a smart contract forrása
- wallet — a felhasználó kulcsai a Hyperledger Fabric API használatához.
- *.cds — a smart contractok lefordított verziói
- *.json fájlok — példák a konfigurációs fájlokra a Hyperledger Fabric API használatához
Ez csak a kezdet!
Forrás: habr.com
