超级账本网络的创建主要包含四个步骤:
特别注意:在需要重新执行下面步骤以前,先执行一下[docker-compose -f $COMPOSE_FILE down --volumes],以确保前次执行结果被清空。否则可能出现权限不正确的问题。
工具cryptogen用来创建网络的拓扑结构,初始化MSP信息,并对所有组织和节点进行签名。cryptogen位于fabric/build/bin目录下,它使用了crypto-config.yaml作为配置文件,我们可以使用[cryptogen showtemplate]查看配置文件模板。实际上,示例代码的crypto-config.yaml就是基于这个模板修改的。具体的配置方法参加模板说明。示例配置文件生产力如下所在的拓扑网络:
如果,包含了两种类型的组织:OrdererOrgs和PeerOrgs。一个Orderer组织下面有一个节点;而Peers有两个组织,每个组织通过Template创建了两个Peers。因此,根据该配置文件,cryptogen将会生成5个节点:
- orderer.example.com
- peer0.org1.example.com
- peer1.org1.example.com
- peer0.org2.example.com
- peer1.org2.example.com
可以使用下面的命令来创建拓扑网络:
cd /opt/gopath/src/github.com/hyperledger/fabric-samples/first-network
../../fabric/build/bin/cryptogen generate --config=./crypto-config.yaml
命令将会在在当前目录下生成crypto-config目录。使用命令[tree crypto-config]命令可以查看目录的整体结构。简单的说,cryptogen完成了以下工作:
至此,网络的拓扑结构生成完毕。MSP模块将使用这些内容对节点进行安全管理和认证。
通道配置信息包括三个方面的内容:创世区块、通道配置信息和各个组织的Anchor Peer。使用configtxgen来完成通道配置信息的创建。可以使用[configtxgen --help]查看工具的使用方法。和cryptogen不同,configtxgen指定使用configtx.yaml。
从这个意义来说,超级账本的分布式更像是基于组织的分布式,这和我们通常理解的分布式和去中心化有很大不同。
创世块的创建可以使用下面的命令完成
export FABRIC_CFG_PATH=$PWD
../../fabric/build/bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
它使用了TwoOrgsOrdererGenesis的profile,生成了genesis.block区块,因此区块应该是一个和排序服务相关的概念。需要注意的是,这里不能修改区块的名字,在我们创建好通道后区块名字会被修改成为[通道名].block。
通道配置信息可以通过下面的命令创建:
export CHANNEL_NAME=shimzhaochnl
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
它使用了TwoOrgsChannel的profile,生成了名外shimzhaochnl的通道。通道配置信息保存在了channel.tx文件中。
Anchor Peer是一个组织内负责与其他组织打交道的门户节点,通常情况它也是背书节点。一个组织可以有多个节点加入到区块链网络,但是必须有至少一个Anchor Peer。Anchor Peer的配置可以使用下面的命令完成:
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
由于Anchor Peer定义在TwoOrgsChannelprofile中,上面分别的命令用到了TwoOrgsChannel profile。上面分别为Org1MSP和OrgMSP定义了Anchor Peer。
至此,通道配置信息创建完毕。生成的文件保存在了当前目录的[channel-artifacts]下面。可以使用下面的命令查看创建的区块信息:
../../fabric/build/bin/configtxgen -inspectBlock ./channel-artifacts/genesis.block
也可以使用下面的信息查看通道信息:
../../fabric/build/bin/configtxgen -inspectChannelCreateTx ./channel-artifacts/channel.tx
除此之外,还可以查看组织信息:
../../fabric/build/bin/configtxgen -printOrg Org1MSP
通道交易信息和创世块准备完毕后就可以启动区块链网络了。在这里我们使用docker-compose-cli.yaml文件启动网络:
vagrant@ubuntu-xenial:first-network$ docker-compose -f docker-compose-cli.yaml up -d
Creating network "net_byfn" with the default driver
Creating peer1.org1.example.com ...
Creating orderer.example.com ...
Creating peer0.org2.example.com ...
Creating peer1.org2.example.com ...
Creating peer0.org1.example.com ...
Creating orderer.example.com
Creating peer1.org1.example.com
Creating peer0.org2.example.com
Creating peer1.org2.example.com
Creating peer1.org2.example.com ... done
Creating cli ...
Creating cli ... done
去掉[-d]可以查看更多的log信息,启动完成后可以使用[docker ps -a]查看所有节点是否正确启动。
网络启动后我们还需要创建通道、加入通道、更新通道的Anchor Peer配置。
创建通道以前我们需要进入到cli节点,cli相当于超级账本的一个application,每次在操作peer的时候它都会去读取下面的环境变量以确定要操作哪一个Peer。cli是通过读取下面的配置文件来确定它连接的是哪个Peer节点。当操作的Peer发送变化的时候都需要重新备注这些环境变量,以确保操作的是正确的Peer节点。这些环境变量包括:
因此,首先我们要指定peer0.org1.example.com节点作为cli的连接节点,然后进入cli docker:
vagrant@ubuntu-xenial: first-network$ export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
vagrant@ubuntu-xenial: first-network$ export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
vagrant@ubuntu-xenial: first-network$ export CORE_PEER_LOCALMSPID="Org1MSP"
vagrant@ubuntu-xenial: first-network$ export 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
vagrant@ubuntu-xenial: first-network$ docker exec -it cli bash
root@bfe07b081e03:/opt/gopath/src/github.com/hyperledger/fabric/peer#
注意,接下来我们的操作就会在cli docker内部进行了。为了使用方便,先定义一个全局变量:
root@bfe07b081e03:/opt/gopath/src/github.com/hyperledger/fabric/peer#export CHANNEL_NAME=shimzhaochnl
然后,使用下面的命令创建通道:
root@bfe07b081e03:/opt/gopath/src/github.com/hyperledger/fabric/peer#peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
需要说明的是,创建通道本身也是超级账本的一个交易,因此首先交易信息会被发送到Orderder排序节点,Orderer排序服务会将交易信息广播到整个网络的所有节点。上面的命令中指定的channel.tx来自configtxgen创建的通道配置信息;而公钥则是排序节点的公钥。
通道创建完成后我们还需要将每个Peer节点加入到通道中。
加入通道需要借助cli容器。比如下面的操作允许我们将peer0.org1.example.com加入到通道:
#设置环境变量
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export 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
#下面的代码在容器内执行,将当期Peer加入通道
peer channel join -b shimzhaochnl.block #注意通道名
#退出
exit
依次将其余的三个Peer都加入到通道中。可以使用[peer channel list]查看当前Peer加入了哪些通道。
接下来需要制定每个Org的Anchor Peer。这个过程也是通过cli容器来实现的:
#设置环境变量
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export 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
#设置当前连接的Peer为组织的Anchor Peer
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
#退出
exit
通过上面的命令设置了peer0.org1.example.com为Org1的Anchor Peer。可以使用同样的方法设置peer0.Org2.example.com为Org2的Anchor Peer。
在进入容器[docker exec -it cli bash]后,可以使用peer命令查看当前链接节点的各种信息。参看[peer --help]了解更多。
链码(即智能合约)是超级账本的重要组成部分。所有的外部程序(application)对账本的访问都是通过链码实现的。对链码的操作包括安装、实例化、查询和更新。
链码的安装也需要进入到cli容易,连接到需要安装的Peer节点,然后执行安装命令。下面的命令用于为peer0.org1.example.com安装链码:
#设置环境变量
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export 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
#为当前Peer安装链码
peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
#退出
exit
链码安装完成后可以使用[peer chaincode list --installed]的命令查看是否已经安装成功。接下来,还需要为其它Peer安装链码,通常我们只需要为Anchor Peer安装链码即可。
链码在安装完成后还需要实例化才能起作用,可以使用下面的方法实例化链码:
#设置环境变量
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export 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
#实例化链码
peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')"
#退出
exit
需要注意的是:
链码的查询首先需要制定Peer,然后进入cli,再执行查询语句:
#设置环境变量
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export 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
#设置通道名
export CHANNEL_NAME=shimzhaochnl
#调用链码查询
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
#退出
exit
更新链码
同理,链码的更新操作类似如下:
#设置环境变量
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export 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
#设置通道名
export CHANNEL_NAME=shimzhaochnl
#调用链码更新账本
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}'
#退出
exit
逻辑上来说,所有Peer保存的账本应该是一致的。可以通过切换Peer来验证所有账本是不是同步更新了。