Blockchain: hvad kræver det for os at bygge en PoC?

Øjnene frygter, men hænderne klør!

I de tidligere artikler har vi undersøgt de teknologier, som blockchain er bygget på (Hvad koster det at bygge en blockchain?) og de anvendelsestilfælde, som man kan realisere med dem (Hvad koster det os at bygge et anvendelsestilfælde?). Det er tid til at få hænderne i sving! For at implementere pilotprojekter og PoC (Proof of Concept) foretrækker jeg at bruge cloud-løsninger, da de kan tilgås fra enhver del af verden, og det ofte ikke kræver tid at installere et miljø, da der er forhåndskonfigurerede opsætninger. Så lad os gøre noget simpelt, for eksempel et netværk til at overføre valuta mellem deltagerne, og lad os beskytte dette beskedne navn Bitcoin. Til dette vil vi bruge IBM's cloud og den universelle blockchain Hyperledger Fabric. Lad os først finde ud af, hvorfor Hyperledger Fabric kaldes en universel blockchain?

Blockchain: hvad kræver det for os at bygge en PoC?

Hyperledger Fabric — en universel blockchain

Generelt set er et universelt informationssystem:

  • Et sæt servere og en software-kerne, der udfører forretningslogik;
  • Grænseflader til interaktion med systemet;
  • Værktøjer til registrering, godkendelse og autorisering af enheder / personer;
  • En database, der gemmer operationelle og arkivdata:

Blockchain: hvad kræver det for os at bygge en PoC?

Den officielle version af, hvad Hyperledger Fabric er, kan læses på websitet, og kort sagt, Hyperledger Fabric er en open-source platform, der gør det muligt at bygge lukkede blockchains og udføre vilkårlige smarte kontrakter skrevet i programmeringssprogene JS og Go. Lad os se nærmere på arkitekturen af Hyperledger Fabric og overbevise os selv om, at dette er et universelt system, som kun har specifikationen for opbevaring og registrering af data. Specifikationen er, at data, som i alle blockchains, gemmes i blokke, der kun placeres i blockchain, hvis deltagerne når til konsensus, og efter registrering kan data ikke ændres eller slettes ubemærket.

Arkitekturen af Hyperledger Fabric

Diagrammet viser arkitekturen af Hyperledger Fabric:

Blockchain: hvad kræver det for os at bygge en PoC?

Organisationer — organisationer indeholder peers, således at blockchain findes takket være organisationernes støtte. Forskellige organisationer kan være med i én channel.

Channel — en logisk struktur, der samler peers i grupper, således at blockchain defineres. Hyperledger Fabric kan samtidig behandle flere blockchains med forskellig forretningslogik.

Membership Services Provider (MSP) — det er CA (Certificate Authority) for udstedelse af identiteter og tildeling af roller. For at oprette en node skal man interagere med MSP.

Peer noder — verificerer transaktioner, opbevarer blockchainen, udfører smart contracts og interagerer med applikationer. Peer-noder har en identitet (digitalt certifikat), som udstedes af MSP. I modsætning til Bitcoin- eller Ethereum-netværket, hvor alle noder er ligeværdige, spiller noderne i Hyperledger Fabric forskellige roller:

  • En peer kan være endorsing peer (EP) og udføre smart contracts.
  • Committing peer (CP) — gemmer kun data i blockchainen og opdaterer "World state".
  • Anchor Peer (AP) — hvis flere organisationer deltager i blockchainen, anvendes anchor peer til at kommunikere mellem dem. Hver organisation skal have en eller flere anchor peers. Med hjælp fra AP kan enhver peer i organisationen få information om alle peers i andre organisationer. Til at synkronisere information mellem AP'er anvendes gossip protokollen.
  • Leader Peer — hvis en organisation har flere peers, vil kun leader peer modtage blokke fra Ordering service og viderebringe dem til de andre peers. Lederen kan både være statisk defineret og vælges dynamisk af peers i organisationen. For at synkronisere information om ledere anvendes også gossip protokollen.

Aktiver — enheder af værdi, der opbevares i blockchainen. Mere specifikt er det key-value data i JSON-format. Det er disse data, der skrives til blockchainen "Blockchain". De har en historie, der opbevares i blockchainen, og en nuværende tilstand, der opbevares i databasen "World state". Datastrukturerne fyldes tilfældigt afhængigt af forretningsopgaverne. Der er ingen obligatoriske felter, mens den eneste anbefaling er, at aktiverne skal have en ejer og repræsentere værdi.

Ledger — består af blockchainen "Blockchain" og databasen "World state", hvor den nuværende tilstand af aktiverne opbevares. World state bruger LevelDB eller CouchDB.

Smart kontrakt — med smart contracts implementeres forretningslogikken i systemet. I Hyperledger Fabric kaldes smart contracts chaincode. Med chaincode defineres aktiverne og transaktionerne på dem. Hvis vi taler i tekniske termer, er smart contracts softwaremoduler implementeret i programmeringssprogene JS eller Go.

Endorsement policy — for hver chaincode kan der angives politikker for, hvor mange og fra hvem, der skal forventes bekræftelser til en transaktion. Hvis politikken ikke er angivet, anvendes som standard: “transaktionen skal bekræftes af ethvert medlem (member) fra enhver organisation i kanalen”. Eksempler på politikker:

  • Transaktionen skal bekræftes af en hvilken som helst administrator af organisationen;
  • Det skal bekræftes af ethvert medlem eller kunde i organisationen;
  • Det skal bekræftes af enhver peer i organisationen.

Bestillingstjeneste — pakker transaktioner i blokke og sender dem til peers i kanalen. Sikrer levering af beskeder til alle peers i netværket. Til industrielle systemer anvendes Kafka-beskedbroker, til udvikling og testning Solo.

CallFlow

Blockchain: hvad kræver det for os at bygge en PoC?

  • Applikationen interagerer med Hyperledger Fabric ved hjælp af Go, Node.js eller Java SDK;
  • Klienten opretter transaktionen tx og sender den til endorsing peers;
  • Peer kontrollerer klientens underskrift, udfører transaktionen og sender endorsement-underskriften tilbage til klienten. Chaincode udføres kun på endorsing peers, og resultatet af deres udførelse distribueres til alle peers. Denne arbejdsmetode kaldes — PBFT (Practical Byzantine Fault Tolerant) konsensus. Det adskiller sig fra klassisk BFT ved at meddelelsen distribueres og bekræftelse forventes ikke fra alle deltagere, men kun fra et bestemt sæt;
  • Når kunden har modtaget et antal svar, der svarer til endorsing policy, sender han transaktionen til bestillingstjenesten;
  • Bestillingstjenesten danner en blok og sender den til alle committing peers. Bestillingstjenesten sikrer sekventiel skrivning af blokke, hvilket udelukker såkaldt ledger fork (se afsnittet "Forks");
  • Peers modtager blokken, kontrollerer endnu en gang endorsing policy, gemmer blokken i blockchainen og opdaterer tilstanden i "World state" DB.

Det vil sige, der opnås en opdeling af rollerne mellem noderne. Dette sikrer skalerbarhed og sikkerhed i blockchainen:

  • Smart contracts (chaincode) udføres af endorsing peers. Dette sikrer fortrolighed af smart contracts, da de ikke lagres hos alle deltagere, men kun på endorsing peers.
  • Bestilling skal fungere hurtigt. Dette sikres ved at Bestilling kun danner blokken og sender den til et fast sæt af leader peers.
  • Committing peers gemmer kun blockchainen — der kan være mange af dem, og de kræver ikke stor kapacitet og øjeblikkelig reaktion.

Yderligere arkitektoniske løsninger i Hyperledger Fabric og hvorfor det fungerer som det gør, kan ses her: Architecture Origins eller her: Hyperledger Fabric: A Distributed Operating System for Permissioned Blockchains.

Så, Hyperledger Fabric er virkelig et alsidigt system, hvorved man kan:

  • Implementere enhver forretningslogik ved hjælp af smart contract-mekanismen;
  • Registrere og hente data fra blockchain-database i JSON-format;
  • Tilvejebringe og verificere adgang til API ved hjælp af Certificate Authority.

Nu hvor vi har fået en grundlæggende forståelse af Hyperledger Fabric, lad os endelig gøre noget nyttigt!

Udrulning af blockchain

Problemformulering

Opgaven er at implementere et Citcoin-netværk med følgende funktioner: oprette en konto, få saldo, genopfylde saldo, overføre mønter fra én konto til en anden. Lad os tegne en objektsmodel, som vi senere vil implementere i smart contracten. Så vi vil have konti, der identificeres med navne (name) og indeholder en saldo (balance), samt en liste over konti. Konti og listen over konti er, i termerne af Hyperledger Fabric, aktiver. Følgelig har de en historie og en aktuel tilstand. Jeg vil forsøge at illustrere dette visuelt:

Blockchain: hvad kræver det for os at bygge en PoC?

De øverste figurer repræsenterer den nuværende tilstand, som opbevares i "World state". Under dem er figurer, der viser historikken, som opbevares i blockchainen. Den aktuelle tilstand af aktiver ændres via transaktioner. Et aktiv ændres kun i sin helhed, så resultatet af en transaktion skaber et nyt objekt, og den aktuelle værdi af aktivet går til historien.

IBM Cloud

Opretter en konto i IBM Cloud. For at bruge blockchain-platformen skal den opgraderes til Pay-As-You-Go. Denne proces kan tage tid, da IBM anmoder om yderligere information og behandler den manuelt. Positivt er, at IBM har gode undervisningsmaterialer, der gør det muligt at udrulle Hyperledger Fabric i deres cloud. Jeg kunne godt lide følgende serie af artikler og eksempler:

Nedenfor er screenshots fra IBM's Blockchain platform. Dette er ikke en vejledning til oprettelse af blockchain, men blot en demonstration af omfanget af opgaven. Så lad os for vores formål oprette én organisation:

Blockchain: hvad kræver det for os at bygge en PoC?

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

Blockchain: hvad kræver det for os at bygge en PoC?

Opretter brugere:

Blockchain: hvad kræver det for os at bygge en PoC?

Opretter Channel og kalder den citcoin:

Blockchain: hvad kræver det for os at bygge en PoC?

I bund og grund er Channel en blockchain, så den starter med blok nummer nul (Genesis block):

Blockchain: hvad kræver det for os at bygge en 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 skal alt være klart her:

  • Der er flere funktioner (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), som demon-programmet vil kalde ved hjælp af Hyperledger Fabric API.
  • Funktionerne SendFrom og RefillBalance genererer begivenheder (Event), som demon-programmet vil modtage.
  • Funktionen instantiate kaldes én gang, når smartkontrakten instansieres. Faktisk kaldes den ikke kun én gang, men hver gang versionen af smartkontrakten ændres. Derfor er det en dårlig idé at initialisere listen med et tomt array, da vi nu vil miste den nuværende liste, når versionen af smartkontrakten ændres. Men ingen bekymringer, jeg er kun i gang med at lære).
  • Accounts og listen over accounts (accounts) er JSON datastrukturer. Dataene manipuleres med JS.
  • Den nuværende værdi af asset kan opnås ved at kalde funktionen getState, og opdateres med putState.
  • Når der oprettes en Account, kaldes funktionen AddAccount, hvor der sammenlignes med det maksimale antal accounts i blockchainen (maxAccounts = 5). Her er der et problem (har I bemærket det?), som fører til en uendelig vækst af antallet af accounts. Sådanne fejl skal undgås)

Dernæst uploader vi smartkontrakten til Channel og instansierer den:

Blockchain: hvad kræver det for os at bygge en PoC?

Lad os se transaktionen for installation af Smart Contract:

Blockchain: hvad kræver det for os at bygge en PoC?

Lad os se detaljerne om vores Channel:

Blockchain: hvad kræver det for os at bygge en PoC?

Som resultat får vi følgende diagram af blockchain-netværket i IBM's cloud. Diagrammet viser også et demo-program, der kører i Amazon's cloud på en virtuel server (mere om dette i næste sektion):

Blockchain: hvad kræver det for os at bygge en PoC?

Oprettelse af GUI til kald af Hyperledger Fabric API

Hyperledger Fabric har et API, der kan bruges til:

  • Oprettelse af channel;
  • Forbindelse af peer til channel;
  • Installation og instansiering af smartkontrakter i channel;
  • Kald af transaktioner;
  • Anmodning om information i blockchainen.

Udvikling af applikation

I vores demo-program vil vi kun bruge API til at kalde transaktioner og anmode om information, da vi allerede har gjort de andre skridt ved at bruge IBM blockchain-platformen. Vi skriver GUI'en ved at bruge den standard teknologi-stack: Express.js + Vue.js + Node.js. Der kan skrives en separat artikel om, hvordan man starter med at oprette moderne webapplikationer. Her lader jeg et link til en række forelæsninger, som jeg fandt mest interessante: Full Stack Web App using Vue.js & Express.js. Som resultat blev der skabt en klient-server-applikation med et velkendt grafisk interface i stil med Material Design fra Google. REST API mellem klienten og serveren består af flere kald:

  • HyperledgerDemo/v1/init — initialisere blockchain;
  • HyperledgerDemo/v1/accounts/list — hente listen over alle accounts;
  • HyperledgerDemo/v1/account?name=Bob&balance=100 — oprette Bob account;
  • HyperledgerDemo/v1/info?account=Bob — hente information om Bob account;
  • HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — overføre to mønter fra Bob til Alice;
  • HyperledgerDemo/v1/disconnect — lukke forbindelsen til blockchainen.

API-beskrivelsen med eksempler er lagt på siden "Postman" — et velkendt program til test af HTTP API'er.

Demo-applikationen i Amazon-cloud

Jeg har uploadet applikationen til Amazon, da IBM stadig ikke har været i stand til at opgradere min konto og tillade mig at oprette virtuelle servere. Som en lille ekstra tilføjelse tilføjede jeg domænet: www.citcoin.info. Jeg vil holde serveren tændt lidt, men derefter slukke den, da omkostningerne for leje løber, og citcoin-mønter er endnu ikke noteret på børsen) I artiklen medtager jeg screenshots af demoen for at tydeliggøre logikken. Demo-applikationen kan:

  • Initialisere blockchain;
  • Oprette Account (men lige nu kan der ikke oprettes en ny Account, da det maksimale antal accounts, der er angivet i smart-kontrakten, er nået);
  • Modtage listen over Accounts;
  • Overføre citcoin-mønter mellem Alice, Bob og Alex;
  • Modtage begivenheder (men i øjeblikket kan begivenheder ikke vises, så der står for enkelhed i grænsefladen, at begivenheder ikke understøttes);
  • Logge handlinger.

Først initialiserer vi blockchain:

Blockchain: hvad kræver det for os at bygge en PoC?

Dernæst opretter vi vores konto, og vi går ikke ned på balancen:

Blockchain: hvad kræver det for os at bygge en PoC?

Vi får listen over alle tilgængelige accounts:

Blockchain: hvad kræver det for os at bygge en PoC?

Vi vælger afsender og modtager og får deres saldi. Hvis afsender og modtager er den samme, vil hans saldo blive opfyldt:

Blockchain: hvad kræver det for os at bygge en PoC?

I loggen følger vi transaktionernes udførelse:

Blockchain: hvad kræver det for os at bygge en PoC?

Det er i grund og bund det hele med demo-programmet. Derefter kan vi se vores transaktion i blockchainen:

Blockchain: hvad kræver det for os at bygge en PoC?

Og den samlede liste over transaktioner:

Blockchain: hvad kræver det for os at bygge en PoC?

Hermed har vi med succes afsluttet implementeringen af PoC for oprettelsen af Citcoin-netværket. Hvad skal der ellers gøres, for at Citcoin bliver et fuldgyldigt netværk til overførsel af mønter? Meget lidt:

  • Ved oprettelsen af account-en skal der implementeres generation af privat/publik nøgle. Den private nøgle skal opbevares af brugeren af account-en, den offentlige i blockchainen.
  • Foretage overførsler af mønter, hvor identifikation af brugeren ikke sker ved navn, men ved den offentlige nøgle.
  • Kryptere transaktioner, der går fra brugeren til serveren med hans private nøgle.

Konklusion

Vi har implementeret netværket Citcoin med funktioner: tilføje account, få saldo, opfylde sin konto, overføre mønter fra én konto til en anden. Så hvad kostede det os at bygge PoC?

  • Vi skal lære om blockchain generelt og Hyperledger Fabric i særdeleshed;
  • Lære at bruge IBM- eller Amazon-cloud.
  • Lær programmeringssproget JS og en web framework;
  • Hvis visse data skal opbevares i en separat database frem for i blockchain, så lær at integrere med f.eks. PostgreSQL;
  • Og sidst men ikke mindst — uden kendskab til Linux kommer man ikke langt i dagens verden!)

Selvfølgelig er det ikke raketvidenskab, men du skal arbejde for det!

Kildekoderne på GitHub

Kildekoden er lagt på GitHub. Kort beskrivelse af repositoryet:
Kataloget „server“ — Node.js server
Kataloget „client“ — Node.js klient
Kataloget „blockchain“ (værdierne i parametrene og nøglerne er naturligvis ikke funktionelle og kun til eksempelets skyld):

  • contract — kildekoden til smart contracten
  • wallet — brugerens nøgler til brug af Hyperledger Fabric API.
  • *.cds — kompilerede versioner af smart contracts
  • *.json filer — eksempler på konfigurationsfiler til brug af Hyperledger Fabric API

Det er kun begyndelsen!

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster