Silmad kardavad, aga kĂ€ed sĂŒgelevad!
Eelmistes artiklites kĂ€sitlesime tehnoloogiaid, millel plokiahelad pĂ”hinevad () ja juhtumeid, mida nende abil ellu viia (). On aeg hakata kĂ€t tööle panema! Pilootide ja PoC (tĂ”estus kontseptsioonist) elluviimiseks eelistan kasutada pilveteenuseid, kuna neile pÀÀseb juurde igast maailma nurgast ning tihti ei pea kulutama aega tĂŒĂŒtule keskkonna seadistamisele, kuna on olemas eelnevalt seadistatud konfiguratsioonid. Alustame lihtsa asjaga, nĂ€iteks vĂ”rguga, et saata mĂŒnte osalejate vahel ning nimetame seda tagasihoidlikult Citooniks. Selleks kasutame IBM-i pilve ja universaalset plokiahelat Hyperledger Fabric. Esiteks, miks nimetatakse Hyperledger Fabricit universaalseks plokiahelaks?

Hyperledger Fabric â universaalne plokiahel
Ăldiselt öeldes on universaalne teabehalduse sĂŒsteem:
- Serverite kogum ja tarkvaratuum, mis teostab Àriloogikat;
- Liidesed sĂŒsteemiga suhtlemiseks;
- Seadmete/inimeste registreerimise, autentimise ja autoriseerimise vahendid;
- Andmebaas, mis salvestab operatiivseid ja arhiivandmeid:

Ametlikku versiooni sellest, mis on Hyperledger Fabric, saab lugeda , ja lĂŒhidalt öeldes on Hyperledger Fabric avatud lĂ€htekoodiga platvorm, mis vĂ”imaldab luua erablokke ja teostada mis tahes nutikaid lepinguid, mis on kirjutatud programmeerimiskeeltes JS ja Go. Vaadakem lĂ€hemalt Hyperledger Fabric'i arhitektuuri ja veendugem, et see on universaalne sĂŒsteem, millel on vaid spetsiifilised andmete salvestamise ja kirjutamise omadused. Spetsiifilisus seisneb selles, et andmed, nagu kĂ”igis blokeeringutes, salvestatakse blokkidesse, mis lisatakse plokiahelasse ainult siis, kui osalejad on jĂ”udnud konsensusele, ja pĂ€rast salvestamist ei saa andmeid mĂ€rkamatult muuta ega kustutada.
Hyperledger Fabric'i arhitektuur
Diagrammil on nÀidatud Hyperledger Fabric'i arhitektuur:

Organisatsioonid â organisatsioonid sisaldavad peer'e, seega eksisteerib plokiahel organisatsioonide toetuse tĂ”ttu. Erinevad organisatsioonid vĂ”ivad kuuluda ĂŒhte kanalisse.
Kanal â loogiline struktuur, mis ĂŒhendab peer'e gruppidesse, seega mÀÀratleb see plokiahela. Hyperledger Fabric suudab samal ajal töödelda mitut plokiahelat erineva Ă€ri loogikaga.
Liikmesuse teenuste pakkuja (MSP) â on CA (Certificate Authority) identiteedi vĂ€ljastamiseks ja rollide mÀÀramiseks. Nodede loomiseks tuleb suhelda MSP-ga.
Peer nodid â kontrollivad tehinguid, salvestavad plokiahelat, tĂ€idavad nutilepinguid ja suhtlevad rakendustega. Peeridel on identiteet (digitaalne sertifikaat), mille vĂ€ljastab 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 ainult andmeid plokiahelas ja ajakohastavad 'World state'.
- Anchor Peer (AP) â kui plokiahelas osaleb mitu organisatsiooni, siis kasutatakse ankur peer-e omavaheliseks ĂŒhendamiseks. Iga organisatsioon peaks omama ĂŒhte vĂ”i mitut ankur peer-i. AP kaudu saab iga peer organisatsioonis teavet kĂ”ikide peer-ide kohta teistes organisatsioonides. AP-de vahelise teabe sĂŒnkroniseerimiseks kasutatakse .
- Leader Peer â kui organisatsioonil on mitu peer'i, siis ainult juhtpeer saab blokke Ordering service'ilt ja jagab neid teiste peer'ide hulka. Juht vĂ”ib olla mÀÀratud staatiliselt vĂ”i valida dĂŒnaamiliselt peer'ide seas organisatsioonis. Infovahetuseks juhtide ĂŒle kasutatakse samuti gossip protokolli.
Varad â vÀÀrtuslikud ĂŒksused, mida hoitakse plokiahelas. TĂ€psemalt on need key-value andmed JSON formaadis. Just need andmed salvestatakse plokiahelasse âBlockchainâ. Neil on ajalugu, mis salvestatakse plokiahelas, ja hetke seis, mis salvestatakse andmebaasis âWorld stateâ. Andmestruktuurid tĂ€idetakse vastavalt Ă€riĂŒlesannetele. Kohustuslikke vĂ€lju ei ole, ainus soovitus on, et varadel peaks olema omanik ja need peaksid omama vÀÀrtust.
Raamatupidamine â koosneb plokiahest âBlockchainâ ja andmebaasist âWorld stateâ, kus hoitakse varade hetke seise. World state kasutab LevelDB-d vĂ”i CouchDB-d.
Nutileping â Ă€riga smartlepingute abil rakendatakse sĂŒsteemi Ă€ri loogikat. Hyperledger Fabricis nimetatakse smartlepinguid chaincode'iks. Chaincode abil mÀÀratakse varad ja nendega seotud tehingud. Tehniliselt öeldes on smartlepingud programmimoodulid, mis on kirjutatud programmeerimiskeeltes JS vĂ”i Go.
Kinnituspolitika â iga chaincode jaoks saab mÀÀrata poliitikad, kui palju ja kellelt tuleb tehingu kinnitusi oodata. Kui poliitikat ei ole mÀÀratud, kasutatakse vaikimisi: âtehingu peab kinnitama ĂŒkskĂ”ik milline liige (member) ĂŒkskĂ”ik millisest organisatsioonist kanalil (channel).â NĂ€iteid poliitikatest:
- Tehingu peab kinnitama igasugune organisatsiooni administraator;
- Peab kinnitama iga liige (member) vÔi organisatsiooni klient;
- Peab kinnitama iga organisatsiooni peer.
Tellimisteenus â pakib tehingud plokkidesse ja saadab need peer'idele kanalisse. Tagab sĂ”numite saatmise kĂ”igile vĂ”rgus olevatele peer'idele. Tööstuslikes sĂŒsteemides kasutatakse , arenduseks ja testimiseks .
CallFlow

- Rakendus suhtleb Hyperledger Fabriciga, kasutades Go, Node.js vÔi Java SDK;
- Kliendil on tehing tx ja ta saadab selle kinnitavatele peer'idele;
- Peer kontrollib kliendi allkirja, viib tehingu lÀbi ja saadab endorsement signature kliendile tagasi. Chaincode töötab ainult endorsing peer'il ja selle tÀitmise tulemus edastatakse kÔikidele peer'idele. See töömehanism on tuntud kui PBFT (Practical Byzantine Fault Tolerant) konsensus. See erineb selle poolest, et sÔnum saadetakse ja oodatakse kinnitust mitte kÔigilt osalistelt, vaid ainult kindlast hulgast;
- PĂ€rast seda, kui klient on saanud vastuseid, mis vastavad endorsement policy'le, saadab ta tehingu Ordering service'ile;
- Ordering service koostab ploki ja saadab selle kÔikidele committing peer'idele. Ordering service tagab plokkide jÀrjestikuse salvestamise, mis vÀlistab nn ledger fork ();
- Peer'id saavad ploki, kontrollivad uuesti endorsement policy't, salvestavad ploki plokiahelasse ja muudavad seisundit âWorld stateâ DB-s.
St. see tagab rollide jagamise sÔlmepunktide vahel. See vÔimaldab skalaarida ja suurendada plokiahela turvalisust:
- Nutilepingud (chaincode) tÀidavad endorsing peer'id. See tagab nutilepingute konfidentsiaalsuse, kuna need ei ole kÔikide osalejate juures, vaid ainult endorsing peer'idel.
- Tellimus peab toimuma kiiresti. Seda tagab asjaolu, et tellimus loob ainult plokki ja saadab selle kindlale rikkapeeride kogumile.
- Kohustavad peers lihtsalt hoiavad plokiahelat â neid vĂ”ib olla palju ja nad ei nĂ”ua suurt vĂ”imsust ega kiiret toimimist.
Ăksikasjalikumalt arhitektuuri lahendustest Hyperledger Fabric ja miks see töötab just nii, saab vaadata siit: vĂ”i sealt: .
Nii et Hyperledger Fabric on tĂ”eliselt universaalne sĂŒsteem, mille abil saab:
- Rakendada suvalist Àriloogikat, kasutades nutikate lepingute mehhanismi;
- Salvestada ja saada andmeid plokiahela andmebaasist JSON-formaadis;
- Osutada ja kontrollida ligipÀÀsu API-le, kasutades sertifitseerimisasutust.
NĂŒĂŒd, kui oleme veidi tutvunud Hyperledger Fabric eripĂ€radega, teeme lĂ”puks midagi kasulikku!
Seame ĂŒles plokiahela
Ălesande seadmine
Ălesanne on luua Citcoin vĂ”rk jĂ€rgmiste funktsioonidega: konto loomine, saldo saamine, konto tĂ€iendamine ja mĂŒntide ĂŒlekandmine ĂŒhest kontost teise. Joonistame objekti mudeli, mille hiljem rakendame nutilepingus. Seega on meil kontod, mida tuvastatakse nimede (name) ja mis sisaldavad saldo (balance) ning konto loend. Kontod ja konto loend on Hyperledger Fabric'i mĂ”istes varad (assets). Vastavalt on neil ajalugu ja hetkeolek. Proovin seda visuaalselt illustreerida:

Ălemised kujundid on hetkeolek, mis on salvestatud andmebaasi âWorld stateâ. Allpool on kujundid, mis nĂ€itavad ajalugu, mis salvestatakse plokiahelas. Varade hetkeolekut muudetakse tehingute kaudu. Vara muutub ainult tervikuna, seega tehingu tĂ€itmise tulemusena luuakse uus objekt ja vara hetkevÀÀrtus lĂ€heb ajalukku.
IBM Cloud
Loome konto . EttevĂ”tte blockchain platvormi kasutamiseks tuleb seda uuendada Pay-As-You-Go mudelile. See protsess vĂ”ib olla ajamahukas, kuna IBM kĂŒsib lisainfot ja kontrollib seda kĂ€sitsi. Positiivse poole pealt vĂ”in öelda, et IBM-il on head Ă”pikurid, mis aitavad Hyperledger Fabricit nende pilves kĂ€ivitada. Mulle meeldis jĂ€rgmine artikkel ja nĂ€idisprotsesside tsĂŒkkel:
JĂ€rgnevalt tuuakse vĂ€lja IBM Blockchain platvormi ekraanipildid. See pole juhend blockchain'i loomise kohta, vaid lihtsalt ĂŒlesande ulatuse nĂ€itamine. Nii et meie eesmĂ€rkide jaoks loome ĂŒhe organisatsiooni:

Selle alla loome sÔlmed: Orderer CA, Org1 CA, Orderer Peer:

Loome kasutajad:

Loo kanal ja nimeta see citcoiniks:

Sisuliselt on kanal blockchain, seega algab see nullplokist (Genesis block):

Kirjuta nutileping
/*
* 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 mitu funktsiooni (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), mida demoprogramm kutsub Hyperledger Fabric API kaudu.
- Funktsioonid SendFrom ja RefillBalance genereerivad sĂŒndmusi (Event), mida demoprogramm saab.
- instantiate funktsioon kĂ€ivitatakse ĂŒks kord nutilepingu instantsimise ajal. Tegelikult kĂ€ivitatakse see mitte ĂŒhe, vaid iga kord, kui nutilepingut muudetakse. Seega on loetelu algvÀÀrtustamine tĂŒhi massiiv â halb mĂ”te, sest nĂŒĂŒd, kui nutilepingut uuendatakse, kaotame me praeguse loendi. Aga pole hullu, ma alles Ă”pin).
- Account-id ja account-ide (accounts) loend on JSON andmestruktuurid. Andmete manipuleerimiseks kasutatakse JS-i.
- VÔite praeguse asset-i vÀÀrtuse saada, kasutades funktsiooni getState, ja uuendada seda funktsiooniga putState.
- Account-i loomisel kÀivitatakse funktsioon AddAccount, kus vÔrreldakse blockchainis maksimaalset account-ide arvu (maxAccounts = 5). Ja siin on aps (kas mÀrkate?), mis viib account-ide arvu lÔpmatu kasvu. Selliseid vigu tuleks vÀltida).
SeejÀrel laadime nutilepingut Channelisse ja instantsime selle:

Vaadake Smart Contracti seadistamise tehingut:

Vaadake meie Channeli ĂŒksikasju:

Saame jĂ€rgmise plaani IBM-i pilve blockchaini vĂ”rgust. Skeemil on samuti demo programm, mis töötab Amazonis virtuaalses serveris (ĂŒksikasjad on jĂ€rgmises peatĂŒkis):

GUI loomine Hyperledger Fabric API kutseteks
Hyperledger Fabric'il on API, mida saab kasutada:
- kanali loomiseks;
- peer'i ĂŒhendamiseks kanaliga;
- tarkade lepingute seadistamiseks ja instantsimiseks kanalil;
- tehingute kutsumiseks;
- informatsiooni pÀrimiseks blockchainis.
Rakenduse arendamine
Kasutame meie demo programmis API-d ainult tehingute kutsmiseks ja informatsiooni pÀrimiseks, kuna kÔik muud sammud on juba tehtud, kasutades IBM-i blockchain platvormi. Loome GUI, kasutades standardtöötleja tehnoloogiaid: Express.js + Vue.js + Node.js. Kuidas alustada tÀnapÀevaste veebirakenduste loomist vÔib kirjutada eraldi artiklis. Siin on link loengute seeriale, mis mulle kÔige rohkem meeldis: . Tulemuseks on kliendi-serveri rakendus tuttava graafilise liidesega, mis jÀrgib Google'i Material Design'i stiili. REST API kliendi ja serveri vahel koosneb mitmest kutsetest:
- HyperledgerDemo/v1/init â blockchaini initsialiseerimine;
- HyperledgerDemo/v1/accounts/list â saada kĂ”igi kontode nimekiri;
- HyperledgerDemo/v1/account?name=Bob&balance=100 â loo konto Bob;
- HyperledgerDemo/v1/info?account=Bob â saa teavet Bob konto kohta;
- HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 â saada kaks mĂŒnter Bob-ilt Alice'ile;
- HyperledgerDemo/v1/disconnect â katkesta ĂŒhendus plokiahelaga.
API kirjeldus koos nĂ€idetega on saadaval â laialdaselt tuntud programm HTTP API testimiseks.
Demorakendus Amazonis
Olen rakenduse ĂŒles laadinud Amazonile, kuna IBM pole siiani suudnud minu kontot uuendada ja lubada virtuaalsete serverite loomist. Nagu kirsiks tordil, lisasin domeeni: . Hoian serverit natuke sisse lĂŒlitatuna, siis lĂŒlitan vĂ€lja, kuna renti kajastuvad sendid ja citcoin mĂŒndid börsil pole veel noteeritud) Artiklis lisasin ekraanipildid demost, et oleks arusaadav tööloogika. Demorakendus saab:
- Algatada plokiahela;
- Luua konto (kuid praegu uut kontot luua ei saa, kuna plokiahelas on saavutatud maksimaalne arvu kontosid, mis on mÀÀratud nutilepingus);
- Saada konto nimekiri;
- Ăle kanda citcoin mĂŒnte Alice, Bobi ja Alexi vahel;
- Saada sĂŒndmusi (aga hetkel ei saa sĂŒndmusi mingil moel nĂ€idata, seega on liideses lihtsuse huvides kirjas, et sĂŒndmusi ei toetata);
- Logige tegevused.
Esialgu initsialiseerime plokiahela:

SeejÀrel loome oma konto, mitte ei hÔlma pÔhjaga:

Saame kÔikide saadaval olevate kontode loendi:

Valime saatja ja saaja, saame nende bilansid. Kui saatja ja saaja on sama, siis toimub tema konto tÀiendamine:

Logis jÀlgime tehingute tÀitmist:

Demoprogrammiga on see kÔik. JÀrgmine samm on meie tehingu vaatamine plokiahelas:

Ja tehingute ĂŒldine nimekiri:

Sellega oleme edukalt lĂ”petanud Citcoin vĂ”rgu PoC rakendamise. Mida veel on vaja teha, et Citcoinist saaks tĂ€ieĂ”iguslik mĂŒntide ĂŒlekandmise vĂ”rk? VĂ€ga vĂ€he:
- Konto loomise etapis rakendada privaatse/publikus vÔti genereerimist. Privaatne vÔti peab olema kasutaja kontol, publiku plokiahelas.
- Teha mĂŒntide ĂŒlekandmine, kus kasutaja tuvastamiseks kasutatakse mitte nime, vaid publikust vĂ”tit.
- KrĂŒpteerida tehingud, mis lĂ€hevad kasutajalt serverisse, tema privaatse vĂ”tmega.
KokkuvÔte
Meie oleme loonud Citcoin vĂ”rgu funktsioonidega: konto lisamine, saldo saamine, oma kontot tĂ€iendamine, mĂŒntide edastamine ĂŒhest kontost teise. Nii et mis maksis meile PoC ehitamine?
- Tuleb uurida plokiahelat ĂŒldiselt ja Hyperledger Fabric'i eriti;
- Ăppida kasutama IBM vĂ”i Amazoni pilvi;
- Selgeks saada programmeerimiskeel JS ja mÔni veebiraamistik;
- Kui mingid andmed tuleb salvestada mitte plokiahelasse, vaid eraldi andmebaasi, siis Ôppida integreeruma nÀiteks PostgreSQL-iga;
- Ja viimane, kuid mitte vĂ€hem oluline â ilma Linuxi tundmisega ei pÀÀse tĂ€napĂ€eva maailmas kuhugi!)
Muidugi, ei ole see just rocket science, aga higi tuleb valada!
Allikakoode GitHubis
Allikakoode olen pannud . LĂŒhikirjeldus hoidlast:
Kataloog âserverâ â Node.js server
Kataloog âclientâ â Node.js klient
Kataloog âplokiahelâ (parameetrite vÀÀrtused ja vĂ”tmed, loomulikult, ei ole töötavad ja on toodud ainult nĂ€itena):
- contract â nutilepingute algfail
- wallet â kasutaja vĂ”tmed Hyperledger Fabric API kasutamiseks.
- *.cds â kompileeritud versioonid nutilepingutest
- *.json failid â nĂ€idised konfiguratsioonifailidest Hyperledger Fabric API kasutamiseks
See on alles algus!
Allikas: habr.com
