Hyperledger Fabric(編寫你的第一個應用程序)

編寫第一個應用程序

若是你還不熟悉Fabric網絡的基本架構,則可能須要在繼續以前訪問「 介紹」和「 構建你的第一個網絡」文檔。

在本節中,咱們將介紹一些示例程序,以瞭解Fabric應用程序的工做原理,這些應用程序(以及他們使用的智能合約) - 統稱爲fabcar - 提供了Fabric功能的普遍演示。值得注意的是,咱們將展現與證書頒發機構進行交互並生成註冊證書的過程,以後咱們將利用這些身份來查詢和更新分類賬。html

咱們將經歷三個主要步驟:node

1.設置開發環境。咱們的應用程序須要一個網絡進行交互,所以咱們將下載一個僅限於咱們所需的註冊/登記,查詢和更新的組件:git

AppConceptsOverview.png

2.學習咱們的應用程序將使用的示例智能合約的參數。咱們的智能合約包含各類功能,使咱們可以以不一樣的方式與分類賬進行交互,咱們將進入並檢查該智能合約,以瞭解咱們的應用程序將使用的功能。github

3.開發應用程序以便可以在分類賬上查詢和更新資產。咱們將進入應用程序代碼自己(咱們的應用程序已用Javascript編寫)並手動操做變量以運行不一樣類型的查詢和更新。docker

完成本教程後,你應該基本瞭解應用程序如何與智能合約一塊兒編程,以與Fabric網絡上的分類賬(即對等方)進行交互。shell

設置開發環境

若是你已經完成了構建你的第一個網絡,你應該已經設置了你的開發環境,而且已經下載了fabric-samples以及隨附的工件。要運行本教程,你如今須要作的就是拆除現有的任何網絡,你能夠經過發出如下命令來執行此操做:npm

./byfn.sh down

若是你沒有開發環境以及網絡和應用程序的附帶工件,訪問「前提條件」頁面,確保你的計算機上已安裝必要的依賴項。編程

接下來,若是你尚未這樣作的話,訪問」安裝示例、二進制文件和Docker鏡像「頁面並按照提供的說明進行操做。克隆fabric-samples存儲庫後返回本教程,並下載最新的穩定Fabric鏡像和可用實用程序。json

此時全部的都應該已安裝,導航到fabric-samples存儲庫中的fabcar子目錄,並查看內部的內容:segmentfault

cd fabric-samples/fabcar  && ls

你應該看到如下內容:

enrollAdmin.js     invoke.js       package.json    query.js        registerUser.js startFabric.sh

在開始以前,咱們還須要作一些家務,運行如下命令以終止任何陳舊或活動容器:

docker rm -f $(docker ps -aq)

清除全部緩存的網絡:

# Press 'y' when prompted by the command

docker network prune

最後,若是你已經完成本教程,你還須要刪除fabcar智能合約的基礎鏈碼鏡像,若是你是第一次瀏覽此內容的用戶,那麼你的系統上將不會顯示此鏈碼鏡像:

docker rmi dev-peer0.org1.example.com-fabcar-1.0-5c906e402ed29f20260ae42283216aa75549c571e2e380f3615826365d8269ba

安裝客戶端並啓動網絡

如下說明要求你位於 fabric-samples repo的本地克隆中的 fabcar子目錄中,在本教程的其他部分中,保留在此子目錄的根目錄下。

運行如下命令以安裝應用程序的Fabric依賴項,咱們關注fabric-ca-client,它容許咱們的應用程序與CA服務器通訊並檢索身份資料,還有fabric-client,它容許咱們加載身份資料並與對等點和排序服務交流。

npm install

使用startFabric.sh shell腳本啓動網絡,此命令將啓動咱們的各類Fabric實體,併爲Golang編寫的鏈碼啓動智能合約容器:

./startFabric.sh

你還能夠選擇針對Node.js中編寫的鏈碼運行本教程,若是你想追求這條路線,請發出如下命令:

./startFabric.sh node
請注意,Node.js鏈碼場景大約須要90秒才能完成;也許更長。腳本沒有掛起,而是增長的時間是在構建鏈碼鏡像時安裝fabric-shim的結果。

好了,如今你有一個示例網絡和一些代碼,讓咱們來看看不一樣的部分如何組合在一塊兒。

應用程序如何與網絡交互

要更深刻地瞭解咱們fabcar網絡中的組件(以及它們如何部署)以及應用程序如何在更精細的級別上與這些組件進行交互,請參閱瞭解Fabcar網絡

開發人員更有興趣瞭解應用程序的做用 - 以及查看代碼自己以查看應用程序的構建方式 - 應該繼續下去,目前,最重要的是要知道應用程序使用軟件開發工具包(SDK)來訪問容許查詢和更新分類賬的API。

登記管理員用戶

如下兩節涉及與證書頒發機構的通訊,你可能會發現當運行即將到來的程序時流式傳輸CA日誌頗有用。

要流式傳輸CA日誌,請拆分終端或打開新shell併發出如下命令:

docker logs -f ca.example.com

如今回到帶着fabcar內容的終端……

當咱們啓動咱們的網絡,管理員用戶 - admin - 已在咱們的證書頒發機構註冊,如今咱們須要向CA服務器發送登記調用,併爲該用戶檢索登記證書(eCert)。咱們不會在這裏深刻研究登記詳情,但只需說SDK和擴展咱們的應用程序須要此證書才能爲管理員造成用戶對象,而後咱們將使用此管理員對象隨後註冊並登記新用戶,發送管理員登記調用到CA服務器:

node enrollAdmin.js

該程序將調用證書籤名請求(CSR)並最終將eCert和密鑰材料輸出到新建立的文件夾 - hfc-key-store - 該項目的根目錄下,當咱們的應用須要爲各類用戶建立或加載身份對象時會查看此位置。

註冊並登記user1

使用咱們新生成的管理員eCert,咱們如今將再次與CA服務器通訊以註冊和登記新用戶。此用戶 - user1 - 將是咱們在查詢和更新分類賬時使用的身份。這裏須要注意的是,管理員身份是爲咱們的新用戶發出註冊和登記調用(即該用戶扮演註冊員的角色),發送爲user1註冊並登記的調用:

node registerUser.js

與管理員登記相似,該程序調用CSR並將密鑰和eCert輸出到hfc-key-store子目錄中,因此如今咱們有兩個獨立用戶的身份資料 - adminuser1,是時候與分類帳互動了......

查詢分類賬

查詢是你從分類賬中讀取數據的方式,該數據存儲爲一系列鍵值對,而且你能夠查詢單個鍵,多個鍵的值,或者 - 若是分類賬是以JSON等豐富的數據存儲格式編寫的 - 對其執行復雜搜索(例如,查找包含特定關鍵字的全部資產)。

這是查詢如何工做的表示:

QueryingtheLedger.png

首先,讓咱們運行query.js程序,返回分類賬中全部汽車的清單,咱們將使用咱們的第二個身份 - user1 - 做爲此應用程序的簽名實體,咱們程序中的如下行將user1指定爲簽名者:

fabric_client.getUserContext('user1', true);

回想一下,user1登記資料已經放入咱們的hfc-key-store子目錄中,因此咱們只須要告訴咱們的應用程序獲取該身份,隨着用戶對象的定義,咱們如今能夠從分類帳中繼續讀取。一個查詢全部汽車的功能,queryAllCars,已預先加載到應用程序中,所以咱們能夠簡單地按原樣運行程序:

node query.js

它應該返回這樣的東西:

Successfully loaded user1 from persistence
Query has completed, checking results
Response is  [{"Key":"CAR0", "Record":{"colour":"blue","make":"Toyota","model":"Prius","owner":"Tomoko"}},
{"Key":"CAR1",   "Record":{"colour":"red","make":"Ford","model":"Mustang","owner":"Brad"}},
{"Key":"CAR2", "Record":{"colour":"green","make":"Hyundai","model":"Tucson","owner":"Jin Soo"}},
{"Key":"CAR3", "Record":{"colour":"yellow","make":"Volkswagen","model":"Passat","owner":"Max"}},
{"Key":"CAR4", "Record":{"colour":"black","make":"Tesla","model":"S","owner":"Adriana"}},
{"Key":"CAR5", "Record":{"colour":"purple","make":"Peugeot","model":"205","owner":"Michel"}},
{"Key":"CAR6", "Record":{"colour":"white","make":"Chery","model":"S22L","owner":"Aarav"}},
{"Key":"CAR7", "Record":{"colour":"violet","make":"Fiat","model":"Punto","owner":"Pari"}},
{"Key":"CAR8", "Record":{"colour":"indigo","make":"Tata","model":"Nano","owner":"Valeria"}},
{"Key":"CAR9", "Record":{"colour":"brown","make":"Holden","model":"Barina","owner":"Shotaro"}}]

這些是10輛車,Adriana擁有的黑色特斯拉Model S,Brad擁有的紅色福特Mustang,Pari擁有的紫羅蘭菲亞特Punto,等等。分類賬是基於鍵值的,在咱們的實現中,鍵是CAR0CAR9,這將在一瞬間變得特別重要。

讓咱們仔細看看這個程序,使用編輯器(例如atom或visual studio)並打開query.js

應用程序的初始部分定義了某些變量,例如通道名稱,證書存儲位置和網絡端點,在咱們的示例應用中,這些變量已被植入,但在真正的應用程序中,這些變量必須由app dev指定。

var channel = fabric_client.newChannel('mychannel');
var peer = fabric_client.newPeer('grpc://localhost:7051');
channel.addPeer(peer);

var member_user = null;
var store_path = path.join(__dirname, 'hfc-key-store');
console.log('Store path:'+store_path);
var tx_id = null;

這是咱們構造查詢的塊:

// queryCar chaincode function - requires 1 argument, ex: args: ['CAR4'],
// queryAllCars chaincode function - requires no arguments , ex: args: [''],
const request = {
  //targets : --- letting this default to the peers assigned to the channel
  chaincodeId: 'fabcar',
  fcn: 'queryAllCars',
  args: ['']
};

當應用程序運行時,它調用了對等點的fabcar鏈碼,在其中運行queryAllCars函數,而且沒有傳遞任何參數。

要了解咱們智能合約中的可用功能,導航到fabric-samples根目錄下的chaincode/fabcar/go子目錄,並在編輯器中打開fabcar.go

這些相同的功能在 fabcar鏈碼的Node.js版本中定義。

你將看到咱們能夠調用如下函數:initLedgerqueryCarqueryAllCarscreateCarchangeCarOwner

讓咱們仔細看看queryAllCars函數,看看它如何與分類賬交互。

func (s *SmartContract) queryAllCars(APIstub shim.ChaincodeStubInterface) sc.Response {

      startKey := "CAR0"
      endKey := "CAR999"

      resultsIterator, err := APIstub.GetStateByRange(startKey, endKey)

這定義了queryAllCars的範圍,CAR0CAR999之間的每輛車 - 總共1,000輛車,假設每一個鍵都已正確標記 - 將由查詢返回。

下面是一個應用程序如何在鏈碼中調用不一樣函數的表示,每一個函數都必須在鏈碼shim接口中針對可用的API進行編碼,這反過來又容許智能合約容器與對等點分類賬正確鏈接。

RunningtheSample.png

咱們能夠看到咱們的queryAllCars函數,以及一個名爲createCar的函數,它將容許咱們更新分類賬並最終在一瞬間將新區塊附加到鏈中。

但首先,返回query.js程序並編輯構造函數請求以查詢CAR4,咱們經過將query.js中的函數從queryAllCars更改成queryCar並將CAR4做爲特定鍵傳遞來完成此操做。

query.js程序如今看起來應該是這樣的:

const request = {
  //targets : --- letting this default to the peers assigned to the channel
  chaincodeId: 'fabcar',
  fcn: 'queryCar',
  args: ['CAR4']
};

保存程序並導航回fabcar目錄,如今再次運行程序:

node query.js

你應該看到如下內容:

{"colour":"black","make":"Tesla","model":"S","owner":"Adriana"}

若是你回過頭來看看咱們以前查詢過每輛車的結果,你能夠看到CAR4是Adriana的黑色特斯拉型號S,這是在這裏返回的結果。

使用queryCar函數,咱們能夠查詢任何鍵(例如CAR0)並獲取與該車相對應的任何品牌,型號,顏色和全部者。

很好,此時你應該熟悉智能合約中的基本查詢功能以及查詢程序中的少數參數,是時候更新分類賬.....

更新分類賬

如今咱們已經完成了一些分類賬查詢並添加了一些代碼,咱們準備更新分類賬,咱們能夠作不少潛在的更新,但讓咱們從建立汽車開始吧。

下面咱們能夠看到這個過程如何運做。一個更新提案,承認,而後返回到應用程序,而後將其發送給每一個對等點的分類賬:

UpdatingtheLedger.png

咱們對分類帳的第一次更新將是建立一輛新車,咱們有一個單獨的Javascript程序 - invoke.js - 咱們將用它來進行更新。就像查詢同樣,使用編輯器打開程序並導航到咱們構造調用的代碼塊:

// createCar chaincode function - requires 5 args, ex: args: ['CAR12', 'Honda', 'Accord', 'Black', 'Tom'],
// changeCarOwner chaincode function - requires 2 args , ex: args: ['CAR10', 'Barry'],
// must send the proposal to endorsing peers
var request = {
  //targets: let default to the peer assigned to the client
  chaincodeId: 'fabcar',
  fcn: '',
  args: [''],
  chainId: 'mychannel',
  txId: tx_id
};

你將看到咱們能夠調用兩個函數之一 - createCarchangeCarOwner,首先,讓咱們建立一個紅色雪佛蘭Volt並將其交給名爲Nick的全部者,咱們的分類賬上有CAR9,因此咱們在這裏使用CAR10做爲識別鍵,編輯此代碼塊以下所示:

var request = {
  //targets: let default to the peer assigned to the client
  chaincodeId: 'fabcar',
  fcn: 'createCar',
  args: ['CAR10', 'Chevy', 'Volt', 'Red', 'Nick'],
  chainId: 'mychannel',
  txId: tx_id
};

保存並運行程序:

node invoke.js

終端中會有一些關於ProposalResponse和promises的輸出,可是,咱們所關注的是這條消息:

The transaction has been committed on peer localhost:7053

查看該交易是否已寫入,返回query.js並將參數從CAR4更改成CAR10

換句話說,改變這一點:

const request = {
  //targets : --- letting this default to the peers assigned to the channel
  chaincodeId: 'fabcar',
  fcn: 'queryCar',
  args: ['CAR4']
};

爲這樣:

const request = {
  //targets : --- letting this default to the peers assigned to the channel
  chaincodeId: 'fabcar',
  fcn: 'queryCar',
  args: ['CAR10']
};

再次保存,而後查詢:

node query.js

應該返回這些:

Response is  {"colour":"Red","make":"Chevy","model":"Volt","owner":"Nick"}

恭喜,你創造了一輛車!

因此如今咱們已經作到了,讓咱們說Nick感到很慷慨,他想把他的雪佛蘭伏特送給名叫Dave的人。

要作到這一點,請返回invoke.js並將函數從createCar更改成changeCarOwner並輸入以下參數:

var request = {
  //targets: let default to the peer assigned to the client
  chaincodeId: 'fabcar',
  fcn: 'changeCarOwner',
  args: ['CAR10', 'Dave'],
  chainId: 'mychannel',
  txId: tx_id
};

第一個參數 - CAR10 - 反映了將改變擁有者的汽車,第二個參數 - Dave - 定義了汽車的新擁有者。

再次保存並執行程序:

node invoke.js

如今讓咱們再次查詢分類賬並確保Dave如今與CAR10鍵相關聯:

node query.js

它應該返回這個結果:

Response is  {"colour":"Red","make":"Chevy","model":"Volt","owner":"Dave"}

CAR10的全部權已從Nick改成Dave。

在現實世界的應用程序中,鏈碼可能具備一些訪問控制邏輯,例如,只有某些受權用戶能夠建立新車,而且只有車主能夠將車轉移給其餘人。

總結

如今咱們已經完成了一些查詢和一些更新,你應該很是清楚應用程序如何與網絡交互,已經看到了智能合約,API和SDK在查詢和更新中扮演的角色的基礎知識,你應該瞭解如何使用不一樣類型的應用程序來執行其餘業務任務和操做。

在隨後的文檔中,咱們將學習如何實際編寫智能合約,以及如何利用其中一些更低級別的應用程序功能(特別是與身份和成員資格服務相關)。

其餘資源

Hyperledger Fabric Node SDK repo是深刻文檔和示例代碼的絕佳資源,你還能夠在Hyperledger Rocket Chat上諮詢Fabric社區和組件專家。

相關文章
相關標籤/搜索