在阅读这篇文章之前,最好先掌握如何使用fabric测试网络和链码部署 如果你还不熟悉如何使用Hyperledger Fabric, 可以移步juejin.cn/post/713800…
如果本文对你有用,麻烦请给我点个赞👍,这是对我很大的鼓励!
下面我们开始解析network.sh的脚本内容
先理清单机的网络步骤:
生成组织
生成组织的证书
生成创世纪块
生成通道
生成结点加入通道
设定锚结点
然后搞清楚脚本中通过那些指令怎样的步骤启动的:
先来看一个网络的启动参数把
cd test-network/
./network.sh up createChannel -c mychannel -ca && ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-java -ccl java
上面 && 的前后实际上是两行不同的指令
-
前一个指令运行脚本,带有参数
upcreateChannelca(带ca和不带ca使用的证书生成方式会不同,目前的工作中我们使用带有ca标签启动) 作用为启动网络创建通道使用ca来生成加密材料 -
后一个指令运行脚本,带有参数
deployCC作用为在通道上安装链码(智能合约)
运行脚本的目录一定得是在test-network/下
1.networkup( )
-
先执行network up()函数,该函数中调用了
-
checkPrep() -- 主要检查docker的版本
-
createOrgs() -- createOrgs分为以下步骤:(这里直接以-ca的启动模式为例)
createOrgs( )
-
通过docker-compose启动ca结点
-
载入 registerEnroll.sh --那么这个脚本有什么内容呢?
- createOrg1()
- createOrg2()
- createOrderer()
- 上面三个函数是这个shell里的定义
-
然后执行shell里定义的函数
-
createOrg1
-
createOrg2
-
createOrderer
-
接下来执行ccp-generate.sh脚本
-
脚本功能是创建证书文件,然后放置在了organizations/ 下
-
-
-
接下来会检查是否使用数据库,如果有使用couchdb,那用docker启动一个相关容器
-
2.createChannel( )
那么组织文件证书弄完了,要使用的话,接下来需要创建创世纪块
创世纪块使用了工具 configtxgen, 创世纪块的配置为TwoOrgsApplicationGenesis
The channel MSP allows the nodes and users to be recognized as members of the network
有了组织的加密文件和创世纪块,peers 和 orderer 的服务就能启动了
这一步会在createChannel() 时进行
-
up( ) 的内容结束,网络启动后会创建通道 也就是createChannel( )这个函数
-
函数第一步是检查网络是否在启动,没有的话就去执行上面的up( )了
-
如果网络没问题,就去跑scripts/ 下的createChannel.sh -- 那么我们去看看里面有什么
createChannel.sh的内容
创建文件夹
- 首先会创建一个文件夹 channel-artifacts/ 来存放通道的文件
四个函数的定义
1.接下来是一个函数的定义 createChannelGenesisBlock( )
-
这个函数中的一条重要指令为
configtxgen -profile TwoOrgsApplicationGenesis -outputBlock ./channel-artifacts/${CHANNEL_NAME}.block -channelID $CHANNEL_NAME #通过这条指令,使用之前说到的configtxgen工具创建创世纪块,存放在刚刚创建的 channel-artifacts/ 下2.定义了一个createChannel( ) -- 内容如下
#脚本中写了个延时的指令,给raft共识留时间,这里就省略了 setGlobals 1 #后面是一条很长指令,看的出来,是根据我们在channel-artifacts/ 中创出来的创世纪块文件来创建通道 osnadmin channel join --channelID $CHANNEL_NAME --config-block ./channel-artifacts/${CHANNEL_NAME}.block -o localhost:7053 --ca-file "$ORDERER_CA" --client-cert "$ORDERER_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER_ADMIN_TLS_PRIVATE_KEY" >&log.txt3.这之外还定义了一项函数 joinChannel( ) -- 内容摘要我也写在代码块里
#先是这么几行指令 $1就是在函数运行时加的第一个参数 #Ep:joinChannel 1 #那么就是在org1创建peer结点并加入通道 ORG=$1 setGlobals $ORG #之后脚本中也是一段延时的指令,这里省略 #接下来就是加入peer结点辣 peer channel join -b $BLOCKFILE >&log.txt4.还有一个设定锚节点的函数定义setAnchorpeer( )
#这个函数也有处理参数 ORG=$1 #接下来进入结点的docker容器内部,这里不是用bash而是直接运行了脚本setAnchorPeer.sh docker exec cli ./scripts/setAnchorPeer.sh $ORG $CHANNEL_NAME #那么上面的那个setAnchorPeer.sh里面根据传入参数不同,设定了不同的host名和端口,即确定了锚节点信息- 那么上面是脚本里的四个函数定义 -- creataChannelGenesisBlock --createChannel --joinChannel --setAnchorpeer()
接下来就调用这些函数,来完成通道的创建.结点的创建加入和锚节点的设定
#创建创世纪块 createChannelGenesisBlock #接下来设定了后面函数里的一些变量位置,比如创世纪块数据的位置BLOCKFILE FABRIC_CFG_PATH=$PWD/../config/ BLOCKFILE="./channel-artifacts/${CHANNEL_NAME}.block" #创建通道 createChannel #为组织org1,org2创建peer结点,加入通道 joinChannel 1 joinChannel 2 #为org1,org2设定锚节点 setAnchorPeer 1 setAnchorPeer 2 -
3.deployCC( )
-
网络和通道都已经启动完毕!那么后面的步骤就是在通道上安装链码并编译app了,那么这就用到后面一步函数 deployCC( )
-
可恶的是,这个函数里面的内容就是运行scripts/ 下的deployCC.sh脚本,当然在运行时会传入很多链码的信息以及通道的信息,这样才能在通道上部署链码,
-
那还有什么好说的,冲这个脚本!让我们vim进去康康
deployCC.sh
因为上面也说了,我们传入了很多参数进去,脚本的开始很长一段就是print 这些变量来检查,并且确认有没有缺少关键信息
根据传入的链码语言信息不同,编译的工具也不同 Ep: java--gradle javascript/typescript---npm
#如果是go if [ "$CC_SRC_LANGUAGE" = "go" ]; then CC_RUNTIME_LANGUAGE=golang infoln "Vendoring Go dependencies at $CC_SRC_PATH" pushd $CC_SRC_PATH GO111MODULE=on go mod vendor popd successln "Finished vendoring Go dependencies"#java elif [ "$CC_SRC_LANGUAGE" = "java" ]; then CC_RUNTIME_LANGUAGE=java infoln "Compiling Java code..." pushd $CC_SRC_PATH ./gradlew installDist popd successln "Finished compiling Java code" CC_SRC_PATH=$CC_SRC_PATH/build/install/$CC_NAME#js elif [ "$CC_SRC_LANGUAGE" = "javascript" ]; then CC_RUNTIME_LANGUAGE=node elif [ "$CC_SRC_LANGUAGE" = "typescript" ]; then CC_RUNTIME_LANGUAGE=node infoln "Compiling TypeScript code into JavaScript..." pushd $CC_SRC_PATH npm install npm run build popd successln "Finished compiling TypeScript code into JavaScript"显而易见,上面的if-elif代码结构并不会全部运行,只会根据你的链码语言参数进行相应的编译,那么脚本中除了上面的编译指令外,还有相当多函数的定义:
packageChaincode()installChaincode()queryInstalled()approveForMyOrg()checkCommitReadiness()commitChaincodeDefinition()queryCommitted()chaincodeInvokeInit()chaincodeQuery()整整九个函数!!!
- packageChaincode()
#主要是一条打包链码的指令 peer lifecycle chaincode package ${CC_NAME}.tar.gz --path ${CC_SRC_PATH} --lang ${CC_RUNTIME_LANGUAGE} --label ${CC_NAME}_${CC_VERSION} >&log.txt-
installChaincode()
#主要是一条安装链码的指令,带参 peer lifecycle chaincode install ${CC_NAME}.tar.gz >&log.txt -
queryInstalled()
#带参 peer lifecycle chaincode queryinstalled >&log.txt -
approveForMyOrg()
#带参 peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --package-id ${PACKAGE_ID} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} >&log.txt -
checkCommitReadiness()
#带参 peer lifecycle chaincode checkcommitreadiness --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} --output json >&log.txt -
commitChaincodeDefinition()
peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" --channelID $CHANNEL_NAME --name ${CC_NAME} "${PEER_CONN_PARMS[@]}" --version ${CC_VERSION} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} >&log.txt -
queryCommitted()
#带参 peer lifecycle chaincode queryinstalled >&log.txt -
chaincodeInvokeInit()
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" -C $CHANNEL_NAME -n ${CC_NAME} "${PEER_CONN_PARMS[@]}" --isInit -c ${fcn_call} >&log.txt -
chaincodeQuery()
#带参 peer chaincode query -C $CHANNEL_NAME -n ${CC_NAME} -c '{"Args":["queryAllCars"]}' >&log.txt
上面是九个函数的定义,不难看出,每个函数都是调用了一条指令(有判断是否超时的部分被我省去了)
函数定义完了,接下来是执行这些函数的指令:
#首先打包链码 packageChaincode #在组织1的peer安装 installChaincode 1 #在组织2的peer安装 installChaincode 2 #检测是否安装成功 queryInstalled 1 #组织1 批准通过 approveForMyOrg 1 #检测链码定义是否通过,这里Org1已经通过了而Org2还没有 checkCommitReadiness 1 "\"Org1MSP\": true" "\"Org2MSP\": false" checkCommitReadiness 2 "\"Org1MSP\": true" "\"Org2MSP\": false" #接下来是组织2的相同步骤 approveForMyOrg 2 #这时两个组织都已经通过,检查一下 checkCommitReadiness 1 "\"Org1MSP\": true" "\"Org2MSP\": true" checkCommitReadiness 2 "\"Org1MSP\": true" "\"Org2MSP\": true" #两个组织都已经同意,提交链码 commitChaincodeDefinition 1 2 #检查org1的提交状态 queryCommitted 1 #检查org2的提交状态 queryCommitted 2 #如果有初始化参数,就执行链码 chaincodeInvokeInit 1 2
-
4.networkDown( )
-
上面的就是使用fabric网络的过程了,那如果关闭网络,有函数network
-
Down( )
-
通过docker-compose删除容器
-
通过docker-compose删除网络产生的证书等文件
关闭网络时直接用脚本down即可
弄明白了网络的启动底层,那么现在来看看如果多机配置需要修改哪些内容呢
docker-compose.yaml
我们通过docker-compose创建3个组织的结点, 那么我们要对这些结点的启动配置文件修改, 使他们连成一个网络
我们创建完orgs的证书文件后,需要拷贝到每台服务器上,保证不同机器上相同组织加密文件仍是一致的
通道文件Channel-artifacts/也同样需要这样拷贝