區塊鏈研究實驗室|使用Node.js開發Hyperledger Fabric Chaincode

買賣虛擬貨幣

Hyperledger Fabric術語中的Chaincode是什麼?

在Hyperledger Fabric中,Chaincode是在網路peer上執行的一段程式碼,用於實現應用程式如何與分類帳互動的業務邏輯。提出交易時,它會觸發Chaincode,該Chaincode決定應將哪種狀態更改應用於分類帳。因此為了在Hyperledger Fabric上開發去中心化的應用程式,必須編寫稱為Chaincode的應用程式邏輯。

Chaincode可以使用Go,Nodejs,Java編寫。其他兩種語言相比,Node.js是一種更容易理解和使用的語言。由於Node.js文件中可用的資訊非常少,但編寫和部署Node.js Chaincode並不困難。因此我決定編寫一些Node.js Chaincode的概念,並逐步編寫和部署簡單的Chaincode。

Hyperledger Fabric資料庫

在深入研究Chaincode之前,首先讓我們看一下Hyperledger Fabric Network中資料的儲存位置。Hyperledger Fabric使用鍵值資料庫儲存其狀態。預設情況下,Fabric使用LevelDB。該資料庫儲存可以使用其鍵查詢的特定物件的二進位制資料。與傳統的資料庫不同,區塊鏈資料庫位於網路的每個peer上。因此它被稱為分散網路。

除了LevelDB,還有另一個用於Hyperledger Fabric的資料庫稱為CouchDB。CouchDB是可選的替代外部可插拔狀態資料庫。與LevelDB鍵值儲存一樣,CouchDB可以儲存以鏈碼建模的任何二進位制資料。但作為JSON文件儲存,當將Chaincode值(例如資產)建模為JSON資料時,CouchDB還可以對Chaincode資料進行豐富的查詢。

Chaincode元件

1.fabric-contract-api:

用於實現智慧合約的高階合約API(作為npm模組提供)

2.fabric-shim:

用於實現智慧合約的低階合約API(作為npm模組提供)

我們可以將fabric-shim視為fabric-contract-api的遞減版本。對新版本的fabric使用高階API是一個好習慣。但是fabric-contract-api可以完成shim可以做的所有事情。當然不止如此。

3.stub:

它是fabric-contract-api中的介面,用於訪問和修改分類帳(資料庫狀態)。因此它是主要資料Chaincode介面,用於在分類賬上讀寫資料,我們如何讀寫資料?讓我們看一下Stub介面中的一些常用方法

Stub介面中的常用方法

1.getState(k):

眾所周知,Hyperledger Fabric資料庫以鍵值對的形式儲存資料。

此方法從分類帳讀取資料。它以輸入“ k”作為鍵,並返回與鍵“ k”關聯的二進位制值。

2.putState(k,v):

此方法將資料寫入分類帳。它以“ k”為鍵,“ v”為值。明確地說,假設我們想將Alice的年齡儲存到分類帳中,我們可以將Alice作為鍵,並將AGE作為值。

3.deleteState(k):

此方法從分類賬中刪除關聯金鑰“ k”的值。

4.getStateByRange(k1,k9):

此方法在分類帳中的一組鍵上返回範圍迭代器。它將迭代startKey(k1)和endKey(k9)並返回這兩個鍵之間的所有鍵值。這類似於javascript中的for迴圈。假設如果我們已經按鍵k1,k2,k3…k99的順序儲存了一些使用者資料,則可以使用此方法簡單地獲取所有這些值的狀態。

5.getTxID():

此方法返回被呼叫事務的事務ID。交易ID對於鏈上的每個交易都是唯一的。因此交易ID在跟蹤交易中起著至關重要的作用。

6.getTxTimestamp():

此方法返回建立事務時的時間戳。這是從交易ChannelHeader獲取的,因此它將指示客戶的時間戳,並且在所有背書人中都具有相同的值。

編寫您的第一個Chaincode

您已經瞭解了在node.js中編寫鏈碼的一些先決條件。因此就目前而言,您可能會非常興奮地編寫您的第一個chaincode。

由於我們要用Nodejs編寫Chaincode,因此我們首先需要建立傳統的npm東西,例如package.json和index.js。如果您不知道此package.json。

列出您的專案所依賴的軟體包

使用語義版本控制規則指定專案可以使用的軟體包的版本

使您的構建具有可複製性,因此更易於與其他開發人員共享.

簡而言之,我們的Chaincode取決於fabric-contract-api和fabric-shim模組。我們在package.json中提到了這些軟體包和版本。

我們還將新增fabric-chaincode-node start作為我們的啟動指令碼,這是在peer節點上安裝chaincode所需的。

這是我們的package.json:

{
"name""Test-Chaincode",
"version""1.0.0",
"description""my first exciting node.js chaincode on Hyperledger-fabric",
"main""index.js",
"engines": {
"node"">=8",
"npm"">=5"
    },
"scripts": {
"lint""eslint .",
"pretest""npm run lint",
"test""nyc mocha --recursive",
"start""fabric-chaincode-node start"
    },
"engineStrict"true,
"author""Hyperledger",
"license""Apache-2.0",
"dependencies": {
"fabric-contract-api""~1.4.0",
"fabric-shim""~1.4.0"
    },
"devDependencies": {
"chai""^4.1.2",
"eslint""^4.19.1",
"mocha""^5.2.0",
"nyc""^12.0.2",
"sinon""^6.0.0",
"sinon-chai""^3.2.0"
    },
"nyc": {
"exclude": [
"coverage/**",
"test/**"
        ],
"reporter": [
"text-summary",
"html"
        ],
"all"true,
"check-coverage"true,
"statements"100,
"branches"100,
"functions"100,
"lines"100
    }
}

如果您可以仔細觀察程式碼,則有一行“ main”:“ index.js”。這意味著什麼—在啟動時(安裝chaincode期間),npm模組用於檢查index.js並在peer節點上安裝提到的合約。”因此我們的index.js包含作為模組匯出的合約。

這是我們的index.js檔案:

'use strict';
const testContract = require(’./logic’);
module.exports.contracts = [ testContract ];

智慧合約:

我們的業務邏輯是什麼?

新增,檢索和刪除學生標記。

1.新增標記涉及將資料寫入分類帳。因此我們將從chaincode的stub介面使用putState(k,v)方法。

2.檢索標記涉及從分類帳讀取資料。因此我們需要使用getState(k)方法。

3.刪除標記涉及刪除資料。因此我們需要使用deleteState(k)方法。

chaincode首先從fabric-contract-api模組引入作用域金鑰類Contract。此類將用於編寫邏輯,所有chaincode函式都應使用This庫類。

const { Contract}=require(’fabric-contract-api’);
classtestContractextendsContract{
//Functions go here
}

新增標記:

我們將建立一個JavaScript物件來儲存每個學科中學生的成績,並將該物件儲存為一個值,並將StudentId儲存為一個鍵。透過伺服器將資料傳送到資料庫時,資料必須是字串。因此我們需要使用JSON.stringify()方法將此標記物件轉換為字串,並應用緩衝區以二進位制資料的形式傳送到資料庫。

asyncaddMarks(ctx,studentId,subject1,subject2,subject3
let marks={
     subj1:subject1, 
     subj2:subject2,
     subj3:subject3 
     }; 
await  ctx.stub.putState(studentId,Buffer.from(JSON.stringify(marks))); 
console.log(’Student Marks added To the ledger Succesfully..’); 
}

刪除標記

asyncdeleteMarks(ctx,studentId{
await ctx.stub.deleteState(studentId); 
console.log(’Student Marks deleted from the ledger Succesfully..’);
    }

查詢學生成績:

由於我們在先前的addMarks()函式中將值以緩衝區的形式放置。一旦查詢,它將返回buffer。因此我們需要將緩衝區轉換為字串並將其解析為原始javascript物件。

async queryMarks(ctx,studentId){

let marksAsBytes = await ctx.stub.getState(studentId); 
if (!marksAsBytes || marksAsBytes.toString().length <= 0) { 
       throw newError(’Student with this Id does not exist: '); 
         } 
let marks=JSON.parse(marksAsBytes.toString()); 
    return JSON.stringify(marks); 
   }

最終版智慧合約程式碼

您可以在此處找到完整的智慧合約。https://gist.github.com/Salmandabbakuti/fb25d0429359c6d77ab64d097c5b588c

'use strict';


const { Contract} = require('fabric-contract-api');


classtestContractextendsContract{


async queryMarks(ctx,studentId) {


let marksAsBytes = await ctx.stub.getState(studentId); 


if (!marksAsBytes || marksAsBytes.toString().length <= 0) {


thrownewError('Student with this Id does not exist: ');


       }


let marks=JSON.parse(marksAsBytes.toString());
returnJSON.stringify(marks);


  }


async addMarks(ctx,studentId,subject1,subject2,subject3) {
let marks={


subj1:subject1,


subj2:subject2,


subj3:subject3


       };


await ctx.stub.putState(studentId,Buffer.from(JSON.stringify(marks))); 


console.log('Student Marks added To the ledger Succesfully..');
  }


async deleteMarks(ctx,studentId) {
await ctx.stub.deleteState(studentId); 
console.log('Student Marks deleted from the ledger Succesfully..');
    }
}


module.exports=testContract;

為了安裝和測試此智慧合約,我將使用包含單個peer的基本網路。在這個網路上,我們將安裝名為mycc的Node.js的chaincode到peer0.org1.example.com上,並在通道mychannel上例項化它。然後我們可以呼叫這些chaincode函式。確保在您的設定中安裝了docker。為了簡單起見,我已經將chaincode檔案(logic.js,index.js,package.json)安裝在chaincode/newcc目錄中。

首先,我們需要啟動網路並建立通道。

git clone https://github.com/Salmandabbakuti/hlf-chaincodeTest.git
cd hlf-chaincodeTest/basic-network
./start.sh

等待片刻。建立網路將需要一段時間。如果遇到任何許可權錯誤,只需在root使用者許可權下執行就行。一旦我們的具有單個peer的網路建立並執行,我們就可以安裝chaincode。

為了安裝和呼叫chaincode,我們可以使用Peer的CLI容器。輸入CLI容器

docker exec -it cli bash

安裝和例項化Chaincode

peer chaincode install -n mycc -v 1.0 -p "/opt/gopath/src/github.com/newcc" -l "node"
peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n mycc -l "node" -v 1.0 -c '{"Args":[]}'

增加學生標誌

peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n mycc -c '{"function":"addMarks","Args":["Alice","68","84","89"]}'

查詢學生“Alice”的標誌

peer chaincode query -o orderer.example.com:7050 -C mychannel -n mycc -c '{"function":"queryMarks","Args":["Alice"]}'

從Ledger刪除“Alice”標誌

peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n mycc -c '{"function":"deleteMarks","Args":["Alice"]}'

上面的指令碼將從賬本中刪除金鑰“ Alice”和相關資料。如果再次查詢Alice的標記,則會收到一條錯誤訊息,提示“ studentId不存在”。

我還製作了一個自動化指令碼,用於在客戶端目錄中安裝和測試此chaincode。請按照以下步驟進行快速演示

首先,退出CLI容器並在客戶端目錄中執行指令碼

exit# exits from CLI docker container if you're in
cd ..
cd client  #change your directory to client
chmod a+x start.sh
./start.sh  #Automated script for testing

您也可以使用client / start.sh檔案中定義的指令碼手動呼叫chaincode函式。

結論

我們在這裡演示了什麼是Chaincode,chaincode的stub介面中的方法,chaincode的部署結構以及編寫chaincode和在網路上進行部署的難易程度。希望本文能以某種方式幫助您開始編寫chaincode並在網路上進行部署。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;