Blockchain: čo nás stojí PoC vybudovať?

Oči sa bojažia, ale ruky svrbia!

V predchádzajúcich článkoch sme sa zaoberali technológiami, na ktorých sú postavené blockchainy (Čo nám stojí postaviť blockchain?) a prípadmi, ktoré je možné s ich pomocou realizovať (Aké je našou úlohou postaviť prípad?). Prišiel čas zamerať sa na praktickú prácu! Na realizáciu pilotných projektov a PoC (Proof of Concept) uprednostňujem používanie cloudových služieb, pretože k nim je prístup z ktorejkoľvek časti sveta a často nemusím tráviť čas nudnou inštaláciou prostredia, pretože existujú predkonfigurované nastavenia. Takže, poďme spraviť niečo jednoduché, napríklad sieť na prevod mincí medzi účastníkmi, a skromne ju nazveme CitiCoin. Na to budeme používať cloud od IBM a univerzálny blockchain Hyperledger Fabric. Na začiatok sa pozrime, prečo sa Hyperledger Fabric nazýva univerzálnym blockchainom?

Blockchain: čo nás stojí PoC vybudovať?

Hyperledger Fabric — univerzálny blockchain

Vo všeobecnosti je univerzálna informačná sústava:

  • Súbor serverov a programové jadro, ktoré vykonáva biznis logiku;
  • Rozhrania na interakciu so systémom;
  • Prostriedky na registráciu, autentifikáciu a autorizáciu zariadení / ľudí;
  • Dátová báza, ktorá uchováva prevádzkové a archívne dáta:

Blockchain: čo nás stojí PoC vybudovať?

Oficiálnu verziu toho, čo je Hyperledger Fabric, si môžete prečítať na webe, a ak to zhrnieme, Hyperledger Fabric je opensource platforma, ktorá umožňuje vytvárať uzavreté blockchainy a vykonávať libovolné smart kontrakty napísané v programovacích jazykoch JS a Go. Pozrime sa podrobne na architektúru Hyperledger Fabric a presvedčme sa, že ide o univerzálny systém, ktorý má len špecifiku v ukladaní a zapisovaní dát. Špecifikum spočíva v tom, že dáta, podobne ako vo všetkých blockchainoch, sú uložené v blokoch, ktoré sú vložené do blockchainu len v prípade, že účastníci dosiahli konsenzus, a po zapísaní nie je možné tieto dáta nenápadne upraviť alebo odstrániť.

Architektúra Hyperledger Fabric

Na schéme je zobrazená architektúra Hyperledger Fabric:

Blockchain: čo nás stojí PoC vybudovať?

Organizácie — organizácie obsahujú peer-ov, pričom blockchain existuje vďaka podpore organizácií. Rôzne organizácie môžu byť súčasťou jedného kanála.

Channel — logická štruktúra, ktorá spája peer-ov do skupín, čím sa určuje blockchain. Hyperledger Fabric môže súčasne spracovávať viacero blockchainov s rôznou biznis logikou.

Membership Services Provider (MSP) — je to CA (Certificate Authority) na vydávanie identities a prideľovanie rolí. Na vytvorenie uzla je potrebné interagovať s MSP.

Peer uzly — kontrolujú transakcie, ukladajú blockchain, vykonávajú smart kontrakty a komunikujú s aplikáciami. Peer uzly majú identitu (digitálny certifikát), ktorý vydáva MSP. Na rozdiel od sietí Bitcoin alebo Ethereum, kde sú všetky uzly rovnaké, v Hyperledger Fabric majú uzly rôzne úlohy:

  • Peer môže byť endorzujúci peer (EP) a môže vykonávať smart kontrakty.
  • Zachovávajúci peer (CP) — len ukladajú dáta do blockchainu a aktualizujú "World state".
  • Anchor Peer (AP) — ak sa do blockchainu zapája niekoľko organizácií, tak sa anchor peer využívajú na spojenie medzi nimi. Každá organizácia musí mať jeden alebo niekoľko anchor peer. Pomocou AP môže akýkoľvek peer v organizácii získať informácie o všetkých peer-och v iných organizáciách. Na synchronizáciu informácií medzi AP sa používa gossip protokol.
  • Líder Peer — ak organizácia má niekoľko peer-ov, len líder peer bude prijímať bloky z Ordering service a distribuovať ich ostatným peer-om. Líder môže byť nastavený staticky, alebo vybraný dynamicky peer-ami v organizácii. Na synchronizáciu informácií o lídroch sa tiež používa gossip protokol.

Aktíva — entity, ktoré majú hodnotu a sú uložené v blockchainu. Presnejšie ide o key-value dáta vo formáte JSON. Práve tieto dáta sú zapisované do blockchainu „Blockchain“. Majú históriu, ktorá je uložená v blockchainu, a aktuálny stav, ktorý je uložený v databáze „World state“. Štruktúry dát sa napĺňajú libovoľne v závislosti od obchodných úloh. Nie sú žiadne povinné polia, jedinou odporúčanou podmienkou je, že aktíva by mali mať vlastníka a predstavovať hodnotu.

Ledger — pozostáva z blockchainu „Blockchain“ a databázy „World state“, v ktorej sa uchováva aktuálny stav aktív. World state využíva LevelDB alebo CouchDB.

Smart kontrakt — pomocou smart kontraktov sa realizuje obchodná logika systému. V Hyperledger Fabric sa smart kontrakty nazývajú chaincode. Pomocou chaincode sa definujú aktíva a transakcie s nimi. Ak hovoríme technicky, tak smart kontrakty sú programové moduly implementované v programovacích jazykoch JS alebo Go.

Politika schválenia — pre každý chaincode je možné nastaviť politiky, koľko a od koho je potrebné očakávať potvrdenia pre transakciu. Ak politika nie je nastavená, predvolene sa používa: “transakciu musí potvrdiť akýkoľvek člen (member) akejkoľvek organizácie v channel”. Príklady politík:

  • Transakciu musí potvrdiť ktorýkoľvek administrátor organizácie;
  • Musí potvrdiť ktorýkoľvek člen (member) alebo klient organizácie;
  • Musí potvrdiť ktorýkoľvek peer organizácie.

Služba Ordering — balí transakcie do blokov a posiela ich peer-om v kanáli. Zabezpečuje doručenie správ všetkým peer-om v sieti. Pre priemyselné systémy sa používa správy broker Kafka, pre vývoj a testovanie Solo.

CallFlow

Blockchain: čo nás stojí PoC vybudovať?

  • Aplikácia interaguje s Hyperledger Fabric, používajúc Go, Node.js alebo Java SDK;
  • Klient vytvára transakciu tx a posiela ju na endorsing peer-ov;
  • Peer kontroluje podpis klienta, vykonáva transakciu a posiela endorsement signature späť klientovi. Chaincode sa vykonáva len na endorsing peer, a výsledok jeho vykonania sa rozosiela na všetky peer-y. Takýto algoritmus práce sa nazýva — PBFT (Practical Byzantine Fault Tolerant) konsenzus. Rozdiel oproti klasickému BFT spočíva v tom, že správa sa rozosiela a očakáva potvrdenie nie od všetkých účastníkov, ale iba od konkrétneho súboru;
  • Keď klient dostane počet odpovedí zodpovedajúci endorsement policy, posiela transakciu na službu Ordering;
  • Služba Ordering vytvára blok a posiela ho všetkým committing peer-om. Služba Ordering zabezpečuje sekvenčné zapisovanie blokov, čím sa vylučuje takzvané ledger fork (pozri časť „Forky“);
  • Peer-om príde blok, opäť overia endorsement policy, zapíšu blok do blockchainu a zmenia stav v „World state“ DB.

To znamená, že dochádza k rozdeleniu rolí medzi nódami. To zabezpečuje škálovateľnosť a bezpečnosť blockchainu:

  • Smart kontrakty (chaincode) vykonávajú endorsing peer-ov. To zabezpečuje dôvernosť smart kontraktov, keďže sú uchovávané nie u všetkých účastníkov, ale len na endorsing peer-och.
  • Ordering musí fungovať rýchlo. To sa zabezpečuje tým, že Ordering iba vytvára blok a posiela ho na pevný súbor leader peer-ov.
  • Committing peers iba uchovávajú blockchain — ich môže byť veľa a nevyžadujú veľkú výkonovú kapacitu a okamžitú prácu.

Podrobnejšie architektonické riešenia Hyperledger Fabric a prečo funguje tak, a nie inak, si môžete pozrieť tu: Architektúra Pôvodu alebo tu: Hyperledger Fabric: Distribuovaný operačný systém pre povolené blockchainy.

Takže, Hyperledger Fabric je naozaj univerzálny systém, pomocou ktorého môžete:

  • Realizovať ľubovoľnú obchodnú logiku, používajúc mechanizmus smart kontraktov;
  • Zaznamenávať a získavať údaje z blockchain databázy vo formáte JSON;
  • Poskytovať a overovať prístup k API pomocou certifikačnej autority.

Teraz, keď sme si trochu objasnili špecifiká Hyperledger Fabric, poďme konečne spraviť niečo užitočné!

Rozvíjame blockchain

Stanovenie úlohy

Úloha — realizovať sieť Citcoin s nasledujúcimi funkciami: vytvoriť účet, získať zostatok, doplniť účet, previesť mince z jedného účtu na druhý. Vykreslíme objektový model, ktorý neskôr implementujeme v smart kontrakte. Takže budeme mať účty, ktoré sú identifikované menami (name) a obsahujú zostatok (balance), a zoznam účtov. Účty a zoznam účtov — to sú v termínoch Hyperledger Fabric aktíva. Zodpovedajúcim spôsobom majú históriu a aktuálny stav. Pokúsim sa to názorne znázorniť:

Blockchain: čo nás stojí PoC vybudovať?

Horné postavy — to je aktuálny stav, ktorý sa uchováva v databáze „World state“. Pod nimi postavy, ktoré ukazujú históriu, ktorá sa uchováva v blockchain. Aktuálny stav aktív sa mení transakciami. Aktívum sa mení iba celé, preto sa v dôsledku vykonania transakcie vytvára nový objekt a aktuálna hodnota aktíva prechádza do histórie.

IBM Cloud

Zakladáme účet v IBM cloude. Na používanie blockchain platformy ju treba upgradovať na Pay-As-You-Go. Tento proces nemusí byť rýchly, pretože IBM požaduje ďalšie informácie a kontroluje ich ručne. Z pozitívneho hľadiska môžem povedať, že IBM má skvelé vzdelávacie materiály, ktoré umožňujú rozvinúť Hyperledger Fabric v ich cloude. Páčil sa mi nasledujúci cyklus článkov a príkladov:

Nasledujú obrazovky Blockchain platformy IBM. Toto nie je návod na vytváranie blockchainu, ale jednoducho ukážka rozsahu úlohy. Takže pre naše účely vytvárame jednu Organizáciu:

Blockchain: čo nás stojí PoC vybudovať?

V nej vytvárame uzly: Orderer CA, Org1 CA, Orderer Peer:

Blockchain: čo nás stojí PoC vybudovať?

Zakladáme používateľov:

Blockchain: čo nás stojí PoC vybudovať?

Vytvárame Channel a nazývame ho citcoin:

Blockchain: čo nás stojí PoC vybudovať?

V podstate Channel — to je blockchain, preto začína s nulovým blokom (Genesis block):

Blockchain: čo nás stojí PoC vybudovať?

Píšeme Smart Contract

/*
 * 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;

Intuitívne by to malo byť všetko jasné:

  • Existuje niekoľko funkcií (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), ktoré bude vyžadovať demo program pomocou Hyperledger Fabric API.
  • Funkcie SendFrom a RefillBalance generujú udalosti (Event), ktoré dostane demo program.
  • Funkcia instantiate – sa volá len raz pri inštancii smart kontraktu. V skutočnosti sa volá nie jedenkrát, ale zakaždým pri zmene verzie smart kontraktu. Preto inicializácia zoznamu prázdnym poľom nie je dobrý nápad, pretože pri zmene verzie smart kontraktu prídeme o aktuálny zoznam. Ale nič, len sa učím).
  • Účty a zoznam účtov (accounts) – to sú JSON štruktúry údajov. Na manipuláciu s údajmi sa používa JS.
  • Aktuálnu hodnotu assetu môžeme získať pomocou volania funkcie getState, a aktualizovať pomocou putState.
  • Pri vytváraní účtu sa volá funkcia AddAccount, v ktorej sa porovnáva maximálny počet účtov v blockchaine (maxAccounts = 5). A tu je problém (ste si všimli?), ktorý vedie k nekonečnému rastu počtu účtov. Takýmto chybám je potrebné sa vyhýbať).

Ďalej nahráme smart kontrakt do Channel a inštancujeme ho:

Blockchain: čo nás stojí PoC vybudovať?

Pozrime sa na transakciu na nastavenie Smart Contract:

Blockchain: čo nás stojí PoC vybudovať?

Pozrime sa na podrobnosti o našom Channel:

Blockchain: čo nás stojí PoC vybudovať?

V dôsledku získavame nasledujúcu schému blockchain siete v cloude IBM. Na schéme je tiež demoprogram, ktorý je spustený v cloude Amazon na virtuálnom serveri (podrobnosti o ňom budú v ďalšej časti):

Blockchain: čo nás stojí PoC vybudovať?

Vytvorenie GUI pre volania Hyperledger Fabric API

Hyperledger Fabric má API, ktoré sa môže použiť na:

  • Vytvorenie channel;
  • Pripojenie peer k channel;
  • Inštaláciu a inštancovanie smart kontraktov v channel;
  • Volanie transakcií;
  • Žiadosť o informácie v blockchaine.

Vývoj aplikácie

V našej demoprogramu budeme používať API len na volanie transakcií a žiadosť o informácie, pretože ostatné kroky sme už uskutočnili pomocou blockchain platformy IBM. Píšeme GUI s použitím štandardného technologického stacku: Express.js + Vue.js + Node.js. O tom, ako začať vytvárať moderné webové aplikácie, by sa mohla napísať samostatná článok. Tu nechám odkaz na sériu prednášok, ktorá sa mi najviac páčila: Full Stack Web App using Vue.js & Express.js. V dôsledku toho vzniklo klient-serverové aplikácie so známym grafickým rozhraním v štýle Material Design od Google. REST API medzi klientom a serverom pozostáva z niekoľkých volaní:

  • HyperledgerDemo/v1/init – inicializovať blockchain;
  • HyperledgerDemo/v1/accounts/list – získať zoznam všetkých účtov;
  • HyperledgerDemo/v1/account?name=Bob&balance=100 – vytvoriť účet Bob;
  • HyperledgerDemo/v1/info?account=Bob – získať informácie o účte Bob;
  • HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — previesť dve mince od Bob k Alice;
  • HyperledgerDemo/v1/disconnect — uzavrieť spojenie s blokchainom.

Popis API s príkladmi som dal na stránku „Postman“ — široko známy program na testovanie HTTP API.

Demo aplikácia v cloude Amazon

Aplikáciu som nahral na Amazon, pretože IBM doteraz nemohol aktualizovať môj účet a povoliť mi vytvárať virtuálne servery. Ako pomyselnú čerešničku som pridal doménu: www.citcoin.info. Trochu podporím server zapnutý, potom ho vypnem, pretože centy za prenájom sa kumulujú, a mince citcoin na burze ešte nie sú obchodované) Do článku vkladám screenshoty demoa, aby bola zrozumiteľná logika fungovania. Demo aplikácia môže:

  • Inicializovať blockchain;
  • Vytvárať účet (ale teraz nie je možné vytvoriť nový účet, pretože v blockchaine bolo dosiahnuté maximálne číslo účtov, uvedené v smart kontrakte);
  • Získať zoznam účtov;
  • Prevádzať mince citcoin medzi Alice, Bobom a Alexom;
  • Získavať udalosti (ale teraz sa žiadne udalosti nemôžu zobraziť, preto je v rozhraní zjednodušene napísané, že udalosti nie sú podporované);
  • Registrovať akcie.

Najprv inicializujeme blockchain:

Blockchain: čo nás stojí PoC vybudovať?

Potom si zakladáme svoj účet, nešetriac s bilanciou:

Blockchain: čo nás stojí PoC vybudovať?

Získavame zoznam všetkých dostupných účtov:

Blockchain: čo nás stojí PoC vybudovať?

Vyberáme odosielateľa a príjemcu, a získavame ich zostatky. Ak je odosielateľ a príjemca ten istý, dojde k navýšeniu jeho zostatku:

Blockchain: čo nás stojí PoC vybudovať?

V logu sledujeme vykonávanie transakcií:

Blockchain: čo nás stojí PoC vybudovať?

Vlastne s demo programom je to všetko. Potom si môžeme pozrieť našu transakciu v blockchaine:

Blockchain: čo nás stojí PoC vybudovať?

A celkový zoznam transakcií:

Blockchain: čo nás stojí PoC vybudovať?

Týmto sme úspešne ukončili implementáciu PoC na vytvorenie siete Citcoin. Čo ešte potrebujeme urobiť, aby sa Citcoin stal plnohodnotnou sieťou na prevod mincí? Veľmi málo:

  • V etape vytvárania účtu realizovať generáciu súkromného / verejného kľúča. Súkromný kľúč by mal byť uložený u užívateľa účtu, verejný v blockchaine.
  • Urobiť prevod mincí, pri ktorom sa na identifikáciu užívateľa používa nie meno, ale verejný kľúč.
  • Šifrovať transakcie, ktoré idú od užívateľa na server jeho súkromným kľúčom.

Záver

Implementovali sme sieť Citcoin s funkciami: pridať účet, získať zostatok, doplniť svoj účet, previesť mince z jedného účtu na iný. Takže, čo nás stálo postaviť PoC?

  • Je potrebné študovať blockchain všeobecne a Hyperledger Fabric konkrétne;
  • Naučiť sa používať cloudy IBM alebo Amazon;
  • Naučiť sa programovací jazyk JS a nejaký webový framework;
  • Ak je potrebné uchovávať niektoré údaje mimo blockchainu, naučiť sa integráciu, napríklad, s PostgreSQL;
  • A posledné, ale nie menej dôležité — bez znalosti Linuxu sa v modernom svete nikam nepohneme!)

Samozrejme, nie je to raketová veda, ale bude treba zapotiť sa!

Zdrojové kódy na GitHub

Súbory sú uložené na GitHub. Stručný popis repozitára:
Adresár „server“ — Node.js server
Adresár „client“ — Node.js klient
Adresár „blockchain“ (hodnoty parametrov a kľúče sú, samozrejme, nefunkčné a uvedené iba ako príklad):

  • contract — zdrojový kód smart kontraktu
  • wallet — kľúče používateľa pre použitie Hyperledger Fabric API.
  • *.cds — skompilované verzie smart kontraktov
  • *.json súbory — príklady konfiguračných súborov pre použitie Hyperledger Fabric API

Je to len začiatok!

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster