Silmad kardavad, kuid kĂ€ed sĂŒgelevad!
Eelmistes artiklites arutlesime tehnoloogiate ĂŒle, millele plokiahelad toetuvad () ja juhtumite ĂŒle, mida nende abil ellu viia (). On aeg asuda tegudele! Pilootprojekti ja PoC (Proof of Concept) elluviimiseks eelistan kasutada pilveteenuseid, kuna neile pÀÀseb ligi igast maailma nurgast ja sageli ei pea aega raiskama tĂŒĂŒtule keskkonna seadistamisele, kuna eksisteerivad eelkonfigureeritud lahendused. Alustame millegi lihtsa loomist, nĂ€iteks vĂ”rku raha ĂŒlekandmiseks osalejate vahel, ja nimetame seda tagasihoidlikult Citcoiniks. Selleks kasutame IBM-i pilve ja universaalset plokiahelat Hyperledger Fabric. Esmalt uurime, miks Hyperledger Fabrici nimetatakse universaalseks plokiahelaks?

Hyperledger Fabric â universaalne plokiahel
Ăldiselt öeldes on universaalne teabesĂŒsteem:
- Serverite kogum ja tarkvara sĂŒda, mis tĂ€idab Ă€ri loogikat;
- Liidesed sĂŒsteemiga suhtlemiseks;
- Seadmete / inimeste registreerimise, autentimise ja autoriseerimise vahendid;
- Andmebaas, mis salvestab operatiivsed ja arhiivandmed:

Hyperledger Fabrici ametlikku definitsiooni saab lugeda , kuid lĂŒhidalt öeldes on Hyperledger Fabric avatud lĂ€htekoodiga platvorm, mis vĂ”imaldab luua suletud plokiahelasid ja teostada mis tahes nutikaid lepinguid, mis on kirjutatud programmeerimiskeeltes JS ja Go. Vaatame lĂ€hemalt Hyperledger Fabrici arhitektuuri ja veendume, et see on universaalne sĂŒsteem, millel on ainult andmete salvestamise ja kirjutamise eripĂ€ra. EripĂ€ra seisneb selles, et andmed, nagu kĂ”igis plokiahelates, salvestatakse plokkides, mis lisatakse plokiahelasse ainult siis, kui osalised saavutavad konsensuse, ja pĂ€rast salvestamist ei saa andmeid mĂ€rkamatult muuta vĂ”i eemaldada.
Hyperledger Fabrici arhitektuur
Diagrammil on kujutatud Hyperledger Fabrici arhitektuur:

Organisatsioonid â organisatsioonidesse kuuluvad peerid, seega toetavad plokiahelat organisatsioonid. Erinevad organisatsioonid vĂ”ivad kuuluda ĂŒhte kanali.
Kanal â loogiline struktuur, mis ĂŒhendab peer'e gruppidesse, seega mÀÀratleb plokiahela. Hyperledger Fabric suudab samal ajal töödelda mitmeid plokiahelaid erineva Ă€ri loogikaga.
Liikmeministeerium (MSP) â see on CA (sertifitseerimisasutus), mis annab identiteete ja mÀÀrab rolle. Noodi loomiseks tuleb suhelda MSP-ga.
Peer nodes â kontrollivad tehinguid, salvestavad plokiahelat, tĂ€idavad nutilepinguid ja suhtlevad rakendustega. Peeridel on identiteet (digitaalne sertifikaat), mille annab vĂ€lja MSP. Erinevalt Bitcoin vĂ”i Etheriumi vĂ”rgust, kus kĂ”ik nodid on vĂ”rdsed, mĂ€ngivad Hyperledger Fabricis nodid erinevaid rolle:
- Peer vÔib olla endorsing peer (EP) ja tÀita nutilepinguid.
- Committing peer (CP) â salvestavad andmeid plokiahelasse ja uuendavad "World state".
- Anchor Peer (AP) â kui plokiahelas osaleb mitu organisatsiooni, kasutatakse ankur-peer'e nende vaheliseks suhtlemiseks. Igal organisatsioonil peab olema ĂŒks vĂ”i mitu ankur-peer'i. AP abil vĂ”ib iga peer organisatsioonis saada teavet kĂ”igi teiste organisatsioonide peer'ide kohta. Teabe sĂŒmbioosi saavutamiseks kasutatakse .
- Leader Peer â kui organisatsioonil on mitu peer'i, siis ainult liider-peer saab blokeerida Ordering service'ist ja edastada neid teistele peer'idele. Liidrit vĂ”ib mÀÀrata staatiliselt vĂ”i valida dĂŒnaamiliselt organisatsioonis olevate peer'ide poolt. Liidrite vahelise teabe sĂŒnkroniseerimiseks kasutatakse samuti gossip protokolli.
Assets â vÀÀrtuslikud ĂŒksused, mida hoitakse plokiahelas. Veelgi tĂ€psemalt â need on key-value andmed JSON formaadis. Just need andmed salvestatakse plokiahelasse "Blockchain". Neil on ajalugu, mida hoitakse plokiahelas ja praegune seisund, mis hoitakse andmebaasis "World state". Andmestruktuure tĂ€iendatakse vastavalt Ă€rivajadustele. Kohustuslikke vĂ€lju ei ole, ainus soovitus on, et varadel peab olema omanik ja need peaksid esindama vÀÀrtust.
Ledger â koosneb plokiahest "Blockchain" ja andmebaasist "World state", kus hoitakse varade praegust seisundit. World state kasutab LevelDB vĂ”i CouchDB.
Smart contract â nutilepingute kaudu rakendatakse sĂŒsteemi Ă€riloogikat. Hyperledger Fabricis nimetatakse nutilepinguid chaincode'iks. Chaincode'i abil mÀÀratakse varad ja tehingud nendega. Tehniliselt öeldes on nutilepingud programmeerimismoodulid, mis on ellu viidud programmeerimiskeeltel JS vĂ”i Go.
Endorsement policy â iga chaincode'i jaoks vĂ”ib mÀÀrata poliitika, kui palju ja kellelt on vaja tehingu kinnitust. Kui poliitika pole mÀÀratud, kasutatakse vaikimisi: "tehingut peab kinnitama iga liikmesorganisatsiooni liige kanalil". Poliitika nĂ€idised:
- Tehingu peab kinnitama organisatsiooni mis tahes administraator;
- Peab kinnitama organisatsiooni mis tahes liige vÔi klient;
- Peab kinnitama organisatsiooni mis tahes peer.
Tellimisteenus â pakib tehingud plokkidesse ja saadab need peer-idele kanalis. Tagab sĂ”numite edastamise kĂ”ikidele peer-idele vĂ”rgus. Tööstuslike sĂŒsteemide jaoks kasutatakse , arendamiseks ja testimiseks .
CallFlow

- Rakendus suhtleb Hyperledger Fabric'iga, kasutades Go, Node.js vÔi Java SDK-d;
- Kliendil on tehingu tx ja saadab selle endorseerimise peer-idele;
- Peer kontrollib kliendi allkirja, viib tehingu lĂ€bi ja saadab tagasi endorsement signature kliendile. Chaincode viiakse lĂ€bi ainult endorseerimise peer-ides ning selle tĂ€itmise tulemus saadetakse kĂ”igile peer-idele. Sellist töömeetodit nimetatakse â PBFT (Practical Byzantine Fault Tolerant) konsensus. Erineb selle poolest, et sĂ”num saadetakse ja oodatakse kinnitamist mitte kĂ”igilt osalejatelt, vaid ainult kindlast kogumist;
- PĂ€rast seda, kui klient on saanud vastuste arvu, mis vastab endorsement policy-le, saadab ta tehingu tellimisteenusele;
- Tellimisteenus koostab ploki ja saadab selle kÔikidele kaasaskantavatele peer-idele. Tellimisteenus tagab plokkide jÀrjekindla kirjutamise, mis vÀlistab nn raamatupidamise fork'i ();
- Peer-id saavad ploki, kontrollivad veelkord endorsement policy-d, kirjutavad ploki plokiahelasse ja muudavad olekut "World state" andmebaasis.
See tÀhendab, et node'de vahel toimub rollide jagamine. See tagab plokiahela skaleeritavuse ja turvalisuse:
- Nutikaid lepinguid (chaincode) viivad lÀbi endorseerimise peer-id. See tagab nutikate lepingute konfidentsiaalsuse, kuna need ei ole kÔigi osalejate, vaid ainult endorseerimise peer-ide valduses.
- Tellimine peab toimuma kiiresti. See tagatakse sellega, et tellimine koostab ainult ploki ja saadab selle kindlale juhivÔrgustikule.
- Kaasaskantavad peer-id ainult hoiavad plokiahelat â neid vĂ”ib olla palju ja nad ei vaja suurt vĂ”imsust ega kohest tööd.
Rohkem Hyperledger Fabric'i arhitektuurilahenduste kohta ja miks see töötab nii, mitte teisiti, saab vaadata siit: vÔi siit: .
Seega, Hyperledger Fabric on tĂ”eliselt universaalne sĂŒsteem, millega saab:
- Reaaliseerida igasugust Àriloogikat, kasutades nutikate lepingute mehhanismi;
- Salvestame ja saame andmeid plokiahela andmebaasist JSON formaadis;
- Pakume ja kontrollime API-le ligipÀÀsu, kasutades sertifikaadi ametit.
NĂŒĂŒd, kui oleme natuke paremini tuttavad Hyperledger Fabric spetsiifikaga, laseme lĂ”puks teha midagi kasulikku!
KĂ€ivitame plokiahela
Ălesande seadmine
Ălesanne on luua Citcoin vĂ”rk, mis sisaldab jĂ€rgmisi funktsioone: luua konto, saada saldo, tĂ€iendada kontot, edastada mĂŒnte ĂŒhest kontost teise. Joonistame objekti mudeli, mille me hiljem teeme tarklepingus. Niisiis, meil on kontod, mis tuvastatakse nimede (name) kaudu ja sisaldavad saldo (balance) ning konto loend. Kontod ja konto loend on Hyperledger Fabricis varad (assets). Vastavalt on neil ajalugu ja praegune seisukord. Proovin seda visuaalselt esitada:

Ălemised kujundid â see on praegune seisukord, mis salvestatakse "World state" andmebaasi. Allpool on kujundid, mis nĂ€itavad ajalugu, mis salvestatakse plokiahelasse. Varade praegune seisukord muutub tehingute kaudu. Vara muutub ainult tĂ€ielikult, seega tehingu teostamise tulemusena luuakse uus objekt ja vara praegune vÀÀrtus lĂ€heb ajalukku.
IBM Cloud
Loome konto . Plokiahela platvormi kasutamiseks tuleb see uuendada Pay-As-You-Go versiooniks. See protsess ei pruugi olla kiire, kuna IBM kĂŒsib tĂ€iendavat teavet ja kontrollib seda kĂ€sitsi. Positiivse kĂŒlje pealt vĂ”in öelda, et IBM-l on head Ă”ppematerjalid, mis vĂ”imaldavad Hyperledger Fabricit nende pilves kĂ€ivitada. Mulle meeldis jĂ€rgmine artiklite ja nĂ€idete tsĂŒkkel:
JĂ€rgnevalt on toodud ekraanipildid IBM plokiahela platvormist. See ei ole juhend plokiahela loomise kohta, vaid lihtsalt ĂŒlesande ulatuse demonstreerimine. Niisiis, meie vajaduste jĂ€rgi loome ĂŒhe organisatsiooni:

Loome selles sÔlmed: Orderer CA, Org1 CA, Orderer Peer:

Loome kasutajad:

Looge kanali ja nimetage see citcoin:

PÔhimÔtteliselt on kanal plokiahel, seega algab see nullbloki (Genesis block) lÔpetamisest:

Kirjutame tarklepingut
/*
* 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;
Siin peaks kÔik intuitiivselt selge olema:
- On mitu funktsiooni (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), mida demo program kasutab Hyperledger Fabric API abil.
- Funktsioonid SendFrom ja RefillBalance genereerivad sĂŒndmusi (Event), mida demo programm saab.
- Funktsioon instantiate kutsutakse vĂ€lja ainult ĂŒks kord nutika lepingu instantiimise ajal. Tegelikult kutsutakse seda vĂ€lja mitte ainult ĂŒks kord, vaid iga kord nutika lepingu versiooni muutmisel. SeetĂ”ttu on loetelu algse tĂŒhi massiiv - halb idee, kuna nĂŒĂŒd kaotame nutika lepingu versiooni muutmisel praeguse loendi. Kuid see pole probleem, ma alles Ă”ppin).
- Account'id ja account'ide (accounts) loend - need on JSON andmestruktuurid. Andmete manipuleerimiseks kasutatakse JS-i.
- KÀesoleva asset'i praeguse vÀÀrtuse saab kÀtte funktsiooni getState kaudu, samas kui seadistamiseks kasutatakse putState'i.
- Account'i loomisel kutsutakse vÀlja funktsioon AddAccount, kus vÔrreldakse plokiahelas maksimaalselt lubatud account'ide arvu (maxAccounts = 5). Siin on viga (kas mÀrkisite?), mis pÔhjustab account'ide arvukuse lÔputu kasvu. Selliseid vigu tuleks vÀltida).
Edasi laadime nutika lepingu Channelisse ja instantiime selle:

Vaadake nutika lepingu seadistamise tehingut:

Vaadake meie Channeli ĂŒksikasju:

Tulemusena saame jĂ€rgmise plokiahela vĂ”rgu skeemi IBM-i pilves. Skeemil on ka demoprogramm, mis töötab Amazoni pilves virtuaalsel serveril (ĂŒksikasjad on jĂ€rgmises osas):

GUI loomine Hyperledger Fabric API kutsumiste jaoks
Hyperledger Fabric'il on API, mida saab kasutada:
- Channeli loomiseks;
- Peer'i ĂŒhendamiseks channeliga;
- Nutika lepingu seadistamiseks ja instantiimiseks channelis;
- Tehingute nn kutse jaoks;
- Informatsiooni kĂŒsimiseks plokiahelas.
Rakenduse arendus
Meie demoprogrammis kavatseme kasutada API-d ainult tehingute kutsumiseks ja informatsiooni kĂŒsimiseks, kuna ĂŒlejÀÀnud sammud oleme juba teinud, kasutades IBM-i plokiahela platvormi. Kirjutame GUI, kasutades standardset tehnoloogiate virna: Express.js + Vue.js + Node.js. Kuidas alustada kaasaegsete veebirakenduste loomist, vĂ”iks kirjutada eraldi artikli. Siin jĂ€tan lingi loengusarjale, mis mulle enim meeldis: . Tulemusena sai kliendi-serveri rakendus tuttava Material Design stiilis graafilise liidese. REST API kliendi ja serveri vahel koosneb mitmest kutsetest:
- HyperledgerDemo/v1/init - plokiahela initsialiseerimine;
- HyperledgerDemo/v1/accounts/list - saada kÔigi account'ide loend;
- HyperledgerDemo/v1/account?name=Bob&balance=100 - luua Bob account;
- HyperledgerDemo/v1/info?account=Bob - saada teavet Bob account'i kohta;
- HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 - edastada kaks mĂŒnti Bobilt Alicele;
- HyperledgerDemo/v1/disconnect â lukusta blockchaini ĂŒhendus.
API kirjeldus koos nĂ€idetega on pandud â laialdaselt tuntud programm HTTP API-de testimiseks.
Demo rakendus Amazonis
Rakendus on ĂŒles laaditud Amazonisse, kuna IBM ei ole siiani suutnud uuendada minu kontot ning lubada virtuaalserverite loomist. Nagu kirss tordil on domeen: . Hoian serverit natuke sisse lĂŒlitatuna, seejĂ€rel lĂŒlitan vĂ€lja, kuna rendihinnad voolavad, aga citcoin mĂŒntide kauplemine börsil ei ole veel alustatud) Panen artiklisse ekraanipildid, et selgitada rakenduse toimimist. Demo rakendus oskab:
- Alustada blockchaini;
- Luua Konto (aga praegu ei saa uut Kontot luua, kuna blockchainis on saavutatud maksimaalne number kontosid, mis on mÀÀratud nutilepingus);
- Saada Kontode nimekiri;
- Edastada citcoin mĂŒnte Alice'i, Bob'i ja Alexi vahel;
- Saada sĂŒndmusi (aga hetkel ei saa sĂŒndmusi nĂ€idata, seega on kasutajaliideses lihtsuse huvides kirjutatud, et sĂŒndmusi ei toetata);
- Logida tegevusi.
Esiteks alustame blockchaini:

SeejĂ€rel loome oma konto, ei kisenda saldo ĂŒle:

Saame nimekirja kÔikidest saadaval olevatest kontodest:

Valime saatja ja saaja, saame nende saldode: Kui saatja ja saaja on ĂŒks ja sama, toimub tema konto tĂ€iendamine:

Logis jÀlgime tehingute tÀitmist:

Kuna demo programm sellega ka lÔppeb. Edasi saab vaadata meie tehingut blockchainis:

Ja kogu tehingute loend:

Selleks saime edukalt lĂ”petatud Citcoini vĂ”rgu PoC rakendamise. Mida on veel vaja teha, et Citcoinist saaks tĂ€ieĂ”iguslik mĂŒnte ĂŒlekandmise vĂ”rk? Ainult vĂ€he:
- Konto loomise etapis rakendada privaatse / avaliku vÔtme genereerimist. PrivaatvÔti peab olema kontoa kasutaja kÀes, avalik vÔtme blockchainis.
- Teha mĂŒnsĂŒ transfer, kus kasutaja identifitseerimiseks kasutatakse mitte nime, vaid avalikku vĂ”tme.
- KrĂŒpteerida tehingud, mis lĂ€hevad kasutajalt serverisse tema privaatse vĂ”tme abil.
KokkuvÔte
Oleme rakendanud Citcoin vĂ”rku funktsioonidega: konto lisamine, saldo saamine, oma konto tĂ€iendamine, mĂŒnte edastamine ĂŒhelt konto teisele. Nii et, mida maksis PoC ehitamine?
- Peame uurima blockchaini ĂŒldiselt ja Hyperledger Fabric'i eriti;
- Ăppima kasutama IBM'i vĂ”i Amazoni pilvi;
- Ăppima programmeerimiskeelt JS ja mĂ”nda veebiraamistikku;
- Kui mÔnda teavet tuleb hoida mitte plokiahelas, vaid eraldi andmebaasis, tuleks Ôppida nÀiteks PostgreSQL-iga integreerima;
- Ja viimane nimekirjas, kuid mitte vĂ€henenud tĂ€htsusega â ilma Linuxi tundmiseta ei pÀÀse tĂ€napĂ€eva maailmas kuhugi!)
Muidugi, see ei ole raketiteadus, aga veidi tuleb vaeva nÀha!
Allikakood GitHubis
Allikaid olen pannud . LĂŒhike kirjeldus repodega:
Kataloog âserverâ â Node.js server
Kataloog âclientâ â Node.js klient
Kataloog âblockchainâ (parameetrite vÀÀrtused ja vĂ”tmed on muidugi mitte töökindlad ja nĂ€idatud ainult nĂ€iteks):
- contract â nutilepingu allikas
- wallet â kasutaja vĂ”tmed Hyperledger Fabric API kasutamiseks.
- *.cds â kompileeritud versioonid nutilepingutest
- *.json failid â nĂ€ited konfiguratsioonifailidest Hyperledger Fabric API kasutamiseks
See on alles algus!
Allikas: habr.com
