Blockchain: hvilken PoC skal vi bygge?

Dine øjne er bange og dine hænder klør!

I tidligere artikler har vi behandlet de teknologier, som blockchains er bygget på (Hvad skal vi bygge en blockchain?) og sager, der kan implementeres med deres hjælp (Hvorfor skal vi bygge en sag?). Det er tid til at arbejde med dine hænder! For at implementere piloter og PoC (Proof of Concept) foretrækker jeg at bruge skyerne, fordi... de kan tilgås fra hvor som helst i verden, og ofte er der ingen grund til at spilde tid på kedelig installation af miljøet, fordi Der er forudindstillede konfigurationer. Så lad os lave noget simpelt, for eksempel et netværk til at overføre mønter mellem deltagere og lad os beskedent kalde det Bitcoin. Til dette vil vi bruge IBM-skyen og den universelle blockchain Hyperledger Fabric. Lad os først finde ud af, hvorfor Hyperledger Fabric kaldes en universel blockchain?

Blockchain: hvilken PoC skal vi bygge?

Hyperledger Fabric - en universel blockchain

Generelt er et universelt informationssystem:

  • Et sæt servere og en softwarekerne, der udfører forretningslogik;
  • Grænseflader til interaktion med systemet;
  • Værktøjer til registrering, autentificering og autorisation af enheder/personer;
  • Database, der lagrer drifts- og arkivdata:

Blockchain: hvilken PoC skal vi bygge?

Den officielle version af, hvad Hyperledger Fabric er, kan læses på Online, og kort fortalt er Hyperledger Fabric en opensource platform, der giver dig mulighed for at bygge private blockchains og udføre vilkårlige smarte kontrakter skrevet i JS og Go programmeringssprogene. Lad os se nærmere på arkitekturen af ​​Hyperledger Fabric og sikre os, at dette er et universelt system, der kun har detaljer til lagring og registrering af data. Specificiteten er, at dataene, som i alle blockchains, lagres i blokke, der kun placeres på blockchainen, hvis deltagerne opnår enighed, og efter registrering af dataene ikke stille og roligt kan rettes eller slettes.

Hyperledger stofarkitektur

Diagrammet viser Hyperledger Fabric-arkitekturen:

Blockchain: hvilken PoC skal vi bygge?

Organisationer — organisationer indeholder jævnaldrende, dvs. blockchain eksisterer på grund af støtte fra organisationer. Forskellige organisationer kan være en del af den samme kanal.

Kanal — en logisk struktur, der forener jævnaldrende i grupper, dvs. blockchain er specificeret. Hyperledger Fabric kan samtidigt behandle flere blockchains med forskellig forretningslogik.

Membership Services Provider (MSP) er en CA (Certificate Authority) til at udstede identitet og tildele roller. For at oprette en node skal du interagere med MSP'en.

Peer noder — verificere transaktioner, gemme blockchain, eksekvere smarte kontrakter og interagere med applikationer. Peers har en identitet (digitalt certifikat), som udstedes af MSP. I modsætning til Bitcoin- eller Etherium-netværket, hvor alle noder har lige rettigheder, spiller Fabric-noder i Hyperledger forskellige roller:

  • Peer måske godkende peer (EP) og udføre smarte kontrakter.
  • Forpligtende peer (CP) - gem kun data i blockchain og opdater "verdenstilstanden".
  • Anker Peer (AP) - hvis flere organisationer deltager i blockchain, så bruges anchor peers til kommunikation mellem dem. Hver organisation skal have en eller flere ankerfæller. Ved hjælp af AP kan enhver peer i en organisation få oplysninger om alle peers i andre organisationer. Bruges til at synkronisere information mellem AP'er sladder protokol.
  • Leder Peer — hvis en organisation har flere peers, er det kun lederen af ​​peeren, der vil modtage blokke fra bestillingstjenesten og give dem til resten af ​​peers. Lederen kan enten specificeres statisk eller vælges dynamisk af peers i organisationen. Sladderprotokollen bruges også til at synkronisere information om ledere.

Aktiver — enheder, der har værdi og er lagret på blockchain. Mere specifikt er dette nøgleværdidata i JSON-format. Det er disse data, der registreres i Blockchain. De har en historie, som er gemt i blockchain, og en aktuel tilstand, som er gemt i "World state"-databasen. Datastrukturer udfyldes vilkårligt afhængigt af forretningsopgaver. Der er ingen obligatoriske felter, den eneste anbefaling er, at aktiver skal have en ejer og være værdifulde.

Ledger — består af Blockchain og Word-statsdatabasen, som gemmer den aktuelle status for aktiver. Verdensstaten bruger LevelDB eller CouchDB.

Smart kontrakt — ved hjælp af smarte kontrakter implementeres systemets forretningslogik. I Hyperledger Fabric kaldes smarte kontrakter for kædekode. Ved hjælp af kædekode specificeres aktiver og transaktioner over dem. Teknisk set er smarte kontrakter softwaremoduler implementeret i programmeringssprogene JS eller Go.

Godkendelsespolitik — for hver kædekode kan du indstille en politik for, hvor mange bekræftelser for en transaktion, der skal forventes, og fra hvem. Hvis politikken ikke er angivet, er standarden: "transaktionen skal bekræftes af ethvert medlem af enhver organisation i kanalen." Eksempler på politikker:

  • Transaktionen skal godkendes af enhver administrator af organisationen;
  • Skal bekræftes af ethvert medlem eller klient af organisationen;
  • Skal bekræftes af enhver peer-organisation.

Bestillingsservice — pakker transaktioner i blokke og sender dem til peers i kanalen. Garanterer levering af beskeder til alle peers på netværket. Anvendes til industrielle systemer Kafka meddelelsesmægler, til udvikling og test Single.

CallFlow

Blockchain: hvilken PoC skal vi bygge?

  • Applikationen kommunikerer med Hyperledger Fabric ved hjælp af Go, Node.js eller Java SDK;
  • Klienten opretter en tx-transaktion og sender den til godkendte peers;
  • Peeren verificerer klientens underskrift, fuldfører transaktionen og sender påtegningssignaturen tilbage til klienten. Kædekode udføres kun på den godkendte peer, og resultatet af dens eksekvering sendes til alle peers. Denne arbejdsalgoritme kaldes PBFT (Practical Byzantine Fault Tolerant) konsensus. Adskiller sig fra klassiske BFT det faktum, at beskeden er sendt og bekræftelse forventes ikke fra alle deltagere, men kun fra et bestemt sæt;
  • Efter at klienten har modtaget det antal svar, der svarer til påtegningspolitikken, sender han transaktionen til bestillingstjenesten;
  • Bestillingstjenesten genererer en blok og sender den til alle forpligtende peers. Bestillingsservice sikrer sekventiel registrering af blokke, hvilket eliminerer den såkaldte hovedgaffel (se afsnittet "Gafler");
  • Peers modtager en blok, tjek godkendelsespolitikken igen, skriv blokken til blockchain og skift tilstanden i "World state" DB.

De der. Dette resulterer i en rollefordeling mellem knudepunkterne. Dette sikrer, at blockchain er skalerbar og sikker:

  • Smarte kontrakter (kædekode) udfører godkendelse af peers. Dette sikrer fortroligheden af ​​smarte kontrakter, fordi det er ikke gemt af alle deltagere, men kun ved at godkende jævnaldrende.
  • Bestilling skal fungere hurtigt. Dette sikres ved, at Bestilling kun danner en blok og sender den til et fast sæt af ledere.
  • Forpligtende peers gemmer kun blockchain - dem kan der være mange af, og de kræver ikke megen strøm og øjeblikkelig betjening.

Flere detaljer om de arkitektoniske løsninger af Hyperledger Fabric og hvorfor det fungerer på denne måde og ikke ellers kan findes her: Arkitekturs oprindelse eller her: Hyperledger Fabric: Et distribueret operativsystem til tilladte blockchains.

Så Hyperledger Fabric er et virkelig universelt system, som du kan:

  • Implementer vilkårlig forretningslogik ved hjælp af den smarte kontraktmekanisme;
  • Optag og modtag data fra blockchain-databasen i JSON-format;
  • Giv og bekræft API-adgang ved hjælp af certifikatmyndighed.

Nu hvor vi forstår lidt om detaljerne i Hyperledger Fabric, lad os endelig gøre noget nyttigt!

Implementering af blockchain

Formulering af problemet

Opgaven er at implementere Citcoin-netværket med følgende funktioner: oprette en konto, få en saldo, fylde din konto op, overføre mønter fra en konto til en anden. Lad os tegne en objektmodel, som vi videre implementerer i en smart kontrakt. Så vi vil have konti, der er identificeret med navne og indeholder en saldo og en liste over konti. Konti og en liste over konti er, hvad angår Hyperledger Fabric-aktiver. Derfor har de en historie og en nuværende tilstand. Jeg vil prøve at tegne dette tydeligt:

Blockchain: hvilken PoC skal vi bygge?

De øverste tal er den aktuelle tilstand, som er gemt i "World state"-databasen. Under dem er der figurer, der viser historien, der er gemt i blockchainen. Aktivernes aktuelle tilstand ændres af transaktioner. Aktivet ændres kun som en helhed, så som et resultat af transaktionen oprettes et nyt objekt, og den aktuelle værdi af aktivet går ind i historien.

IBM Cloud

Vi opretter en konto i IBM sky. For at bruge blockchain-platformen skal den opgraderes til Pay-As-You-Go. Denne proces er måske ikke hurtig, fordi... IBM anmoder om yderligere oplysninger og verificerer dem manuelt. På en positiv bemærkning kan jeg sige, at IBM har gode træningsmaterialer, der giver dig mulighed for at implementere Hyperledger Fabric i deres sky. Jeg kunne godt lide følgende serie af artikler og eksempler:

Følgende er skærmbilleder af IBM Blockchain-platformen. Dette er ikke en instruktion i, hvordan man laver en blockchain, men blot en demonstration af opgavens omfang. Så til vores formål laver vi én organisation:

Blockchain: hvilken PoC skal vi bygge?

Vi opretter noder i det: Orderer CA, Org1 CA, Orderer Peer:

Blockchain: hvilken PoC skal vi bygge?

Vi opretter brugere:

Blockchain: hvilken PoC skal vi bygge?

Opret en kanal og kald den citcoin:

Blockchain: hvilken PoC skal vi bygge?

I det væsentlige er Channel en blockchain, så den starter med blok nul (Genesis-blok):

Blockchain: hvilken PoC skal vi bygge?

At skrive en smart kontrakt

/*
 * 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 burde alt være klart her:

  • Der er flere funktioner (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance), som demoprogrammet vil kalde ved hjælp af Hyperledger Fabric API.
  • SendFrom- og RefillBalance-funktionerne genererer hændelser, som demoprogrammet vil modtage.
  • Instantieringsfunktionen kaldes én gang, når en smart kontrakt instantieres. Faktisk kaldes det ikke bare én gang, men hver gang den smarte kontraktversion ændres. Derfor er initialisering af en liste med et tomt array en dårlig idé, fordi Nu, når vi ændrer versionen af ​​den smarte kontrakt, mister vi den aktuelle liste. Men det er okay, jeg lærer bare).
  • Konti og en liste over konti er JSON-datastrukturer. JS bruges til datamanipulation.
  • Du kan få den aktuelle værdi af et aktiv ved hjælp af getState-funktionskaldet og opdatere det ved hjælp af putState.
  • Ved oprettelse af en konto kaldes AddAccount-funktionen, hvor der sammenlignes for det maksimale antal konti i blockchainen (maxAccounts = 5). Og her er der en jamb (har du lagt mærke til det?), som fører til en endeløs stigning i antallet af konti. Sådanne fejl skal undgås)

Dernæst indlæser vi den smarte kontrakt i kanalen og instansierer den:

Blockchain: hvilken PoC skal vi bygge?

Lad os se på transaktionen for installation af Smart Contract:

Blockchain: hvilken PoC skal vi bygge?

Lad os se på detaljerne om vores kanal:

Blockchain: hvilken PoC skal vi bygge?

Som et resultat får vi følgende diagram over et blockchain-netværk i IBM-skyen. Diagrammet viser også et demoprogram, der kører i Amazon-skyen på en virtuel server (mere om det i næste afsnit):

Blockchain: hvilken PoC skal vi bygge?

Oprettelse af en GUI til Hyperledger Fabric API-kald

Hyperledger Fabric har en API, der kan bruges til at:

  • Opret kanal;
  • Forbindelser peer-to-kanal;
  • Installation og instansiering af smarte kontrakter i kanalen;
  • Opkaldstransaktioner;
  • Anmod om information om blockchain.

Applikationsudvikling

I vores demoprogram vil vi kun bruge API'et til at kalde transaktioner og anmode om information, fordi Vi har allerede gennemført de resterende trin ved hjælp af IBM blockchain-platformen. Vi skriver en GUI ved hjælp af en standard teknologistack: Express.js + Vue.js + Node.js. Du kan skrive en separat artikel om, hvordan du begynder at skabe moderne webapplikationer. Her vil jeg efterlade et link til den serie af foredrag, som jeg kunne lide mest: Full Stack Web App ved hjælp af Vue.js & Express.js. Resultatet er en klient-server-applikation med en velkendt grafisk grænseflade i Googles Material Design-stil. REST API mellem klient og server består af flere kald:

  • HyperledgerDemo/v1/init - initialiser blokkæden;
  • HyperledgerDemo/v1/accounts/list — få en liste over alle konti;
  • HyperledgerDemo/v1/account?name=Bob&balance=100 — opret Bob-konto;
  • HyperledgerDemo/v1/info?account=Bob — få oplysninger om Bob-konto;
  • HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — overfør to mønter fra Bob til Alice;
  • HyperledgerDemo/v1/disconnect - luk forbindelsen til blockchain.

Beskrivelse af API'et med eksempler inkluderet i Postmands hjemmeside - et velkendt program til test af HTTP API.

Demo-applikation i Amazon cloud

Jeg uploadede applikationen til Amazon, fordi... IBM har stadig ikke været i stand til at opgradere min konto og tillade mig at oprette virtuelle servere. Sådan tilføjer du et kirsebær til domænet: www.citcoin.info. Jeg beholder serveren tændt et stykke tid, og så slukker jeg den, fordi... cents til leje drypper, og citcoin-mønter er endnu ikke noteret på børsen) Jeg medtager skærmbilleder af demoen i artiklen, så logikken i arbejdet er klar. Demoapplikationen kan:

  • Initialiser blockchainen;
  • Opret en konto (men nu kan du ikke oprette en ny konto, fordi det maksimale antal konti angivet i den smarte kontrakt er nået i blockchainen);
  • Modtag en liste over konti;
  • Overfør citcoin-mønter mellem Alice, Bob og Alex;
  • Modtag begivenheder (men nu er der ingen måde at vise begivenheder på, så for nemheds skyld siger grænsefladen, at begivenheder ikke understøttes);
  • Log handlinger.

Først initialiserer vi blockchain:

Blockchain: hvilken PoC skal vi bygge?

Dernæst opretter vi vores konto, spild ikke tid med saldoen:

Blockchain: hvilken PoC skal vi bygge?

Vi får en liste over alle tilgængelige konti:

Blockchain: hvilken PoC skal vi bygge?

Vi udvælger afsender og modtager og får deres saldi. Hvis afsender og modtager er den samme, vil hans konto blive genopfyldt:

Blockchain: hvilken PoC skal vi bygge?

I loggen overvåger vi udførelsen af ​​transaktioner:

Blockchain: hvilken PoC skal vi bygge?

Faktisk er det alt sammen med demoprogrammet. Nedenfor kan du se vores transaktion i blockchain:

Blockchain: hvilken PoC skal vi bygge?

Og den generelle liste over transaktioner:

Blockchain: hvilken PoC skal vi bygge?

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

  • På kontooprettelsesstadiet skal du implementere genereringen af ​​en privat/offentlig nøgle. Den private nøgle skal gemmes hos kontobrugeren, den offentlige nøgle skal gemmes i blockchainen.
  • Foretag en møntoverførsel, hvor en offentlig nøgle, i stedet for et navn, bruges til at identificere brugeren.
  • Krypter transaktioner, der går fra brugeren til serveren med hans private nøgle.

Konklusion

Vi har implementeret Citcoin-netværket med følgende funktioner: tilføje en konto, få en saldo, fylde din konto op, overføre mønter fra en konto til en anden. Så hvad kostede det os at bygge en PoC?

  • Du skal studere blockchain generelt og Hyperledger Fabric i særdeleshed;
  • Lær at bruge IBM- eller Amazon-skyer;
  • Lær JS-programmeringssproget og nogle web-framework;
  • Hvis nogle data skal lagres ikke i blockchain, men i en separat database, så lær at integrere f.eks. med PostgreSQL;
  • Og sidst men ikke mindst - du kan ikke leve i den moderne verden uden kendskab til Linux!)

Selvfølgelig er det ikke raketvidenskab, men du bliver nødt til at arbejde hårdt!

Kilder på GitHub

Kilder sat på GitHub. Kort beskrivelse af depotet:
Katalog «server» — Node.js-server
Katalog «kunde» — Node.js-klient
Katalog «blockchain"(parameterværdier og nøgler virker selvfølgelig ikke og gives kun som et eksempel):

  • kontrakt — smart kontrakt kildekode
  • tegnebog — brugernøgler til brug af Hyperledger Fabric API.
  • *.cd'er - kompilerede versioner af smarte kontrakter
  • *.json-filer - eksempler på konfigurationsfiler til brug af Hyperledger Fabric API

Det er kun begyndelsen!

Kilde: www.habr.com

Tilføj en kommentar