Plokiahel: mida me peame PoC’i loomiseks?

Silmad kardavad, kuid kĂ€ed sĂŒgelevad!

Eelmistes artiklites arutlesime tehnoloogiate ĂŒle, millele plokiahelad toetuvad (Mis on vajalik blockchain'i loomiseks?) ja juhtumite ĂŒle, mida nende abil ellu viia (Mis meid takistab juhtumi loomisel?). On aeg asuda tegudele! Pilootprojekti ja PoC (Proof of Concept) elluviimiseks eelistan kasutada pilveteenuseid, kuna neile pÀÀseb ligi igast maailma nurgast ja sageli ei pea aega raiskama tĂŒĂŒtule keskkonna seadistamisele, kuna eksisteerivad eelkonfigureeritud lahendused. Alustame millegi lihtsa loomist, nĂ€iteks vĂ”rku raha ĂŒlekandmiseks osalejate vahel, ja nimetame seda tagasihoidlikult Citcoiniks. Selleks kasutame IBM-i pilve ja universaalset plokiahelat Hyperledger Fabric. Esmalt uurime, miks Hyperledger Fabrici nimetatakse universaalseks plokiahelaks?

Plokiahel: mida me peame PoC’i loomiseks?

Hyperledger Fabric — universaalne plokiahel

Üldiselt öeldes on universaalne teabesĂŒsteem:

  • Serverite kogum ja tarkvara sĂŒda, mis tĂ€idab Ă€ri loogikat;
  • Liidesed sĂŒsteemiga suhtlemiseks;
  • Seadmete / inimeste registreerimise, autentimise ja autoriseerimise vahendid;
  • Andmebaas, mis salvestab operatiivsed ja arhiivandmed:

Plokiahel: mida me peame PoC’i loomiseks?

Hyperledger Fabrici ametlikku definitsiooni saab lugeda veebisaidil, kuid lĂŒhidalt öeldes on Hyperledger Fabric avatud lĂ€htekoodiga platvorm, mis vĂ”imaldab luua suletud plokiahelasid ja teostada mis tahes nutikaid lepinguid, mis on kirjutatud programmeerimiskeeltes JS ja Go. Vaatame lĂ€hemalt Hyperledger Fabrici arhitektuuri ja veendume, et see on universaalne sĂŒsteem, millel on ainult andmete salvestamise ja kirjutamise eripĂ€ra. EripĂ€ra seisneb selles, et andmed, nagu kĂ”igis plokiahelates, salvestatakse plokkides, mis lisatakse plokiahelasse ainult siis, kui osalised saavutavad konsensuse, ja pĂ€rast salvestamist ei saa andmeid mĂ€rkamatult muuta vĂ”i eemaldada.

Hyperledger Fabrici arhitektuur

Diagrammil on kujutatud Hyperledger Fabrici arhitektuur:

Plokiahel: mida me peame PoC’i loomiseks?

Organisatsioonid — organisatsioonidesse kuuluvad peerid, seega toetavad plokiahelat organisatsioonid. Erinevad organisatsioonid vĂ”ivad kuuluda ĂŒhte kanali.

Kanal — loogiline struktuur, mis ĂŒhendab peer'e gruppidesse, seega mÀÀratleb plokiahela. Hyperledger Fabric suudab samal ajal töödelda mitmeid plokiahelaid erineva Ă€ri loogikaga.

Liikmeministeerium (MSP) — see on CA (sertifitseerimisasutus), mis annab identiteete ja mÀÀrab rolle. Noodi loomiseks tuleb suhelda MSP-ga.

Peer nodes — kontrollivad tehinguid, salvestavad plokiahelat, tĂ€idavad nutilepinguid ja suhtlevad rakendustega. Peeridel on identiteet (digitaalne sertifikaat), mille annab vĂ€lja 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 andmeid plokiahelasse ja uuendavad "World state".
  • Anchor Peer (AP) — kui plokiahelas osaleb mitu organisatsiooni, kasutatakse ankur-peer'e nende vaheliseks suhtlemiseks. Igal organisatsioonil peab olema ĂŒks vĂ”i mitu ankur-peer'i. AP abil vĂ”ib iga peer organisatsioonis saada teavet kĂ”igi teiste organisatsioonide peer'ide kohta. Teabe sĂŒmbioosi saavutamiseks kasutatakse gossip protokolli.
  • Leader Peer — kui organisatsioonil on mitu peer'i, siis ainult liider-peer saab blokeerida Ordering service'ist ja edastada neid teistele peer'idele. Liidrit vĂ”ib mÀÀrata staatiliselt vĂ”i valida dĂŒnaamiliselt organisatsioonis olevate peer'ide poolt. Liidrite vahelise teabe sĂŒnkroniseerimiseks kasutatakse samuti gossip protokolli.

Assets — vÀÀrtuslikud ĂŒksused, mida hoitakse plokiahelas. Veelgi tĂ€psemalt — need on key-value andmed JSON formaadis. Just need andmed salvestatakse plokiahelasse "Blockchain". Neil on ajalugu, mida hoitakse plokiahelas ja praegune seisund, mis hoitakse andmebaasis "World state". Andmestruktuure tĂ€iendatakse vastavalt Ă€rivajadustele. Kohustuslikke vĂ€lju ei ole, ainus soovitus on, et varadel peab olema omanik ja need peaksid esindama vÀÀrtust.

Ledger — koosneb plokiahest "Blockchain" ja andmebaasist "World state", kus hoitakse varade praegust seisundit. World state kasutab LevelDB vĂ”i CouchDB.

Smart contract — nutilepingute kaudu rakendatakse sĂŒsteemi Ă€riloogikat. Hyperledger Fabricis nimetatakse nutilepinguid chaincode'iks. Chaincode'i abil mÀÀratakse varad ja tehingud nendega. Tehniliselt öeldes on nutilepingud programmeerimismoodulid, mis on ellu viidud programmeerimiskeeltel JS vĂ”i Go.

Endorsement policy — iga chaincode'i jaoks vĂ”ib mÀÀrata poliitika, kui palju ja kellelt on vaja tehingu kinnitust. Kui poliitika pole mÀÀratud, kasutatakse vaikimisi: "tehingut peab kinnitama iga liikmesorganisatsiooni liige kanalil". Poliitika nĂ€idised:

  • Tehingu peab kinnitama organisatsiooni mis tahes administraator;
  • Peab kinnitama organisatsiooni mis tahes liige vĂ”i klient;
  • Peab kinnitama organisatsiooni mis tahes peer.

Tellimisteenus — pakib tehingud plokkidesse ja saadab need peer-idele kanalis. Tagab sĂ”numite edastamise kĂ”ikidele peer-idele vĂ”rgus. Tööstuslike sĂŒsteemide jaoks kasutatakse Kafka sĂ”numite maaklerit, arendamiseks ja testimiseks Solo.

CallFlow

Plokiahel: mida me peame PoC’i loomiseks?

  • Rakendus suhtleb Hyperledger Fabric'iga, kasutades Go, Node.js vĂ”i Java SDK-d;
  • Kliendil on tehingu tx ja saadab selle endorseerimise peer-idele;
  • Peer kontrollib kliendi allkirja, viib tehingu lĂ€bi ja saadab tagasi endorsement signature kliendile. Chaincode viiakse lĂ€bi ainult endorseerimise peer-ides ning selle tĂ€itmise tulemus saadetakse kĂ”igile peer-idele. Sellist töömeetodit nimetatakse — PBFT (Practical Byzantine Fault Tolerant) konsensus. Erineb klassikalisest BFT-st selle poolest, et sĂ”num saadetakse ja oodatakse kinnitamist mitte kĂ”igilt osalejatelt, vaid ainult kindlast kogumist;
  • PĂ€rast seda, kui klient on saanud vastuste arvu, mis vastab endorsement policy-le, saadab ta tehingu tellimisteenusele;
  • Tellimisteenus koostab ploki ja saadab selle kĂ”ikidele kaasaskantavatele peer-idele. Tellimisteenus tagab plokkide jĂ€rjekindla kirjutamise, mis vĂ€listab nn raamatupidamise fork'i (vt jaotist "Forkid");
  • Peer-id saavad ploki, kontrollivad veelkord endorsement policy-d, kirjutavad ploki plokiahelasse ja muudavad olekut "World state" andmebaasis.

See tÀhendab, et node'de vahel toimub rollide jagamine. See tagab plokiahela skaleeritavuse ja turvalisuse:

  • Nutikaid lepinguid (chaincode) viivad lĂ€bi endorseerimise peer-id. See tagab nutikate lepingute konfidentsiaalsuse, kuna need ei ole kĂ”igi osalejate, vaid ainult endorseerimise peer-ide valduses.
  • Tellimine peab toimuma kiiresti. See tagatakse sellega, et tellimine koostab ainult ploki ja saadab selle kindlale juhivĂ”rgustikule.
  • Kaasaskantavad peer-id ainult hoiavad plokiahelat — neid vĂ”ib olla palju ja nad ei vaja suurt vĂ”imsust ega kohest tööd.

Rohkem Hyperledger Fabric'i arhitektuurilahenduste kohta ja miks see töötab nii, mitte teisiti, saab vaadata siit: Architektuuri originaalid vĂ”i siit: Hyperledger Fabric: jaotatud operatsioonisĂŒsteem lubatud plokiahelate jaoks.

Seega, Hyperledger Fabric on tĂ”eliselt universaalne sĂŒsteem, millega saab:

  • Reaaliseerida igasugust Ă€riloogikat, kasutades nutikate lepingute mehhanismi;
  • Salvestame ja saame andmeid plokiahela andmebaasist JSON formaadis;
  • Pakume ja kontrollime API-le ligipÀÀsu, kasutades sertifikaadi ametit.

NĂŒĂŒd, kui oleme natuke paremini tuttavad Hyperledger Fabric spetsiifikaga, laseme lĂ”puks teha midagi kasulikku!

KĂ€ivitame plokiahela

Ülesande seadmine

Ülesanne on luua Citcoin vĂ”rk, mis sisaldab jĂ€rgmisi funktsioone: luua konto, saada saldo, tĂ€iendada kontot, edastada mĂŒnte ĂŒhest kontost teise. Joonistame objekti mudeli, mille me hiljem teeme tarklepingus. Niisiis, meil on kontod, mis tuvastatakse nimede (name) kaudu ja sisaldavad saldo (balance) ning konto loend. Kontod ja konto loend on Hyperledger Fabricis varad (assets). Vastavalt on neil ajalugu ja praegune seisukord. Proovin seda visuaalselt esitada:

Plokiahel: mida me peame PoC’i loomiseks?

Ülemised kujundid – see on praegune seisukord, mis salvestatakse "World state" andmebaasi. Allpool on kujundid, mis nĂ€itavad ajalugu, mis salvestatakse plokiahelasse. Varade praegune seisukord muutub tehingute kaudu. Vara muutub ainult tĂ€ielikult, seega tehingu teostamise tulemusena luuakse uus objekt ja vara praegune vÀÀrtus lĂ€heb ajalukku.

IBM Cloud

Loome konto IBM Cloudis. Plokiahela platvormi kasutamiseks tuleb see uuendada Pay-As-You-Go versiooniks. See protsess ei pruugi olla kiire, kuna IBM kĂŒsib tĂ€iendavat teavet ja kontrollib seda kĂ€sitsi. Positiivse kĂŒlje pealt vĂ”in öelda, et IBM-l on head Ă”ppematerjalid, mis vĂ”imaldavad Hyperledger Fabricit nende pilves kĂ€ivitada. Mulle meeldis jĂ€rgmine artiklite ja nĂ€idete tsĂŒkkel:

JĂ€rgnevalt on toodud ekraanipildid IBM plokiahela platvormist. See ei ole juhend plokiahela loomise kohta, vaid lihtsalt ĂŒlesande ulatuse demonstreerimine. Niisiis, meie vajaduste jĂ€rgi loome ĂŒhe organisatsiooni:

Plokiahel: mida me peame PoC’i loomiseks?

Loome selles sÔlmed: Orderer CA, Org1 CA, Orderer Peer:

Plokiahel: mida me peame PoC’i loomiseks?

Loome kasutajad:

Plokiahel: mida me peame PoC’i loomiseks?

Looge kanali ja nimetage see citcoin:

Plokiahel: mida me peame PoC’i loomiseks?

PÔhimÔtteliselt on kanal plokiahel, seega algab see nullbloki (Genesis block) lÔpetamisest:

Plokiahel: mida me peame PoC’i loomiseks?

Kirjutame tarklepingut

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

Siin peaks kÔik intuitiivselt selge olema:

  • On mitu funktsiooni (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), mida demo program kasutab Hyperledger Fabric API abil.
  • Funktsioonid SendFrom ja RefillBalance genereerivad sĂŒndmusi (Event), mida demo programm saab.
  • Funktsioon instantiate kutsutakse vĂ€lja ainult ĂŒks kord nutika lepingu instantiimise ajal. Tegelikult kutsutakse seda vĂ€lja mitte ainult ĂŒks kord, vaid iga kord nutika lepingu versiooni muutmisel. SeetĂ”ttu on loetelu algse tĂŒhi massiiv - halb idee, kuna nĂŒĂŒd kaotame nutika lepingu versiooni muutmisel praeguse loendi. Kuid see pole probleem, ma alles Ă”ppin).
  • Account'id ja account'ide (accounts) loend - need on JSON andmestruktuurid. Andmete manipuleerimiseks kasutatakse JS-i.
  • KĂ€esoleva asset'i praeguse vÀÀrtuse saab kĂ€tte funktsiooni getState kaudu, samas kui seadistamiseks kasutatakse putState'i.
  • Account'i loomisel kutsutakse vĂ€lja funktsioon AddAccount, kus vĂ”rreldakse plokiahelas maksimaalselt lubatud account'ide arvu (maxAccounts = 5). Siin on viga (kas mĂ€rkisite?), mis pĂ”hjustab account'ide arvukuse lĂ”putu kasvu. Selliseid vigu tuleks vĂ€ltida).

Edasi laadime nutika lepingu Channelisse ja instantiime selle:

Plokiahel: mida me peame PoC’i loomiseks?

Vaadake nutika lepingu seadistamise tehingut:

Plokiahel: mida me peame PoC’i loomiseks?

Vaadake meie Channeli ĂŒksikasju:

Plokiahel: mida me peame PoC’i loomiseks?

Tulemusena saame jĂ€rgmise plokiahela vĂ”rgu skeemi IBM-i pilves. Skeemil on ka demoprogramm, mis töötab Amazoni pilves virtuaalsel serveril (ĂŒksikasjad on jĂ€rgmises osas):

Plokiahel: mida me peame PoC’i loomiseks?

GUI loomine Hyperledger Fabric API kutsumiste jaoks

Hyperledger Fabric'il on API, mida saab kasutada:

  • Channeli loomiseks;
  • Peer'i ĂŒhendamiseks channeliga;
  • Nutika lepingu seadistamiseks ja instantiimiseks channelis;
  • Tehingute nn kutse jaoks;
  • Informatsiooni kĂŒsimiseks plokiahelas.

Rakenduse arendus

Meie demoprogrammis kavatseme kasutada API-d ainult tehingute kutsumiseks ja informatsiooni kĂŒsimiseks, kuna ĂŒlejÀÀnud sammud oleme juba teinud, kasutades IBM-i plokiahela platvormi. Kirjutame GUI, kasutades standardset tehnoloogiate virna: Express.js + Vue.js + Node.js. Kuidas alustada kaasaegsete veebirakenduste loomist, vĂ”iks kirjutada eraldi artikli. Siin jĂ€tan lingi loengusarjale, mis mulle enim meeldis: Full Stack Web App using Vue.js & Express.js. Tulemusena sai kliendi-serveri rakendus tuttava Material Design stiilis graafilise liidese. REST API kliendi ja serveri vahel koosneb mitmest kutsetest:

  • HyperledgerDemo/v1/init - plokiahela initsialiseerimine;
  • HyperledgerDemo/v1/accounts/list - saada kĂ”igi account'ide loend;
  • HyperledgerDemo/v1/account?name=Bob&balance=100 - luua Bob account;
  • HyperledgerDemo/v1/info?account=Bob - saada teavet Bob account'i kohta;
  • HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 - edastada kaks mĂŒnti Bobilt Alicele;
  • HyperledgerDemo/v1/disconnect — lukusta blockchaini ĂŒhendus.

API kirjeldus koos nĂ€idetega on pandud «Postman» site'ile — laialdaselt tuntud programm HTTP API-de testimiseks.

Demo rakendus Amazonis

Rakendus on ĂŒles laaditud Amazonisse, kuna IBM ei ole siiani suutnud uuendada minu kontot ning lubada virtuaalserverite loomist. Nagu kirss tordil on domeen: www.citcoin.info. Hoian serverit natuke sisse lĂŒlitatuna, seejĂ€rel lĂŒlitan vĂ€lja, kuna rendihinnad voolavad, aga citcoin mĂŒntide kauplemine börsil ei ole veel alustatud) Panen artiklisse ekraanipildid, et selgitada rakenduse toimimist. Demo rakendus oskab:

  • Alustada blockchaini;
  • Luua Konto (aga praegu ei saa uut Kontot luua, kuna blockchainis on saavutatud maksimaalne number kontosid, mis on mÀÀratud nutilepingus);
  • Saada Kontode nimekiri;
  • Edastada citcoin mĂŒnte Alice'i, Bob'i ja Alexi vahel;
  • Saada sĂŒndmusi (aga hetkel ei saa sĂŒndmusi nĂ€idata, seega on kasutajaliideses lihtsuse huvides kirjutatud, et sĂŒndmusi ei toetata);
  • Logida tegevusi.

Esiteks alustame blockchaini:

Plokiahel: mida me peame PoC’i loomiseks?

SeejĂ€rel loome oma konto, ei kisenda saldo ĂŒle:

Plokiahel: mida me peame PoC’i loomiseks?

Saame nimekirja kÔikidest saadaval olevatest kontodest:

Plokiahel: mida me peame PoC’i loomiseks?

Valime saatja ja saaja, saame nende saldode: Kui saatja ja saaja on ĂŒks ja sama, toimub tema konto tĂ€iendamine:

Plokiahel: mida me peame PoC’i loomiseks?

Logis jÀlgime tehingute tÀitmist:

Plokiahel: mida me peame PoC’i loomiseks?

Kuna demo programm sellega ka lÔppeb. Edasi saab vaadata meie tehingut blockchainis:

Plokiahel: mida me peame PoC’i loomiseks?

Ja kogu tehingute loend:

Plokiahel: mida me peame PoC’i loomiseks?

Selleks saime edukalt lĂ”petatud Citcoini vĂ”rgu PoC rakendamise. Mida on veel vaja teha, et Citcoinist saaks tĂ€ieĂ”iguslik mĂŒnte ĂŒlekandmise vĂ”rk? Ainult vĂ€he:

  • Konto loomise etapis rakendada privaatse / avaliku vĂ”tme genereerimist. PrivaatvĂ”ti peab olema kontoa kasutaja kĂ€es, avalik vĂ”tme blockchainis.
  • Teha mĂŒnsĂŒ transfer, kus kasutaja identifitseerimiseks kasutatakse mitte nime, vaid avalikku vĂ”tme.
  • KrĂŒpteerida tehingud, mis lĂ€hevad kasutajalt serverisse tema privaatse vĂ”tme abil.

KokkuvÔte

Oleme rakendanud Citcoin vĂ”rku funktsioonidega: konto lisamine, saldo saamine, oma konto tĂ€iendamine, mĂŒnte edastamine ĂŒhelt konto teisele. Nii et, mida maksis PoC ehitamine?

  • Peame uurima blockchaini ĂŒldiselt ja Hyperledger Fabric'i eriti;
  • Õppima kasutama IBM'i vĂ”i Amazoni pilvi;
  • Õppima programmeerimiskeelt JS ja mĂ”nda veebiraamistikku;
  • Kui mĂ”nda teavet tuleb hoida mitte plokiahelas, vaid eraldi andmebaasis, tuleks Ă”ppida nĂ€iteks PostgreSQL-iga integreerima;
  • Ja viimane nimekirjas, kuid mitte vĂ€henenud tĂ€htsusega — ilma Linuxi tundmiseta ei pÀÀse tĂ€napĂ€eva maailmas kuhugi!)

Muidugi, see ei ole raketiteadus, aga veidi tuleb vaeva nÀha!

Allikakood GitHubis

Allikaid olen pannud GitHub. LĂŒhike kirjeldus repodega:
Kataloog „server“ — Node.js server
Kataloog „client“ — Node.js klient
Kataloog „blockchain“ (parameetrite vÀÀrtused ja vĂ”tmed on muidugi mitte töökindlad ja nĂ€idatud ainult nĂ€iteks):

  • contract — nutilepingu allikas
  • wallet — kasutaja vĂ”tmed Hyperledger Fabric API kasutamiseks.
  • *.cds — kompileeritud versioonid nutilepingutest
  • *.json failid — nĂ€ited konfiguratsioonifailidest Hyperledger Fabric API kasutamiseks

See on alles algus!

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster