Hyperledger Fabric学习笔记——商业票券案例

Fabric最近更新到了2.x版本的第一个LTS版本,官方文档也进行了相应的更新,如当时刚进入2.0beta版本介绍所说,将采用test-network作为学习的基础,因此我也升级到了2.1版本,后续都是在2.1版本上进行。

1、建立网络

test network由两个对等节点组织和一个排序组织组成,每个节点组织操作一个对等节点,排序组织操作一个节点raft排序服务。两个对等节点,节点中的账本,orderer和CA分别运行在各自的Docker容器中,在生产环境中,组织一般使用和其他系统共享的存在的CAs,并不是专用于fabric网络。

通过提供的脚本运行网络:

cd fabric-samples/commercial-paper
./network-starter.sh

2、作为MagnetoCorp监视网络

打开一个新的终端窗口,进入MagnetoCorp目录,首先要做的是监视PaperNet的组件,管理员通过logsout工具可以看到一系列docker容器的所有输出。这个工具收集不同的输出流到同一个地方,使我们能够从一个窗口中看到发生了什么。

cd /commercial-paper/organization/magnetocorp
./configuration/cli/monitordocker.sh net_test

3、商业票据智能合约

用VScode打开magnetocorp下的contract目录,其中lib目录下的papercontract.js包含了商业票据的智能合约。下面简单介绍一下papercontract.js中的一些关键代码:

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

上面声明将两个将会在智能合约中广泛用到的关键Hyperledger Fabric类加入域中——Contract和Context。

class CommmercialPaperContract extends Contract {

基于内置的Fabric Contract类定义了智能合约类CommercialPaperContract,实施issue,buy和redeem的事务的方法将会定义在这个类中。

async issue(ctx, issuer, paperNumber, issueDateTime, maturityDateTime...){

issue方法,传递的参数将用于发行一个新的商业票券。

let paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime...);

通过CommercialPaper类在内存中创建了一个新的商业票券。

await ctx.paperList.addPaper(paper);

使用ctx.paperList将新的商业票券加入到账本中,ctx.paperList是PaperList类的一个实例,在智能合约context CommercialPaperContext被初始化的时候被创建。

return paper;

上面的声明返回一个二进制缓存作为调用智能合约issue transaction的响应。

4、作为MagnetoCorp安装和批准智能合约

MagnetoCorp管理员可以使用peer CLI和PaperNet交互,但是需要在其命令窗口设置特定的环境变量来使用正确的peer二进制集合,发送命令到MagnetoCorp地址以及用正确的加密材料签署请求。这里可以使用提供的脚本设置环境变量:

source magnetocorp.sh

由于我将macos系统更新到了Catalina,所以默认的是zsh而不是bash,方便起见这里将默认shell切换为bash。

cash -s /bin/bash

脚本执行成功后,所有的环境变量都会列在窗口中,接下来就可以使用这个命令窗口作为MagnetoCorp管理员和PaperNet进行交互了。

首先安装papercontract智能合约,先用peer lifecycle chaincode package命令将智能合约打包在一个链码中:

peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0

然后管理员用peer lifecycle chaincode install命令将链码安装到MagnetoCorp节点上:

peer lifecycle chaincode install cp.tar.gz

安装好智能合约后,需要作为MagnetoCorp批准链码定义。首先使用peer lifecycle chaincode queryinstalled命令找出安装在peer上的链码的packageID;

peer lifecycle chaincode queryinstalled

将packageID保存为环境变量:

export PACKAGE_ID=cp_0:355ef57f6144995eec41cfead08556396e64052ff4a4f9b95a8cb576aa612d98

现在管理员可以代表MagnetoCorp用peer lifecycle chaincode approveformyorg命令批准链码定义:

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

通道成员需要就链码定义达成一致最重要的参数之一是认可策略(endorsement policy),认可策略描述了在一个transaction将要生效前需要执行和签名的组织的集合。在上面批准papercontract链码的时候并没有使用--policy标志,这说明MagnetoCorp的管理员使用默认的认可策略,即需要通道中的大部分组织来认可一个transaction。所有的transactions,无论生效还是不生效,都会被记录在区块链上,但是只有生效的transactions会更新world state。

5、作为DigiBank安装并批准智能合约

默认的,Fabric Chaincode lifecycle需要通道上大多数组织成功提交链码定义到通道中,因此我们需要作为DigiBank将papernet 链码提交到通道并批准。打开一个新的终端窗口并导航到digibank目录,之后的步骤和第4步中完全一样。

cd commercial-paper/organization/digibank
source digibank.sh
peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0
peer lifecycle chaincode install cp.tar.gz
export PACKAGE_ID=cp_0:126f0d300535d3469008a02a7c9555cb09f9de0c53c02814aa2b3c0772bb7b77
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

6、将链码定义提交到通道

两个组织都已经在组织层面批准了链码,接下来只需要一个组织将链码定义提交到通道即可。DigiBank管理员使用peer lifecycle chaincode commit命令将链码定义提交到通道:

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容器将被创建——papercontract容器运行在两个节点上。

7、应用程序

上图展示了issue应用程序提交transaction的整个流程,之前都有介绍过,之前有所忽视的一点是,Hyperledger Fabric SDK提供了网关的抽象。

打开一个新的控制台窗口,导航到magnetocorp/application目录下,用VScode打开,下面是issue.js的一些关键语句:

const { Wallets, Gateway } = require('fabric-network');

将两个关键Hyperledger Fabric SDK类加入域中。

const wallet = await Wallets.newFileSystemWallet('../identity/user/isabella/wallet');

标明该应用程序使用isabella的钱包连接到区块链网络通道。

await gateway.connect(connectionProfile, connectionOptions);

这行代码使用connectionProfile标识的网关和ConnectionOptions中提及的身份连接到网络,../gateway/networkConnection.yaml标识了网关,[email protected]是ConnectionOptions中提及的身份。

const network = await gateway.getNetwork('mychannel');

将应用程序连接到网络通道mychannel,即papercontract已经实例化的通道。

const contract = await network.getContract('papercontract');

声明给了应用程序连接到papercontract链码的方式。

const issueResponse = await contract.submitTransaction('issue', 'MagnetoCorp', '00001', ...);

提交一个transaction到网络,使用定义在智能合约中的issue transaction。

let paper = CommercialPaper.fromBuffer(issueResponse);

处理issue transaction的响应,响应需要从缓冲区反序列化到paper,一个可以被应用程序正确解释的CommercialPaper对象。

8、应用程序依赖

issue.js需要饱含js-yaml包来处理YAML网关连接文件以及fabric-network包来加入Gateway和Wallet类:

const yaml = require('js-yaml');

const { Wallets, Gateway} = require('fabric-network');

这些包通过npm install命令从npm下载到本地文件系统,通常这些包必须安装在应用程序相应的/node_modules目录以在运行时使用。

"dependencies":{

"fabric-network": "~1.4.0",

"fabric-client" : "~1.4.0",

"js-yaml" : "^3.12.0"

}

package.json文件中标识了需要包的名称和具体版本。

使用npm install安装应用程序依赖,如果出现问题用nvm切换一下node.js和npm的版本,也可能此处出现网络问题,多尝试几次即可。安装完成后,node_modules目录下会多很多的包,因为js-yaml和fabric-network本身建立在其他npm包的基础上。

9、钱包

因为issue.js是以Isabella身份执行的,因此需要通过运行addToWallet.js将Isabella的身份信息加入到她的钱包中:

node addToWallet.js

addToWallet.js是一个简单的文件拷贝程序,它将一个test network中的身份拷贝到Isabella的钱包中,Isabella可以存储多个身份在她的钱包中,查看isabella.id文件可以看到如下重要身份信息:

privateKey:用于签名和Isabella相关的transactions,本人所有,不传播到网络中。

certificate:包含Isabella的公钥和其他在CA建立身份时添加的X.509属性,这个证书会传播到网络中,这样其他角色在不同的时间都可以加密地验证Isabella私钥创立的信息。

在实践中,证书文件还包含一些Fabric特殊的元信息,比如Isabella的组织以及角色等。

10、Issue应用程序

现在Isabella可以使用issue.js来提交一个transaction发行MagnetoCorp商业票券00001:

node issue.js

发行新票券的整个流程大概如下:

应用程序调用在papercontract.js中定义的CommercialPaper智能合约中的issue transaction。这个链码被MagnetoCorp管理员安装并实例化在网络mychannel通道中。智能合约通过Fabric APIs和账本交互,最主要通过putState()和getState(),新的商业票券以向量状态的形式保存在world state中,后续将会被同样定义在智能合约中的buy和redeem控制。

底层的Fabric SDK一直处理着transaction的认可,排序和通知过程,使得应用程序逻辑更加简单。SDK使用网关来抽象出区块链网络的细节并用connectionOptions来声明更高级的处理策略例如transaction retry。

11、Digibank应用程序与运行

Digibank的buy.js应用程序和MagnetoCorp的issue.js非常相似,主要有两个重要不同:

const wallet = await Wallets.newFileSystemWallet('../identity/user/balaji/wallet');

使用的身份不同。

const buyResponse = await contract.submitTransaction('buy',...);

调用的transaction不同。

接下来和上面相似,安装应用程序依赖,并将balaji的身份加入到其钱包中:

cd digibank/application
npm install
node addToWallet.js
node buy.js
node redeem.js

12、清理环境

cd fabric-samples/commercial-paper
./network-clean.sh

 

猜你喜欢

转载自blog.csdn.net/Nemoosi/article/details/105782599
今日推荐