Fabric默认使用LevelDB,在对链码数据建模为JSON之后,CouchDB具有针对状态数据库数据内容执行丰富和复杂查询的附加功能。
1. 关闭已经启动的fabric网络
2. 生成启动first-network步骤生成网络启动所需要材料 1 2 3 4 5 6 cryptogen generate --config=./crypto-config.yaml export FABRIC_CFG_PATH=$PWD configtxgen -profile TwoOrgsOrdererGenesis -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block export CHANNEL_NAME=mychannel && configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME 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
3.启动CouchDB 1 docker-compose -f docker-compose-cli.yaml -f docker-compose-couch.yaml up -d
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 [root@localhost first-network]# docker-compose -f docker-compose-cli.yaml -f docker-compose-couch.yaml up -d Creating network "net_byfn" with the default driver Creating volume "net_peer0.org2.example.com" with default driver Creating volume "net_peer1.org2.example.com" with default driver Creating volume "net_peer1.org1.example.com" with default driver Creating volume "net_peer0.org1.example.com" with default driver Creating volume "net_orderer.example.com" with default driver Creating couchdb3 ... done Creating orderer.example.com ... done Creating couchdb1 ... done Creating couchdb0 ... done Creating couchdb2 ... done Creating peer1.org2.example.com ... done Creating peer0.org1.example.com ... done Creating peer0.org2.example.com ... done Creating peer1.org1.example.com ... done Creating cli ... done [root@localhost first-network]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0b819576bb29 hyperledger/fabric-tools:latest "/bin/bash" About a minute ago Up About a minute cli 924a616c7885 hyperledger/fabric-peer:latest "peer node start" About a minute ago Up About a minute 0.0.0.0:8051->8051/tcp peer1.org1.example.com e0d8ddd1cbdc hyperledger/fabric-peer:latest "peer node start" About a minute ago Up About a minute 0.0.0.0:9051->9051/tcp peer0.org2.example.com 7d48491351e0 hyperledger/fabric-peer:latest "peer node start" About a minute ago Up About a minute 0.0.0.0:7051->7051/tcp peer0.org1.example.com 14f48756e507 hyperledger/fabric-peer:latest "peer node start" About a minute ago Up About a minute 0.0.0.0:10051->10051/tcp peer1.org2.example.com 9cce36571279 hyperledger/fabric-couchdb "tini -- /docker-ent…" About a minute ago Up About a minute 4369/tcp, 9100/tcp, 0.0.0.0:6984->5984/tcp couchdb1 42761a41bb38 hyperledger/fabric-couchdb "tini -- /docker-ent…" About a minute ago Up About a minute 4369/tcp, 9100/tcp, 0.0.0.0:7984->5984/tcp couchdb2 1d6db23645d0 hyperledger/fabric-couchdb "tini -- /docker-ent…" About a minute ago Up About a minute 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb0 8b2facd544eb hyperledger/fabric-orderer:latest "orderer" About a minute ago Up About a minute 0.0.0.0:7050->7050/tcp orderer.example.com a2cdad7d30ab hyperledger/fabric-couchdb "tini -- /docker-ent…" About a minute ago Up About a minute 4369/tcp, 9100/tcp, 0.0.0.0:8984->5984/tcp couchdb3
注:因为不是在生产环境,所以对couchDB容器做了到主机端口的映射,使得开发环境中可以直接使用CouchDB的REST API,可通过CouchDB的WEB界面可视化数据库。生产环境需要避免端口映射,限制外部对CouchDB容器的访问。
4. 创建加入通道并更新锚节点 1 2 3 4 5 docker exec -it cli bash export CHANNEL_NAME=mychannel 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 peer channel join -b mychannel.block 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
1 2 3 4 5 6 CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt peer channel join -b mychannel.block peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.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
5.链码安装与实例化 1 2 peer chaincode install -n marbles -v 1.0 -p github.com/chaincode/marbles02/go 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 marbles -v 1.0 -c '{"Args":["init"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')"
6.链码调用 1 2 3 4 5 6 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 marbles -c '{"Args":["initMarble","marble1","blue","35","tom"]}' 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 marbles -c '{"Args":["initMarble","marble2","red","50","tom"]}' 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 marbles -c '{"Args":["initMarble","marble3","blue","70","tom"]}' 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 marbles -c '{"Args":["transferMarble","marble2","jerry"]}' 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 marbles -c '{"Args":["transferMarblesBasedOnColor","blue","jerry"]}' 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 marbles -c '{"Args":["delete","marble1"]}'
1 2 3 4 5 6 2019-10-21 06:39:47.840 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 2019-10-21 06:39:47.892 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 2019-10-21 06:39:47.945 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 2019-10-21 06:39:48.002 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 2019-10-21 06:39:48.050 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 payload:"Transferred 0 blue marbles to jerry" 2019-10-21 06:41:05.065 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
因为CouchDB容器与主机做了端口映射,所以可以通过CouchDB Web接口来可视化状态数据库 通过访问 http://localhost:5984/_utils
,可以看到下图界面:
7.链码查询 1 peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["readMarble","marble2"]}'
1 {"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50}
历史查询
1 peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["getHistoryForMarble","marble1"]}'
1 2 [{"TxId":"f94ca6cf8d184cb999c589eaa2c69ee8d73e76eba9c9e617f81076eec4c386d9", "Value":{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}, "Timestamp":"2019-10-21 06:39:47.834102301 +0000 UTC", "IsDelete":"false"}, {"TxId":"0a8d6d9aaf3d2cb4088d92d6269572a8aca0134efc295c776f8be56b8bd1ef5f", "Value":null, "Timestamp":"2019-10-21 06:41:05.059717786 +0000 UTC", "IsDelete":"true"}]
根据数据内容查询
1 peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesByOwner","jerry"]}'
附1:为什么要使用CouchDB CouchDB是一种NoSQL解决方案。是一个面向文件的数据库,其中文件字段存储为键值映射。 字段可以是简单的键值对,列表或映射。 除了LevelDB支持的键/复合键/键范围查询外,CouchDB还支持丰富的全数据查询功能,例如针对整个区块链数据的非键查询,因为其数据内容以JSON格式存储,并且完全可查询。 因此,CouchDB在许多使用场景中可以满足LevelDB不支持的链码、审计和报告要求。
另外,CouchDB属于CAP定理的AP类型(可用性和分区容差)。 它使用具有最终一致性的主-主复制模型。 但是,在每个peer节点下,没有数据库副本,数据库的写入是一致且持久的(不是最终一致性)。
CouchDB是第一个用于Fabric的外部可插入状态数据库,并且可能并且应该有其他外部数据库选项。 例如,IBM为其区块链启用关系数据库。 并且可能还需要CP类型(一致性和分区容差)数据库,以便在不保证应用程序级别的情况下实现数据一致性。
附2:关于数据持久性 如果要在peer容器或者CouchDB容器上保持数据持久性,可以选择将主机中目录挂在到容器的相关目录中。如:在 docker-compose-cli.yaml 文件的peer容器说明中添加:
1 2 volumes: - /var/hyperledger/peer0:/var/hyperledger/production
对于CouchDB容器,添加以下两行在CouchDB容器说明中:
1 2 volumes: - /var/hyperledger/couchdb0:/opt/couchdb/data