Blockchain: Hva koster det Ă„ lage PoC?

Øynene er redde, men hendene klÞr!

I forrige artikler diskuterte vi teknologiene som blockchain er bygget pÄ (Hva skal vi bygge blockchain for?) og tilfellene som kan implementeres ved hjelp av dem (Hva mÄ til for Ä bygge et tilfelle?). Det er pÄ tide Ä jobbe med hendene! For implementering av piloter og PoC (Proof of Concept) foretrekker jeg Ä bruke skyer, siden de er tilgjengelige fra hvor som helst i verden, og ofte slipper man Ä bruke tid pÄ kjedelig installasjon av miljÞet, da det finnes forhÄndsinstallerte konfigurasjoner. SÄ la oss lage noe enkelt, for eksempel et nettverk for Ä overfÞre mynter mellom deltakerne og kalle det beskjedent Citcoin. Til dette skal vi bruke IBM-skyen og den universelle blockchain Hyperledger Fabric. La oss fÞrst forstÄ hvorfor Hyperledger Fabric kalles en universell blockchain?

Blockchain: Hva koster det Ă„ lage PoC?

Hyperledger Fabric — en universell blockchain

Generelt sett er et universelt informasjonssystem:

  • En samling servere og et programkjern som utfĂžrer forretningslogikk;
  • Grensesnitt for interaksjon med systemet;
  • VerktĂžy for registrering, autentisering og autorisering av enheter / personer;
  • En database som lagrer operative og arkiverte data:

Blockchain: Hva koster det Ă„ lage PoC?

Den offisielle versjonen av hva Hyperledger Fabric er, kan leses pÄ nettsiden, og hvis man skal oppsummere, sÄ er Hyperledger Fabric en open source plattform som gjÞr det mulig Ä bygge lukkede blockchains og utfÞre vilkÄrlige smartkontrakter skrevet i programmeringssprÄkene JS og Go. La oss se nÊrmere pÄ arkitekturen til Hyperledger Fabric og forsikre oss om at dette er et universelt system, hvor det bare er spesifikasjoner for lagring og registrering av data. Spesifikasjonen gÄr ut pÄ at data, som i alle blockchains, lagres i blokker som kun plasseres i blockchain nÄr deltakerne har nÄdd konsensus, og etter at dataene er skrevet, er det umulig Ä endre eller slette dem usett.

Arkitekturen til Hyperledger Fabric

Diagrammet viser arkitekturen til Hyperledger Fabric:

Blockchain: Hva koster det Ă„ lage PoC?

Organisasjoner — organisasjoner inneholder peer-er, slik at blockchain eksisterer takket vĂŠre stĂžtten fra organisasjonene. Ulike organisasjoner kan delta i Ă©n kanal.

Kanal — en logisk struktur som samler peer-er i grupper, slik at det defineres en blockchain. Hyperledger Fabric kan samtidig hĂ„ndtere flere blockchains med ulik forretningslogikk.

Membership Services Provider (MSP) — dette er CA (Certificate Authority) for utstedelse av identiteter og tildeling av roller. For Ă„ opprette en node mĂ„ man samarbeide med MSP.

Noder — kontrollerer transaksjoner, lagrer blokkjedene, utfþrer smarte kontrakter og samhandler med applikasjoner. Noder har en identitet (digitalt sertifikat) utstedt av MSP. I motsetning til Bitcoin- eller Etherium-nettverk, der alle noder er like, spiller noder i Hyperledger Fabric forskjellige roller:

  • En node kan vĂŠre endorserende node (EP) og utfĂžre smarte kontrakter.
  • Committing node (CP) — lagrer kun data i blokkjedene og oppdaterer «Verdistatus».
  • Anchor Node (AP) — hvis blokkjedene involverer flere organisasjoner, brukes anker noder til Ă„ knytte dem sammen. Hver organisasjon mĂ„ ha en eller flere anker noder. Med hjelp av AP kan enhver node i organisasjonen fĂ„ informasjon om alle noder i andre organisasjoner. For synkronisering av informasjon mellom AP brukes gossip-protokollen.
  • Leder Node — hvis organisasjonen har flere noder, vil kun ledernoden motta blokker fra bestillingstjenesten og gi dem til de andre nodene. Leder kan vĂŠre bĂ„de statisk satt og velges dynamisk av nodene i organisasjonen. For synkronisering av informasjon om ledere brukes ogsĂ„ gossip-protokollen.

Eiendeler — enheter med verdi som lagres i blokkjedene. Mer spesifikt er dette key-value data i JSON-format. Det er disse dataene som registreres i blokkjedene «Blockchain». De har en historikk som lagres i blokkjedene og en nĂ„vĂŠrende tilstand som lagres i databasen «Verdistatus». Datakonstruksjoner fylles vilkĂ„rlig avhengig av forretningsbehov. Det finnes ingen obligatoriske felt, det eneste rĂ„det er — eiendeler mĂ„ ha en eier og representere verdi.

Hovedbok — bestĂ„r av blokkjedene «Blockchain» og databasen «Word state», der den nĂ„vĂŠrende tilstanden til eiendelene lagres. Verdistatus bruker LevelDB eller CouchDB.

Smart kontrakt — forretningslogikk i systemet implementeres ved hjelp av smarte kontrakter. I Hyperledger Fabric kalles smarte kontrakter chaincode. Gjennom chaincode defineres eiendelene og transaksjonene i dem. Med teknisk sprĂ„k brukes smarte kontrakter — programmoduler implementert pĂ„ programmeringssprĂ„kene JS eller Go.

Endorsere politikk — for hver chaincode kan det defineres politikk for hvor mange og fra hvem som mĂ„ bekrefte transaksjonen. Hvis politikken ikke er definert, brukes som standard: “transaksjonen mĂ„ bekreftes av ethvert medlem (member) fra enhver organisasjon i kanalen”. Eksempler pĂ„ politikk:

  • Transaksjonen mĂ„ bekreftes av en hvilken som helst administrator i organisasjonen;
  • Hvilken som helst medlem (member) eller kunde i organisasjonen mĂ„ bekrefte;
  • Hvilken som helst peer i organisasjonen mĂ„ bekrefte.

Bestillingstjeneste — pakker transaksjoner i blokker og sender dem til peer-er i kanalen. Sikrer levering av meldinger til alle peer-er i nettverket. For industrielle systemer brukes meldingsmegler Kafka, for utvikling og testing Solo.

CallFlow

Blockchain: Hva koster det Ă„ lage PoC?

  • Applikasjonen interagerer med Hyperledger Fabric ved hjelp av Go, Node.js eller Java SDK;
  • Klienten oppretter transaksjonen tx og sender den til endorsing peer-er;
  • Peer-verifiserer klientens signatur, utfĂžrer transaksjonen og sender endorsement signature tilbake til klienten. Chaincode kjĂžres kun pĂ„ endorsing peer, og resultatet av utfĂžrelsen sendes til alle peer-er. Denne arbeidsalgoritmen kalles — PBFT (Practical Byzantine Fault Tolerant) konsensus. Det skiller seg fra klassisk BFT ved at meldingen sendes og bekreftelse forventes ikke fra alle deltakere, men bare fra et bestemt sett;
  • NĂ„r klienten har mottatt antallet svar som samsvarer med endorsement policy, sender han transaksjonen til bestillingstjenesten;
  • Bestillingstjenesten danner en blokk og sender den til alle committing peer-er. Bestillingstjenesten sikrer sekvensiell innspilling av blokker, noe som utelukker, sĂ„kalt, ledger fork (se avsnitt «Forker»);
  • Peer-er mottar blokken, sjekker endorsement policy pĂ„ nytt, registrerer blokken i blokkjeden og endrer tilstanden i «World state» DB.

Det vil si at det oppstÄr en rollefordeling mellom nodene. Dette sikrer skalerbarhet og sikkerhet i blokkjeden:

  • Smartkontrakter (chaincode) kjĂžres av endorsing peer-er. Dette sikrer konfidensialitet for smartkontraktene, da de ikke lagres hos alle deltakerne, men kun pĂ„ endorsing peer-ene.
  • Bestilling mĂ„ fungere raskt. Dette sikres ved at bestillingen kun danner blokker og sender dem til et fast sett med leder peer-er.
  • Committing peers lagrer bare blokkjeden — det kan vĂŠre mange av dem, og de krever ikke stor kraft eller umiddelbar ytelse.

For mer informasjon om arkitektoniske lĂžsninger i Hyperledger Fabric og hvorfor det fungerer slik, se her: Arkitekturens opprinnelse eller her: Hyperledger Fabric: Et distribuert operativsystem for tillatelsesbaserte blokkjeder.

SĂ„, Hyperledger Fabric er virkelig et allsidig system som kan gjĂžre:

  • Implementere vilkĂ„rlig forretningslogikk ved hjelp av mekanismen for smartkontrakter;
  • Lagre og hent data fra blockchain-databasen i JSON-format;
  • Gi tilgang til og verifisere API-bruk ved hjelp av et sertifiseringsorgan.

NÄ som vi har forstÄtt spesifikasjonene til Hyperledger Fabric litt bedre, la oss endelig gjÞre noe nyttig!

Distribuerer blockchain

Definering av oppgaven

MÄlet er Ä implementere et Citcoin-nettverk med fÞlgende funksjoner: opprette en konto, hente saldo, fylle pÄ konto, overfÞre mynter fra én konto til en annen. La oss tegne en objektmodell som vi senere vil implementere i en smart kontrakt. Vi vil ha kontoer som identifiseres med navn (name) og inneholder saldo (balance), samt en liste over kontoer. Kontoer og listen over kontoer er, i henhold til Hyperledger Fabric, eiendeler (assets). De har dermed en historikk og en nÄvÊrende tilstand. Jeg vil prÞve Ä illustrere dette tydelig:

Blockchain: Hva koster det Ă„ lage PoC?

De Þverste figurene representerer nÄvÊrende tilstand, som lagres i «World state»-databasen. Under dem er figurer som viser historikken, som lagres i blockchain. Den nÄvÊrende tilstanden for eiendeler endres av transaksjoner. En eiendel kan kun endres helt, sÄ resultatet av en transaksjon opprettes som et nytt objekt, mens den nÄvÊrende verdien av eiendelen gÄr inn i historikken.

IBM Cloud

Opprett en konto i IBM-cloud. For Ä bruke blockchain-plattformen mÄ den oppgraderes til Pay-As-You-Go. Denne prosessen kan ta tid, ettersom IBM ber om ekstra informasjon og sjekker den manuelt. Til det positive kan jeg si at IBM har gode lÊringsressurser som lar deg distribuere Hyperledger Fabric i skyen deres. Jeg likte denne serien av artikler og eksempler:

Her er skjermbilder fra IBM Blockchain-plattformen. Dette er ikke en instruksjon for Ä lage en blockchain, men en enkel demonstrasjon av omfanget av oppgaven. SÄ for vÄre formÄl lager vi én organisasjon:

Blockchain: Hva koster det Ă„ lage PoC?

I den oppretter vi noder: Orderer CA, Org1 CA, Orderer Peer:

Blockchain: Hva koster det Ă„ lage PoC?

Oppretter brukere:

Blockchain: Hva koster det Ă„ lage PoC?

Oppretter en kanal og kaller den citcoin:

Blockchain: Hva koster det Ă„ lage PoC?

I bunn og grunn er kanal en blockchain, sÄ den begynner med nullblokken (Genesis block):

Blockchain: Hva koster det Ă„ lage PoC?

Skriver 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;

Intuitivt bÞr alt her vÊre forstÄelig:

  • Det er flere funksjoner (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance) som vil bli kalt av demoprogrammet ved hjelp av Hyperledger Fabric API.
  • Funksjonene SendFrom og RefillBalance genererer hendelser (Event) som demoprogrammet vil motta.
  • Instantiate-funksjonen kalles Ă©n gang nĂ„r smart-kontrakten instansieres. Faktisk blir den ikke kalt bare Ă©n gang, men hver gang smart-kontrakten endres. Derfor er det en dĂ„rlig idĂ© Ă„ initialisere listen med en tom matrise, ettersom vi nĂ„ vil miste den nĂ„vĂŠrende listen ved versjonsendring av smart-kontrakten. Men det er okei, jeg lĂŠrer bare).
  • Account-er og listen av account-er (accounts) er JSON-datastrukturer. JS brukes til Ă„ manipulere dataene.
  • Den nĂ„vĂŠrende verdien av asset kan hentes ved Ă„ kalle funksjonen getState, og oppdateres med putState.
  • NĂ„r en Account opprettes, kalles funksjonen AddAccount, som sammenligner med det maksimale antallet accounts i blokkjeden (maxAccounts = 5). Og her er det en feil (la merke til?), som fĂžrer til uendelig vekst av antall accounts. Slike feil mĂ„ unngĂ„s)

Deretter laster vi opp smart-kontrakten til Channel og instansierer den:

Blockchain: Hva koster det Ă„ lage PoC?

Vi ser pÄ transaksjonen for Ä etablere Smart Contract:

Blockchain: Hva koster det Ă„ lage PoC?

Vi ser detaljene om vÄr Channel:

Blockchain: Hva koster det Ă„ lage PoC?

Som et resultat fÄr vi fÞlgende diagram av blockchain-nettverket i IBM-skyen. Diagrammet inkluderer ogsÄ et demoprogram som kjÞrer i Amazon-skyen pÄ en virtuell server (mer om det i neste avsnitt):

Blockchain: Hva koster det Ă„ lage PoC?

Opprettelse av GUI for Ă„ kalle Hyperledger Fabric API

Hyperledger Fabric har et API som kan brukes til:

  • Å opprette channel;
  • Å koble peer til channel;
  • Å installere og instansiere smart-kontrakter i channel;
  • Å kalle transaksjoner;
  • Å be om informasjon i blokkjeden.

Utvikling av applikasjoner

I vÄrt demoprogram vil vi bruke API kun til Ä kalle transaksjoner og be om informasjon, da vi allerede har fullfÞrt de andre trinnene ved Ä bruke IBM-blockchain-plattformen. Vi skriver GUI ved Ä bruke standard teknologistack: Express.js + Vue.js + Node.js. Hvordan man kan begynne Ä lage moderne webapplikasjoner kan skrive en egen artikkel om. Her legger jeg igjen lenken til en serie forelesninger som jeg likte best: Full Stack Web App using Vue.js & Express.js. Resultatet ble en klient-server-applikasjon med en kjent grafisk grensesnitt i Material Design-stil fra Google. REST API mellom klient og server bestÄr av flere kall:

  • HyperledgerDemo/v1/init - initialisere blokkjeden;
  • HyperledgerDemo/v1/accounts/list - hente listen over alle accounts;
  • HyperledgerDemo/v1/account?name=Bob&balance=100 - opprette Bob account;
  • HyperledgerDemo/v1/info?account=Bob - hente informasjon om Bob account;
  • HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — overfĂžre to mynter fra Bob til Alice;
  • HyperledgerDemo/v1/disconnect — avslutte forbindelsen til blokkjeden.

API-beskrivelsen med eksempler la jeg pĂ„ nettstedet «Postman» — et velkjent program for testing av HTTP API.

Demoapplikasjonen pÄ Amazon Cloud

Jeg lastet opp applikasjonen til Amazon, ettersom IBM fortsatt ikke har klart Ä oppgradere kontoen min og tillate opprettelse av virtuelle servere. Som en liten bonus har jeg festet domenet: www.citcoin.info. Jeg vil holde serveren pÄ en stund, men deretter slÄ den av, ettersom leiekostnadene Þker, og citcoin-myntene er ennÄ ikke notert pÄ bÞrsen) I artikkelen legger jeg inn skjermbilder av demoen for Ä gjÞre logikken tydelig. Demoapplikasjonen kan:

  • Initialisere blokkjeden;
  • Opprette Account (men nĂ„ kan ikke ny Account opprettes, ettersom det maksimale antallet account-er i blokkjeden, som er spesifisert i smartkontrakten, er nĂ„dd);
  • FĂ„ en liste over Accounts;
  • OverfĂžre citcoin-mynter mellom Alice, Bob og Alex;
  • FĂ„ hendelser (men nĂ„ kan ikke hendelser vises, derfor stĂ„r det i grensesnittet for enkelhetens skyld at hendelser ikke stĂžttes);
  • LoggfĂžre handlinger.

FĂžrst initialiserer vi blokkjeden:

Blockchain: Hva koster det Ă„ lage PoC?

Deretter oppretter vi vÄr egen account, og vi slÞser ikke med balansen:

Blockchain: Hva koster det Ă„ lage PoC?

Vi fÄr en liste over alle tilgjengelige accounts:

Blockchain: Hva koster det Ă„ lage PoC?

Vi velger avsender og mottaker, og fÄr deres balanser. Hvis avsender og mottaker er den samme, vil kontoen bli fylt opp:

Blockchain: Hva koster det Ă„ lage PoC?

I loggen fÞlger vi med pÄ utfÞrelsen av transaksjoner:

Blockchain: Hva koster det Ă„ lage PoC?

Egentlig er dette alt med demo-programmet. Videre kan vi se transaksjonen vÄr i blokkjeden:

Blockchain: Hva koster det Ă„ lage PoC?

Og den samlede transaksjonslisten:

Blockchain: Hva koster det Ă„ lage PoC?

Vi har nÄ med suksess fullfÞrt implementeringen av PoC for Ä opprette Citcoin-nettverket. Hva mÄ vi gjÞre for at Citcoin skal bli et fullverdig nettverk for overfÞring av mynter? Ikke mye:

  • Ved opprettelse av account, implementere generering av privat / offentlig nĂžkkel. Den private nĂžkkelen skal lagres av brukerens account, den offentlige i blokkjeden.
  • GjĂžre overfĂžringer av mynter der identifikasjon av brukeren skjer ikke med navn, men med offentlig nĂžkkel.
  • Kryptere transaksjoner som gĂ„r fra brukeren til serveren med hans private nĂžkkel.

Konklusjon

Vi har implementert Citcoin-nettverket med funksjoner: legge til account, fÄ balanse, fylle opp kontoen, overfÞre mynter fra en konto til en annen. SÄ hva kostet det oss Ä bygge PoC?

  • Vi mĂ„ studere blokkjeden generelt og Hyperledger Fabric spesielt;
  • LĂŠre Ă„ bruke IBM- eller Amazon-skyer;
  • LĂŠre programmeringssprĂ„ket JS og en web rammeverk;
  • Hvis data mĂ„ lagres ikke pĂ„ blokkjeden, men i en egen database, sĂ„ lĂŠr deg Ă„ integrere, for eksempel med PostgreSQL;
  • Og sist, men ikke minst — uten kunnskap om Linux kommer man ikke langt i dagens verden!)

SelvfĂžlgelig, det er ikke rocket science, men det vil kreve litt arbeid!

Kildekode pÄ GitHub

Kildekoden la jeg pÄ GitHub. Kort beskrivelse av lageret:
Katalogen «server» — Node.js-server
Katalogen «klient» — Node.js-klient
Katalogen «blockchain» (verdiene til parametere og nÞkler er selvfÞlgelig ikke operative og bare gitt som eksempel):

  • contract — kildekoden til smarte kontrakter
  • wallet — brukerens nĂžkler for Ă„ bruke Hyperledger Fabric API.
  • *.cds — kompilerte versjoner av smarte kontrakter
  • *.json-filer — eksempler pĂ„ konfigurasjonsfiler for bruk med Hyperledger Fabric API

Det er bare begynnelsen!

Kilde: habr.com

KjĂžp pĂ„litelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KjĂžp pĂ„litelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere | ProHoster