回顧一下我以前的一篇博客,在Fabric 1.0中,咱們存在3種類型的數據存儲,一種是基於文件系統的區塊鏈數據,這個跟比特幣很像,比特幣也是文件形式存儲的。Fabric1.0中的區塊鏈存儲了Transaction訂單讀寫集。而讀寫集究竟是讀什麼?寫什麼?其實就是咱們的State Database,也叫作World State,裏面以鍵值對的方式存儲了咱們在ChainCode中操做的業務數據。另外還有就是對歷史數據和區塊鏈索引的數據庫。html
區塊鏈是文件系統,這個目前不支持更改,歷史數據和區塊鏈的索引是LevelDB,這個也不能更改。而對於State Database,因爲和業務相關,因此提供了替換數據庫,目前支持默認的LevelDB和用戶可選擇的CouchDB。這裏要說到2點,一個是在0.6的時候其實用的RockDB,可是因爲License的考慮,因此在1.0改爲了LevelDB。另外就是CouchDB也不必定是最優的,不少人還考慮到MongoDB或者MySQL等,可是因爲如今Fabric那邊開發資源有限,因此在1.0還不會作,之後可能會實現。git
下面咱們來講一說這個CouchDB。github
CouchDB是一個徹底局域RESTful API的鍵值數據庫,也就是說咱們不須要任何客戶端,只須要經過HTTP請求就能夠操做數據庫了。LevelDB是Peer的本地數據庫,那麼確定是和Peer一對一的關係,那麼CouchDB是個網絡數據庫,應該和Peer是什麼樣一個關係呢?在生產環境中,咱們會爲每一個組織部署節點,並且爲了高可用,可能會在一個組織中部署多個Peer。一樣咱們在一個組織中也部署多個CouchDB,每一個Peer對應一個CouchDB。docker
HyperLedger在Docker Hub上也發佈了CouchDB的鏡像,爲了可以深刻研究CouchDB和Fabric的集成,咱們就採用官方發佈的CouchDB來作。數據庫
docker pull klaemo/couchdb
【注意,若是咱們是docker pull couchdb,那麼只能得到1.6版本的CouchDB,而要得到最新的2.0版,就須要用上面這個鏡像。】瀏覽器
能夠得到官方的CouchDB鏡像。CouchDB在啓動的時候須要指定一個本地文件夾映射成CouchDB的數據存儲文件夾,因此咱們能夠在當前用戶的目錄下建立一個文件夾用於存放數據。網絡
mkdir couchdb
下載完成後,咱們只須要執行如下命令便可啓用一個CouchDB的實例:app
docker run -p 5984:5984 -d --name my-couchdb -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v ~/couchdb:/opt/couchdb/data klaemo/couchdb
啓動後咱們打開瀏覽器,訪問Linux的IP的5984端口的URL,好比個人Linux是192.168.100.129,那麼URL是:
http://192.168.100.129:5984/_utils
這個時候咱們就能夠看到CouchDB的Web管理界面了。輸入用戶名admin密碼password便可進入。
如今是一個空數據庫,咱們將CouchDB和Peer結合起來後再看會是什麼樣的效果。
先刪除剛纔建立的CouchDB容器:
docker rm -f my-couchdb
首先咱們是4個Peer+1Orderer的模式,因此咱們先建立4個CouchDB數據庫:
cd ~ mkdir couchdb0 mkdir couchdb1 mkdir couchdb2 mkdir couchdb3 docker run -p 5984:5984 -d --name couchdb0 -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v ~/couchdb0:/opt/couchdb/data klaemo/couchdb docker run -p 6984:5984 -d --name couchdb1 -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v ~/couchdb1:/opt/couchdb/data klaemo/couchdb docker run -p 7984:5984 -d --name couchdb2 -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v ~/couchdb2:/opt/couchdb/data klaemo/couchdb docker run -p 8984:5984 -d --name couchdb3 -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v ~/couchdb3:/opt/couchdb/data klaemo/couchdb
而後咱們須要啓動Fabric了。Fabric的準備環境,能夠參見咱們這篇博客:http://www.cnblogs.com/studyzy/p/6973334.htmlcurl
官方已經提供了多個Docker-compose文件,若是咱們使用的是./network_setup.sh up命令,那麼啓用的就是docker-compose-cli.yaml這個文件。若是要基於這個yaml文件啓用CouchDB的Peer,則打開該文件,並編輯其中的Peer節點,改成以下的形式:區塊鏈
peer0.org1.example.com:
container_name: peer0.org1.example.com
environment:
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=192.168.100.129:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=password
extends:
file: base/docker-compose-base.yaml
service: peer0.org1.example.com
這裏的192.168.100.129:5984是我映射CouchDB後的Linux的IP地址和IP。而後是設置用戶名和密碼。把4個Peer的配置都改好後,保存,咱們試着啓用Fabric:
./network_setup.sh up
等Fabric啓動完成並運行了ChainCode測試後,咱們刷新http://192.168.100.129:5984/_utils ,能夠看到以Channel名字建立的Database,另外還有幾個是系統數據庫。
點進mychannel數據庫,咱們能夠看到其中的數據內容。點擊「Mango Query」能夠編寫查詢,默認提供的查詢能夠點擊Run Query按鈕查詢全部的數據結果:
接下來咱們使用Linux的curl來查詢CouchDB數據庫。
好比咱們要看看mychannel數據庫下有哪些數據:
curl http://192.168.100.129:5984/mychannel/_all_docs
能夠看到我運行了一些ChainCode後的State DATABASE結果:
{"total_rows":7,"offset":0,"rows":[
{"id":"devincc\u0000a","key":"devincc\u0000a","value":{"rev":"2-a979bf6c2716ecae6d106999f833a59c"}},
{"id":"devincc\u0000b","key":"devincc\u0000b","value":{"rev":"2-ad1c549305fd277097180405f96bdcd8"}},
{"id":"lscc\u0000devincc","key":"lscc\u0000devincc","value":{"rev":"1-05d2cd0b344c4dd8a8d1a3ffd7332544"}},
{"id":"lscc\u0000mycc","key":"lscc\u0000mycc","value":{"rev":"1-2cba0344b1610b9d9254bbafbda5e9b1"}},
{"id":"mycc\u0000a","key":"mycc\u0000a","value":{"rev":"2-588a45b289359afa9dc6e5e7866eaf97"}},
{"id":"mycc\u0000b","key":"mycc\u0000b","value":{"rev":"2-54e6639a858b0f91298c9a354484513a"}},
{"id":"statedb_savepoint","key":"statedb_savepoint","value":{"rev":"10-6ccde2a55c71d7d6a70d9333d119fc8e"}}
]}
若是咱們要查詢其中的一條數據,只須要用/ChannelId/id來查詢,好比查詢:statedb_savepoint
curl http://192.168.100.129:5984/mychannel/statedb_savepoint
返回的結果:
{"_id":"statedb_savepoint","_rev":"10-6ccde2a55c71d7d6a70d9333d119fc8e","BlockNum":4,"TxNum":0,"UpdateSeq":"19-g1AAAAEzeJzLYWBg4MhgTmHgzcvPy09JdcjLz8gvLskBCjMlMiTJ____PyuRAYeCJAUgmWQPVsOCS40DSE08WA0jLjUJIDX1eO3KYwGSDA1ACqhsPiF1CyDq9mclsuJVdwCi7j4h8x5A1AHdx5kFAI6sYwk"}
麻煩的是業務數據是「ChainCodeName\u0000數據」這樣的格式的ID,而若是咱們要經過這個ID查詢,那麼就根本找不到啊!
curl http://192.168.100.129:5984/mychannel/mycc\u0000a
{"error":"not_found","reason":"missing"}
正確的作法是把\u0000替換爲%00,也就是說咱們的查詢應該是:
curl http://192.168.100.129:5984/mychannel/mycc%00a
正確返回結果:
{"_id":"mycc\u0000a","_rev":"2-588a45b289359afa9dc6e5e7866eaf97","chaincodeid":"mycc","version":"4:0","_attachments":{"valueBytes":{"content_type":"application/octet-stream","revpos":2,"digest":"md5-hhOYXsSeuPdXrmQ56Hm7Kg==","length":2,"stub":true}}}
雖然區塊鏈是一個只能插入和查詢的數據庫,可是咱們的業務數據是存放在State Database中的,若是咱們直接修改了CouchDB的數據,那麼接下來的查詢和事務是直接基於修改後的CouchDB的,並不會去檢查區塊鏈中的記錄,因此理論上是能夠經過直接改CouchDB來實現業務數據的修改。
咱們以官方的Marble爲例,看看修改CouchDB會怎麼樣?
具體操做步驟以下:
1.Install,instantiate和初始化數據:
peer chaincode install -n marbles02 -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/marbles02 peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --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 mychannel -n marbles02 -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/marbles02 -c '{"Args":["init"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --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 mychannel -n marbles02 -c '{"Args":["initMarble","marble2","red","50","tom"]}' peer chaincode query -C mychannel -n marbles02 -c '{"Args":["readMarble","marble2"]}'
咱們能夠看到經過curl直接查詢CouchDB中的數據:
curl http://192.168.100.129:5984/mychannel/marbles02%00marble2
{"_id":"marbles02\u0000marble2","_rev":"1-a1844f47b9ed94294b430c9a9a6f543b","chaincodeid":"marbles02","data":{"docType":"marble","name":"marble2","color":"red","size":50,"owner":"tom"},"version":"6:0"}
若是咱們要修改其中的數據,把顏色改爲green,大小改爲10,那麼咱們能夠運行:
curl -X PUT http://192.168.100.129:5984/mychannel/marbles02%00marble2 -d '{"_id":"marbles02\u0000marble2","_rev":"1-a1844f47b9ed94294b430c9a9a6f543b","chaincodeid":"marbles02","data":{"docType":"marble","name":"marble2","color":"green","size":10,"owner":"tom"},"version":"6:0"}'
系統返回結果:
{"ok":true,"id":"marbles02\u0000marble2","rev":"2-6ffc6652cfc707f8352a5f06c3ce1ce6"}
咱們在4個CouchDB中都運行這個命令,把4個數據庫的數據都改了。
接下來咱們經過ChainCode來查詢,看看會怎麼樣。
peer chaincode query -C mychannel -n marbles02 -c '{"Args":["readMarble","marble2"]}'
返回結果:
Query Result: {"color":"green","docType":"marble","name":"marble2","owner":"tom","size":10}
能夠看到數據已經變成新的值,那麼接下來運行其餘的Transaction會怎麼樣?咱們試一試轉帳操做:
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --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 mychannel -n marbles02 -c '{"Args":["transferMarble","marble2","jerry"]}'
系統返回成功,咱們再查一下呢
peer chaincode query -C mychannel -n marbles02 -c '{"Args":["readMarble","marble2"]}'
Query Result: {"color":"green","docType":"marble","name":"marble2","owner":"jerry","size":10}
因此咱們對CouchDB數據庫的更改都是有效的,在Fabric看來彷佛並不知道咱們改了CouchDB的內容。