Blockchain: millise PoC peaksime ehitama?

Su silmad kardavad ja käed sügelevad!

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?

Blockchain: millise PoC peaksime ehitama?

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:

Blockchain: millise PoC peaksime ehitama?

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:

Blockchain: millise PoC peaksime ehitama?

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

Blockchain: millise PoC peaksime ehitama?

  • 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.

Lisateavet Hyperledger Fabricu arhitektuursete lahenduste ja selle kohta, miks see nii ja mitte teisiti töötab, leiate siit: Arhitektuuri päritolu või siin: Hyperledger Fabric: hajutatud operatsioonisüsteem lubatud plokiahelate jaoks.

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:

Blockchain: millise PoC peaksime ehitama?

Ü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:

Blockchain: millise PoC peaksime ehitama?

Loome selles sõlmed: Tellija CA, Org1 CA, Tellija Peer:

Blockchain: millise PoC peaksime ehitama?

Loome kasutajaid:

Blockchain: millise PoC peaksime ehitama?

Looge kanal ja nimetage seda citcoiniks:

Blockchain: millise PoC peaksime ehitama?

Põhimõtteliselt on kanal plokiahel, nii et see algab plokist nullist (Genesise plokk):

Blockchain: millise PoC peaksime ehitama?

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:

Blockchain: millise PoC peaksime ehitama?

Vaatame Smart Contracti installimise tehingut:

Blockchain: millise PoC peaksime ehitama?

Vaatame meie kanali üksikasju:

Blockchain: millise PoC peaksime ehitama?

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):

Blockchain: millise PoC peaksime ehitama?

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/init – plokiahela lähtestamine;
  • HyperledgerDemo/v1/accounts/list — hankige kõigi kontode loend;
  • HyperledgerDemo/v1/account?name=Bob&balance=100 — loo Bobi konto;
  • HyperledgerDemo/v1/info?account=Bob — hankige teavet Bobi konto kohta;
  • 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:

Blockchain: millise PoC peaksime ehitama?

Järgmisena loome oma konto, ärge raisake aega saldoga:

Blockchain: millise PoC peaksime ehitama?

Saame kõigi saadaolevate kontode loendi:

Blockchain: millise PoC peaksime ehitama?

Valime saatja ja saaja ning saame nende saldod. Kui saatja ja saaja on samad, täiendatakse tema kontot:

Blockchain: millise PoC peaksime ehitama?

Logis jälgime tehingute täitmist:

Blockchain: millise PoC peaksime ehitama?

Tegelikult on see kõik demoprogrammiga. Allpool näete meie tehingut plokiahelas:

Blockchain: millise PoC peaksime ehitama?

Ja tehingute üldine loend:

Blockchain: millise PoC peaksime ehitama?

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.
  • *.cds – nutikate lepingute kompileeritud versioonid
  • *.json-failid – konfiguratsioonifailide näited Hyperledger Fabric API kasutamiseks

See on alles algus!

Allikas: www.habr.com

Lisa kommentaar