准备工作
开发环境:Mac + Parallels + Ubuntu 16.04.4 LTS(虚拟机操作系统)
1、安装cURL
$ sudo apt install curl
$ curl -V
2、安装 Docker CE
Hyperledger Fabric系统需要将多个模块分离部署在不同节点上,为了方便演示,通过docker模拟各个节点,因此,需要安装docker以及相关组件。
Docker CE安装方法:https://docs.docker.com/install/linux/docker-ce/ubuntu/#upgrade-docker-ce
3、增加一个docker非root用户
$ sudo groupadd docker
$ sudo usermod -aG docker $USER
$ docker run hello-world
4、安装Docker Compose组件
$ sudo apt update
$ sudo apt install docker-compose
$ docker --version && docker-compose --version
5、安装 Node.js
$ curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - sudo apt-get install -y nodejs
6、安装Go Language
$ sudo curl -O https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz
$ sudo tar -xvf go1.9.2.linux-amd64.tar.gz
$ sudo mv go /usr/local
$ echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
$ source ~/.profile
$ go version
安装Hyperledger Fabric Docker镜像
$ curl -sSL
https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh | bash -s 1.1.0
注意:如果上述命令执行失败或者卡住,可以先按照下面方式将bootstrap.sh脚本下载到本地后执行。
$ curl –O https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh
$ sudo bash bootstrap.sh –s 1.1.0
$ docker images
下载Hyperledger Fabric示例工程
$ export PATH=$PWD/bin:$PATH
$ git clone https://github.com/hyperledger/fabric-samples.git
(或者:git clone https://gerrit.hyperledger.org/r/fabric-samples)
$ cd fabric-samples/first-network
启动Hyperledger Fabric测试网络
Hyperledger Fabric安装完成后,通过docker镜像构建一个简单的测试网络,包含两个organizations,每个organization包含两个peers节点,然后共用一个ordering service节点(SOLO模式)。
1、创建网络节点
./byfn.sh generate
Generating certs and genesis block for with channel 'mychannel' and CLI timeout of '10' Continue? [Y/n] y proceeding ... /Users/xxx/dev/fabric-samples/bin/cryptogen ########################################################## ##### Generate certificates using cryptogen tool ######### ########################################################## org1.example.com 2017-06-12 21:01:37.334 EDT [bccsp] GetDefault -> WARN 001 Before using BCCSP, please call InitFactories(). Falling back to bootBCCSP. ... /Users/xxx/dev/fabric-samples/bin/configtxgen ########################################################## ######### Generating Orderer Genesis block ############## ########################################################## 2017-06-12 21:01:37.558 EDT [common/configtx/tool] main -> INFO 001 Loading configuration 2017-06-12 21:01:37.562 EDT [msp] getMspConfig -> INFO 002 intermediate certs folder not found at [/Users/xxx/dev/byfn/crypto-config/ordererOrganizations/example.com/msp/intermediatecerts]. Skipping.: [stat /Users/xxx/dev/byfn/crypto-config/ordererOrganizations/example.com/msp/intermediatecerts: no such file or directory] ... 2017-06-12 21:01:37.588 EDT [common/configtx/tool] doOutputBlock -> INFO 00b Generating genesis block 2017-06-12 21:01:37.590 EDT [common/configtx/tool] doOutputBlock -> INFO 00c Writing genesis block ################################################################# ### Generating channel configuration transaction 'channel.tx' ### ################################################################# 2017-06-12 21:01:37.634 EDT [common/configtx/tool] main -> INFO 001 Loading configuration 2017-06-12 21:01:37.644 EDT [common/configtx/tool] doOutputChannelCreateTx -> INFO 002 Generating new channel configtx 2017-06-12 21:01:37.645 EDT [common/configtx/tool] doOutputChannelCreateTx -> INFO 003 Writing new channel tx ################################################################# ####### Generating anchor peer update for Org1MSP ########## ################################################################# 2017-06-12 21:01:37.674 EDT [common/configtx/tool] main -> INFO 001 Loading configuration 2017-06-12 21:01:37.678 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 002 Generating anchor peer update 2017-06-12 21:01:37.679 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 003 Writing anchor peer update ################################################################# ####### Generating anchor peer update for Org2MSP ########## ################################################################# 2017-06-12 21:01:37.700 EDT [common/configtx/tool] main -> INFO 001 Loading configuration 2017-06-12 21:01:37.704 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 002 Generating anchor peer update 2017-06-12 21:01:37.704 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 003 Writing anchor peer update
2、运行测试网络
./byfn.sh up
启动容器测试网络,然后运行一些基本的测试用例,包括创建channel、加入channel、部署智能合约、调用智能合约等步骤,具体代码实现细节可以参考:
https://github.com/hyperledger/fabric-samples/blob/release-1.2/first-network/scripts/script.sh
启动成功后的日志如下:
用例运行结束后的日志,说明所有用例执行成功:
最后,关闭测试网络并清理环境:
$ ./byfn.sh down
开发一个简单的应用程序
在fabric-samples中有一个fabcar应用程序,模拟了一个简单的车辆管理系统,包括创建车辆、交易车辆等操作。应用程序通过智能合约接口和账本交互,然后将信息结果呈现在用户界面(例如,linux terminal)。
1、fabcar目录结构:
fabcar应用程序由5个文件组成,每个文件完成一个独立的功能模块,后面会详细解释。
# cd fabric-samples/fabcar && ls
enrollAdmin.js
invoke.js
package.json
query.js registerUser.js
startFabric.sh
2、安装应用客户端
首先,安装nodejs开发依赖库,这个过程可能会出现一些依赖库安装失败,有可能是由于系统中缺少一些基础库,可以通过单独安装后解决。
$ npm install
3、启动区块链网络,这个脚本会先初始化各个网络实体(endorsing peers、ordering service、committing peers等等)并创建关联channel,然后,部署智能合约并调用初始化方法插入一些车辆信息。startFabric.sh完成了区块链系统的初始化工作。
$ ./startFabric.sh
4、注册admin用户
首先向CA服务器发送一个注册请求,然后获取认证证书(包括一组公钥私钥),后面可以用证书创建一些普通用户。执行js脚本后,项目根目录会生成hfc-key-store
目录(类似以太坊的keystore文件),里面包含证书信息。
$ node enrollAdmin.js
5、注册普通用户user1
通过admin的eCert证书,继续向CA服务器发送注册请求,创建一个新的普通用户user1。
$ node registerUser.js
6、查询账本信息
车辆信息是以key-value形式保存在账本中的,key是CAR0、CAR1…车辆编号,value是具体的车辆属性。通过js脚本查询到10条车辆信息。
# 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"}}]
查询过程只是通过APIs获取账本中的数据,并不改变区块链状态,也不会产生新的区块。所以,整个过程不需要 endorsing peers、ordering service和committing peers参与。
query.js脚本通过调用fabcar智能合约的queryAllCars方法,完成查询动作。
// 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: ['']
};
// send the query proposal to the peer
return channel.queryByChaincode(request);
fabcar.go智能合约中的queryAllCars函数查询从startKey到endKey范围的value,并打印出来。
func (s *SmartContract) queryAllCars(APIstub shim.ChaincodeStubInterface) sc.Response {
resultsIterator, err := APIstub.GetStateByRange(startKey, endKey)
…
}
fabcar.go智能合约中包含所有车辆信息管理接口,例如创建车辆(createCar)、更新车辆颜色(updateCarColor)等等:
7、更新账本信息
更新账本的过程会改变区块链状态,需要ordering节点将交易信息打包成区块,然后发给committing peers节点写入区块链。
通过invoke.js脚本调用智能合约的createCar函数创建一辆车,在执行脚本之前需要按照注释内容修改一下具体调用的函数,具体如下:
// 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: 'createCar',
args: ['CAR12', 'Honda', 'Accord', 'Black', 'Tom'],
chainId: 'mychannel',
txId: tx_id
};
运行脚本后,即可创建一条车辆信息,然后通过query.js脚本可以查询到。
$ node invoke.js
总结
通过这个简单的车辆信息管理程序,我们可以很直观的感受到上层应用是如何通过智能合约与区块链数据库交互的。首先,最上层的业务逻辑调用智能合约函数接口,然后,智能合约通过协议层的SDK接口与区块链服务层交互,进行查询、更新操作,最后,上层应用将处理结果呈现到用户界面。其实,本质上,底层的区块链系统就是一个黑盒分布式数据库,同时提供防篡改、数据加密、权限控制等功能。
通过Hyperledger Fabric框架,开发者可以无需关注底层区块链的技术细节,只关注上层业务逻辑开发即可,极大的简化了应用开发难度,同时,通过各个模块的分离部署,实现了模块的插件式管理,更加灵活可靠。