Blockchain: vilken PoC ska vi bygga?

Dina ögon är rädda och dina händer kliar!

I tidigare artiklar har vi behandlat de teknologier som blockkedjor bygger på (Vad ska vi bygga en blockchain?) och fall som kan implementeras med deras hjälp (Varför ska vi bygga ett fall?). Det är dags att arbeta med händerna! För att implementera piloter och PoC (Proof of Concept) föredrar jag att använda molnen, eftersom... de kan nås från var som helst i världen och ofta finns det ingen anledning att slösa tid på tråkig installation av miljön, eftersom Det finns förinställda konfigurationer. Så, låt oss göra något enkelt, till exempel ett nätverk för att överföra mynt mellan deltagare och låt oss blygsamt kalla det Bitcoin. För detta kommer vi att använda IBM-molnet och den universella blockkedjan Hyperledger Fabric. Låt oss först ta reda på varför Hyperledger Fabric kallas en universell blockchain?

Blockchain: vilken PoC ska vi bygga?

Hyperledger Fabric - en universell blockchain

Generellt sett är ett universellt informationssystem:

  • En uppsättning servrar och en mjukvarukärna som utför affärslogik;
  • Gränssnitt för interaktion med systemet;
  • Verktyg för registrering, autentisering och auktorisering av enheter/personer;
  • Databas som lagrar drifts- och arkivdata:

Blockchain: vilken PoC ska vi bygga?

Den officiella versionen av vad Hyperledger Fabric är kan läsas på Online, och kort sagt, Hyperledger Fabric är en öppen källkodsplattform som låter dig bygga privata blockkedjor och exekvera godtyckliga smarta kontrakt skrivna i programmeringsspråken JS och Go. Låt oss titta i detalj på arkitekturen hos Hyperledger Fabric och se till att detta är ett universellt system som bara har detaljer för lagring och inspelning av data. Specificiteten är att data, som i alla blockkedjor, lagras i block som placeras på blockkedjan endast om deltagarna når en konsensus och efter inspelning inte kan korrigeras eller raderas i tysthet.

Hyperledger tygarkitektur

Diagrammet visar Hyperledger Fabric-arkitekturen:

Blockchain: vilken PoC ska vi bygga?

Organisationer — organisationer innehåller kamrater, dvs. blockchain existerar på grund av stöd från organisationer. Olika organisationer kan vara en del av samma kanal.

Kanal — en logisk struktur som förenar kamrater i grupper, d.v.s. blockkedjan är specificerad. Hyperledger Fabric kan samtidigt bearbeta flera blockkedjor med olika affärslogik.

Medlemstjänstleverantör (MSP) är en CA (Certificate Authority) för att utfärda identitet och tilldela roller. För att skapa en nod måste du interagera med MSP.

Peer noder — verifiera transaktioner, lagra blockkedjan, utföra smarta kontrakt och interagera med applikationer. Peers har en identitet (digitalt certifikat), som utfärdas av MSP. Till skillnad från Bitcoin- eller Etherium-nätverket, där alla noder har lika rättigheter, i Hyperledger Fabric spelar noder olika roller:

  • Peer kanske stödja peer (EP) och utföra smarta kontrakt.
  • Engagerande kamrat (CP) - spara bara data i blockkedjan och uppdatera "World state".
  • Ankare Peer (AP) - om flera organisationer deltar i blockkedjan används ankarkamrater för kommunikation mellan dem. Varje organisation måste ha en eller flera ankarkamrater. Med hjälp av AP kan alla kamrater i en organisation få information om alla kamrater i andra organisationer. Används för att synkronisera information mellan AP:er skvallerprotokoll.
  • Ledare Peer — om en organisation har flera kamrater är det bara ledaren för kamraten som kommer att få block från beställningstjänsten och ge dem till resten av kamraterna. Ledaren kan antingen specificeras statiskt eller väljas dynamiskt av kamrater i organisationen. Skvallerprotokollet används också för att synkronisera information om ledare.

Tillgångar — enheter som har värde och lagras i blockkedjan. Mer specifikt är detta nyckel-värdedata i JSON-format. Det är denna data som registreras i Blockchain. De har en historik som lagras i blockkedjan och ett aktuellt tillstånd som lagras i databasen "World state". Datastrukturer fylls godtyckligt beroende på affärsuppgifter. Det finns inga obligatoriska fält, den enda rekommendationen är att tillgångar måste ha en ägare och vara värdefulla.

Ledger — består av blockkedjan och Word-tillståndsdatabasen, som lagrar tillgångarnas aktuella tillstånd. World state använder LevelDB eller CouchDB.

Smart kontrakt — Med hjälp av smarta kontrakt implementeras systemets affärslogik. I Hyperledger Fabric kallas smarta kontrakt för kedjekod. Med hjälp av kedjekod specificeras tillgångar och transaktioner över dem. I tekniska termer är smarta kontrakt programvarumoduler implementerade i programmeringsspråken JS eller Go.

Policy för rekommendationer — för varje kedjekod kan du ställa in en policy för hur många bekräftelser för en transaktion som ska förväntas och från vem. Om policyn inte är inställd är standardinställningen: "transaktionen måste bekräftas av alla medlemmar i någon organisation i kanalen." Exempel på policyer:

  • Transaktionen måste godkännas av organisationens administratör;
  • Måste bekräftas av någon medlem eller kund i organisationen;
  • Måste bekräftas av någon kamratorganisation.

Beställningstjänst — packar transaktioner i block och skickar dem till peers i kanalen. Garanterar leverans av meddelanden till alla peers i nätverket. Används för industriella system Kafka meddelande mäklare, för utveckling och testning Solo.

CallFlow

Blockchain: vilken PoC ska vi bygga?

  • Applikationen kommunicerar med Hyperledger Fabric med hjälp av Go, Node.js eller Java SDK;
  • Klienten skapar en tx-transaktion och skickar den till stödjande peers;
  • Peer verifierar klientens signatur, slutför transaktionen och skickar rekommendationssignaturen tillbaka till klienten. Kedjekod exekveras endast på den godkända peeren, och resultatet av dess exekvering skickas till alla peers. Denna arbetsalgoritm kallas PBFT (Practical Byzantine Fault Tolerant) konsensus. Skiljer sig från klassiska BFT det faktum att meddelandet skickas och bekräftelse förväntas inte från alla deltagare, utan endast från en viss uppsättning;
  • Efter att kunden har fått det antal svar som motsvarar påskriftspolicyn skickar han transaktionen till Beställningstjänsten;
  • Beställningstjänsten genererar ett block och skickar det till alla förpliktande kamrater. Beställningstjänst säkerställer sekventiell registrering av block, vilket eliminerar den så kallade reskontragaffeln (se avsnittet "Gafflar");
  • Peers får ett block, kontrollera rekommendationspolicyn igen, skriv blocket till blockkedjan och ändra tillståndet i "World state" DB.

De där. Detta resulterar i en rollfördelning mellan noderna. Detta säkerställer att blockkedjan är skalbar och säker:

  • Smarta kontrakt (chaincode) utför stödjande av kamrater. Detta säkerställer sekretessen för smarta kontrakt, eftersom den lagras inte av alla deltagare, utan endast av stödjande kamrater.
  • Beställning bör fungera snabbt. Detta säkerställs av det faktum att Beställning endast bildar ett block och skickar det till en fast uppsättning ledarkamrater.
  • Engagerande kamrater lagrar bara blockkedjan - det kan finnas många av dem och de kräver inte mycket kraft och omedelbar drift.

Mer information om de arkitektoniska lösningarna för Hyperledger Fabric och varför det fungerar på det här sättet och inte på annat sätt kan hittas här: Arkitektur ursprung eller här: Hyperledger Fabric: Ett distribuerat operativsystem för tillåtna blockkedjor.

Så, Hyperledger Fabric är ett verkligt universellt system med vilket du kan:

  • Implementera godtycklig affärslogik med den smarta kontraktsmekanismen;
  • Spela in och ta emot data från blockchain-databasen i JSON-format;
  • Bevilja och verifiera API-åtkomst med hjälp av certifikatutfärdare.

Nu när vi förstår lite om detaljerna i Hyperledger Fabric, låt oss äntligen göra något användbart!

Implementera blockchain

Problem uttalande

Uppgiften är att implementera Citcoin-nätverket med följande funktioner: skapa ett konto, få ett saldo, fylla på ditt konto, överföra mynt från ett konto till ett annat. Låt oss rita en objektmodell, som vi kommer att implementera vidare i ett smart kontrakt. Så vi kommer att ha konton som identifieras med namn och som innehåller ett saldo och en lista över konton. Konton och en lista över konton är, i termer av Hyperledger Fabric-tillgångar. Följaktligen har de en historia och ett aktuellt tillstånd. Jag ska försöka rita detta tydligt:

Blockchain: vilken PoC ska vi bygga?

De översta siffrorna är det aktuella tillståndet, som lagras i databasen "World state". Under dem finns siffror som visar historiken som är lagrad i blockkedjan. Tillgångarnas nuvarande tillstånd ändras av transaktioner. Tillgången ändras bara som en helhet, så som ett resultat av transaktionen skapas ett nytt objekt och tillgångens nuvarande värde går in i historien.

IBM Cloud

Vi skapar ett konto i IBM moln. För att använda blockchain-plattformen måste den uppgraderas till Pay-As-You-Go. Denna process kanske inte är snabb, eftersom... IBM begär ytterligare information och verifierar den manuellt. Positivt kan jag säga att IBM har bra utbildningsmaterial som låter dig distribuera Hyperledger Fabric i deras moln. Jag gillade följande serie med artiklar och exempel:

Följande är skärmdumpar av IBM Blockchain-plattformen. Detta är inte en instruktion om hur man skapar en blockchain, utan bara en demonstration av uppgiftens omfattning. Så för våra syften skapar vi en organisation:

Blockchain: vilken PoC ska vi bygga?

Vi skapar noder i den: Orderer CA, Org1 CA, Orderer Peer:

Blockchain: vilken PoC ska vi bygga?

Vi skapar användare:

Blockchain: vilken PoC ska vi bygga?

Skapa en kanal och kalla den citcoin:

Blockchain: vilken PoC ska vi bygga?

Channel är i huvudsak en blockkedja, så den börjar med block noll (Genesis block):

Blockchain: vilken PoC ska vi bygga?

Att skriva ett 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 borde allt vara klart här:

  • Det finns flera funktioner (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance) som demoprogrammet kommer att anropa med hjälp av Hyperledger Fabric API.
  • Funktionerna SendFrom och RefillBalance genererar händelser som demoprogrammet kommer att ta emot.
  • Instantieringsfunktionen anropas en gång när ett smart kontrakt instansieras. I själva verket kallas det inte bara en gång, utan varje gång den smarta kontraktsversionen ändras. Därför är det en dålig idé att initiera en lista med en tom array, eftersom Nu, när vi ändrar versionen av det smarta kontraktet, kommer vi att förlora den aktuella listan. Men det är okej, jag lär mig bara).
  • Konton och en lista över konton är JSON-datastrukturer. JS används för datamanipulation.
  • Du kan få det aktuella värdet av en tillgång med hjälp av getState-funktionsanropet och uppdatera det med putState.
  • När du skapar ett konto anropas funktionen AddAccount, där en jämförelse görs för det maximala antalet konton i blockkedjan (maxAccounts = 5). Och här finns en jamb (har du märkt det?), som leder till en oändlig ökning av antalet konton. Sådana misstag bör undvikas)

Därefter laddar vi det smarta kontraktet i kanalen och instansierar det:

Blockchain: vilken PoC ska vi bygga?

Låt oss titta på transaktionen för att installera Smart Contract:

Blockchain: vilken PoC ska vi bygga?

Låt oss titta på detaljerna om vår kanal:

Blockchain: vilken PoC ska vi bygga?

Som ett resultat får vi följande diagram över ett blockchain-nätverk i IBM-molnet. Diagrammet visar också ett demoprogram som körs i Amazon-molnet på en virtuell server (mer om det i nästa avsnitt):

Blockchain: vilken PoC ska vi bygga?

Skapa ett GUI för Hyperledger Fabric API-anrop

Hyperledger Fabric har ett API som kan användas för att:

  • Skapa kanal;
  • Anslutningar peer to channel;
  • Installation och instansiering av smarta kontrakt i kanalen;
  • Ringa transaktioner;
  • Begär information om blockchain.

Applikationsutveckling

I vårt demoprogram kommer vi att använda API endast för att ringa transaktioner och begära information, eftersom Vi har redan slutfört de återstående stegen med IBMs blockchain-plattform. Vi skriver ett GUI med hjälp av en standardteknikstack: Express.js + Vue.js + Node.js. Du kan skriva en separat artikel om hur du börjar skapa moderna webbapplikationer. Här lämnar jag en länk till den serie föreläsningar som jag gillade mest: Full Stack Web App med Vue.js & Express.js. Resultatet är en klient-serverapplikation med ett välbekant grafiskt gränssnitt i Googles materialdesignstil. REST API mellan klient och server består av flera anrop:

  • HyperledgerDemo/v1/init - initiera blockkedjan;
  • HyperledgerDemo/v1/accounts/list — få en lista över alla konton;
  • HyperledgerDemo/v1/account?name=Bob&balance=100 — skapa Bob-konto;
  • HyperledgerDemo/v1/info?account=Bob — få information om Bob-kontot;
  • HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — överför två mynt från Bob till Alice;
  • HyperledgerDemo/v1/disconnect - stäng anslutningen till blockkedjan.

Beskrivning av API:t med exempel inkluderade i Postman hemsida - ett välkänt program för att testa HTTP API.

Demoapplikation i Amazons moln

Jag laddade upp applikationen till Amazon eftersom... IBM har fortfarande inte kunnat uppgradera mitt konto och tillåta mig att skapa virtuella servrar. Så här lägger du till ett körsbär till domänen: www.citcoin.info. Jag håller servern på ett tag och stänger sedan av den, för... cent för uthyrning droppar, och citcoin-mynt är ännu inte noterade på börsen) Jag inkluderar skärmdumpar av demon i artikeln så att logiken i arbetet är tydlig. Demoapplikationen kan:

  • Initiera blockkedjan;
  • Skapa ett konto (men nu kan du inte skapa ett nytt konto, eftersom det maximala antalet konton som anges i det smarta kontraktet har uppnåtts i blockkedjan);
  • Få en lista över konton;
  • Överför citcoin-mynt mellan Alice, Bob och Alex;
  • Ta emot händelser (men nu finns det inget sätt att visa händelser, så för enkelhetens skull säger gränssnittet att händelser inte stöds);
  • Logga åtgärder.

Först initierar vi blockkedjan:

Blockchain: vilken PoC ska vi bygga?

Därefter skapar vi vårt konto, slösa inte tid med saldot:

Blockchain: vilken PoC ska vi bygga?

Vi får en lista över alla tillgängliga konton:

Blockchain: vilken PoC ska vi bygga?

Vi väljer avsändare och mottagare och får deras saldon. Om avsändaren och mottagaren är samma, kommer hans konto att fyllas på:

Blockchain: vilken PoC ska vi bygga?

I loggen övervakar vi utförandet av transaktioner:

Blockchain: vilken PoC ska vi bygga?

Egentligen är det allt med demoprogrammet. Nedan kan du se vår transaktion i blockkedjan:

Blockchain: vilken PoC ska vi bygga?

Och den allmänna listan över transaktioner:

Blockchain: vilken PoC ska vi bygga?

Med detta har vi framgångsrikt slutfört implementeringen av PoC för att skapa Citcoin-nätverket. Vad mer behöver göras för att Citcoin ska bli ett fullfjädrat nätverk för överföring av mynt? Väldigt lite:

  • Vid skapande av konto, implementera genereringen av en privat/offentlig nyckel. Den privata nyckeln måste lagras hos kontoanvändaren, den offentliga nyckeln måste lagras i blockkedjan.
  • Gör en myntöverföring där en offentlig nyckel, snarare än ett namn, används för att identifiera användaren.
  • Kryptera transaktioner som går från användaren till servern med hans privata nyckel.

Slutsats

Vi har implementerat Citcoin-nätverket med följande funktioner: lägga till ett konto, få ett saldo, fylla på ditt konto, överföra mynt från ett konto till ett annat. Så vad kostade det oss att bygga en PoC?

  • Du behöver studera blockchain i allmänhet och Hyperledger Fabric i synnerhet;
  • Lär dig att använda IBM eller Amazons moln;
  • Lär dig programmeringsspråket JS och en del webbramverk;
  • Om vissa data behöver lagras inte i blockkedjan, utan i en separat databas, lär dig då att integrera till exempel med PostgreSQL;
  • Och sist men inte minst - du kan inte leva i den moderna världen utan kunskap om Linux!)

Naturligtvis är det inte raketvetenskap, men du måste jobba hårt!

Källor på GitHub

Källor satt på GitHub. Kort beskrivning av förvaret:
Katalog "server» — Node.js-server
Katalog "klient» — Node.js-klient
Katalog "blockchain"(parametervärden och nycklar, naturligtvis, fungerar inte och ges endast som ett exempel):

  • kontrakt — källkod för smart kontrakt
  • plånbok — användarnycklar för att använda Hyperledger Fabric API.
  • *.cds - kompilerade versioner av smarta kontrakt
  • *.json-filer - exempel på konfigurationsfiler för användning av Hyperledger Fabric API

Det är bara början!

Källa: will.com

Lägg en kommentar