創(chuàng)建你的第一個Hyperledger Fabric網(wǎng)絡

1. 啟動第一個網(wǎng)絡

首先要下載fabric的示例代碼

$ git clone https://github.com/hyperledger/fabric-samples.git

然后找到目錄first-network牡借,這里我們會用到的一個腳本就是byfn.sh

  1. 首先執(zhí)行如下命令,
$ ./byfn.sh -m generate

這個命令執(zhí)行如下的操作

  • 生成密碼和證書,用于身份認證幻馁;
  • 創(chuàng)建orderer的創(chuàng)世紀區(qū)塊庇配,genesis.block;
  • 創(chuàng)建通道配置交易所需的工件尊残,channel.tx;
  • 創(chuàng)建錨節(jié)點更新工件炒瘸,Org1MSPanchor.tx/Org2MSPanchor.tx;
  1. 然后執(zhí)行命令,
$ ./byfn.sh -m up

這個命令會啟動所有所需的容器寝衫,

  • 一個ordere容器顷扩;
  • 四個peer節(jié)點容器;
  • 一個CLI容器慰毅;
    之后再CLI容器中自動運行腳本隘截,執(zhí)行如下操作
  • 創(chuàng)建通道;
  • 節(jié)點加入到通道;
  • 更新錨節(jié)點婶芭;
  • 安裝和實例化chaincode东臀;
  • 進行查詢和更新操作;

2. 密碼生成器

使用cryptogen工具來生成用于多個網(wǎng)絡實體的密碼材料犀农,這些證書是識別身份的代表惰赋。
通過這些證書可以運行不同的網(wǎng)絡實體之間通信過程中身份認證的登陸/驗證

2.1 這是如何工作的?

cyptogen工具需要有個配置文件:crypto-config.yaml呵哨,這個文件包含網(wǎng)絡拓撲赁濒,基于這個配置文件我們可以生成一個集合的證書和密鑰;這些證書和密鑰既可以用于這些組織孟害,也可以用于屬于這些組織的部件拒炎。

  • 每個組織都準備了一個獨有的根證書(ca-cert),這個根證書把一些特殊的組件(peers和orderers節(jié)點)綁定到了這個組織挨务;通過給每個組織分配一個特有的CA證書枝冀,我們就模擬出了一個典型的網(wǎng)絡,在這個網(wǎng)絡里所有的參與者都要使用他自己獨有的證書鑒權(quán)耘子。
  • Hyperledger Fabric里面所有的交易和通信都被一個實體(entity)的私鑰(keystore)簽名果漾,然后通過公鑰(signcerts)來進行驗證;
  • 你會發(fā)現(xiàn)這個文件里面有一個計數(shù)器變量谷誓。我們用這個來指定每個組織里面的peers節(jié)點的個數(shù)绒障;這個例子里面每個組織(Orgnization)都有兩個peers節(jié)點。
  • 我們這里不會去鉆研x.509證書和公鑰這些基礎設施的細節(jié)捍歪。
    首先來簡單看一下這個yaml文件户辱,尤其注意“Name”,“Domain”和“Specs這些參數(shù)”
OrdererOrgs:
#---------------------------------------------------------
# Orderer
# --------------------------------------------------------
- Name: Orderer
  Domain: example.com
  CA:
    Country: US
    Province: California
    Locality: San Francisco
  # OrganizationalUnit: Hyperledger Fabric
  # StreetAddress: address for org # default nil
  # PostalCode: postalCode for org # default nil
  # ------------------------------------------------------
  # "Specs" - See PeerOrgs below for complete description
  # -----------------------------------------------------
  Specs:
    - Hostname: orderer
# -------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ------------------------------------------------------
PeerOrgs:
# -----------------------------------------------------
# Org1
# ----------------------------------------------------
- Name: Org1
  Domain: org1.example.com

網(wǎng)絡實體(entity)的命名規(guī)則如下 - "{{.Hostname}}.{{.Domain}}"糙臼;這里拿ordering節(jié)點為例庐镐,orderer.example.com這個名字就和Orderer的一個MSP ID關(guān)聯(lián)上了。這個文件還包含了一個擴展文件变逃,描述定義和符號規(guī)則必逆,可以參考成員服務提供者(MSP: Membership Service Provider)文檔來進一步理解MSP
運行完cyptogen工具后,生成的證書和密鑰會被保存到crypto-config文件夾中揽乱。
本文例子中的crypto-config文件夾的目錄結(jié)構(gòu)如下

.
├── ordererOrganizations
│   └── example.com
│       ├── ca
│       ├── msp
│       ├── orderers
│       ├── tlsca
│       └── users
└── peerOrganizations
    ├── org1.example.com
    │   ├── ca
    │   ├── msp
    │   ├── peers
    │   ├── tlsca
    │   └── users
    └── org2.example.com
        ├── ca
 ...
  • 可見名眉,生成了兩個組織:orderer以及peer
  • ca目錄下保存了根證書,有兩個文件凰棉,一個是證書文件损拢,一個密鑰文件
    我們打開證書文件ca.example.com-cert.pem來看看到底生成了什么
-----BEGIN CERTIFICATE-----
MIICLjCCAdWgAwIBAgIQT+87OiMiSvnXF74e2QOp2jAKBggqhkjOPQQDAjBpMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEUMBIGA1UEChMLZXhhbXBsZS5jb20xFzAVBgNVBAMTDmNhLmV4YW1w
bGUuY29tMB4XDTE4MDMyMjEyMTY1NFoXDTI4MDMxOTEyMTY1NFowaTELMAkGA1UE
BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lz
Y28xFDASBgNVBAoTC2V4YW1wbGUuY29tMRcwFQYDVQQDEw5jYS5leGFtcGxlLmNv
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFwgglk7r8kqdR69C+SA0A9EBLhL
QALXpsAnqojj9btYfTCRdXbGu1SmkE88o8Qel8q42vjN8XTQO6dmco3E3XijXzBd
MA4GA1UdDwEB/wQEAwIBpjAPBgNVHSUECDAGBgRVHSUAMA8GA1UdEwEB/wQFMAMB
Af8wKQYDVR0OBCIEIIfdbeaMNg+kkU9Kp89R7jUulqNYoaRtSLkHM/s31MyuMAoG
CCqGSM49BAMCA0cAMEQCIGHPp0S8x/nOcrNHu6SP0muhX884sxAbZnFi+GMzLZes
AiBm/LZOkRZVgw6ud3SUIjnSqUJ4dr9tcw5IOzr4MPdRMQ==
-----END CERTIFICATE-----

再打開密鑰文件看看

-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8DtexDbtkQMUiZ7W
v/IVUvwSfUa2rtYBRymyXyK1X8ihRANCAARcIIJZO6/JKnUevQvkgNAPRAS4S0AC
16bAJ6qI4/W7WH0wkXV2xrtUppBPPKPEHpfKuNr4zfF00DunZnKNxN14
-----END PRIVATE KEY-----

其實看起來就是一串雜亂無章的字符串。

3. 配置交易生成器

configtxgen 工具(Channel configuration)是用來創(chuàng)建四個配置構(gòu)建

  • orderer的創(chuàng)世紀塊(genesis block)
  • channel的配置交易(configuration transaction)
  • 以及兩個錨節(jié)點交易(anchor peer transaction) - 一個Peer組織一個
    orderer區(qū)塊是ordering服務的創(chuàng)世紀區(qū)塊撒犀,并且在channel創(chuàng)建的時候會把channel交易文件廣播到orderer福压。
    顧名思義掏秩,每個錨節(jié)點交易(anchor peer transaction)就指定了每個組織在這個channel上的的錨節(jié)點(anchor peer)

3.1. 配置交易生成器如何工作

Configtxgen會讀取配置文件configtx.yaml,這個配置文件包含了示例網(wǎng)絡的的定義荆姆。這個網(wǎng)絡里面一共有三種成員:

  • 一個Orderer組織(OrdererOrg)哗讥;
  • 兩個Peer組織(Org1和Org2),每個組織管理和維護兩個peer節(jié)點胞枕;
    參看下面這段配置
...
################################################################################
#
#   Section: Organizations
#
#   - This section defines the different organizational identities which will
#   be referenced later in the configuration.
#
################################################################################
Organizations:

    # SampleOrg defines an MSP using the sampleconfig.  It should never be used
    # in production but may be used as a template for other definitions
    - &OrdererOrg
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: OrdererOrg

        # ID to load the MSP definition as
        ID: OrdererMSP

        # MSPDir is the filesystem path which contains the MSP configuration
        MSPDir: crypto-config/ordererOrganizations/example.com/msp

    - &Org1
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: Org1MSP

        # ID to load the MSP definition as
        ID: Org1MSP

        MSPDir: crypto-config/peerOrganizations/org1.example.com/msp

        AnchorPeers:
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context
            - Host: peer0.org1.example.com
              Port: 7051

    - &Org2
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: Org2MSP

        # ID to load the MSP definition as
        ID: Org2MSP

        MSPDir: crypto-config/peerOrganizations/org2.example.com/msp

        AnchorPeers:
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context

...

這個文件同時還定義了一個共同體(consortium) - SampleConsortium,這個共同體包含了我們的兩個Peer組織魏宽;尤其注意這個文件最上面的"Profiles"部分腐泻。你會發(fā)現(xiàn)有兩個特殊的頭:

  • 一個用于orderer的創(chuàng)世紀區(qū)塊 - TwoOrgsOrdererGeneisis;
  • 另一個用于我們的channel - TwoOrgsChannel
    參看如下這段配置
################################################################################
#
#   Profile
...
################################################################################
Profiles:

    TwoOrgsOrdererGenesis:
        Orderer:
            <<: *OrdererDefaults
            Organizations:
                - *OrdererOrg
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *Org1
                    - *Org2
    TwoOrgsChannel:
        Consortium: SampleConsortium
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *Org1
                - *Org2
....

這些頭和重用队询,當我們創(chuàng)建工件(artifacts)的時候會把他們作為參數(shù)傳遞進去派桩;
NOTE: 注意我們的SampleConsortium定義在系統(tǒng)級別的配置文件里,但是被我們的channel級別的配置文件引用蚌斩。channels只存在于一個共同體(consortium)的職權(quán)范圍內(nèi)铆惑,在網(wǎng)絡范圍內(nèi)必須定義所有的聯(lián)盟(consortia)

這個文件還包含了兩個額外的沒有太多價值的定義

  • 第一個是定義了每個Peer Org的錨節(jié)點(peer0.org1.example.com & peer0.org2.example.com );
  • 第二個送膳,我們指向了每個成員的MSP的文件夾路徑员魏,這樣我們就可以把每個org的根證書保存到orderer的創(chuàng)世區(qū)塊中了;這是一個關(guān)鍵原理叠聋,現(xiàn)在任何一個和ordering服務進行通信網(wǎng)絡實體就都可以驗證自己的數(shù)字簽名了撕阎。

4. 運行工具

4.1. 手動生成工件(artifact)

你可以在命令行里手動運行這兩個程序來生成證書和密鑰,以及那些配置工件碌补;或者你也可以試著修改一下byfn.sh腳本來實現(xiàn)你要的目的虏束。
我們這里簡單介紹一下怎么使用,
首先運行一下cryptogen 工具厦章,

../bin/cryptogen generate --config=./crypto-config.yaml

你有可能會看到如下告警镇匀,可以選擇忽略這些告警

[bccsp] GetDefault -> WARN 001 Before using BCCSP, please call InitFactories(). Falling back to bootBCCSP.

接著,我們需要告訴工具configtxgen怎么找到它需要的configx.yaml配置文件袜啃,
第一步汗侵,設置環(huán)境變量,指定配置文件的搜索路徑群发,比如說設置成了當前目錄

export FABRIC_CFG_PATH=$PWD

第二步晃择,運行configtxgen工具,創(chuàng)建orderer創(chuàng)世紀區(qū)塊

../bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block

你可以忽略日志中關(guān)于中間證書也物,證書撤銷列表(crls)和MSP配置的那些告警宫屠,在這個示例網(wǎng)絡里面我們不會使用這些功能。

4.2. 創(chuàng)建通道配置交易

現(xiàn)在滑蚯,我們需要創(chuàng)建一個通道交易工件浪蹂。在這之前確保環(huán)境變量$CHANNEL_NAME已經(jīng)設置好了

export CHANNEL_NAME=mychannel
# this file contains the definitions for our sample channel
../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME

接下來抵栈,我們會在我們構(gòu)造的通道上定義Org1的錨節(jié)點。同樣的我們要保證環(huán)境變量$CHANNEL_NAME已經(jīng)設置好了并且可以被如下的命令使用坤次,

../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP

現(xiàn)在古劲,我就可以在同一個通道上間里Org2的錨節(jié)點

../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP

5. 啟動網(wǎng)絡

我們會使用一個docker-compose腳本來把我們的網(wǎng)絡帶起來,這個docker-compose文件使用了我們之前下載的那些docker鏡像文件缰猴,并且使用我們之前創(chuàng)建的genesis.block來引導啟動了orderer

working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
# command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME}; sleep $TIMEOUT'
volumes

如果第二行不注釋掉产艾,這個腳本會在網(wǎng)絡啟動后執(zhí)行所有的CLI命令,但是我們希望手動的一步一步運行一下這些命令來了解一下這完整的語法和每次調(diào)用的功能
傳進去一個適當?shù)拇笠稽c的TIMEOUT變量值(單位是秒)滑绒;不然的話闷堡,CLI容器默認會在60秒后退出。
啟動你的網(wǎng)絡:

CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=<pick_a_value> docker-compose -f docker-compose-cli.yaml up -d

如果你希望看到你網(wǎng)絡的實時log疑故,那么就不要添加-d標志

5.1. 環(huán)境變量

為了保證后面針對peer0.org1.example.com的CLI命令可以正常工作杠览,我們首先需要設置如下的四個環(huán)境變量。這些用于peer0.org1.example.com的環(huán)境變量都已經(jīng)打包進了CLI容器中了纵势,就不需要額外的去傳遞這些環(huán)境變量了踱阿;但是如果你想要往其他的節(jié)點或者是orderer發(fā)送調(diào)用,你就需要相應的提供這些參數(shù)了钦铁。檢查一下docker-compose-base.yaml文件软舌,

# Environment variables for PEER0
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

5.2. 創(chuàng)建并加入通道

回想一下之前我們創(chuàng)建了通道配置交易,你可以重復這個步驟來創(chuàng)建一個額外的通道配置交易
使用configtx.yaml中相同的或者不同的配置文件并傳遞給configtxgen工具牛曹,這樣你就可以在你的網(wǎng)絡中創(chuàng)建其他的通道葫隙。
首先進入CLI container

docker exec -it cli bash

如果成功了,你會看到如下信息

root@0d78bb69300d:/opt/gopath/src/github.com/hyperledger/fabric/peer#

接下來躏仇,我們要傳遞生成的通道配置交易工件(channel.tx)給orderer作為創(chuàng)建通道請求的一部分恋脚。
我們通過-c標簽指定了我們的通道名字,使用-f標簽指定我們的通道配置交易焰手,在這個例子里面是channel.tx糟描。當然你也可以掛載你自己的配置交易

export CHANNEL_NAME=mychannel
# the channel.tx file is mounted in the channel-artifacts directory within your CLI container
# as a result, we pass the full path for the file
# we also pass the path for the orderer ca-cert in order to verify the TLS handshake
# be sure to replace the $CHANNEL_NAME variable appropriately
peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME 
    -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED 
    --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

Note:注意命令行參數(shù)里面--cafile這個選項,這是orderer的根證書的文件路徑书妻,允許我們來驗證TLS握手船响。
這個命令返回了一個創(chuàng)世紀區(qū)塊-<channel-ID.block>,我們會使用這個區(qū)塊來加入通道中躲履。
Note:手動運行完這些命令以后你還會留在容器中见间,記住,當你要針對除了peer0.org1.example.com以外的其他節(jié)點創(chuàng)建通道工猜,你要預先把所有的環(huán)境變量設置成相應的值
現(xiàn)在我們開始把節(jié)點peer0.org1.example.com加入到通道中

# By default, this joins ``peer0.org1.example.com`` only
# the <channel-ID.block> was returned by the previous command
peer channel join -b <channel-ID.block>

5.3. 安裝和實例化(Instantiate)Chaincode

Note: 我們這里利用一個簡單的chaincode來學習怎么樣編寫自己的chaincode
應用程序通過chaincode來作用于區(qū)塊鏈賬本米诉。我們需要在每個可能執(zhí)行我們交易的節(jié)點上面安裝chaincode,然后在通道上實例化這些chaincode
首先在四個peer節(jié)點上的一個安裝示例程序篷帅,下面的命令把我們的源代碼部署到四個節(jié)點的文件系統(tǒng)中

peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02

Next, instantiate the chaincode on the channel. This will initialize the chaincode on the channel, set the endorsement
接下來史侣,在通道上實例化chaincode拴泌,這一步驟會在通道上初始化chaincode;設置chaincode的背書(endorsement)策略惊橱;為目標節(jié)點啟動chaincode容器蚪腐。注意一下-P選項,這是我們的策略税朴,定義當前這個chaincode在驗證一個交易過程中的背書的級別(回季?)
在如下的命令中,你注意到我們是這么來指定我們的策略的:-P "OR('Org0MSP.member', 'Org1MSP.member')"正林。這就意味著我們需要屬于Org1或者Org2的節(jié)點的背書泡一,如果我們把語法改為AND,這樣我們就需要兩個組織節(jié)點的背書

# 確保你替換了 $CHANNEL_NAME 環(huán)境變量值
# 如果你沒有把你安裝的chaincode的名字定義為mycc卓囚,那么就修改成你定義的那個
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/tlscacerts/tlsca.example.com-cert.pem 
  -C $CHANNEL_NAME -n mycc -v 1.0 
  -c '{"Args":["init","a", "100", "b","200"]}' 
  -P "OR ('Org1MSP.member','Org2MSP.member')"

5.4. 查詢

接下來我們查詢一下a的值,來確保chaincode正常實例化了诅病,并且state DB也部署了哪亿。查詢的語法如下,

#  確保-C 和 -n 標志都設置準確了
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'

5.5. 調(diào)用

Now let’s move 10 from a to b . This transaction will cut a new block and update the state DB. The syntax for invoke
現(xiàn)在我們從a轉(zhuǎn)移10個到b贤笆,這個交易會切割一個新的區(qū)塊蝇棉,并且更新state DB。調(diào)用的語法如下,

# be sure to set the -C and -n flags appropriately
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/tlscacerts/tlsca.example.com-cert.pem 
    -C $CHANNEL_NAME -n mycc 
    -c '{"Args":["invoke","a","b","10"]}'

然后再查詢一下,我們要確認之前的調(diào)用正常執(zhí)行了衡便。

# be sure to set the -C and -n flags appropriately
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'

正常來說我們會得到如下的查詢結(jié)果:

Query Result: 90

5.6. 這些現(xiàn)象背后發(fā)生了些什么?

NOTE: 上述的那些步驟是在script.sh腳本中運行的河狐,cli容器啟動以后會自動調(diào)用這個腳本運行;在你自己一步步執(zhí)行的時候剿干,你需要在docker-compose-cli.yaml文件中把這一行給注銷掉。

  1. 一個腳本 - script.sh
  • 這個腳本被安裝到CLI容器內(nèi)了。這個腳本驅(qū)動了依據(jù)提供的channel名稱來運行createChannel的命令劲弦,同時使用channel.tx文件來進行通道配置;

  • createChannel的輸出是一個genesis區(qū)塊 - <your_channel_name>.block - 這個區(qū)塊會保存到peers節(jié)點的文件系統(tǒng)中并且包含一個channel.tx指定的通道配置醇坝;

  • 對4個peer執(zhí)行joinChannel邑跪,之前一步生成的genesis區(qū)塊做為輸入。這個命令指示這些節(jié)點加入通道<your_channel_name>中呼猪,并且創(chuàng)建一個由<your_channel_name>.block起頭的區(qū)塊鏈画畅;

現(xiàn)在我們就創(chuàng)建了一個通道,包含4個節(jié)點宋距,以及兩個組織轴踱。這就是我們的TwoOrgsChannelprofile

  • 節(jié)點peer0.org1.example.com 和peer1.org1.example.com 屬于Org1;

  • 節(jié)點peer0.org2.example.com 和peer1.org2.example.com 屬于Org2;

  • 這些關(guān)系通過crypto-config.yaml配置文件來定義,MSP的路徑定義在docker compose文件中谚赎;

  • 這個時候會更新Org1MSP(peer0.org1.example.com )和Org2MSP(peer0.org2.example.com ) 的錨節(jié)點寇僧。我們是通過傳遞Org1MSPanchors.tx和Org2MSPanchors.tx工件傳遞給ordering服務摊腋,同時還帶上了我們通道的名字來實現(xiàn)更新的;

  1. 一個chaincode - chaincode_example02安裝到了節(jié)點peer0.org1.example.com和peer0.org2.example.com中了
  • 這個chaincode這個時候就在peer0.org2.example.com上實例化了(instantiated)嘁傀。實例化會把chaincode添加到channel上兴蒸,為每個目標節(jié)點啟動容器,并且初始化和chaincode相關(guān)聯(lián)的密鑰對细办;
    這個例子里面初始化值是 [”a”,”100” “b”,”200”]橙凳。這個實例化的結(jié)局是啟動了一個名叫dev-peer0.org2.example.com-mycc-1.0的容器;
  • 這個實例化還會為背書策略傳遞一個參數(shù)進去笑撞。這個策略定義為-P "OR
    ('Org1MSP.member','Org2MSP.member')"岛啸,意味著任何交易都必須被一個綁定到Org1或者Org2的peer節(jié)點準許(背書,endose)
  • 往節(jié)點peer0.org1.example.com發(fā)起一次針對變量"a"的查詢茴肥。之前有chaincode安裝到了節(jié)點peer0.org1.example.com坚踩,所以這個查詢會為Org1 peer0啟動一個名叫dev-peer0.org1.example.com-mycc-1.0的容器。同時也會返回查詢結(jié)果
  • 發(fā)送一個調(diào)用給peer0.org1.example.com來從“a”轉(zhuǎn)移10到"b"上瓤狐;
  • 這個時候chaincode被安裝到了peer1.org2.example.com上瞬铸;
  • 往節(jié)點peer1.org2.example.com發(fā)起一次針對變量"a"的查詢。這個操作會啟動第三個chaincode容器础锐,名字是dev-peer1.org2.example.com-mycc-1.0嗓节。 返回值是90,正確反映了之前的交易皆警。

5.7. 這個證明了什么拦宣?

Chaincode必須安裝到一個節(jié)點上,以保證可以成功實現(xiàn)對賬本的讀寫信姓。
進一步的鸵隧,一個chaincode容器不會為這個節(jié)點啟動,直到發(fā)生了初始化意推,或者針對這個chaincode執(zhí)行了傳統(tǒng)的交易 - 讀寫(比如說掰派,查詢"a"的值),這個交易會導致容器的啟動左痢。
當然靡羡,通道上的所有peers節(jié)點維護一個額外的賬本拷貝,這個賬本拷貝由區(qū)塊鏈組成俊性;區(qū)塊鏈上保存了不可變更的略步,有序的記錄,以及一個狀態(tài)數(shù)據(jù)庫來維護當前狀態(tài)的snapshot定页。
這也包含那些上面沒有安裝chaincode的節(jié)點(比如說上述例子中的peer1.org1.example.com)趟薄。最終,chaincode在安裝完成后就可以對他進行訪問了(比如說上述例子中的peer1.org2.example.com )典徊,這是因為它已經(jīng)實例化了杭煎。

5.8. 怎么看到這些交易恩够?

可以通過查看CLI容器的logs

docker logs -f cli

你會看到如下的輸出

2017-05-16 17:08:01.366 UTC [msp] GetLocalMSP -> DEBU 004 Returning existing local MSP
2017-05-16 17:08:01.366 UTC [msp] GetDefaultSigningIdentity -> DEBU 005 Obtaining
?→default signing identity
2017-05-16 17:08:01.366 UTC [msp/identity] Sign -> DEBU 006 Sign: plaintext:
?→0AB1070A6708031A0C08F1E3ECC80510...6D7963631A0A0A0571756572790A0161
2017-05-16 17:08:01.367 UTC [msp/identity] Sign -> DEBU 007 Sign: digest:
?→E61DB37F4E8B0D32C9FE10E3936BA9B8CD278FAA1F3320B08712164248285C54
Query Result: 90
2017-05-16 17:08:15.158 UTC [main] main -> INFO 008 Exiting.....
===================== Query on PEER3 on channel 'mychannel' is successful
?→=====================
===================== All GOOD, BYFN execution completed =====================
_____ _ _ ____
| ____| | \ | | | _ \
| _| | \| | | | | |
| |___ | |\ | | |_| |
|_____| |_| \_| |____/

5.9. 怎么查看chaincode的日志

查看每個單獨的chaincode容器來看看針對每個容器分別執(zhí)行的交易,這里是每個容器的輸出的集合

$ docker logs dev-peer0.org2.example.com-mycc-1.0
04:30:45.947 [BCCSP_FACTORY] DEBU : Initialize BCCSP [SW]
ex02 Init
Aval = 100, Bval = 200

$ docker logs dev-peer0.org1.example.com-mycc-1.0
04:31:10.569 [BCCSP_FACTORY] DEBU : Initialize BCCSP [SW]
ex02 Invoke
Query Response:{"Name":"a","Amount":"100"}
ex02 Invoke
Aval = 90, Bval = 210

$ docker logs dev-peer1.org2.example.com-mycc-1.0
04:31:30.420 [BCCSP_FACTORY] DEBU : Initialize BCCSP [SW]
ex02 Invoke
Query Response:{"Name":"a","Amount":"90"}

6. 理解Docker Compose拓撲

BYFN這個例子給我提供了兩個Docker compose文件的風味羡铲,這兩個例子都是從docker-compose-base.yaml文件擴展而來蜂桶。我們的第一種風味,docker-compose-cli.yaml也切,提供給我們CLI容器扑媚,以及一個orderer,四個peers雷恃。
NOTE: 這一部分的描述涉及SDK中docker-compose文件的設計疆股,參考Node SDK部分的描述來理解這些步驟的細節(jié)

第二道風味,docker-compose-e2e.yaml倒槐,可以用于通過Node.js SDK運行一個端到端的測試

拋開SDK的功能不說旬痹,它的主要區(qū)別就是,有一個用于fabric-ca服務的容器

結(jié)果就是我們可以通過發(fā)送一個REST調(diào)用給CAs組織來進行用戶注冊和登記讨越。
如果你想不通過運行byfn.sh腳本來使用docker-compose-e2e.yaml文件两残,那你可能需要做一些小的改動,
我們需要在yaml文件里面指定我們組織的CA's(證書)的密鑰谎痢,這些密鑰保存在crypto-config文件夾中磕昼。
比如說卷雕,Org1的私鑰就保存在這樣的目錄中 - crypto-config/peerOrganizations/org1.example.com/ca/节猿。私鑰是一個以_sk為后綴的很長的哈希值。Org2的路徑是 - crypto-config/peerOrganizations/org2.example.com/ca/漫雕;
在docker-compose-e2e.yaml文件中滨嘱,需要為ca0和ca1更新一下FABRIC_CA_SERVER_TLS_KEYFILE變量的值。在啟動ca服務的時候你還需要修改命令行參數(shù)中的路徑浸间,你要為每個CA容器提供兩次私鑰太雨。

7 使用CouchDB

狀態(tài)數(shù)據(jù)庫可以從默認的goleveldb切換成CouchDB。同樣的chaincode也可以和CoubhDB一起工作魁蒜,當然囊扳,用了CouchDB之后,我們就可能執(zhí)行更加豐富和復雜的查詢DB操作了兜看;這些查詢可以通過JSON的格式來進行
使用CouchDB需要在之前描述的生成工件的步驟基礎上做一些修改锥咸,在啟動網(wǎng)絡的時候把yaml文件替換成docker-compose-couch.yaml

CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=<pick_a_value> docker-compose -f docker-compose-cli.yaml -f docker-compose-couch.yaml up -d

下面chaincode_example02就可以和CouchDB一起工作了。
NOTE:如果你這里選擇把fabric-couchdb容器的端口映射到主機端口上细移,請確保你意識到了這里可能有安全隱患搏予。在開發(fā)環(huán)境中做這樣的映射使得CouchDB的REST接口可用了,但是同時CouchDB的數(shù)據(jù)口內(nèi)容也通過web接口Fauxton變得可視了弧轧。生產(chǎn)環(huán)境中要注意限制外部環(huán)境的CouchDB容器的訪問雪侥。
如果你想要使用CouchDB的查詢能力碗殷,這個時候就需要使用數(shù)據(jù)建模成JSON格式的chaincode了,比如說marbles02.
首先還是創(chuàng)建通道速缨,并把節(jié)點加進通道中去锌妻。

  • 在節(jié)點peer0.org1.example.com上安裝和實例化chaincode
# be sure to modify the $CHANNEL_NAME variable accordingly for the instantiate command
peer chaincode install -n marbles -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/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME 
  -n marbles -v 1.0 -c '{"Args":["init"]}' -P "OR ('Org0MSP.member','Org1MSP.member')"
  • 制造一些marbles,然后使用
# be sure to modify the $CHANNEL_NAME variable accordingly
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/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 $CORE_PEER_TLS_ENABLED 
  --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 $CORE_PEER_TLS_ENABLED 
  --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 $CORE_PEER_TLS_ENABLED 
  --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 $CORE_PEER_TLS_ENABLED 
  --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 $CORE_PEER_TLS_ENABLED 
  --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"]}'

? If you chose to map the CouchDB ports in docker-compose, you can now view the state database through the

  • 如果你選擇在docker-compose中映射CouchDB端口鸟廓,你現(xiàn)在就可以通過web接口查看CouchDB的數(shù)據(jù)庫內(nèi)容了从祝。用瀏覽器打開http://localhost:5984/_utils
    你可以看到一個名叫mychannel的數(shù)據(jù)庫引谜,里面有一些文件牍陌,
    Note: For the below commands, be sure to update the $CHANNEL_NAME variable appropriately.
    You can run regular queries from the CLI (e.g. reading marble2 ):
    NOTE: 對于下面的這些命令,請確保你以及相應的更新了$CHANNEL_NAME變量员咽。
    你可以通過CLI來進行一些常規(guī)查詢毒涧,比如說讀取marble2:
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["readMarble","marble2"]}'

輸出結(jié)果會顯示marble2的一些細節(jié),

Query Result: {"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50}

You can retrieve the history of a specific marble - e.g. marble1 :
你可以獲取一個特定marble的歷史 - 比如說marble1:

peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["getHistoryForMarble","marble1"]}'

結(jié)果會顯示marble1的歷史交易記錄贝室,

Query Result: [
  { "TxId":"1c3d3caf124c89f91a4c0f353723ac736c58155325f02890adebaa15e16e6464", 
    "Value":{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}},
  { "TxId":"755d55c281889eaeebf405586f9e25d71d36eb3d35420af833a20a2f53a3eefd", 
    "Value":{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"jerry"}},
  { "TxId":"819451032d813dde6247f85e56a89262555e04f14788ee33e28b232eef36d98f", 
    "Value":}
]

You can also perform rich queries on the data content, such as querying marble fields by owner jerry :
你也可以對數(shù)據(jù)內(nèi)容進行富查詢契讲,比如說查詢jerry這個擁有者的marble,

peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesByOwner","jerry"]}'

輸出顯示jerry擁有的兩個marbles滑频,

Query Result: [
  { "Key":"marble2", "Record":{"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50}}, 
  { "Key":"marble3", "Record":{"color":"blue","docType":"marble","name":"marble3","owner":"jerry","size":70}}
]

7.1. 為什么用CouchDB

CouchDB采用的是NoSQL的解決方案捡偏,是一種面向文檔的數(shù)據(jù)庫,文檔的內(nèi)容都以鍵值對的方式保存在數(shù)據(jù)庫中峡迷;可以實簡單的鍵值對银伟,列表,或者映射表绘搞。
除了LevelDB支持的這些鍵值查詢之外彤避,CouchDB還支持完整數(shù)據(jù)的富查詢能力,比如說針對整個區(qū)塊鏈數(shù)據(jù)的非鍵值查詢夯辖,這些數(shù)據(jù)內(nèi)容以JSON格式存儲琉预。
CouchDB還可以增強區(qū)塊鏈上數(shù)據(jù)保護的安全性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蒿褂,一起剝皮案震驚了整個濱河市圆米,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌啄栓,老刑警劉巖娄帖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異谴供,居然都是意外死亡块茁,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來数焊,“玉大人永淌,你說我怎么就攤上這事∨宥” “怎么了遂蛀?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長干厚。 經(jīng)常有香客問我李滴,道長,這世上最難降的妖魔是什么蛮瞄? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任所坯,我火速辦了婚禮,結(jié)果婚禮上挂捅,老公的妹妹穿的比我還像新娘芹助。我一直安慰自己,他們只是感情好闲先,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布状土。 她就那樣靜靜地躺著,像睡著了一般伺糠。 火紅的嫁衣襯著肌膚如雪蒙谓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天训桶,我揣著相機與錄音累驮,去河邊找鬼。 笑死渊迁,一個胖子當著我的面吹牛慰照,可吹牛的內(nèi)容都是我干的灶挟。 我是一名探鬼主播琉朽,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼稚铣!你這毒婦竟也來了箱叁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤惕医,失蹤者是張志新(化名)和其女友劉穎耕漱,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抬伺,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡螟够,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妓笙。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡若河,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出寞宫,到底是詐尸還是另有隱情萧福,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布辈赋,位于F島的核電站鲫忍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏钥屈。R本人自食惡果不足惜悟民,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望篷就。 院中可真熱鬧逾雄,春花似錦、人聲如沸腻脏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽永品。三九已至做鹰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鼎姐,已是汗流浹背钾麸。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留炕桨,地道東北人饭尝。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像献宫,于是被迫代替她去往敵國和親钥平。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容