Ankstesniuose straipsniuose nagrinėjome technologijas, kuriomis remiantis kuriamos blokų grandinės (Ką turėtume sukurti blokų grandinę?) ir atvejai, kuriuos galima įgyvendinti su jų pagalba (Kodėl turėtume kurti bylą?). Atėjo laikas dirbti savo rankomis! Norėdamas įgyvendinti pilotus ir PoC (Proof of Concept), norėčiau naudoti debesis, nes... juos galima pasiekti iš bet kurios pasaulio vietos ir dažnai nereikia gaišti laiko varginančiam aplinkos įrengimui, nes Yra iš anksto nustatytų konfigūracijų. Taigi, sukurkime ką nors paprasto, pavyzdžiui, monetų pervedimo tarp dalyvių tinklą ir kukliai pavadinkime jį Bitcoin. Tam naudosime IBM debesį ir universalią blockchain Hyperledger Fabric. Pirmiausia išsiaiškinkime, kodėl Hyperledger Fabric vadinamas universalia blokų grandine?
Hyperledger Fabric – universali blokų grandinė
Apskritai, universali informacinė sistema yra:
Serverių rinkinys ir programinės įrangos branduolys, atliekantis verslo logiką;
Sąsajos sąveikai su sistema;
Įrenginių/žmonių registravimo, autentifikavimo ir autorizacijos įrankiai;
Duomenų bazė, kurioje saugomi operatyviniai ir archyviniai duomenys:
Oficialią „Hyperledger Fabric“ versiją galite perskaityti adresu Dabar naršo, o trumpai tariant, Hyperledger Fabric yra atvirojo kodo platforma, leidžianti kurti privačias blokų grandines ir vykdyti savavališkas išmaniąsias sutartis, parašytas JS ir Go programavimo kalbomis. Išsamiai pažvelkime į „Hyperledger Fabric“ architektūrą ir įsitikinkime, kad tai universali sistema, turinti tik duomenų saugojimo ir įrašymo specifiką. Specifiškumas yra tas, kad duomenys, kaip ir visose blokų grandinėse, yra saugomi blokuose, kurie dedami į blokų grandinę tik tada, kai dalyviai pasiekia konsensusą ir įrašius duomenų negalima tyliai taisyti ar ištrinti.
Organizacijos — organizacijose yra bendraamžių, t.y. „blockchain“ egzistuoja dėl organizacijų paramos. Įvairios organizacijos gali būti vieno kanalo dalimi.
Kanalas — loginė struktūra, jungianti bendraamžius į grupes, t.y. nurodyta blokų grandinė. „Hyperledger Fabric“ gali vienu metu apdoroti kelias blokų grandines, turinčias skirtingą verslo logiką.
Narystės paslaugų teikėjas (MSP) yra CA (sertifikavimo institucija), išduodanti tapatybę ir priskirianti vaidmenis. Norėdami sukurti mazgą, turite bendrauti su MSP.
Lygiaverčiai mazgai - patikrinti sandorius, saugoti blokų grandinę, vykdyti išmaniąsias sutartis ir sąveikauti su programomis. Bendraamžiai turi tapatybę (skaitmeninį sertifikatą), kurį išduoda MSP. Skirtingai nuo Bitcoin arba Etherium tinklo, kuriame visi mazgai turi lygias teises, Hyperledger Fabric mazgai atlieka skirtingus vaidmenis:
Galbūt bendraamžis pritariantis bendraamžis (EP) ir vykdyti išmaniąsias sutartis.
Įsipareigojęs bendraamžis (CP) - išsaugokite duomenis tik blokų grandinėje ir atnaujinkite „Pasaulio būseną“.
Inkaro bendraamžis (AP) – jei blokų grandinėje dalyvauja kelios organizacijos, tada tarpusavio bendravimui naudojami inkaro partneriai. Kiekviena organizacija turi turėti vieną ar daugiau pagrindinių partnerių. Naudodamas AP, bet kuris organizacijos partneris gali gauti informacijos apie visus kitų organizacijų bendraamžius. Naudojamas informacijai tarp AP sinchronizuoti apkalbų protokolas.
Lyderis Peer — jei organizacija turi kelis bendraamžius, blokus iš Užsakymų tarnybos gaus ir kitiems bendraamžiams atiduos tik to partnerio vadovas. Lyderį gali nurodyti statiškai arba dinamiškai pasirinkti organizacijos bendraamžiai. Apkalbų protokolas taip pat naudojamas informacijai apie lyderius sinchronizuoti.
Aktyvai — subjektai, kurie turi vertę ir yra saugomi blokų grandinėje. Tiksliau tariant, tai yra JSON formato rakto vertės duomenys. Būtent šie duomenys yra įrašomi į Blockchain. Jie turi istoriją, kuri saugoma blokų grandinėje, ir dabartinę būseną, kuri saugoma „Pasaulio būsenos“ duomenų bazėje. Duomenų struktūros pildomos savavališkai, atsižvelgiant į verslo užduotis. Privalomų laukelių nėra, vienintelė rekomendacija – turtas turi turėti savininką ir būti vertingas.
buhalterijos didžioji knyga — susideda iš „Blockchain“ ir „Word“ būsenos duomenų bazės, kurioje saugoma dabartinė turto būklė. Pasaulio valstybė naudoja LevelDB arba CouchDB.
Protinga sutartis — naudojant išmaniąsias sutartis, įgyvendinama sistemos verslo logika. „Hyperledger Fabric“ išmaniosios sutartys vadinamos grandininiu kodu. Naudojant grandininį kodą, nurodomas turtas ir operacijos su jais. Techniniu požiūriu išmaniosios sutartys yra programinės įrangos moduliai, įdiegti JS arba Go programavimo kalbomis.
Patvirtinimo politika – kiekvienam grandinės kodui galite nustatyti politiką, kiek ir iš ko reikia tikėtis operacijos patvirtinimų. Jei politika nenustatyta, tada numatytasis nustatymas yra: „operaciją turi patvirtinti bet kurios kanalo organizacijos narys“. Politikos pavyzdžiai:
Sandoriui turi pritarti bet kuris organizacijos administratorius;
Turi patvirtinti bet kuris organizacijos narys ar klientas;
Turi būti patvirtinta bet kurios kolegos organizacijos.
Užsakymo paslauga - supakuoja operacijas į blokus ir siunčia juos bendraamžiams kanale. Garantuoja pranešimų pristatymą visiems bendraamžiams tinkle. Naudojamas pramoninėms sistemoms Kafka žinučių brokeris, kūrimui ir testavimui Solo.
CallFlow
Programa bendrauja su „Hyperledger Fabric“ naudodama „Go“, „Node.js“ arba „Java“ SDK;
Klientas sukuria tx operaciją ir siunčia ją patvirtinantiems kolegoms;
Partneris patikrina kliento parašą, užbaigia operaciją ir siunčia patvirtinimo parašą atgal klientui. Grandininis kodas vykdomas tik patvirtinančiame bendradarbyje, o jo vykdymo rezultatas siunčiamas visiems bendraamžiams. Šis darbo algoritmas vadinamas PBFT (Practical Byzantine Fault Tolerant) konsensusu. Skiriasi nuo klasikinis BFT tai, kad žinutė išsiųsta ir patvirtinimo laukiama ne iš visų dalyvių, o tik iš tam tikro rinkinio;
Klientas, gavęs patvirtinimo politiką atitinkantį atsakymų skaičių, siunčia operaciją Užsakymų tarnybai;
Užsakymo paslauga sukuria bloką ir siunčia jį visiems įsipareigojusiems partneriams. Užsakymo paslauga užtikrina nuoseklų blokų įrašymą, kuris pašalina vadinamąją knygos šakę (žiūrėkite skyrių "Šakės");
Bendraamžiai gauna bloką, dar kartą patikrina patvirtinimo politiką, įrašo bloką į blokų grandinę ir pakeičia būseną „World state“ DB.
Tie. Dėl to vaidmenys pasiskirsto tarp mazgų. Tai užtikrina, kad blokų grandinė yra keičiamo dydžio ir saugi:
Išmaniosios sutartys (grandinės kodas) patvirtina bendraamžius. Taip užtikrinamas išmaniųjų sutarčių konfidencialumas, nes jį saugo ne visi dalyviai, o tik pritariantys bendraamžiai.
Užsakymas turėtų veikti greitai. Tai užtikrina tai, kad „Ordering“ formuoja tik bloką ir siunčia jį fiksuotam lyderių bendraamžių rinkiniui.
Įsipareigoję bendraamžiai saugo tik blokų grandinę – jų gali būti daug ir jos nereikalauja daug energijos ir momentinio veikimo.
Taigi, Hyperledger Fabric yra tikrai universali sistema, su kuria galite:
Įdiegti savavališką verslo logiką naudojant išmaniųjų sutarčių mechanizmą;
Įrašykite ir gaukite duomenis iš blockchain duomenų bazės JSON formatu;
Suteikite ir patvirtinkite API prieigą naudodami sertifikavimo įstaigą.
Dabar, kai šiek tiek supratome apie „Hyperledger Fabric“ specifiką, pagaliau padarykime ką nors naudingo!
Blockchain diegimas
Problemos teiginys
Užduotis yra įdiegti Citcoin tinklą su šiomis funkcijomis: susikurti sąskaitą, gauti likutį, papildyti savo sąskaitą, pervesti monetas iš vienos sąskaitos į kitą. Nubraižykime objekto modelį, kurį toliau diegsime išmaniojoje sutartyje. Taigi, turėsime sąskaitas, kurios identifikuojamos pagal pavadinimus ir kuriose yra likutis, ir sąskaitų sąrašą. Paskyros ir sąskaitų sąrašas yra „Hyperledger Fabric“ turto atžvilgiu. Atitinkamai, jie turi istoriją ir dabartinę būklę. Pabandysiu tai aiškiai nupiešti:
Didžiausi skaičiai yra dabartinė būsena, kuri saugoma „Pasaulio būsenos“ duomenų bazėje. Po jais yra skaičiai, rodantys istoriją, kuri yra saugoma blokų grandinėje. Dabartinę turto būklę keičia sandoriai. Turtas keičiasi tik kaip visuma, todėl po operacijos sukuriamas naujas objektas, o dabartinė turto vertė patenka į istoriją.
IBM debesis
Mes sukuriame paskyrą IBM debesis. Norint naudoti „blockchain“ platformą, ji turi būti atnaujinta į „Pay-As-You-Go“. Šis procesas gali būti ne greitas, nes... IBM prašo papildomos informacijos ir ją patikrina rankiniu būdu. Teigiamai galiu pasakyti, kad IBM turi gerą mokomąją medžiagą, leidžiančią įdiegti „Hyperledger Fabric“ jų debesyje. Man patiko šios straipsnių ir pavyzdžių serijos:
Toliau pateikiamos IBM Blockchain platformos ekrano kopijos. Tai ne instrukcija, kaip sukurti blokų grandinę, o tiesiog užduoties apimties demonstravimas. Taigi savo tikslams sudarome vieną organizaciją:
Jame kuriame mazgus: Orderer CA, Org1 CA, Orderer Peer:
Kuriame vartotojus:
Sukurkite kanalą ir pavadinkite jį citcoin:
Iš esmės „Channel“ yra „blockchain“, todėl jis prasideda nuo nulio bloko (Genesis blokas):
Protingos sutarties rašymas
/*
* 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;
Intuityviai čia viskas turėtų būti aišku:
Yra keletas funkcijų (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), kurias demonstracinė programa iškvies naudodama Hyperledger Fabric API.
Funkcijos SendFrom ir RefillBalance generuoja įvykius, kuriuos gaus demonstracinė programa.
Instantiavimo funkcija iškviečiama vieną kartą, kai yra išmanioji sutartis. Tiesą sakant, jis vadinamas ne vieną kartą, o kiekvieną kartą, kai keičiasi išmaniosios sutarties versija. Todėl sąrašo inicijavimas tuščiu masyvu yra bloga idėja, nes Dabar, kai pakeisime išmaniosios sutarties versiją, prarasime dabartinį sąrašą. Bet viskas gerai, aš tik mokausi).
Paskyros ir paskyrų sąrašas yra JSON duomenų struktūros. JS naudojamas duomenų apdorojimui.
Dabartinę turto vertę galite gauti naudodami funkcijos getState iškvietimą ir atnaujinti naudodami putState.
Kuriant Paskyrą iškviečiama AddAccount funkcija, kurioje lyginamas maksimalus blokų grandinėje esančių paskyrų skaičius (maxAccounts = 5). Ir čia yra stakta (ar pastebėjote?), dėl kurios be galo daugėja paskyrų. Reikėtų vengti tokių klaidų)
Tada įkeliame išmaniąją sutartį į kanalą ir ją sukuriame:
Pažvelkime į „Smart Contract“ diegimo operaciją:
Pažiūrėkime išsamią informaciją apie mūsų kanalą:
Dėl to gauname šią „blockchain“ tinklo schemą IBM debesyje. Diagramoje taip pat parodyta demonstracinė programa, veikianti „Amazon“ debesyje virtualiame serveryje (daugiau apie tai kitame skyriuje):
„Hyperledger Fabric“ API skambučių GUI kūrimas
„Hyperledger Fabric“ turi API, kurią galima naudoti:
Sukurti kanalą;
Ryšiai su kanalu;
Išmaniųjų sutarčių diegimas ir realizavimas kanale;
Skambinimo operacijos;
Prašyti informacijos apie blokų grandinę.
Programų kūrimas
Demonstracinėje programoje API naudosime tik norėdami iškviesti operacijas ir prašyti informacijos, nes Likusius veiksmus jau atlikome naudodami IBM blockchain platformą. Rašome GUI naudodami standartinį technologijų krūvą: Express.js + Vue.js + Node.js. Galite parašyti atskirą straipsnį apie tai, kaip pradėti kurti modernias žiniatinklio programas. Čia paliksiu nuorodą į man labiausiai patikusį paskaitų ciklą: „Full Stack“ žiniatinklio programa naudojant „Vue.js“ ir „Express.js“.. Rezultatas yra kliento-serverio programa su pažįstama grafine sąsaja Google Material Design stiliumi. REST API tarp kliento ir serverio susideda iš kelių skambučių:
HyperledgerDemo/v1/accounts/list — gauti visų paskyrų sąrašą;
HyperledgerDemo/v1/account?name=Bob&balance=100 — sukurti Bobo paskyrą;
HyperledgerDemo/v1/info?account=Bob — gauti informacijos apie Bob paskyrą;
HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 – perkelkite dvi monetas iš Bobo Alisai;
HyperledgerDemo/v1/disconnect – uždarykite ryšį su blokų grandine.
API aprašymas su pavyzdžiais, įtrauktais į Paštininko svetainė - gerai žinoma programa, skirta HTTP API testavimui.
Demonstracinė programa „Amazon“ debesyje
Įkėliau programą į „Amazon“, nes... IBM vis dar negalėjo atnaujinti mano paskyros ir leisti kurti virtualius serverius. Kaip pridėti vyšnią prie domeno: www.citcoin.info. Palaikysiu serverį kurį laiką įjungtą, tada išjungsiu, nes... varva centai už nuomą, o citkoinų monetos dar neįtrauktos į biržą) Straipsnyje įdedu demo ekrano kopijas, kad būtų aiški darbo logika. Demonstracinė programa gali:
Inicijuoti blokų grandinę;
Susikurti Paskyrą (tačiau dabar naujos Paskyros kurti negalite, nes blokų grandinėje pasiektas maksimalus išmaniojoje sutartyje nurodytas paskyrų skaičius);
Gauti sąskaitų sąrašą;
Perkelkite citcoin monetas tarp Alisos, Bobo ir Alekso;
Gauti įvykius (tačiau dabar nėra galimybės rodyti įvykių, todėl dėl paprastumo sąsaja sako, kad įvykiai nepalaikomi);
Žurnalo veiksmai.
Pirmiausia inicijuojame blokų grandinę:
Tada sukuriame savo sąskaitą, nešvaistydami laiko su likučiu:
Gauname visų galimų paskyrų sąrašą:
Mes pasirenkame siuntėją ir gavėją ir gauname jų likučius. Jei siuntėjas ir gavėjas yra tas pats, tada jo sąskaita bus papildyta:
Žurnale stebime operacijų vykdymą:
Tiesą sakant, visa tai yra demonstracinėje programoje. Žemiau galite pamatyti mūsų sandorį blokų grandinėje:
Ir bendras operacijų sąrašas:
Taip sėkmingai užbaigėme PoC, kad sukurtume Citcoin tinklą. Ką dar reikia padaryti, kad „Citcoin“ taptų visaverčiu monetų pervedimo tinklu? Labai mažai:
Paskyros kūrimo etape įdiekite privataus / viešo rakto generavimą. Privatus raktas turi būti saugomas pas paskyros vartotoją, viešasis raktas turi būti saugomas blokų grandinėje.
Atlikite monetų pervedimą, kai vartotojui identifikuoti naudojamas viešasis raktas, o ne vardas.
Šifruokite operacijas, einančias iš vartotojo į serverį, naudodami jo privatų raktą.
išvada
Įdiegėme Citcoin tinklą su šiomis funkcijomis: pridėti sąskaitą, gauti likutį, papildyti savo sąskaitą, pervesti monetas iš vienos sąskaitos į kitą. Taigi, kiek mums kainavo sukurti PoC?
Jums reikia studijuoti blokų grandinę apskritai ir ypač Hyperledger Fabric;
Išmok naudotis IBM arba Amazon debesimis;
Išmokti JS programavimo kalbą ir tam tikrą žiniatinklio sistemą;
Jei kai kuriuos duomenis reikia saugoti ne blokų grandinėje, o atskiroje duomenų bazėje, tai išmokite integruoti, pavyzdžiui, su PostgreSQL;
Ir paskutinis, bet ne mažiau svarbus dalykas - jūs negalite gyventi šiuolaikiniame pasaulyje be žinių apie Linux!)
Žinoma, tai nėra raketų mokslas, bet jūs turėsite sunkiai dirbti!
Šaltiniai GitHub
Uždėti šaltiniai GitHub. Trumpas saugyklos aprašymas:
Katalogas «serveris» — Node.js serveris
Katalogas «klientas» — Node.js klientas
Katalogas «blockchain"(parametrų reikšmės ir raktai, žinoma, neveikia ir pateikiami tik kaip pavyzdys):
sutartis – išmaniosios sutarties šaltinio kodas
piniginė – vartotojo raktai, skirti naudoti Hyperledger Fabric API.
*.cds – sukompiliuotos išmaniųjų sutarčių versijos
*.json failai – konfigūracijos failų, skirtų naudoti Hyperledger Fabric API, pavyzdžiai