/*
* 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;
直觀上,這裡一切都應該很清楚:
演示程式將使用 Hyperledger Fabric API 呼叫多個函數(AddAccount、GetAccounts、SendFrom、GetBalance、RefillBalance)。
結果,我們得到了 IBM 雲端中的區塊鏈網路的下圖。 該圖還顯示了在亞馬遜雲端虛擬伺服器上運行的演示程式(下一節將詳細介紹):
為 Hyperledger Fabric API 呼叫建立 GUI
Hyperledger Fabric 有一個 API,可用來:
創建頻道;
對等通道的連接;
通道中智能合約的安裝和實例化;
調用交易;
請求區塊鏈上的信息。
應用開發
在我們的演示程式中,我們將僅使用 API 來呼叫交易和請求訊息,因為我們已經使用 IBM 區塊鏈平台完成了剩餘步驟。 我們使用標準技術堆疊來編寫 GUI:Express.js + Vue.js + Node.js。 您可以撰寫一篇單獨的文章來介紹如何開始建立現代 Web 應用程式。 在這裡我留下我最喜歡的系列講座的連結: 使用 Vue.js 和 Express.js 的全端 Web 應用程式。 結果是一個客戶端-伺服器應用程序,具有熟悉的 Google 材料設計風格的圖形介面。 客戶端和伺服器之間的 REST API 由多個呼叫組成:
HyperledgerDemo/v1/init - 初始化區塊鏈;
HyperledgerDemo/v1/accounts/list — 取得所有帳戶的清單;
HyperledgerDemo/v1/account?name=Bob&balance=100 — 建立 Bob 帳戶;
HyperledgerDemo/v1/info?account=Bob — 取得有關 Bob 帳戶的資訊;
HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 — 將兩個幣從 Bob 轉移給 Alice;