Ăynene er redde, men hendene klĂžr!
I forrige artikler diskuterte vi teknologiene som blockchain er bygget pÄ () og tilfellene som kan implementeres ved hjelp av dem (). 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?

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:

Den offisielle versjonen av hva Hyperledger Fabric er, kan leses pÄ , 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:

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 .
- 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 , for utvikling og testing .
CallFlow

- 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 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 ();
- 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: eller her: .
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:

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 . 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:

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

Oppretter brukere:

Oppretter en kanal og kaller den citcoin:

I bunn og grunn er kanal en blockchain, sÄ den begynner med nullblokken (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 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:

Vi ser pÄ transaksjonen for Ä etablere Smart Contract:

Vi ser detaljene om vÄr Channel:

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):

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: . 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Ă„ â 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: . 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:

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

Vi fÄr en liste over alle tilgjengelige accounts:

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

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

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

Og den samlede transaksjonslisten:

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Ä . 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
