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?
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:
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:
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
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.
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:
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:
Vi opretter noder i det: Orderer CA, Org1 CA, Orderer Peer:
Vi opretter brugere:
Opret en kanal og kald den citcoin:
I det væsentlige er Channel en blockchain, så den starter med blok nul (Genesis-blok):
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:
Lad os se på transaktionen for installation af Smart Contract:
Lad os se på detaljerne om vores kanal:
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):
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/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:
Dernæst opretter vi vores konto, spild ikke tid med saldoen:
Vi får en liste over alle tilgængelige konti:
Vi udvælger afsender og modtager og får deres saldi. Hvis afsender og modtager er den samme, vil hans konto blive genopfyldt:
I loggen overvåger vi udførelsen af transaktioner:
Faktisk er det alt sammen med demoprogrammet. Nedenfor kan du se vores transaktion i blockchain:
Og den generelle liste over transaktioner:
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