Eelmistes artiklites käsitlesime tehnoloogiaid, millele plokiahelad on üles ehitatud (Mida peaksime plokiahela üles ehitama?) ja juhtumid, mida saab nende abiga ellu viia (Miks peaksime juhtumit koostama?). On aeg oma kätega töötada! Pilootide ja PoC (Proof of Concept) rakendamiseks eelistan kasutada pilvi, sest... neile pääseb ligi kõikjalt maailmast ja sageli pole vaja raisata aega tüütule keskkonnapaigaldamisele, sest Seal on eelseadistatud konfiguratsioonid. Niisiis, teeme midagi lihtsat, näiteks võrgustikku osalejate vahel müntide ülekandmiseks ja nimetagem seda tagasihoidlikult Bitcoiniks. Selleks kasutame IBMi pilve ja universaalset plokiahelat Hyperledger Fabric. Esiteks selgitame välja, miks nimetatakse Hyperledger Fabricut universaalseks plokiahelaks?
Hyperledger Fabric – universaalne plokiahel
Üldiselt on universaalne infosüsteem:
Serverite komplekt ja tarkvaratuum, mis täidab äriloogikat;
Liidesed süsteemiga suhtlemiseks;
Vahendid seadmete/inimeste registreerimiseks, autentimiseks ja autoriseerimiseks;
Andmebaas, mis salvestab tegevus- ja arhiiviandmeid:
Ametlikku versiooni selle kohta, mis on Hyperledger Fabric, saab lugeda aadressilt veebisait, ja lühidalt öeldes on Hyperledger Fabric avatud lähtekoodiga platvorm, mis võimaldab luua privaatseid plokiahelaid ja täita suvalisi JS- ja Go-programmeerimiskeeltes kirjutatud nutikaid lepinguid. Vaatame üksikasjalikult Hyperledger Fabricu arhitektuuri ja veendume, et see on universaalne süsteem, millel on ainult andmete salvestamise ja salvestamise spetsiifika. Spetsiifilisus seisneb selles, et andmed salvestatakse nagu kõigi plokiahelate puhul plokkidesse, mis paigutatakse plokiahelale ainult siis, kui osalejad jõuavad üksmeelele ja pärast salvestamist ei saa andmeid vaikselt parandada ega kustutada.
Hyperledgeri kangaarhitektuur
Diagramm näitab Hyperledger Fabrici arhitektuuri:
Organisatsioonid — organisatsioonid sisaldavad eakaaslasi, s.o. plokiahel eksisteerib tänu organisatsioonide toele. Erinevad organisatsioonid võivad kuuluda samasse kanalisse.
Kanal — loogiline struktuur, mis ühendab eakaaslased rühmadesse, s.t. plokiahel on täpsustatud. Hyperledger Fabric suudab samaaegselt töödelda mitut erineva äriloogikaga plokiahelat.
Liikmeteenuste pakkuja (MSP) on CA (sertifitseerimisasutus) identiteedi väljastamiseks ja rollide määramiseks. Sõlme loomiseks peate suhtlema MSP-ga.
Peer sõlmed — kontrollida tehinguid, salvestada plokiahelat, täita nutikaid lepinguid ja suhelda rakendustega. Partneritel on identiteet (digitaalne sertifikaat), mille väljastab MSP. Erinevalt Bitcoini või Etheriumi võrgust, kus kõigil sõlmedel on võrdsed õigused, mängivad Hyperledger Fabricus sõlmed erinevat rolli:
Peer ehk eakaaslase heakskiitmine (EP) ja täitma nutikaid lepinguid.
Pühendunud kolleeg (CP) - salvestage andmed ainult plokiahelasse ja värskendage maailma seisundit.
Ankur Peer (AP) - kui plokiahelas osaleb mitu organisatsiooni, kasutatakse nendevaheliseks suhtluseks ankurpartnereid. Igal organisatsioonil peab olema üks või mitu ankurpartnerit. AP abil saab iga organisatsiooni eakaaslane saada teavet kõigi teiste organisatsioonide kaaslaste kohta. Kasutatakse teabe sünkroonimiseks AP-de vahel kuulujuttude protokoll.
Juht Peer — kui organisatsioonil on mitu partnerit, saab tellimisteenusest plokke ja annab need ülejäänutele üle ainult kaaslase juht. Juht saab määrata staatiliselt või valida dünaamiliselt organisatsiooni kaaslaste poolt. Kõmuprotokolli kasutatakse ka juhtide info sünkroonimiseks.
vara — üksused, millel on väärtus ja mis on salvestatud plokiahelasse. Täpsemalt on need võtmeväärtuse andmed JSON-vormingus. Need andmed salvestatakse plokiahelasse. Neil on ajalugu, mis salvestatakse plokiahelasse, ja praegune olek, mis salvestatakse andmebaasi “Maailma olek”. Andmestruktuure täidetakse suvaliselt sõltuvalt äriülesannetest. Kohustuslikke välju ei ole, ainus soovitus on, et varadel peab olema omanik ja need peavad olema väärtuslikud.
pearaamat — koosneb Blockchaini ja Wordi olekuandmebaasist, mis salvestab varade hetkeseisu. Maailmariik kasutab LevelDB-d või CouchDB-d.
Nutikas leping — nutikate lepingute abil realiseeritakse süsteemi äriloogika. Hyperledger Fabricus nimetatakse nutikaid lepinguid kettkoodiks. Ahelkoodi abil määratakse varad ja nende üle tehtavad tehingud. Tehnilises mõttes on nutikad lepingud tarkvaramoodulid, mis on realiseeritud JS või Go programmeerimiskeeltes.
Kinnituspoliitika — iga kettkoodi jaoks saab määrata reegli, mitu tehingu kinnitust oodatakse ja kellelt. Kui poliitikat pole määratud, on vaikeseade: "Tehingu peab kinnitama kanali mis tahes organisatsiooni liige." Näited eeskirjadest:
Tehingu peab heaks kiitma organisatsiooni mis tahes administraator;
Seda peab kinnitama iga organisatsiooni liige või klient;
Peab kinnitama mis tahes kolleegiorganisatsioon.
Tellimisteenus — pakib tehingud plokkidesse ja saadab need kanali kaaslastele. Garanteerib sõnumite edastamise kõigile võrgus olevatele kaaslastele. Kasutatakse tööstussüsteemide jaoks Kafka sõnumite vahendaja, arendamiseks ja testimiseks Vallaline.
CallFlow
Rakendus suhtleb Hyperledger Fabricuga, kasutades Go, Node.js või Java SDK;
Klient loob tx-tehingu ja saadab selle kinnitavatele partneritele;
Partner kontrollib kliendi allkirja, viib tehingu lõpule ja saadab kinnitusallkirja kliendile tagasi. Ahelkoodi käivitatakse ainult kinnitaval partneril ja selle täitmise tulemus saadetakse kõigile partneritele. Seda tööalgoritmi nimetatakse PBFT (Practical Byzantine Fault Tolerant) konsensuseks. Erineb klassikaline BFT asjaolu, et sõnum saadetakse ja kinnitust ei oodata kõigilt osalejatelt, vaid ainult teatud komplektilt;
Pärast seda, kui klient on saanud kinnituspoliitikale vastava arvu vastuseid, saadab ta tehingu Tellimisteenusele;
Tellimisteenus genereerib ploki ja saadab selle kõigile pühendunud partneritele. Tellimisteenus tagab plokkide järjestikuse salvestamise, mis välistab nn pearaamatu kahvli (vaata jaotist "Kahvlid");
Partnerid saavad ploki, kontrollivad uuesti kinnituspoliitikat, kirjutavad plokk plokiahelasse ja muudavad olekut andmebaasis “Maailma olek”.
Need. Selle tulemuseks on rollide jaotus sõlmede vahel. See tagab, et plokiahel on skaleeritav ja turvaline:
Nutikad lepingud (ahelakood) toetavad kolleege. See tagab nutikate lepingute konfidentsiaalsuse, sest seda ei salvesta kõik osalejad, vaid ainult toetavad kolleegid.
Tellimine peaks toimima kiiresti. Selle tagab asjaolu, et Tellimine moodustab ainult ploki ja saadab selle kindlale liidrikaaslastele.
Pühendunud kaaslased talletavad ainult plokiahelat – neid võib olla palju ning need ei nõua palju jõudu ja kohest töötamist.
Niisiis, Hyperledger Fabric on tõeliselt universaalne süsteem, millega saate:
Rakendada suvalist äriloogikat nutika lepingu mehhanismi abil;
Salvestage ja võtke vastu andmeid plokiahela andmebaasist JSON-vormingus;
Andke ja kinnitage API-juurdepääs sertifitseerimisasutuse abil.
Nüüd, kui oleme Hyperledger Fabricu spetsiifikast pisut aru saanud, teeme lõpuks midagi kasulikku!
Plokiahela juurutamine
Probleemi avaldus
Ülesandeks on Citcoini võrgustiku juurutamine järgmiste funktsioonidega: konto loomine, saldo saamine, konto täiendamine, müntide ülekandmine ühelt kontolt teisele. Joonistame objektimudeli, mida edaspidi nutikas lepingus juurutame. Seega on meil kontod, mis on identifitseeritud nimede järgi ja sisaldavad saldot, ja kontode loend. Kontod ja kontode loend on Hyperledger Fabrici varade osas. Sellest lähtuvalt on neil ajalugu ja praegune seis. Püüan selle selgelt joonistada:
Ülemised arvud näitavad hetkeseisu, mis on salvestatud andmebaasi “Maailma seisund”. Nende all on joonised, mis näitavad plokiahelasse salvestatud ajalugu. Varade hetkeseisu muudavad tehingud. Vara muutub ainult tervikuna, seega tehingu tulemusel luuakse uus objekt ning vara hetkeväärtus läheb ajalukku.
IBM Cloud
Loome konto sisse IBM pilv. Plokiahela platvormi kasutamiseks tuleb see üle viia Pay-As-You-Go-le. See protsess ei pruugi olla kiire, sest... IBM küsib lisateavet ja kontrollib seda käsitsi. Positiivsena võin öelda, et IBM-il on head koolitusmaterjalid, mis võimaldavad Hyperledger Fabricu nende pilves juurutada. Mulle meeldisid järgmised artiklite ja näidete seeriad:
Järgmised on IBM Blockchaini platvormi ekraanipildid. See ei ole juhis plokiahela loomise kohta, vaid lihtsalt ülesande ulatuse demonstratsioon. Seega loome oma eesmärkidel ühe organisatsiooni:
Loome selles sõlmed: Tellija CA, Org1 CA, Tellija Peer:
Loome kasutajaid:
Looge kanal ja nimetage seda citcoiniks:
Põhimõtteliselt on kanal plokiahel, nii et see algab plokist nullist (Genesise plokk):
Nutika lepingu kirjutamine
/*
* 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;
Intuitiivselt peaks siin kõik selge olema:
On mitmeid funktsioone (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), mida demoprogramm Hyperledger Fabric API abil kutsub.
Funktsioonid SendFrom ja RefillBalance genereerivad sündmusi, mille demoprogramm vastu võtab.
Instantimise funktsiooni kutsutakse üks kord, kui nutikat lepingut luuakse. Tegelikult kutsutakse seda mitte ainult üks kord, vaid iga kord, kui nutika lepingu versioon muutub. Seetõttu on tühja massiiviga loendi lähtestamine halb mõte, sest Nüüd, kui muudame nutika lepingu versiooni, kaotame praeguse loendi. Aga pole midagi, ma alles õpin).
Kontod ja kontode loend on JSON-i andmestruktuur. JS-i kasutatakse andmetega manipuleerimiseks.
Vara praeguse väärtuse saate hankida funktsiooni getState abil ja värskendada seda kasutades putState.
Konto loomisel kutsutakse välja funktsioon AddAccount, milles võrreldakse plokiahelas olevate kontode maksimaalset arvu (maxAccounts = 5). Ja siin on jamb (olete märganud?), mis toob kaasa kontode arvu lõputu kasvu. Selliseid vigu tuleks vältida)
Järgmisena laadime nutika lepingu kanalisse ja loome selle:
Vaatame Smart Contracti installimise tehingut:
Vaatame meie kanali üksikasju:
Selle tulemusena saame järgmise diagrammi plokiahela võrgust IBM-i pilves. Diagrammil on näha ka virtuaalserveris Amazoni pilves töötav demoprogramm (sellest lähemalt järgmises jaotises):
GUI loomine Hyperledger Fabric API kõnede jaoks
Hyperledger Fabricul on API, mida saab kasutada:
Loo kanal;
Ühendused kanalile;
Nutikate lepingute paigaldamine ja realiseerimine kanalis;
Helistamise tehingud;
Küsige teavet plokiahela kohta.
Rakenduste arendamine
Meie demoprogrammis kasutame API-d ainult tehingutele helistamiseks ja teabe küsimiseks, kuna Ülejäänud sammud oleme IBM-i plokiahela platvormi kasutades juba lõpetanud. GUI kirjutame standardse tehnoloogiavirna: Express.js + Vue.js + Node.js. Sellest, kuidas alustada moodsate veebirakenduste loomisega, saate kirjutada eraldi artikli. Jätan siia lingi loengusarjale, mis mulle enim meeldis: Full Stack veebirakendus Vue.js ja Express.js abil. Tulemuseks on klient-server rakendus, millel on tuttav Google'i materjalidisaini stiilis graafiline liides. Kliendi ja serveri vaheline REST API koosneb mitmest kõnest:
HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — kahe mündi ülekandmine Bobilt Alice'ile;
HyperledgerDemo/v1/disconnect – sulgege ühendus plokiahelaga.
API kirjeldus koos näidetega Postimehe veebisait - tuntud programm HTTP API testimiseks.
Demorakendus Amazoni pilves
Laadisin rakenduse Amazoni üles, sest... IBM ei ole ikka veel saanud minu kontot uuendada ja lubada mul virtuaalservereid luua. Kuidas domeenile kirsi lisada: www.citcoin.info. Hoian serverit mõnda aega sees ja siis lülitan välja, sest... tilguvad üürisendid ja tsitcoini münte veel börsil ei ole) Lisan artiklisse demo ekraanipildid, et töö loogika oleks selge. Demorakendus võib:
Initsialiseerige plokiahel;
Loo konto (aga nüüd ei saa uut Kontot luua, sest plokiahelas on täis nutilepingus määratud kontode maksimumarv);
Saate kontode loendi;
Citcoini müntide ülekandmine Alice'i, Bobi ja Alexi vahel;
Sündmuste vastuvõtmine (kuid nüüd pole sündmusi võimalik näidata, nii et lihtsuse huvides ütleb liides, et sündmusi ei toetata);
Logi toimingud.
Kõigepealt initsialiseerime plokiahela:
Järgmisena loome oma konto, ärge raisake aega saldoga:
Saame kõigi saadaolevate kontode loendi:
Valime saatja ja saaja ning saame nende saldod. Kui saatja ja saaja on samad, täiendatakse tema kontot:
Logis jälgime tehingute täitmist:
Tegelikult on see kõik demoprogrammiga. Allpool näete meie tehingut plokiahelas:
Ja tehingute üldine loend:
Sellega oleme edukalt lõpule viinud PoC juurutamise Citcoini võrgustiku loomiseks. Mida tuleb veel teha, et Citcoinist saaks täisväärtuslik müntide ülekandmise võrgustik? Väga vähe:
Konto loomise etapis rakendage privaatse / avaliku võtme genereerimine. Privaatvõti tuleb hoida konto kasutaja juures, avalik võti plokiahelas.
Tehke mündiülekanne, milles kasutaja tuvastamiseks kasutatakse avalikku võtit, mitte nime.
Krüptige kasutajalt serverisse minevad tehingud tema privaatvõtmega.
Järeldus
Oleme Citcoini võrgustiku juurutanud järgmiste funktsioonidega: konto lisamine, saldo saamine, konto täiendamine, müntide ülekandmine ühelt kontolt teisele. Niisiis, mis meile PoC ehitamine maksma läks?
Peate õppima plokiahelat üldiselt ja eriti Hyperledger Fabricit;
Õppige kasutama IBMi või Amazoni pilvi;
Õppige JS programmeerimiskeelt ja mõnda veebiraamistikku;
Kui osa andmeid on vaja salvestada mitte plokiahelasse, vaid eraldi andmebaasi, siis õpi integreerima näiteks PostgreSQL-iga;
Ja viimane, kuid mitte vähem oluline – te ei saa elada kaasaegses maailmas ilma Linuxi tundmiseta!)
Muidugi pole see raketiteadus, kuid peate kõvasti tööd tegema!
Allikad GitHubis
Allikad pandud GitHub. Hoidla lühikirjeldus:
Kataloog «server» — Node.js server
Kataloog «klient» — Node.js klient
Kataloog «blockchain"(parameetrite väärtused ja võtmed muidugi ei tööta ja on toodud ainult näitena):
leping — nutika lepingu lähtekood
rahakott — kasutajavõtmed Hyperledger Fabric API kasutamiseks.