商業票據教程
受眾: 架構師,應用和智能合約開發者,管理員
本教程將向您展示如何安裝和使用商業票據樣例應用程式和智能合約,該主題是以任務為導向的, 因此它更側重的是流程而不是概念,如果您想更深入地了解這些概念,可以閱讀開發應用程式主題,

在本教程中,MagnetoCorp 和 DigiBank 這兩個組織使用 Hyperledger Fabric 區塊鏈網路 PaperNet 相互交易商業票據,
一旦建立了一個基本的網路,您就將扮演 MagnetoCorp 的員工 Isabella,她將代表公司發行商業票據,然后,您將轉換角色,擔任 DigiBank 的員工 Balaji,他將購買此商業票據,持有一段時間,然后向 MagnetoCorp 贖回該商業票據,以獲取小額利潤,
您將扮演開發人員,最終用戶和管理員,這些角色位于不同組織中,都將執行以下步驟,這些步驟旨在幫助您了解作為兩個不同組織獨立作業,但要根據Hyperledger Fabric 網路中雙方共同商定的規則來進行協作是什么感覺,
- 環境配置 和 下載示例
- 創建網路
- 檢查商業票據智能合約
- 通過以MagnetoCorp和MagnetoCorp組織的身份同意鏈碼定義,將智能合約部署到通道,
- 理解一個MagnetoCorp 應用程式的結構, 包括它的依賴
- 配置和使用錢包和身份
- 運行一個MagnetoCorp應用程式來 發行商業票據
- 理解DigiBank是如何在應用程式 中使用智能合約的
- 以Digibank組織的身份運行應用程式來 購買 和 贖回 商業票據
本教程已經在 MacOS 和 Ubuntu 上進行了測驗,應該可以在其他 Linux 發行版上運行,Windows版本的教程正在開發中,
準備階段
在開始之前,您必須安裝本教程所需的一些必備工具,我們將必備工具控制在最低限度,以便您能快速開始,
您必須安裝以下軟體:
- Node, Node.js SDK的README檔案包含準備階段中 對應最新版本的清單,
您會發現安裝以下軟體很有幫助:
-
原始碼編輯器,如 Visual Studio Code 版本 1.28,或更高版本,VS Code 將會幫助您開發和測驗您的應用程式和智能合約,安裝 VS Code 看這里,
許多優秀的代碼編輯器都可以使用,包括 Atom, Sublime Text 和 Brackets,
您可能會發現,隨著您在應用程式和智能合約開發方面的經驗越來越豐富,安裝以下軟體會很有幫助,首次運行教程時無需安裝這些:
- Node Version Manager,NVM 幫助您輕松切換不同版本的 node——如果您同時處理多個專案的話,那將非常有用,安裝NVM 看這里,
下載示例
商業票據教程是fabric-samples倉庫中的示例之一, 在開始本教程之前, 確保您已經按照說明安裝了Fabric 準備階段必備工具 并下載示例、二進制檔案和Docker映像, 當您完成后,您便克隆了包含教程腳本、 智能合約和應用程式檔案的 fabric-samples 倉庫,

下載 fabric-samples GitHub倉庫到您的本地機器,
下載后,可隨意查看fabric-samples的目錄結構:
$ cd fabric-samples
$ ls
CODEOWNERS SECURITY.md first-network
CODE_OF_CONDUCT.md chaincode high-throughput
CONTRIBUTING.md chaincode-docker-devmode interest_rate_swaps
LICENSE ci off_chain_data
MAINTAINERS.md commercial-paper test-network
README.md fabcar
注意 commercial-paper 目錄,我們的示例就在這里!
現在您已經完成了教程的第一個階段!隨著您繼續操作,您將為不同用戶和組件打開多個命令視窗,例如:
- 為了顯示來自您的網路的peer節點、排序服務節點和CA日志輸出,
- 作為MagnetoCorp組織和DigiBank組織的管理員,審批同意鏈碼,
代表Isabella和Balaji運行應用程式, 他們將使用智能合約彼此交易商業票據,
當您應該從特定命令視窗運行一項命令時,我們將詳細說明這一點,例如:
(isabella)$ ls
這表示您應該在 Isabella 的視窗中執行 ls 命令,
創建網路
本教程將使用Fabric測驗網路部署智能合約, 測驗網路由兩個peer組織和一個排序服務組織組成, 兩個peer組織各自操作一個peer節點, 而排序服務組織操作單個Raft排序服務節點, 我們還將使用測驗網路創建一個名為mychannel的單一通道, 兩個peer組織都將是該通道的成員,

The Hyperledger Fabric 基礎網路的組成部分包括一個節點及該節點的賬本資料庫,一個排序服務和一個證書授權中心,以上每個組件都在一個 Docker 容器中運行,
每個組織運行自己的證書頒發機構, 兩個peer節點、狀態資料庫、排序服務節點 和每個組織CA都在各自的Docker容器中運行, 在生產環境中,組織通常使用與其他系統共享的現有CA; 它們不是專用于Fabric網路的,
測驗網路的兩個組織允許我們以兩個獨立的組織形式, 操作不同的peer節點與一個區塊鏈帳本互動, 在本教程中,我們將作為DigiBank操作測驗網路中的Org1 以及作為MagnetoCorp操作Org2,
您可以啟動測驗網路, 并使用商業票據目錄中提供的腳本創建通道, 進入到fabric-samples中的commercial-paper目錄:
cd fabric-samples/commercial-paper
然后使用腳本啟動測驗網路:
./network-starter.sh
當腳本運行時,您將看到部署測驗網路的日志, 當腳本完成后,您可以使用docker ps命令 查看Fabric節點在您的本地機器上的運行情況:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a86f50ca1907 hyperledger/fabric-peer:latest "peer node start" About a minute ago Up About a minute 7051/tcp, 0.0.0.0:9051->9051/tcp peer0.org2.example.com
77d0fcaee61b hyperledger/fabric-peer:latest "peer node start" About a minute ago Up About a minute 0.0.0.0:7051->7051/tcp peer0.org1.example.com
7eb5f64bfe5f hyperledger/fabric-couchdb "tini -- /docker-ent…" About a minute ago Up About a minute 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb0
2438df719f57 hyperledger/fabric-couchdb "tini -- /docker-ent…" About a minute ago Up About a minute 4369/tcp, 9100/tcp, 0.0.0.0:7984->5984/tcp couchdb1
03373d116c5a hyperledger/fabric-orderer:latest "orderer" About a minute ago Up About a minute 0.0.0.0:7050->7050/tcp orderer.example.com
6b4d87f65909 hyperledger/fabric-ca:latest "sh -c 'fabric-ca-se…" About a minute ago Up About a minute 7054/tcp, 0.0.0.0:8054->8054/tcp ca_org2
7b01f5454832 hyperledger/fabric-ca:latest "sh -c 'fabric-ca-se…" About a minute ago Up About a minute 7054/tcp, 0.0.0.0:9054->9054/tcp ca_orderer
87aef6062f23 hyperledger/fabric-ca:latest "sh -c 'fabric-ca-se…" About a minute ago Up About a minute 0.0.0.0:7054->7054/tcp ca_org1
看看您是否可以將這些容器映射到基本網路上(可能需要橫向移動才能找到資訊):
- Org1的peer,
peer0.org1.example.com, 在容器a86f50ca1907上運行 - Org2的peer,
peer0.org2.example.com, 在容器77d0fcaee61b上運行 - Org1的peer對應的CouchDB資料庫,
couchdb0, 在容器7eb5f64bfe5f上運行 - Org2的peer對應的CouchDB資料庫,
couchdb1, 在容器2438df719f57上運行 - 排序服務節點,
orderer.example.com, 在容器03373d116c5a上運行 - Org1的CA,
ca_org1, 在容器87aef6062f23上運行 - Org2的CA,
ca_org2, 在容器6b4d87f65909上運行 - 排序服務Org的CA,
ca_orderer, 在容器7b01f5454832上運行
所有這些容器構成了被稱作 fabric_test 的 docker 網路,您可以使用 docker network 命令查看該網路:
$ docker network inspect fabric_test
[
{
"Name": "net_test",
"Id": "f4c9712139311004b8f7acc14e9f90170c5dcfd8cdd06303c7b074624b44dc9f",
"Created": "2020-04-28T22:45:38.525016Z",
"Containers": {
"03373d116c5abf2ca94f6f00df98bb74f89037f511d6490de4a217ed8b6fbcd0": {
"Name": "orderer.example.com",
"EndpointID": "0eed871a2aaf9a5dbcf7896aa3c0f53cc61f57b3417d36c56747033fd9f81972",
"MacAddress": "02:42:c0:a8:70:05",
"IPv4Address": "192.168.112.5/20",
"IPv6Address": ""
},
"2438df719f57a597de592cfc76db30013adfdcfa0cec5b375f6b7259f67baff8": {
"Name": "couchdb1",
"EndpointID": "52527fb450a7c80ea509cb571d18e2196a95c630d0f41913de8ed5abbd68993d",
"MacAddress": "02:42:c0:a8:70:06",
"IPv4Address": "192.168.112.6/20",
"IPv6Address": ""
},
"6b4d87f65909afd335d7acfe6d79308d6e4b27441b25a829379516e4c7335b88": {
"Name": "ca_org2",
"EndpointID": "1cc322a995880d76e1dd1f37ddf9c43f86997156124d4ecbb0eba9f833218407",
"MacAddress": "02:42:c0:a8:70:04",
"IPv4Address": "192.168.112.4/20",
"IPv6Address": ""
},
"77d0fcaee61b8fff43d33331073ab9ce36561a90370b9ef3f77c663c8434e642": {
"Name": "peer0.org1.example.com",
"EndpointID": "05d0d34569eee412e28313ba7ee06875a68408257dc47e64c0f4f5ef4a9dc491",
"MacAddress": "02:42:c0:a8:70:08",
"IPv4Address": "192.168.112.8/20",
"IPv6Address": ""
},
"7b01f5454832984fcd9650f05b4affce97319f661710705e6381dfb76cd99fdb": {
"Name": "ca_orderer",
"EndpointID": "057390288a424f49d6e9d6f788049b1e18aa28bccd56d860b2be8ceb8173ef74",
"MacAddress": "02:42:c0:a8:70:02",
"IPv4Address": "192.168.112.2/20",
"IPv6Address": ""
},
"7eb5f64bfe5f20701aae8a6660815c4e3a81c3834b71f9e59a62fb99bed1afc7": {
"Name": "couchdb0",
"EndpointID": "bfe740be15ec9dab7baf3806964e6b1f0b67032ce1b7ae26ac7844a1b422ddc4",
"MacAddress": "02:42:c0:a8:70:07",
"IPv4Address": "192.168.112.7/20",
"IPv6Address": ""
},
"87aef6062f2324889074cda80fec8fe014d844e10085827f380a91eea4ccdd74": {
"Name": "ca_org1",
"EndpointID": "a740090d33ca94dd7c6aaf14a79e1cb35109b549ee291c80195beccc901b16b7",
"MacAddress": "02:42:c0:a8:70:03",
"IPv4Address": "192.168.112.3/20",
"IPv6Address": ""
},
"a86f50ca19079f59552e8674932edd02f7f9af93ded14db3b4c404fd6b1abe9c": {
"Name": "peer0.org2.example.com",
"EndpointID": "6e56772b4783b1879a06f86901786fed1c307966b72475ce4631405ba8bca79a",
"MacAddress": "02:42:c0:a8:70:09",
"IPv4Address": "192.168.112.9/20",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
看看這八個容器如何在作為單個 Docker 網路一部分的同時使用不同的 IP 地址,(為了清晰起見,我們對輸出進行了縮寫,)
由于我們是以DigiBank和MagnetoCorp的身份來操作測驗網路的, peer0.org1.example.com將屬于DigiBank組織, 而peer0.org2.example.com將由MagnetoCorp操作, 現在測驗網路已經啟動并運行, 從現在開始我們可以將我們的網路稱為PaperNet,
回顧一下: 您已經從 GitHub 下載了 Hyperledger Fabric 示例倉庫,并且已經在本地機器上運行了基本的網路,現在讓我們開始扮演 MagnetoCorp 的角色來交易商業票據,
以 MagnetoCorp 的身份管理網路
商業票據教程允許您通過為DigiBank和MagnetoCorp 提供兩個單獨的檔案夾來充當兩個組織, 這兩個檔案夾包含每個組織的智能合約和應用程式檔案, 由于這兩個組織在商業票據交易中有不同的角色, 所以每個組織的應用程式檔案也不同, 在fabric-samples倉庫下打開一個新視窗, 并使用以下命令切換到MagnetoCorp目錄:
cd commercial-paper/organization/magnetocorp
我們要做的第一件事就是以 MagnetoCorp 的角色監控 PaperNet 網路中的組件,管理員可以使用 logspout 工具 ,該工具可以將不同輸出流采集到一個地方,從而在一個視窗中就可以輕松看到正在發生的事情,比如,對于正在安裝智能合約的管理員或者正在呼叫智能合約的開發人員來說,這個工具確實很有幫助,
在MagnetoCorp目錄下,運行下列命令以運行monitordocker.sh腳本, 并為運行在net_test上的與PaperNet相關聯的容器 啟動logspout工具:
(magnetocorp admin)$ ./configuration/cli/monitordocker.sh fabric_test
...
latest: Pulling from gliderlabs/logspout
4fe2ade4980c: Pull complete
decca452f519: Pull complete
(...)
Starting monitoring on all containers on the network net_test
b7f3586e5d0233de5a454df369b8eadab0613886fc9877529587345fc01a3582
注意,如果 monitordocker.sh 中的默認埠已經在使用,您可以傳入一個埠號,
(magnetocorp admin)$ ./monitordocker.sh fabric_test <port_number>
現在,這個視窗將為本教程剩余部分顯示Docker容器的日志輸出, 那么繼續并打開另一個命令視窗, 我們要做的下一件事是 檢查MagnetoCorp將用于發行商業票據的智能合約,
檢查商業票據智能合約
issue, buy 和 redeem 是 PaperNet 智能合約的三個核心功能,應用程式使用這些功能來提交交易,相應地,在賬本上會發行、購買和贖回商業票據,我們接下來的任務就是檢查這個智能合約,
打開一個新的終端視窗來代表 MagnetoCorp 開發人員,
cd commercial-paper/organization/magnetocorp
然后,您可以使用您選擇的編輯器(本教程中的VS Code) 在contract目錄中查看智能合約:
(magnetocorp developer)$ code contract
在這個檔案夾的 lib 目錄下,您將看到 papercontract.js 檔案,其中包含了商業票據智能合約!

一個示例代碼編輯器在 papercontract.js 檔案中展示商業票據智能合約
papercontract.js 是一個在 Node.js 環境中運行的 JavaScript 程式,注意下面的關鍵程式行:
-
const { Contract, Context } = require('fabric-contract-api');
這個陳述句引入了兩個關鍵的 Hyperledger Fabric 類:Contract和Context,它們被智能合約廣泛使用,您可以在fabric-shimJSDOCS 中了解到這些類的更多資訊, -
class CommercialPaperContract extends Contract {
這里基于內置的 FabricContract類定義了智能合約類CommercialPaperContract,實作了issue,buy和redeem商業票據關鍵交易的方法被定義在該類中, -
async issue(ctx, issuer, paperNumber, issueDateTime, maturityDateTime...) {
這個方法為 PaperNet 定義了商業票據issue交易,傳入的引數用于創建新的商業票據,
找到并檢查智能合約內的buy和redeem交易, -
let paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime...);
在issue交易內部,這個陳述句根據提供的交易輸入使用CommercialPaper類在記憶體中創建了一個新的商業票據,檢查buy和redeem交易看如何類似地使用該類, -
await ctx.paperList.addPaper(paper);
這個陳述句使用ctx.paperList在賬本上添加了新的商業票據,其中ctx.paperList是PaperList類的一個實體,當智能合約場景CommercialPaperContext被初始化時,就會創建出一個ctx.paperList,再次檢查buy和redeem方法,以了解這些方法是如何使用這一類的, -
return paper;
該陳述句回傳一個二進制緩沖區,作為來自issue交易的回應,供智能合約的呼叫者處理,
歡迎檢查 contract 目錄下的其他檔案來理解智能合約是如何作業的,請仔細閱讀智能合約處理主題中 papercontract.js 是如何設計的,
將智能合約部署到通道
在應用程式呼叫papercontract之前, 必須將它安裝到測驗網路中合適的peer節點上, 然后在通道上使用 Fabric鏈碼生命周期定義它, Fabric鏈碼生命周期允許多個組織 在鏈碼被部署到通道之前同意鏈碼的引數, 因此,我們需要以MagnetoCorp和DigiBank的管理員的身份 來安裝和審批同意鏈碼,

MagnetoCorp 的管理員將 papercontract 的一個副本安裝在 MagnetoCorp 的節點上,
智能合約是應用開發的重點,它被包含在一個名為鏈碼的 Hyperledger Fabric 構件中,在一個鏈碼中可以定義一個或多個智能合約,安裝鏈碼就使得 PaperNet 中的不同組織可以使用其中的智能合約,這意味著只有管理員需要關注鏈碼;其他人都只需關注智能合約,
以 MagnetoCorp 的身份安裝和批準智能合約
我們將首先以MagnetoCorp管理員的身份安裝并同意智能合約, 確保您正在magnetocorp檔案夾里操作, 或使用以下命令瀏覽至該檔案夾:
cd commercial-paper/organization/magnetocorp
MagnetoCorp管理員可以通過使用peerCLI與PaperNet互動, 然而,管理員需要在其命令視窗中設定某些環境變數, 以使用正確的peer二進制檔案集, 向MagnetoCorp的peer節點的地址發送命令 和使用正確的加密資料對請求進行簽名,
您可以使用示例提供的腳本在命令視窗中設定環境變數, 在magnetocorp目錄中執行如下命令:
source magnetocorp.sh
您將在視窗中看到被列印出來的環境變數的完整串列, 我們現在可以使用這個命令視窗來以 MagnetoCorp管理員的身份與PaperNet互動,
第一步是安裝papercontract智能合約, 可以使用peer lifecycle chaincode package命令 將智能合約打包成鏈碼, 在MagnetoCorp管理員的命令視窗中, 執行如下命令創建鏈碼包:
(magnetocorp admin)$ peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0
MagnetoCorp管理員現在可以使用peer lifecycle chaincode install命令 在MagnetoCorp的peer節點上安裝鏈碼:
(magnetocorp admin)$ peer lifecycle chaincode install cp.tar.gz
在安裝了鏈碼包后, 您會在您的終端上看到類似如下的訊息:
2020-01-30 18:32:33.762 EST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nEcp_0:ffda93e26b183e231b7e9d5051e1ee7ca47fbf24f00a8376ec54120b1a2a335c\022\004cp_0" >
2020-01-30 18:32:33.762 EST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: cp_0:ffda93e26b183e231b7e9d5051e1ee7ca47fbf24f00a8376ec54120b1a2a335c
因為MagnetoCorp管理員已經設定了CORE_PEER_ADDRESS=localhost:9051 來將peer0.org2.example.com作為指令的目標, 所以INFO 001 Installed remotely...表示 papercontract已被成功安裝在此peer節點上,
在安裝智能合約之后,我們需要以MagnetoCorp的身份 同意papercontract的鏈碼定義, 第一步是找到我們安裝在我們的peer上的鏈碼的packageID, 我們可以使用peer lifecycle chaincode queryinstalled 命令查詢packageID:
peer lifecycle chaincode queryinstalled
該命令將回傳與安裝命令相同的包識別符號, 您應該會看到類似如下的輸出:
Installed chaincodes on peer:
Package ID: cp_0:ffda93e26b183e231b7e9d5051e1ee7ca47fbf24f00a8376ec54120b1a2a335c, Label: cp_0
在下一步中,我們將需要package ID, 因此我們將其保存為一個環境變數, 對于所有用戶,package ID可能不相同, 因此您需要使用從命令視窗回傳的package ID來完成這個步驟,
export PACKAGE_ID=cp_0:ffda93e26b183e231b7e9d5051e1ee7ca47fbf24f00a8376ec54120b1a2a335c
管理員現在可以使用peer lifecycle chaincode approveformyorg命令 為MagnetoCorp同意鏈碼定義:
(magnetocorp admin)$ peer lifecycle chaincode approveformyorg --orderer localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name papercontract -v 0 --package-id $PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA
為了使用鏈碼定義,通道成員需要同意的最重要的鏈碼引數之一 是鏈碼背書策略, 背書策略描述了在確定交易有效之前必須背書(執行和簽署)的組織集合, 通過不指定--policy標志而同意papercontract鏈碼, MagnetoCorp管理員將同意使用通道的默認Endorsement策略, 這在mychannel測驗通道的實體下 要求通道上的大多陣列織來背書交易, 所有的交易,無論有效還是無效,都將被記錄在 區塊鏈賬本上, 但只有有效的交易才會更新世界狀態,
以 DigiBank 的身份安裝和批準智能合約
基于mychannel的LifecycleEndorsement策略, Fabric鏈碼生命周期將要求通道上的大多陣列織 在將鏈碼提交到通道之前同意鏈碼的定義, 這意味著我們需要以MagnetoCorp和DigiBank的身份同意papernet鏈碼, 以達成所需的多數即2/2的要求, 在fabric-samples檔案夾下打開一個新的終端視窗, 并瀏覽到包含DigiBank智能合約和應用程式檔案的檔案夾:
(digibank admin)$ cd commercial-paper/organization/digibank/
使用DigiBank檔案夾中的腳本設定環境變數, 這將允許您作為DigiBank管理員操作:
source digibank.sh
我們現在可以以DigiBank的身份安裝和同意papercontract, 執行如下命令打包鏈碼:
(digibank admin)$ peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0
管理員現在可以在DigiBank的peer節點上安裝鏈碼:
(digibank admin)$ peer lifecycle chaincode install cp.tar.gz
然后我們需要查詢并保存剛剛安裝的 鏈碼的packageID:
(digibank admin)$ peer lifecycle chaincode queryinstalled
將package ID保存為環境變數, 使用從控制臺回傳的package ID完成此步驟,
export PACKAGE_ID=cp_0:ffda93e26b183e231b7e9d5051e1ee7ca47fbf24f00a8376ec54120b1a2a335c
Digibank管理員現在可以同意papercontract的鏈碼定義:
(digibank admin)$ peer lifecycle chaincode approveformyorg --orderer localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name papercontract -v 0 --package-id $PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA
將鏈碼定義提交到通道
現在,DigiBank和MagnetoCorp都同意了papernet鏈碼, 我們有了我們需要的大多數(2/2)組織的條件來提交鏈碼定義到通道, 一旦在通道上成功定義了鏈碼, 通道上的客戶端應用程式就可以呼叫 papercontract鏈碼中的CommercialPaper智能合約, 由于任何一個機構都可以提交鏈碼到通道, 我們將繼續以DigiBank管理員的身份操作:

在DigiBank管理員將papercontract鏈碼的定義提交到通道后,將創建一個新的Docker鏈碼容器,以便在PaperNet的兩個peer節點上運行papercontract
DigiBank管理員使用peer lifecycle chaincode commit命令 將papercontract的鏈碼定義提交到mychannel:
(digibank admin)$ peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --peerAddresses localhost:7051 --tlsRootCertFiles ${PEER0_ORG1_CA} --peerAddresses localhost:9051 --tlsRootCertFiles ${PEER0_ORG2_CA} --channelID mychannel --name papercontract -v 0 --sequence 1 --tls --cafile $ORDERER_CA --waitForEvent
鏈碼容器將在鏈碼定義提交到通道后啟動, 您可以使用docker ps命令在兩個peer節點上 看到papercontract容器的啟動,
(digibank admin)$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d4ba9dc9c55f dev-peer0.org1.example.com-cp_0-ebef35e7f1f25eea1dcc6fcad5019477cd7f434c6a5dcaf4e81744e282903535-05cf67c20543ee1c24cf7dfe74abce99785374db15b3bc1de2da372700c25608 "docker-entrypoint.s…" 30 seconds ago Up 28 seconds dev-peer0.org1.example.com-cp_0-ebef35e7f1f25eea1dcc6fcad5019477cd7f434c6a5dcaf4e81744e282903535
a944c0f8b6d6 dev-peer0.org2.example.com-cp_0-1487670371e56d107b5e980ce7f66172c89251ab21d484c7f988c02912ddeaec-1a147b6fd2a8bd2ae12db824fad8d08a811c30cc70bc5b6bc49a2cbebc2e71ee "docker-entrypoint.s…" 31 seconds ago Up 28 seconds dev-peer0.org2.example.com-cp_0-1487670371e56d107b5e980ce7f66172c89251ab21d484c7f988c02912ddeaec
注意,容器的命名指出了啟動它的peer節點, 以及它正在運行papercontract版本0的實際情況,
現在我們已經將papercontract鏈代碼部署到通道, 我們可以使用MagnetoCorp應用程式來發行商業票據, 讓我們花點時間檢查一下應用程式的結構,
應用結構
包含在 papercontract 中的智能合約由 MagnetoCorp 的應用程式 issue.js 呼叫,Isabella 使用該程式向發行商業票據 00001 的賬本提交一項交易,讓我么來快速檢驗一下 issue 應用是怎么作業的,

gateway允許應用程式專注于交易的生成、提交和回應,它協調不同網路組件之間的交易提案、排序和通知處理,
issue 應用程式代表 Isabella 提交交易,它通過從 Isabella 的 錢包 中索取其 X.509 證書來開始運行,此證書可能儲存在本地檔案系統中或一個硬體安全模塊 HSM 里,隨后,issue 應用程式就能夠利用gateway在通道上提交交易,Hyperledger Fabric的軟體開發包(SDK)提供了一個 gateway 抽象,因此應用程式在將網路互動托管給網關時能夠專注于應用邏輯,網關和錢包使得撰寫 Hyperledger Fabric 應用程式變得很簡單,
讓我們來檢驗一下 Isabella 將要使用的 issue 應用程式,為其打開另一個終端視窗,在 fabric-samples 中找到 MagnetoCorp 的 /application 檔案夾:
(isabella)$ cd commercial-paper/organization/magnetocorp/application/
(isabella)$ ls
enrollUser.js issue.js package.json
addToWallet.js 是 Isabella 將用來把自己的身份裝進錢包的程式,而 issue.js 將使用這一身份通過呼叫 papercontract 來代表 MagnetoCorp 生成商業票據 00001,
切換至包含 MagnetoCorp 的 issue.js 應用程式副本的目錄,并且使用您的代碼編輯器檢查此目錄:
(isabella)$ cd commercial-paper/organization/magnetocorp/application
(isabella)$ code issue.js
檢查該目錄;目錄包含了 issue 應用程式和其所有依賴項,

一個展示了商業票據應用程式目錄內容的代碼編輯器,
注意以下在 issue.js 中的關鍵程式行:
-
const { Wallets, Gateway } = require('fabric-network');
該陳述句把兩個關鍵的 Hyperledger Fabric 軟體開發包(SDK)類引入了Wallet和Gateway, -
const wallet = await Wallets.newFileSystemWallet('../identity/user/isabella/wallet');
該陳述句表明了應用程式在連接到區塊鏈網路通道上時將使用Isabella錢包,因為 Isabella 的 X.509 證書位于本地檔案系統中,所以應用程式創建了一個FileSystemWallet,應用程式會在isabella錢包中選擇一個特定的身份, -
await gateway.connect(connectionProfile, connectionOptions);
此行代碼使用connectionProfile識別的網關來連接到網路,使用ConnectionOptions當中參考的身份,
看看../gateway/networkConnection.yaml和User1@org1.example.com是如何分別被用于這些值的, -
const network = await gateway.getNetwork('mychannel');
該陳述句是將應用程式連接到網路通道mychannel上,papercontract之前就已經在該通道上部署過了, -
const contract = await network.getContract('papercontract');
該陳述句是讓應用程式可以訪問由papercontract中的org.papernet.commercialpaper命名空間定義的智能合約,一旦應用程式請求了 getContract,那么它就能提交任意在其內實作的交易, -
const issueResponse = await contract.submitTransaction('issue', 'MagnetoCorp', '00001', ...);
該行代碼是使用在智能合約中定義的 issue 交易來向網路提交一項交易,MagnetoCorp,00001… 都是被issue交易用來生成一個新的商業票據的值, -
let paper = CommercialPaper.fromBuffer(issueResponse);
此陳述句是處理issue交易發來的回應,該回應需要從緩沖區被反序列化成paper,這是一個能夠被應用程式準確解釋的CommercialPaper物件,
歡迎檢查 /application 目錄下的其他檔案來了解 issue.js 是如何作業的,并仔細閱讀應用程式 主題 中關于如何實作 issue.js 的內容,
應用程式依賴
issue.js 應用程式是用 JavaScript 撰寫的,旨在作為 PaperNet 網路的客戶端來在 node.js 環境中運行,按照慣例,會在多個網路外部的節點包上建立 MagnetoCorp 的應用程式,以此來提升開發的質量和速度,考慮一下 issue.js 是如何納入 js-yaml 包 來處理 YAML 網關連接組態檔的,或者 issue.js 是如何納入 fabric-network 包 來訪問 Gateway 和 Wallet 類的:
const yaml = require('js-yaml');
const { Wallets, Gateway } = require('fabric-network');
需要使用 npm install 命令來將這些包從 npm 下載到本地檔案系統中,按照慣例,必須將包安裝進一個相對于應用程式的 /node_modules 目錄中,以供運行時使用,
檢查 package.json 檔案來看看 issue.js 是如何通過識別包裝來下載自己的準確版本的:
npm 版本控制功能非常強大;點擊這里可以了解更多相關資訊,
讓我們使用 npm install 命令來安裝這些包,安裝程序可能需要一分鐘:
(isabella)$ cd commercial-paper/organization/magnetocorp/application/
(isabella)$ npm install
( ) extract:lodash: sill extract ansi-styles@3.2.1
(...)
added 738 packages in 46.701s
看看這個命令是如何更新目錄的:
(isabella)$ ls
enrollUser.js node_modules package.json
issue.js package-lock.json
檢查 node_modules 目錄,查看已經安裝的包,能看到很多已經安裝了的包,這是因為 js-yaml 和 fabric-network 本身都被搭建在其他 npm 包中! package-lock.json 檔案 能準確識別已安裝的版本,如果您想用于生產環境的話,那么這一點對您來說就很重要,例如,測驗、排查問題或者分發已驗證的應用,
錢包
Isabella 馬上就能夠運行 issue.js 來發行 MagnetoCorp 商業票票據 00001 了;現在還剩最后一步!因為 issue.js 代表 Isabella,所以也就代表 MagnetoCorp, issue.js 將會使用 Isabella 錢包中反應以上事實的身份,現在我們需要執行這個一次性的活動,向 Isabella 的錢包中添 X.509 證書,
運行在PaperNet上的MagnetoCorp證書頒發機構ca_org2, 有一個在部署網路時便注冊的應用程式用戶, Isabella可以使用身份名和secret 為issue.js應用程式生成X.509加密材料, 使用CA生成客戶端加密資料的程序稱為enrollment, 在實際的應用場景中,網路運營商將向應用程式開發人員 提供使用CA所注冊的客戶端身份的名稱和secret, 然后,開發人員將使用證書憑據注冊他們的應用程式并與網路互動,
enrollUser.js程式使用fabric-ca-client類生成私有、公共密鑰對, 然后發起一個Certificate Signing Request給CA, 如果Isabella提交的身份名稱和secret匹配CA注冊的證書憑據, CA將發行并簽名一個編碼了公鑰的證書, 證明Isabella屬于Isabella簽名,簽名請求完成后, enrollUser.js將私鑰和簽名證書存盤在Isabella的錢包中, 您可以查看enrollUser.js檔案, 了解更多關于Node SDK如何使用fabric-ca-client類來完成這些任務的資訊,
在 Isabella 的終端視窗中運行 addToWallet.js 程式來把身份資訊添加到她的錢包中:
(isabella)$ node enrollUser.js
Wallet path: /Users/nikhilgupta/fabric-samples/commercial-paper/organization/magnetocorp/identity/user/isabella/wallet
Successfully enrolled client user "isabella" and imported it into the wallet
現在我們可以把焦點轉向這個程式的結果—— 將用于提交交易到PaperNet的錢包內容:
(isabella)$ ls ../identity/user/isabella/wallet/
isabella.id
Isabella可以在她的錢包中存盤多個身份, 但在我們的示例中,她只使用一個, wallet檔案夾里有一個isabella.id檔案, 該檔案提供Isabella連接到網路所需的資訊, Isabella使用的其他身份都有自己對應的檔案, 您可以打開這個檔案, 查看JSON檔案中issue.js將使用的代表Isabella的身份標識資訊, 為清晰起見,輸出已經進行了格式化,
(isabella)$ cat ../identity/user/isabella/wallet/*
{
"credentials": {
"certificate": "-----BEGIN CERTIFICATE-----\nMIICKTCCAdCgAwIBAgIQWKwvLG+sqeO3LwwQK6avZDAKBggqhkjOPQQDAjBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMi5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMi5leGFtcGxlLmNvbTAeFw0yMDAyMDQxOTA5MDBaFw0zMDAyMDExOTA5MDBa\nMGwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMQ8wDQYDVQQLEwZjbGllbnQxHzAdBgNVBAMMFlVzZXIxQG9y\nZzIuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT4TnTblx0k\ngfqX+NN7F76Me33VTq3K2NUWZRreoJzq6bAuvdDR+iFvVPKXbdORnVvRSATcXsYl\nt20yU7n/53dbo00wSzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADArBgNV\nHSMEJDAigCDOCdm4irsZFU3D6Hak4+84QRg1N43iwg8w1V6DRhgLyDAKBggqhkjO\nPQQDAgNHADBEAiBhzKix1KJcbUy9ey5ulWHRUMbqdVCNHe/mRtUdaJagIgIgYpbZ\nXf0CSiTXIWOJIsswN4Jp+ZxkJfFVmXndqKqz+VM=\n-----END CERTIFICATE-----\n",
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQggs55vQg2oXi8gNi8\nNidE8Fy5zenohArDq3FGJD8cKU2hRANCAAT4TnTblx0kgfqX+NN7F76Me33VTq3K\n2NUWZRreoJzq6bAuvdDR+iFvVPKXbdORnVvRSATcXsYlt20yU7n/53db\n-----END PRIVATE KEY-----\n"
},
"mspId": "Org2MSP",
"type": "X.509",
"version": 1
}
在檔案中您可以注意到以下內容:
"privateKey":用來代表Isabella簽名交易, 但不能被分發到她的直接控制范圍之外,"certificate":它包含Isabella的公鑰和證書頒發機構在 創建證書時添加的其他X.509屬性,該證書被分發到網路中, 以便不同的參與者可以在不同的時間 以加密方式驗證由Isabella的私鑰加密過的資訊,
點擊此處獲取更多關于證書資訊,在實踐中,證書檔案還包含一些 Fabric 專門的元資料,例如 Isabella 的組織和角色——在錢包主題閱讀更多內容,
發行應用
Isabella 現在可以用 issue.js 來提交一項交易,該交易將發行 MagnetoCorp 商業票據 00001:
(isabella)$ node issue.js
Connect to Fabric gateway.
Use network channel: mychannel.
Use org.papernet.commercialpaper smart contract.
Submit commercial paper issue transaction.
Process issue transaction response.{"class":"org.papernet.commercialpaper","key":"\"MagnetoCorp\":\"00001\"","currentState":1,"issuer":"MagnetoCorp","paperNumber":"00001","issueDateTime":"2020-05-31","maturityDateTime":"2020-11-30","faceValue":"5000000","owner":"MagnetoCorp"}
MagnetoCorp commercial paper : 00001 successfully issued for value 5000000
Transaction complete.
Disconnect from Fabric gateway.
Issue program complete.
node 命令初始化一個 node.js 環境,并運行 issue.js,從程式輸出我們能看到,系統發行了一張 MagnetoCorp 商業票據 00001,面值為 500 萬美元,
如您所見,為實作這一點,應用程式呼叫了 papercontract.js 中 CommercialPaper 智能合約里定義的 issue 交易,MagnetoCorp 管理員已經在網路上安裝并實體化了 CommercialPaper 智能合約,在世界狀態里作為一個矢量狀態來代表新的商業票據的是通過 Fabric 應用程式編碼埠(API)來與賬本互動的智能合約,其中最顯著的 API 是 putState() 和 getState(),我們即將看到該矢量狀態在隨后是如何被 buy 和 redeem 交易來操作的,這兩項交易同樣也是定義在那個智能合約中,
潛在的 Fabric 軟體開發包(SDK)一直都在處理交易的背書、排序和通知流程,使得應用程式的邏輯變得簡單明了; SDK 用網關提取出網路細節資訊和連接選項 ,以此來宣告更先進的流程策略,如交易重試,
現在讓我們將重點轉換到 DigiBank(將購買商業票據),以遵循 MagnetoCorp 00001 的生命周期,
DigiBank應用
Balaji 使用 DigiBank 的 buy 應用程式來向賬本提交一項交易,該賬本將商業票據 00001 的所屬權從 MagnetoCorp 轉向 DigiBank, CommercialPaper 智能合約與 MagnetoCorp 應用程式使用的相同,但是此次的交易不同,是 buy 交易而不是 issue 交易,讓我們檢查一下 DigiBank 的應用程式是怎樣作業的,
為 Balaji 打開另一個終端視窗, 在 fabric-samples 中,切換到包含 buy.js 應用程式的 DigiBank 應用程式目錄,并用編輯器打開該目錄:
(balaji)$ cd commercial-paper/organization/digibank/application/
(balaji)$ code buy.js
如您所見,該目錄同時包含了 Balaji 將使用的 buy 和 redeem 應用程式 ,

DigiBank 的商業票據目錄包含 buy.js 和 redeem.js 應用程式,
DigiBank 的 buy.js 應用程式在結構上與 MagnetoCorp的 issue.js 十分相似,但存在兩個重要的差異:
- 身份:用戶是 DigiBank 的用戶
Balaji而不是 MagnetoCorp 的Isabella
const wallet = await Wallets.newFileSystemWallet('../identity/user/balaji/wallet');
看看應用程式在連接到 PaperNet 網路上時是如何使用 balaji 錢包的,buy.js 在 balaji 錢包里選擇一個特定的身份,
- 交易:被呼叫的交易是
buy而不是issue
const buyResponse = await contract.submitTransaction('buy', 'MagnetoCorp', '00001', ...);
提交一項 buy 交易,其值為 MagnetoCorp, 00001…, CommercialPaper 智能合約類使用這些值來將商業票據 00001 的所屬權轉換成 DigiBank,
歡迎檢查 application 目錄下的其他檔案來理解應用程式的作業原理,并仔細閱讀應用程式主題中關于如何實作 buy.js 的內容,
以 DigiBank 的身份運行
負責購買和贖回商業票據的 DigiBank 應用程式的結構和 MagnetoCorp 的發行交易十分相似,所以,我們來安裝這些應用程式 的依賴項,并搭建 Balaji 的錢包,這樣一來,Balaji 就能使用這些應用程式購買和贖回商業票據,
和 MagnetoCorp 一樣, Digibank 必須使用 npm install 命令來安裝規定的應用包,同時,安裝時間也很短,
在 DigiBank 管理員視窗安裝應用程式依賴項:
(digibank admin)$ cd commercial-paper/organization/digibank/application/
(digibank admin)$ npm install
( ) extract:lodash: sill extract ansi-styles@3.2.1
(...)
added 738 packages in 46.701s
在 Balaji 的終端視窗運行 addToWallet.js 程式,把身份資訊添加到他的錢包中:
addToWallet.js 程式為 balaji 將其身份資訊添加到他的錢包中, buy.js 和 redeem.js 將使用這些身份資訊來向 PaperNet 提交交易,
(balaji)$ node enrollUser.js
Wallet path: /Users/nikhilgupta/fabric-samples/commercial-paper/organization/digibank/identity/user/balaji/wallet
Successfully enrolled client user "balaji" and imported it into the wallet
addToWallet.js程式已經將balaji的身份資訊添加到他的錢包中, 該錢包將被buy.js和redeem.js用于向PaperNet提交交易,
與Isabella一樣,Balaji可以在他的錢包中存盤多個身份, 但在我們的示例中,他只使用一個, 他在digibank/identity/user/balaji/wallet/balaji.id對應的id檔案 和Isabella的非常相似——請隨意查看,
購買應用
Balaji 現在可以使用 buy.js 來提交一項交易,該交易將會把 MagnetoCorp 商業票據 00001 的所屬權轉換成 DigiBank,
在 Balaji 的視窗運行 buy 應用程式:
(balaji)$ node buy.js
Connect to Fabric gateway.
Use network channel: mychannel.
Use org.papernet.commercialpaper smart contract.
Submit commercial paper buy transaction.
Process buy transaction response.
MagnetoCorp commercial paper : 00001 successfully purchased by DigiBank
Transaction complete.
Disconnect from Fabric gateway.
Buy program complete.
您可看到程式輸出為:Balaji 已經代表 DigiBank 成功購買了 MagnetoCorp 商業票據 00001, buy.js 呼叫了 CommercialPaper 智能合約中定義的 buy 交易,該智能合約使用 Fabric 應用程式編程介面(API) putState() 和 getState() 在世界狀態中更新了商業票據 00001 ,如您所見,就智能合約的邏輯來說,購買和發行商業票據的應用程式邏輯彼此十分相似,
贖回應用
商業票據 00001 生命周期的最后一步交易是 DigiBank 從 MagnetoCorp 那里贖回商業票據,Balaji 使用 redeem.js 提交一項交易來執行智能合約中的贖回邏輯,
在Balaji的視窗運行 redeem 交易:
(
balaji)$ node redeem.js
Connect to Fabric gateway.
Use network channel: mychannel.
Use org.papernet.commercialpaper smart contract.
Submit commercial paper redeem transaction.
Process redeem transaction response.
MagnetoCorp commercial paper : 00001 successfully redeemed with MagnetoCorp
Transaction complete.
Disconnect from Fabric gateway.
Redeem program complete.
同樣地,看看當 redeem.js 呼叫了 CommercialPaper 中定義的 redeem 交易時,商業票據 00001 是如何被成功贖回的, redeem 交易在世界狀態中更新了商業票據 00001 ,以此來反映商業票據的所屬權又歸回其發行方 MagnetoCorp,
清理
在您完成商業票據教程后, 您可以使用一個腳本來清理您的環境, 打開一個命令視窗瀏覽回商業票據示例的根目錄:
cd fabric-samples/commercial-paper
然后您可以使用以下命令關閉網路:
./network-clean.sh
除了logspout工具之外, 這個命令還將關閉peer節點、CouchDB容器和網路中的排序節點, 它還會移除我們為Isabella和Balaji創造的身份標識, 請注意,賬本上的所有資料都將丟失, 如果你想再次學習教程,你將從一個干凈的初始狀態開始,
下一步
要想更深入地理解以上教程中所介紹的應用程式和智能合約的作業原理,可以參照 開發應用程式,該主題將為您詳細介紹商業票據場景、PaperNet 商業網路,網路操作者以及它們所使用的應用程式和智能合約的作業原理,
歡迎使用該樣本來開始創造您自己的應用程式和智能合約!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/296666.html
標籤:區塊鏈
上一篇:什么是GAMEFI?一款好的GAMEFI具備哪些特性?
下一篇:震驚 BTC和ETH同時斬殺
