Ăgonen skrĂ€ms, men hĂ€nderna kliar!
I tidigare artiklar har vi gÄtt igenom de teknologier som blockchain bygger pÄ () och de fallstudier som kan realiseras med deras hjÀlp (). Det Àr dags att arbeta praktiskt! För att genomföra piloter och PoC (Proof of Concept) föredrar jag att anvÀnda moln, eftersom de Àr tillgÀngliga frÄn vilken plats som helst i vÀrlden och ofta sparar tid pÄ att installera miljöer, eftersom det finns förkonfigurerade instÀllningar. SÄ lÄt oss göra nÄgot enkelt, till exempel ett nÀtverk för att överföra mynt mellan deltagare och kalla det blygsamt Citcoin. För detta kommer vi att anvÀnda IBM:s moln och den universella blockchainen Hyperledger Fabric. LÄt oss först ta reda pÄ varför Hyperledger Fabric kallas en universell blockchain?

Hyperledger Fabric â en universell blockchain
Om man talar i allmÀnna termer, sÄ Àr ett universellt informationssystem:
- En uppsÀttning servrar och en programkÀrna som utför affÀrslogik;
- GrÀnssnitt för interaktion med systemet;
- Verktyg för registrering, autentisering och auktorisering av enheter / personer;
- En databas som lagrar operativa och arkiverade data:

Den officiella versionen av vad Hyperledger Fabric Àr kan lÀsas pÄ , och kort sagt, Hyperledger Fabric Àr en öppen plattform som möjliggör byggandet av privata blockchain och utförande av godtyckliga smarta kontrakt skrivna pÄ programmeringssprÄken JS och Go. LÄt oss titta nÀrmare pÄ arkitekturen i Hyperledger Fabric och försÀkra oss om att det Àr ett universellt system dÀr det bara finns specifika krav för lagring och registrering av data. Specifika krav innebÀr att data, precis som i alla blockchains, lagras i block som lÀggs till blockchainen endast om deltagarna nÄr konsensus och efter registrering kan data inte Àndras eller tas bort obemÀrkt.
Arkitektur av Hyperledger Fabric
I diagrammet visas arkitekturen för Hyperledger Fabric:

Organisationer â organisationerna innehĂ„ller peers, vilket gör att blockchainen existerar tack vare stödet frĂ„n organisationerna. Olika organisationer kan ingĂ„ i en och samma channel.
Channel â en logisk struktur som förenar peers i grupper, vilket definierar blockchainen. Hyperledger Fabric kan samtidigt hantera flera blockchains med olika affĂ€rslogik.
Membership Services Provider (MSP) â detta Ă€r CA (Certificate Authority) för att utfĂ€rda identiteter och tilldela roller. För att skapa en nod mĂ„ste man interagera med MSP.
Peer-noder â kontrollerar transaktioner, lagrar blockkedjan, utför smarta kontrakt och interagerar med applikationer. Peer-noder har en identitet (digitalt certifikat) som utfĂ€rdas av MSP. Till skillnad frĂ„n Bitcoin- eller Ethereum-nĂ€tverk, dĂ€r alla noder Ă€r lika, spelar noder i Hyperledger Fabric olika roller:
- Peer kan vara endorsing peer (EP) och utföra smarta kontrakt.
- Committing peer (CP) â sparar endast data i blockkedjan och uppdaterar "World state".
- Anchor Peer (AP) â om flera organisationer deltar i blockkedjan, anvĂ€nds anchor peers för att koppla samman dem. Varje organisation mĂ„ste ha en eller flera anchor peers. Med hjĂ€lp av AP kan varje peer i en organisation fĂ„ information om alla peers i andra organisationer. För att synkronisera information mellan AP anvĂ€nds .
- Leader Peer â om en organisation har flera peers, kommer endast ledande peer att ta emot block frĂ„n Ordering service och vidarebefordra dem till de andra peers. Ledaren kan antingen stĂ€llas in statiskt eller vĂ€ljas dynamiskt av peers inom organisationen. För att synkronisera information om ledarna anvĂ€nds Ă€ven gossip-protokollet.
TillgĂ„ngar â enheter som har vĂ€rde och som lagras i blockkedjan. Mer specifikt Ă€r detta key-value data i JSON-format. Det Ă€r dessa data som registreras i blockkedjan "Blockchain". De har en historia som lagras i blockkedjan och ett aktuellt tillstĂ„nd som lagras i databasen "World state". Datastrukturer fylls jĂ€mnt beroende pĂ„ affĂ€rsbehov. Det finns inga obligatoriska fĂ€lt, den enda rekommendationen Ă€r att tillgĂ„ngarna bör ha en Ă€gare och representera ett vĂ€rde.
Huvudbok â bestĂ„r av blockkedjan "Blockchain" och databasen "World state", dĂ€r det aktuella tillstĂ„ndet för tillgĂ„ngarna lagras. World state anvĂ€nder LevelDB eller CouchDB.
Smart kontrakt â genom smarta kontrakt implementeras systemets affĂ€rslogik. I Hyperledger Fabric kallas smarta kontrakt för chaincode. Med hjĂ€lp av chaincode definieras tillgĂ„ngar och transaktioner pĂ„ dem. Om man talar tekniskt Ă€r smarta kontrakt programmoduler som implementeras i programmeringssprĂ„ken JS eller Go.
Endorsement policy â för varje chaincode kan man stĂ€lla in policys för hur mĂ„nga och frĂ„n vem bekrĂ€ftelser mĂ„ste förvĂ€ntas för en transaktion. Om policyn inte Ă€r angiven anvĂ€nds som standard: âtransaktionen mĂ„ste bekrĂ€ftas av varje medlem (member) i nĂ„gon organisation i channelâ. Exempel pĂ„ policys:
- Transaktionen mÄste bekrÀftas av en administratör i organisationen;
- MÄste bekrÀftas av en medlem eller kund i organisationen;
- MÄste bekrÀftas av en peer i organisationen.
Ordering service â paketerar transaktioner i block och skickar dem till peers i channel. Den garanterar leverans av meddelanden till alla peers i nĂ€tverket. För industrisystem anvĂ€nds , för utveckling och testning .
CallFlow

- Applikationen interagerar med Hyperledger Fabric med hjÀlp av Go, Node.js eller Java SDK;
- Klienten skapar transaktionen tx och skickar den till endorsing peers;
- Peer kontrollerar klientens signatur, utför transaktionen och skickar endorsement signature tillbaka till klienten. Chaincode körs endast pĂ„ endorsing peers och resultatet av denna körning distribueras till alla peers. Denna arbetsmetod kallas â PBFT (Practical Byzantine Fault Tolerant) konsensus. Den skiljer sig frĂ„n genom att meddelandet skickas och ett bekrĂ€ftande svar inte förvĂ€ntas frĂ„n alla deltagare, utan endast frĂ„n ett visst urval;
- Efter att klienten fÄtt ett antal svar som motsvarar endorsement policy, skickar han transaktionen till Ordering service;
- Ordering service skapar ett block och skickar det till alla committing peers. Ordering service sÀkerstÀller en sekventiell inspelning av block, vilket utesluter sÄ kallad ledger fork ();
- Peers fÄr blocket, kontrollerar ytterligare endorsement policy, skriver blocket i blockchain och Àndrar tillstÄndet i "World state" DB.
Dvs. det blir en uppdelning av roller mellan noderna. Detta möjliggör skalning och sÀkerhet för blockchain:
- Smartkontrakt (chaincode) körs av endorsing peers. Detta sÀkerstÀller konfidentialitet för smartkontrakten, eftersom de inte lagras av alla deltagare, utan endast av endorsing peers.
- Ordering mÄste arbeta snabbt. Detta sÀkerstÀlls genom att Ordering endast skapar block och skickar det till en fast uppsÀttning leader peers.
- Committing peers lagrar endast blockchain â de kan vara mĂ„nga och de krĂ€ver inte stor kraft och omedelbarhet.
För mer information om den arkitektoniska lösningen för Hyperledger Fabric och varför den fungerar sÄ, kan du se hÀr: eller hÀr: .
SÄ, Hyperledger Fabric Àr verkligen ett mÄngsidigt system, med hjÀlp av vilket man kan:
- Genomföra godtycklig affÀrslogik, med hjÀlp av smartkontraktssystemet;
- Skriva och hÀmta data frÄn blockkedjedatabasen i JSON-format;
- TillhandahÄlla och verifiera Ätkomst till API, med hjÀlp av certifikatutfÀrdare.
Nu nÀr vi har förstÄtt nÄgra specifika aspekter av Hyperledger Fabric, lÄt oss Àntligen göra nÄgot nyttigt!
SĂ€tter upp en blockkedja
UppgiftsstÀllande
Uppgiften Àr att implementera ett Citcoin-nÀtverk med följande funktioner: skapa konto, hÀmta saldo, fylla pÄ konto, överföra mynt frÄn ett konto till ett annat. Vi kommer att rita en objektsmodell som vi sedan implementerar i smarta kontrakt. SÄ, vi kommer att ha konton som identifieras av namn (name) och som innehÄller saldo (balance), samt en lista över konton. Konton och lista över konton Àr tillgÄngar (assets) i termer av Hyperledger Fabric. DÀrför har de en historia och ett aktuellt tillstÄnd. Jag ska försöka att visa detta tydligt:

De övre figurerna representerar det aktuella tillstÄndet som lagras i "World state". Under dem finns figurer som visar historiken som lagras i blockkedjan. Det aktuella tillstÄndet för tillgÄngar förÀndras genom transaktioner. En tillgÄng Àndras endast helt, sÄ i resultatet av transaktionen skapas ett nytt objekt, medan det aktuella vÀrdet för tillgÄngen gÄr till historien.
IBM-molnet
Skapa ett konto i . För att anvÀnda blockkedjeplattformen mÄste den uppgraderas till Pay-As-You-Go. Denna process kan ta tid, eftersom IBM begÀr ytterligare information och kontrollerar den manuellt. PÄ den positiva sidan kan jag sÀga att IBM har bra utbildningsmaterial som gör det möjligt att sÀtta upp Hyperledger Fabric i deras moln. Jag gillade följande artiklar och exempel:
Nedan följer skÀrmdumpar av IBMs Blockchain-plattform. Detta Àr ingen instruktion för att skapa en blockkedja, utan bara en demonstration av uppgiftens omfattning. SÄ för vÄra ÀndamÄl skapar vi en organisation:

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

Skapar anvÀndare:

Skapa Channel och kalla den citcoin:

I grunden Àr Channel en blockkedja, sÄ den börjar med block noll (Genesis block):

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 allt vara sjÀlvklart hÀr:
- Det finns flera funktioner (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance) som demoprogrammet kommer att kalla via Hyperledger Fabric API.
- Funktionerna SendFrom och RefillBalance genererar hÀndelser (Event) som demoprogrammet kommer att ta emot.
- Funktionen instantiate anropas en gÄng vid instansiering av smarta kontrakt. Faktiskt anropas den inte bara en gÄng utan varje gÄng vid Àndring av versionen av det smarta kontraktet. DÀrför Àr det en dÄlig idé att initiera listan med en tom array, eftersom vi nu kommer att förlora den aktuella listan vid versionbyte. Men det Àr okej, jag lÀr mig ju bara).
- Conton och listan över konton (accounts) Àr JSON datakonstruktioner. För datahantering anvÀnds JS.
- Det aktuella vÀrdet av tillgÄngen (asset) kan hÀmtas med hjÀlp av funktionen getState, och uppdateras med putState.
- Vid skapandet av ett Account anropas funktionen AddAccount, dÀr en jÀmförelse görs med det maximala antalet konton i blockkedjan (maxAccounts = 5). HÀr finns en bugg (la ni mÀrke till det?) som leder till en oÀndlig ökning av antalet konton. SÄdana fel mÄste undvikas).
DĂ€refter laddar vi upp det smarta kontraktet till Channel och instansierar det:

Vi tittar pÄ transaktionen för installation av Smart Contract:

Vi ser detaljer om vÄr Channel:

Som resultat fÄr vi följande schema av blockkedjenÀtverket i IBM:s moln. Schemata visar ocksÄ ett demo-program som körs i Amazons moln pÄ en virtuell server (detaljer om det kommer i nÀsta avsnitt):

Skapa GUI för att anropa Hyperledger Fabric API
Hyperledger Fabric har ett API som kan anvÀndas för:
- Att skapa channel;
- Ansluta peer till channel;
- Installera och instansiera smarta kontrakt i channel;
- Anropa transaktioner;
- BegÀra information i blockkedjan.
Utveckling av applikation
I vÄrt demo-program kommer vi att anvÀnda API:et endast för att anropa transaktioner och begÀra information, eftersom de andra stegen redan har gjorts med hjÀlp av IBM:s blockkedjeplattform. Vi skriver GUI med hjÀlp av en standardteknikstack: Express.js + Vue.js + Node.js. Hur man börjar skapa moderna webbapplikationer skulle kunna bli en separat artikel. HÀr lÀmnar jag en lÀnk till en serie förelÀsningar som jag tyckte mycket om: . Som resultat blev det en klient-serverapplikation med ett bekant grafiskt grÀnssnitt i stil med Material Design frÄn Google. REST API mellan klienten och servern bestÄr av flera anrop:
- HyperledgerDemo/v1/init â initiera blockkedjan;
- HyperledgerDemo/v1/accounts/list â hĂ€mta lista över alla konton;
- HyperledgerDemo/v1/account?name=Bob&balance=100 â skapa Bob konto;
- HyperledgerDemo/v1/info?account=Bob â hĂ€mta information om Bob konto;
- HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 â överföra tvĂ„ mynt frĂ„n Bob till Alice;
- HyperledgerDemo/v1/disconnect â stĂ€nga anslutningen till blockkedjan.
API-beskrivningen med exempel har jag lagt pĂ„ â en vĂ€lkĂ€nd programvara för testning av HTTP API.
Demoprogrammet i Amazon-molnet
Jag har laddat upp appen till Amazon, eftersom IBM Ànnu inte har kunnat uppgradera mitt konto och tillÄta skapande av virtuella servrar. Som pricket över i:et har jag lagt en domÀn: . Jag kommer att hÄlla servern pÄslagen ett tag, men sedan stÀnga av den eftersom kostnaderna för uthyrning tickar, och citcoin-mynten Àr fortfarande inte noterade pÄ börsen) I artikeln lÀgger jag in skÀrmdumpar av demon sÄ att logiken för arbetet blir tydlig. Demoprogrammet kan:
- Initiera blockkedjan;
- Skapa konto (men just nu gÄr det inte att skapa nytt konto eftersom det maximala antalet konton som anges i smartkontraktet har nÄtts);
- HÀmta lista över konton;
- Ăverföra citcoin-mynt mellan Alice, Bob och Alex;
- HÀmta hÀndelser (men just nu kan hÀndelser inte visas, dÀrför har det skrivits i grÀnssnittet för enkelhetens skull att hÀndelser inte stöds);
- Logga ÄtgÀrder.
Först initierar vi blockkedjan:

DÀrefter skapar vi vÄrt konto, vi snÄlar inte med saldot:

Vi hÀmtar lista över alla tillgÀngliga konton:

VÀljer avsÀndare och mottagare, vi fÄr deras saldon. Om avsÀndare och mottagare Àr samma person, sÄ kommer dennes saldo att öka:

I loggen följer vi transaktionernas genomförande:

Det var faktist allt om demoprogrammet. Vi kan nu se vÄr transaktion i blockkedjan:

Och den totala listan över transaktioner:

HÀrmed har vi framgÄngsrikt avslutat genomförandet av PoC för att skapa nÀtverket Citcoin. Vad mer behövs för att Citcoin ska bli ett fullfjÀdrat nÀtverk för överföring av mynt? Inte mycket:
- Vid skapandet av kontot implementera genereringen av privat/offentligt nyckel. Den privata nyckeln ska lagras av kontoanvÀndaren, den offentliga i blockkedjan.
- Göra överföring av mynt dÀr anvÀndarens identifiering anvÀnder den offentliga nyckeln istÀllet för namnet.
- Kryptera transaktionerna som gÄr frÄn anvÀndaren till servern med dennes privata nyckel.
Slutsats
Vi har implementerat nÀtverket Citcoin med funktionerna: lÀgga till konto, fÄ saldo, fylla pÄ sitt konto, överföra mynt frÄn ett konto till ett annat. SÄ, vad krÀvdes för att bygga PoC?
- Vi mÄste studera blockkedjan i allmÀnhet och Hyperledger Fabric i synnerhet;
- LÀra oss att anvÀnda IBM:s eller Amazons molntjÀnster;
- LÀr dig programmeringssprÄket JS och nÄgon webbramverk;
- Om vissa data behöver lagras inte i blockchain, utan i en separat databas, sÄ lÀr dig att integrera, till exempel med PostgreSQL;
- Och sist men inte minst â utan kunskaper i Linux kommer man inte lĂ„ngt i dagens vĂ€rld!)
SjÀlvklart, inte rocket science, men det kommer att krÀva lite anstrÀngning!
KÀllkoden pÄ GitHub
KÀllkoden har lagts pÄ . Kort beskrivning av förvaret:
Katalogen "server" â Node.js-servern
Katalogen "klient" â Node.js-klienten
Katalogen "blockchain" (parametervÀrden och nycklar Àr givetvis inte funktionella och endast exempelvis):
- contract â kĂ€llkod för smart kontrakt
- wallet â anvĂ€ndarnycklar för att anvĂ€nda Hyperledger Fabric API.
- *.cds â kompilerade versioner av smarta kontrakt
- *.json-filer â exempel pĂ„ konfigurationsfiler för att anvĂ€nda Hyperledger Fabric API
Det Àr bara början!
KĂ€lla: habr.com
