从2006年到现在,云计算、NOSQL、大数据、机器学习、人工智能……隔一年半载就会有某种技术成为热点,诡异的是当这种技术成为热点后,就变得看不懂了。比如区块链,这两年已经变成了“有巨大潜力颠覆行业,创造让人们参与其创造价值的繁荣世界”“彻底改变人类社会文明”的技术。关于区块链的原理网上有很多浅显易懂的文章、视频,本文只讨论技术上的使用,结合Fabric(v1.0-alpha2)来说明。
Fabric没有看到图灵完备的描述,区块链用来保存记录,这些记录被称为block,每个block包含时间戳和上一个block的信息。所以技术上来说,Fabric的区块链是一种分布式数据库。transaction可以类比数据库的查询操作,但只能创建和移动。在Fabric中,区块链数据由State和Ledger构成,State为key-value结构,支持put/get操作;Ledger保存所有对State的、成功的操作,每个Peer都有一份Ledger。
上文提到的Peer,是Fabric的一种节点,有Committer和Endorser两种角色。Fabric有三种节点:Client/Peer/Orderer。Orderer提供channel给Client和Peer,Client通过这个channel,根据endorsement policy,将transaction广播给角色是Endorser的Peer。
Peer收到transaction,执行chaincode——用户编写的程序,这是跟Ledger交互的唯一方式——对transaction进行签署,返回给Client。Client收到所有返回的transaction后,转给Orderer(由Peer做代理),写到State和Ledger。这个流程很类似pub/sub消息系统。
Install Fabric
Fabric用GO语言编写,如果使用安装脚本而不是从源代码make,可以不安装GO编译器。安装环境如下:
Ubuntu 16.04.2
docker 1.12.6
docker-compose 1.8.0
安装docker和docker-compose,创建fabric-sample文件夹,用curl下载安装脚本并执行:
apt install docker docker-compose curl
# 如果docker-compose不在源里,可以用 pip 安装: pip install docker-compose
mkdir fabric-sample && cd fabric-sample
curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/master/examples/e2e_cli/bootstrap.sh | bash
执行结束后会创建release目录,包含根据系统生成的文件夹(例如当前环境是linux-amd64),也会下载docker镜像。镜像下载如果遇到问题,在release/linux-amd64目录执行这条命令可以继续下载:
sh download-dockerimages.sh -c $(uname -m)-1.0.0-alpha2 -f $(uname -m)-1.0.0-alpha2
脚本会列出下载的images,例如:
===> List out hyperledger docker images
hyperledger/fabric-couchdb latest 3d89ac4895f9 2 weeks ago 1.515 GB
hyperledger/fabric-couchdb x86_64-1.0.0-alpha2 3d89ac4895f9 2 weeks ago 1.515 GB
Fabric自带的脚本创建一个演示环境只需要两条命令:先用generateArtifacts.sh生成证书和配置文件,再用docker-compose根据docker-compose-cli.yaml启动镜像,docker会挂载crypto-config/channel-artifacts/chaincode这些包含证书和chaincode的目录。官方文档建议注释docker-compose-cli.yaml中cli部分的command(在volumns之前,当前版本是52行,内容是command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME}; sleep $TIMEOUT'
)。:
# 传递channel-ID
./generateArtifacts.sh perchouli
# 用docker-compose启动
CHANNEL_NAME=perchouli TIMEOUT=30 docker-compose -f docker-compose-cli.yaml up -d
生成的文件在channel-artifacts和crypto-config文件夹中。再执行docker ps
,可以看到启动了5个docker容器:
IMAGE COMMAND STATUS PORTS NAMES
hyperledger/fabric-peer "peer node start" Up About an hour cli
hyperledger/fabric-peer "peer node start --pe" Up About an hour 0.0.0.0:10051->7051/tcp, 0.0.0.0:10053->7053/tcp peer1.org2.example.com
hyperledger/fabric-orderer "orderer" Up About an hour 0.0.0.0:7050->7050/tcp orderer.example.com
hyperledger/fabric-peer "peer node start --pe" Up About an hour 0.0.0.0:9051->7051/tcp, 0.0.0.0:9053->7053/tcp peer0.org2.example.com
hyperledger/fabric-peer "peer node start --pe" Up About an hour 0.0.0.0:8051->7051/tcp, 0.0.0.0:8053->7053/tcp peer1.org1.example.com
hyperledger/fabric-peer "peer node start --pe" Up About an hour 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp peer0.org1.example.com
CLI
上文说过,Client和Peer的要通过channel来通讯,所以先创建channel。
在容器中执行peer channel create
,指定orderer、证书、channel名称和配置文件:
docker exec -it cli bash
# root@容器ID:/opt/gopath/src/github.com/hyperledger/fabric/peer#
peer channel create --tls -o orderer.example.com:7050 --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/cacerts/ca.example.com-cert.pem -c perchouli -f ./channel-artifacts/channel.tx
执行成功会在当前目录生成
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
默认是对peer0进行操作,执行peer channel join
:
echo $CORE_PEER_ADDRESS
peer channel join -b perchouli.block
###
# Peer joined the channel!
# 2017-03-05 04:01:46.733 UTC [main] main -> INFO 008 Exiting.....
# 可以执行 peer channel list验证:
peer channel list
# Channels peers has joined to:
# perchouli
加入了channel,就可以通过chaincode操作了。使用cli容器中的示例chaincode,将它安装到各个Peer的/var/hyperledger/production/chaincodes目录下:
peer chaincode install -n example02_cc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
然后执行chaincode,也是要指定Orderer、channel、证书,还有之前安装的chaincode。以及,通过-P
指定endorsement policy。-c
以JSON的格式传参给chiancode:
peer chaincode instantiate --tls -o orderer.example.com:7050 -C perchouli -n example02_cc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -P "OR ('Org1MSP.member','Org2MSP.member')" --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/cacerts/ca.example.com-cert.pem -c '{"Args":["init","a", "100", "b","200"]}'
执行需要一定的时间,现在a是100,b是200。通过查询操作进行验证:
peer chaincode query -C perchouli -n example02_cc -c '{"Args":["query","a"]}'
# Query Result: 100
peer chaincode query -C perchouli -n example02_cc -c '{"Args":["query","b"]}'
# Query Result: 200
Invoke操作可以更新State:
peer chaincode invoke --tls -o orderer.example.com:7050 -C perchouli -n example02_cc --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/cacerts/ca.example.com-cert.pem -c '{"Args":["invoke","a","b","10"]}'
peer chaincode query -C perchouli -n example02_cc -c '{"Args":["query","a"]}'
# Query Result: 90
最后,如果需要停止服务、销毁容器、删除之前生成的证书:
./network_setup.sh down perchouli
Afterwords
作为一种数据库,区块链的查询效率没什么优势。去中心化的特征,在Fabric的设计里不够明显,因为大多数请求都要经过Orderer。虽然channel实现了隔离,但没有传统数据库那种严格的权限设计,“安全”更多只是针对记录的“不可篡改”。区块链适合做的事,绕来绕去就货币、合约这两种了,除此以外众多DAPP没有找到超越经典架构的,是创新还是蹭热点现在还看不出来。