帶你玩轉區塊鏈--基於Fabric實現一個聯盟鏈-第三章-第一節【Fabric篇】

一、意義:

             在本節內容開始之前,我先跟讀者朋友們一起分享一下公鏈、聯盟鏈、私有鏈的優劣勢。

1、公有鏈

任何節點都是向任何人開放的,每個人都可以參與到這個區塊鏈中進行計算,而且任何人都可以下載獲得完整區塊鏈數據(全部賬本)。比特幣就是最典型的公有鏈。

優點:公有鏈最大的優點就是去中心化和安全性。目前像一般比較出名的數字貨幣:比特幣、以太幣、瑞波幣等都是使用公有鏈來運行的。由此可見,這些數字貨幣安全性很高,同時也不受到誰的控制。
缺點:儘管公有鏈很好很安全,但是設想一下,這麼多隨意出入的節點是很難達成共識的(上一篇文章提到的共識)因爲有些節點可能隨時宕機,黑客也可能僞造很多虛假的節點。所以,公有鏈有一套很嚴格的共識機制,因此公有鏈最大的問題就是共識問題,共識問題直接導致了公有鏈處理數據的速度問題,因此如果你玩比特幣就知道了,轉賬要很久才能到。

2、私有鏈

有些區塊鏈的應用場景下,並不希望這個系統任何人都可以參與,任何人都可以查看所有數據,只有被許可的節點纔可以參與並且查看所有數據,這種區塊鏈結構我們稱爲私有鏈。

優點:私有鏈可以完全自己定製策略,因此速度極快
缺點:相比較而言,私有鏈不具備去中心化

3、聯盟鏈

聯盟鏈是指有若干機構或組織共同參與管理的區塊鏈,他們各自運行着一個或多個節點,之中的數據只允許系統內不同的機構進行讀取和發送交易,並且共同記錄交易數據。R3組成的銀行區塊鏈聯盟要構建的就是典型的聯盟鏈。

優點:聯盟鏈優點就是比公有鏈處理速度要快,因爲節點的數量和身份都已經規定好了,所以可以使用相對鬆散的共識機制,因此數據的處理速度就會比公有鏈大大提高。目前,聯盟鏈的發展速度很驚人。
缺點:儘管聯盟鏈速度加快,但是相比公有鏈來說,聯盟鏈並不是完全去中心化的。因爲理論上聯盟之間可以聯合起來修改區塊鏈數據。發幣無意義。

從上述描述中,我們瞭解到了一點聯盟鏈的優劣勢。拋開這些爭論,秉承存在即合理的原則。我們深入研究一下聯盟鏈。目前聯盟鏈大多數都是基於Hyper Ledger fabric來實現的。下面我們來認識一下Hyper Ledger fabric的概念。

二、HyperLedger fabric:

Hyperledger Fabric是Linux基金會所主導的Hyperledger(超級賬本)的項目之一。Hyperledger Fabric旨在作爲開發模塊化體系結構的區塊鏈應用程序的基礎,以便諸如共識和會員服務等組件可以即插即用。它使用容器技術來託管構成系統應用邏輯的智能合約(也稱爲鏈代碼)。 簡而言之,Hyperledger Fabric就是開發聯盟鏈應用的最好工具之一。

腳本安裝Fabric(略)

由於fabric安裝比較複雜,所以我單獨寫了一個文檔。安裝文檔我將放入github中,待文章寫畢,將安裝文檔上傳github。

github鏈接:https://github.com/lsy-zhaoshuaiji/faricInstall

手動組件Fabric網絡

1.生成模板,

cryptogen showtemplate > crypto-config.yaml

2.修改模板後生成

模板如下,請按照自己的需求修改

# ---------------------------------------------------------------------------
  # "OrdererOrgs" - Definition of organizations managing orderer nodes
  # ---------------------------------------------------------------------------
  OrdererOrgs:	# 排序節點組織信息
    # ---------------------------------------------------------------------------
    # Orderer
    # ---------------------------------------------------------------------------
    - Name: Orderer	# 排序節點組織的名字
      Domain: example.com	# 根域名, 排序節點組織的根域名
      Specs:
        - Hostname: orderer # 訪問這臺orderer對應的域名爲: orderer.example.com
        - Hostname: order2 # 訪問這臺orderer對應的域名爲: order2.example.com
  # ---------------------------------------------------------------------------
  # "PeerOrgs" - Definition of organizations managing peer nodes
  # ---------------------------------------------------------------------------
  PeerOrgs:
    # ---------------------------------------------------------------------------
    # Org1
    # ---------------------------------------------------------------------------
    - Name: Org1	# 第一個組織的名字, 自己指定
      Domain: org1.example.com	# 訪問第一個組織用到的根域名
      EnableNodeOUs: true			# 是否支持node.js
      Template:					# 模板, 根據默認的規則生成2個peer存儲數據的節點
        Count: 2 # 1. peer0.org1.example.com 2. peer1.org1.example.com
      Users:	   # 創建的普通用戶的個數
        Count: 3
        
    # ---------------------------------------------------------------------------
    # Org2: See "Org1" for full specification
    # ---------------------------------------------------------------------------
    - Name: Org2
      Domain: org2.example.com
      EnableNodeOUs: true
      Template:
        Count: 2
      Specs:
        - Hostname: hello
      Users:
        Count: 1

 修改後爲:

# ---------------------------------------------------------------------------
  # "OrdererOrgs" - Definition of organizations managing orderer nodes
  # ---------------------------------------------------------------------------
  OrdererOrgs:
    # ---------------------------------------------------------------------------
    # Orderer
    # ---------------------------------------------------------------------------
    - Name: Orderer
      Domain: itcast.com
      Specs:
        - Hostname: orderer
  
  # ---------------------------------------------------------------------------
  # "PeerOrgs" - Definition of organizations managing peer nodes
  # ---------------------------------------------------------------------------
  PeerOrgs:
    # ---------------------------------------------------------------------------
    # Org1
    # ---------------------------------------------------------------------------
    - Name: OrgGo
      Domain: orggo.itcast.com
      EnableNodeOUs: true
      Template:
        Count: 2
      Users:
        Count: 3
  
    # ---------------------------------------------------------------------------
    # Org2: See "Org1" for full specification
    # ---------------------------------------------------------------------------
    - Name: OrgCpp
      Domain: orgcpp.itcast.com
      EnableNodeOUs: true
      Template:
        Count: 2
      Users:
        Count: 3

運行

cryptogen generate --config=crypto-config.yaml

3.創始塊文件和通道文件的生成(複製時請保存在txt文件中,再修改文件名,不然會亂碼)

命令介紹:

$ configtxgen --help 
  # 輸出創始塊區塊文件的路徑和名字
  `-outputBlock string`
  # 指定創建的channel的名字, 如果沒指定系統會提供一個默認的名字.
  `-channelID string`
  # 表示輸通道文件路徑和名字
  `-outputCreateChannelTx string`
  # 指定配置文件中的節點
  `-profile string`
  # 更新channel的配置信息
  `-outputAnchorPeersUpdate string`
  # 指定所屬的組織名稱
  `-asOrg string`
  # 要想執行這個命令, 需要一個配置文件 configtx.yaml
```

配置文件模板:

```yaml
  
  ---
  ################################################################################
  #
  #   Section: Organizations
  #
  #   - This section defines the different organizational identities which will
  #   be referenced later in the configuration.
  #
  ################################################################################
  Organizations:			# 固定的不能改
      - &OrdererOrg		# 排序節點組織, 自己起個名字
          Name: OrdererOrg	# 排序節點的組織名
          ID: OrdererMSP		# 排序節點組織的ID
          MSPDir: crypto-config/ordererOrganizations/example.com/msp # 組織的msp賬號信息
  
      - &Org1			# 第一個組織, 名字自己起
          Name: Org1MSP # 第一個組織的名字
          ID: Org1MSP		# 第一個組織的ID
          MSPDir: crypto-config/peerOrganizations/org1.example.com/msp
          AnchorPeers: # 錨節點
              - Host: peer0.org1.example.com  # 指定一個peer節點的域名
                Port: 7051					# 端口不要改
  
      - &Org2
          Name: Org2MSP
          ID: Org2MSP
          MSPDir: crypto-config/peerOrganizations/org2.example.com/msp
          AnchorPeers:
              - Host: peer0.org2.example.com
                Port: 7051
  
  ################################################################################
  #
  #   SECTION: Capabilities, 在fabric1.1之前沒有, 設置的時候全部設置爲true
  #   
  ################################################################################
  Capabilities:
      Global: &ChannelCapabilities
          V1_1: true
      Orderer: &OrdererCapabilities
          V1_1: true
      Application: &ApplicationCapabilities
          V1_2: true
  
  ################################################################################
  #
  #   SECTION: Application
  #
  ################################################################################
  Application: &ApplicationDefaults
      Organizations:
  
  ################################################################################
  #
  #   SECTION: Orderer
  #
  ################################################################################
  Orderer: &OrdererDefaults
      # Available types are "solo" and "kafka"
      # 共識機制 == 排序算法
      OrdererType: solo	# 排序方式
      Addresses:			# orderer節點的地址
          - orderer.example.com:7050	# 端口不要改
  
  	# BatchTimeout,MaxMessageCount,AbsoluteMaxBytes只要一個滿足, 區塊就會產生
      BatchTimeout: 2s	# 多長時間產生一個區塊
      BatchSize:
          MaxMessageCount: 10		# 交易的最大數據量, 數量達到之後會產生區塊, 建議100左右
          AbsoluteMaxBytes: 99 MB # 數據量達到這個值, 會產生一個區塊, 32M/64M
          PreferredMaxBytes: 512 KB
      Kafka:
          Brokers:
              - 127.0.0.1:9092
      Organizations:
  
  ################################################################################
  #
  #   Profile
  #
  ################################################################################
  Profiles:	# 不能改
      TwoOrgsOrdererGenesis:	# 區塊名字, 隨便改
          Capabilities:
              <<: *ChannelCapabilities
          Orderer:
              <<: *OrdererDefaults
              Organizations:
                  - *OrdererOrg
              Capabilities:
                  <<: *OrdererCapabilities
          Consortiums:
              SampleConsortium:	# 這個名字可以改
                  Organizations:
                      - *Org1
                      - *Org2
      TwoOrgsChannel:	# 通道名字, 可以改
          Consortium: SampleConsortium	# 這個名字對應93行
          Application:
              <<: *ApplicationDefaults
              Organizations:
                  - *Org1
                  - *Org2
              Capabilities:
                  <<: *ApplicationCapabilities
  
  ```

 配置文件修改(configtx.yaml)後爲:

################################################################################
  #
  #   Section: Organizations
  #
  ################################################################################
  Organizations:
      - &OrdererOrg
          Name: OrdererOrg
          ID: OrdererMSP
          MSPDir: crypto-config/ordererOrganizations/itcast.com/msp
  
      - &org_go
          Name: OrgGoMSP
          ID: OrgGoMSP
          MSPDir: crypto-config/peerOrganizations/orggo.itcast.com/msp
          AnchorPeers:
              - Host: peer0.orggo.itcast.com
                Port: 7051
  
      - &org_cpp
          Name: OrgCppMSP
          ID: OrgCppMSP
          MSPDir: crypto-config/peerOrganizations/orgcpp.itcast.com/msp
          AnchorPeers:
              - Host: peer0.orgcpp.itcast.com
                Port: 7051
  
  ################################################################################
  #
  #   SECTION: Capabilities
  #
  ################################################################################
  Capabilities:
      Global: &ChannelCapabilities
          V1_1: true
      Orderer: &OrdererCapabilities
          V1_1: true
      Application: &ApplicationCapabilities
          V1_2: true
  
  ################################################################################
  #
  #   SECTION: Application
  #
  ################################################################################
  Application: &ApplicationDefaults
      Organizations:
  
  ################################################################################
  #
  #   SECTION: Orderer
  #
  ################################################################################
  Orderer: &OrdererDefaults
      # Available types are "solo" and "kafka"
      OrdererType: solo
      Addresses:
          - orderer.itcast.com:7050
      BatchTimeout: 2s
      BatchSize:
          MaxMessageCount: 100
          AbsoluteMaxBytes: 32 MB
          PreferredMaxBytes: 512 KB
      Kafka:
          Brokers:
              - 127.0.0.1:9092
      Organizations:
  
  ################################################################################
  #
  #   Profile
  #
  ################################################################################
  Profiles:
      ItcastOrgsOrdererGenesis:
          Capabilities:
              <<: *ChannelCapabilities
          Orderer:
              <<: *OrdererDefaults
              Organizations:
                  - *OrdererOrg
              Capabilities:
                  <<: *OrdererCapabilities
          Consortiums:
              SampleConsortium:
                  Organizations:
                      - *org_go
                      - *org_cpp
      ItcastOrgsChannel:
          Consortium: SampleConsortium
          Application:
              <<: *ApplicationDefaults
              Organizations:
                  - *org_go
                  - *org_cpp
              Capabilities:
                  <<: *ApplicationCapabilities
  

生成創始塊文件

configtxgen -profile ItcastOrgsOrdererGenesis -outputBlock ./genesis.block
- 在當前目錄下得到一個文件: genesis.block

生成通道文件

configtxgen -profile ItcastOrgsChannel -outputCreateChannelTx channel.tx -channelID itcastchannel

若未指定channelID,則默認是mychannel 

-生成錨節點更新文件( >這個操作是可選的)

  # cpp組織錨節點文件
configtxgen -profile ItcastOrgsChannel -outputAnchorPeersUpdate CppMSPanchors.tx -channelID itcastchannel -asOrg OrgCppMSP
go組織錨節點文件
configtxgen -profile ItcastOrgsChannel -outputAnchorPeersUpdate GoMSPanchors.tx -channelID itcastchannel -asOrg OrgGoMSP

創建文件channel-artifacts文件夾, 並移動文件

mkdir channel-artifacts
mv *.tx *.block channel-artifacts

4. docker-compose文件的編寫

1. 客戶端角色需要使用的環境變量

```shell
# 客戶端docker容器啓動之後, go的工作目錄
- GOPATH=/opt/gopath    # 不需要修改
# docker容器啓動之後, 對應的守護進程的本地套接字, 不需要修改
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_LOGGING_LEVEL=INFO    # 日誌級別
- CORE_PEER_ID=cli            # 當前客戶端節點的ID, 自己指定
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051 # 客戶端連接的peer節點
- CORE_PEER_LOCALMSPID=     # 組織ID
- CORE_PEER_TLS_ENABLED=true    # 通信是否使用tls加密
- CORE_PEER_TLS_CERT_FILE=        # 證書文件
 /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=        # 私鑰文件
 /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
-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
# 指定當前客戶端的身份
- CORE_PEER_MSPCONFIGPATH=      /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
```

2 orderer節點需要使用的環境變量

```shell
- ORDERER_GENERAL_LOGLEVEL=INFO    # 日誌級別
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0    # orderer節點監聽的地址
- ORDERER_GENERAL_GENESISMETHOD=file    # 創始塊的來源, 指定file來源就是文件中
# 創始塊對應的文件, 這個不需要改
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP    # orderer節點所屬的組的ID
- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp    # 當前節點的msp賬號路徑
# enabled TLS
- ORDERER_GENERAL_TLS_ENABLED=true    # 是否使用tls加密
- ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key    # 私鑰
- ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt    # 證書
- ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]            # 根證書
```

3 peer節點需要使用的環境變量

```shell
- CORE_PEER_ID=peer0.orggo.test.com    # 當前peer節點的名字, 自己起
# 當前peer節點的地址信息
- CORE_PEER_ADDRESS=peer0.orggo.test.com:7051
# 啓動的時候, 指定連接誰, 一般寫自己就行
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.orggo.test.com:7051
# 爲了被其他節點感知到, 如果不設置別的節點不知有該節點的存在
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.orggo.test.com:7051
- CORE_PEER_LOCALMSPID=OrgGoMSP
# docker的本地套接字地址, 不需要改
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
# 當前節點屬於哪個網絡
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=network_default
- CORE_LOGGING_LEVEL=INFO
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_GOSSIP_USELEADERELECTION=true    # 釋放自動選舉leader節點
- CORE_PEER_GOSSIP_ORGLEADER=false            # 當前不是leader
- CORE_PEER_PROFILE_ENABLED=true    # 在peer節點中有一個profile服務
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
```

4 相關配置文件

- **啓動docker-compose使用的配置文件** - `docker-compose.yaml
  # docker-compose.yaml

  version: '2'
  
  volumes:
    orderer.itcast.com:
    peer0.orggo.itcast.com:
    peer1.orggo.itcast.com:
    peer0.orgcpp.itcast.com:
    peer1.orgcpp.itcast.com:
  
  networks:
    byfn:
  
  services:
  
    orderer.itcast.com:
      extends:
        file:   base/docker-compose-base.yaml
        service: orderer.itcast.com
      container_name: orderer.itcast.com
      networks:
        - byfn
  
    peer0.orggo.itcast.com:
      container_name: peer0.orggo.itcast.com
      extends:
        file:  base/docker-compose-base.yaml
        service: peer0.orggo.itcast.com
      networks:
        - byfn
  
    peer1.orggo.itcast.com:
      container_name: peer1.orggo.itcast.com
      extends:
        file:  base/docker-compose-base.yaml
        service: peer1.orggo.itcast.com
      networks:
        - byfn
  
    peer0.orgcpp.itcast.com:
      container_name: peer0.orgcpp.itcast.com
      extends:
        file:  base/docker-compose-base.yaml
        service: peer0.orgcpp.itcast.com
      networks:
        - byfn
  
    peer1.orgcpp.itcast.com:
      container_name: peer1.orgcpp.itcast.com
      extends:
        file:  base/docker-compose-base.yaml
        service: peer1.orgcpp.itcast.com
      networks:
        - byfn
  
    cli:
      container_name: cli
      image: hyperledger/fabric-tools:latest
      tty: true
      stdin_open: true
      environment:
        - GOPATH=/opt/gopath
        - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
        - CORE_LOGGING_LEVEL=DEBUG
        #- CORE_LOGGING_LEVEL=INFO
        - CORE_PEER_ID=cli
        - CORE_PEER_ADDRESS=peer0.orggo.itcast.com:7051
        - CORE_PEER_LOCALMSPID=OrgGoMSP
        - CORE_PEER_TLS_ENABLED=true
        - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/server.crt
        - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/server.key
        - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/ca.crt
        - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/users/[email protected]/msp
      working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
      command: /bin/bash
      volumes:
          - /var/run/:/host/var/run/
          - ./chaincode/:/opt/gopath/src/github.com/chaincode
          - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
          - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
      depends_on:
        - orderer.itcast.com
        - peer0.orggo.itcast.com
        - peer1.orggo.itcast.com
        - peer0.orgcpp.itcast.com
        - peer1.orgcpp.itcast.com
      networks:
        - byfn

 被`docker-compose.yaml`依賴的文件 - `base/docker-compose-base.yaml`
  

  version: '2'
  
  services:
  
    orderer.itcast.com:
      container_name: orderer.itcast.com
      image: hyperledger/fabric-orderer:latest
      environment:
        - ORDERER_GENERAL_LOGLEVEL=INFO
        - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
        - ORDERER_GENERAL_GENESISMETHOD=file
        - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
        - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
        - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
        # enabled TLS
        - ORDERER_GENERAL_TLS_ENABLED=true
        - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
        - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
        - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
      working_dir: /opt/gopath/src/github.com/hyperledger/fabric
      command: orderer
      volumes:
      - ../channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
      - ../crypto-config/ordererOrganizations/itcast.com/orderers/orderer.itcast.com/msp:/var/hyperledger/orderer/msp
      - ../crypto-config/ordererOrganizations/itcast.com/orderers/orderer.itcast.com/tls/:/var/hyperledger/orderer/tls
      - orderer.itcast.com:/var/hyperledger/production/orderer
      # /var/lib/docker/volumes/order.itcast.com
      ports:
        - 7050:7050
  
    peer0.orggo.itcast.com:
      container_name: peer0.orggo.itcast.com
      extends:
        file: peer-base.yaml
        service: peer-base
      environment:
        - CORE_PEER_ID=peer0.orggo.itcast.com
        - CORE_PEER_ADDRESS=peer0.orggo.itcast.com:7051
        - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.orggo.itcast.com:7051
        - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.orggo.itcast.com:7051
        - CORE_PEER_LOCALMSPID=OrgGoMSP
      volumes:
          - /var/run/:/host/var/run/
          - ../crypto-config/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/msp:/etc/hyperledger/fabric/msp
          - ../crypto-config/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls:/etc/hyperledger/fabric/tls
          - peer0.orggo.itcast.com:/var/hyperledger/production
      ports:
        - 7051:7051
        - 7053:7053
  
    peer1.orggo.itcast.com:
      container_name: peer1.orggo.itcast.com
      extends:
        file: peer-base.yaml
        service: peer-base
      environment:
        - CORE_PEER_ID=peer1.orggo.itcast.com
        - CORE_PEER_ADDRESS=peer1.orggo.itcast.com:7051
        - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.orggo.itcast.com:7051
        - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.orggo.itcast.com:7051
        - CORE_PEER_LOCALMSPID=OrgGoMSP
      volumes:
          - /var/run/:/host/var/run/
          - ../crypto-config/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/msp:/etc/hyperledger/fabric/msp
          - ../crypto-config/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/tls:/etc/hyperledger/fabric/tls
          - peer1.orggo.itcast.com:/var/hyperledger/production
  
      ports:
        - 8051:7051
        - 8053:7053
  
    peer0.orgcpp.itcast.com:
      container_name: peer0.orgcpp.itcast.com
      extends:
        file: peer-base.yaml
        service: peer-base
      environment:
        - CORE_PEER_ID=peer0.orgcpp.itcast.com
        - CORE_PEER_ADDRESS=peer0.orgcpp.itcast.com:7051
        - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.orgcpp.itcast.com:7051
        - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.orgcpp.itcast.com:7051
        - CORE_PEER_LOCALMSPID=OrgCppMSP
      volumes:
          - /var/run/:/host/var/run/
          - ../crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/msp:/etc/hyperledger/fabric/msp
          - ../crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/tls:/etc/hyperledger/fabric/tls
          - peer0.orgcpp.itcast.com:/var/hyperledger/production
      ports:
        - 9051:7051
        - 9053:7053
  
    peer1.orgcpp.itcast.com:
      container_name: peer1.orgcpp.itcast.com
      extends:
        file: peer-base.yaml
        service: peer-base
      environment:
        - CORE_PEER_ID=peer1.orgcpp.itcast.com
        - CORE_PEER_ADDRESS=peer1.orgcpp.itcast.com:7051
        - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.orgcpp.itcast.com:7051
        - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.orgcpp.itcast.com:7051
        - CORE_PEER_LOCALMSPID=OrgCppMSP
      volumes:
          - /var/run/:/host/var/run/
          - ../crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/msp:/etc/hyperledger/fabric/msp
          - ../crypto-config/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/tls:/etc/hyperledger/fabric/tls
          - peer1.orgcpp.itcast.com:/var/hyperledger/production
      ports:
        - 10051:7051
        - 10053:7053

被 ``docker-compose-base.yaml` 依賴的文件 - `base/peer-base.yaml`

  version: '2'
  
  services:
    peer-base:
      image: hyperledger/fabric-peer:latest
      environment:
        - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
        # the following setting starts chaincode containers on the same
        # bridge network as the peers
        # https://docs.docker.com/compose/networking/
        - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=xxxx_byfn
        - CORE_LOGGING_LEVEL=INFO
        #- CORE_LOGGING_LEVEL=DEBUG
        - CORE_PEER_TLS_ENABLED=true
        - CORE_PEER_GOSSIP_USELEADERELECTION=true
        - CORE_PEER_GOSSIP_ORGLEADER=false
        - CORE_PEER_PROFILE_ENABLED=true
        - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
        - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
        - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
      working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
      command: peer node start
  

5 啓動docker-compose

啓動命令:

# 在docker-compose.yaml 文件目錄下執行下邊命令
docker-compose up -d

檢測網絡是否正常啓動了:

docker-compose ps

如下,則代表成功: 

Name                 Command       State                        Ports                      
----------------------------------------------------------------------------------------------------
cli                       /bin/bash         Up                                                      
orderer.itcast.com        orderer           Up      0.0.0.0:7050->7050/tcp                          
peer0.orgcpp.itcast.com   peer node start   Up      0.0.0.0:9051->7051/tcp, 0.0.0.0:9053->7053/tcp  
peer0.orggo.itcast.com    peer node start   Up      0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp  
peer1.orgcpp.itcast.com   peer node start   Up      0.0.0.0:10051->7051/tcp, 0.0.0.0:10053->7053/tcp
peer1.orggo.itcast.com    peer node start   Up      0.0.0.0:8051->7051/tcp, 0.0.0.0:8053->7053/tcp

6. Peer操作

1.創建通道,通過客戶端來完成

 進入cli容器:

docker exec -it cli /bin/bash

peer 創建命令,參數詳情如下:

$ peer channel create [flags], 常用參數爲:
	`-o, --orderer: orderer節點的地址
	`-c, --channelID: 要創建的通道的ID, 必須小寫, 在250個字符以內
	`-f, --file: 由configtxgen 生成的通道文件, 用於提交給orderer
	-t, --timeout: 創建通道的超時時長, 默認爲5s
	`--tls: 通信時是否使用tls加密
	`--cafile: 當前orderer節點pem格式的tls證書文件, 要使用絕對路徑.
# orderer節點pem格式的tls證書文件路徑參考: 
crypto-config/ordererOrganizations/itcast.com/orderers/orderer.itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem

創建通道,格式爲:

peer channel create -o orderer節點地址:端口 -c 通道名 -f 通道文件 --tls true --cafile orderer節點pem格式的證書文件

創建通道:

peer channel create -o orderer.itcast.com:7050 -c itcastchannel -f ./channel-artifacts/channel.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem

 執行命令後,會在當前工作目錄下生成一個文件: 通道名.block, 本例: itcastchannel.block

2 加入通道
默認節點、加入管道

$ peer channel join[flags], 常用參數爲:
    `-b, --blockpath: 通過 peer channel create 命令生成的通道文件 
$ peer channel join -b 生成的通道block文件
$ peer channel join -b ./itcastchannel.block

其他的節點,加入通道

我們只需在cli容器中,設置以下環境變量,讓節點連接到其他節點中,再執行peer channel join命令即可將節點加入到通道中。

比如:第二個節點(Go組織的 peer1)加入通道,我們只需賦值第二個節點的export內容,在cli容器中粘貼,然後執行加入通道的命令。加入節點命令如上:

```
# 第1個節點 Go組織的 peer0
export CORE_PEER_ADDRESS=peer0.orggo.itcast.com:7051
export CORE_PEER_LOCALMSPID=OrgGoMSP
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/users/[email protected]/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/ca.crt
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer0.orggo.itcast.com/tls/server.key

# 第2個節點 Go組織的 peer1
export CORE_PEER_ADDRESS=peer1.orggo.itcast.com:7051
export CORE_PEER_LOCALMSPID=OrgGoMSP
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/users/[email protected]/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/tls/ca.crt
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orggo.itcast.com/peers/peer1.orggo.itcast.com/tls/server.key

# 第3個節點 Cpp組織的 peer0 注意:cli爲自己定義的客戶端名稱,根據自己的命名進行修改
export CORE_PEER_ID=cli
export CORE_PEER_ADDRESS=peer0.orgcpp.itcast.com:7051
export CORE_PEER_LOCALMSPID=OrgCppMSP
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/users/[email protected]/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/tls/ca.crt
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer0.orgcpp.itcast.com/tls/server.key

# 第4個節點 Cpp組織的 peer1 注意:cli爲自己定義的客戶端名稱,根據自己的命名進行修改
export CORE_PEER_ID=cli
export CORE_PEER_ADDRESS=peer1.orgcpp.itcast.com:7051
export CORE_PEER_LOCALMSPID=OrgCppMSP
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/users/[email protected]/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/tls/ca.crt
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/orgcpp.itcast.com/peers/peer1.orgcpp.itcast.com/tls/server.key
```

4 安裝鏈碼**

```shell
$ peer chaincode install [flags], 常用參數爲:
    -c, --ctor: JSON格式的構造參數, 默認是"{}"
    `-l, --lang: 編寫chaincode的編程語言, 默認值是 golang
    `-n, --name: chaincode的名字
    `-p, --path: chaincode源代碼的目錄, 從 $GOPATH/src 路徑後開始寫
    `-v, --version: 當前操作的chaincode的版本, 適用這些命令install/instantiate/upgrade
$ peer chaincode install -n 鏈碼的名字 -v 鏈碼的版本 -l 鏈碼的語言 -p 鏈碼的位置
    - 鏈碼名字自己起
    - 鏈碼的版本, 自己根據實際情況指定
$ peer chaincode install -n testcc -v 1.0 -l golang -p github.com/chaincode

返回值 有下面這句話 則代表成功:
2020-03-19 07:25:26.416 UTC [chaincodeCmd] install -> INFO 005 Installed remotely response:<status:200 payload:"OK" > 

4 更新錨節點(可略)

$ peer channel update [flags], 常用參數爲:
    `-o, --orderer: orderer節點的地址
    `-c, --channelID: 要創建的通道的ID, 必須小寫, 在250個字符以內
    `-f, --file: 由configtxgen 生成的組織錨節點文件, 用於提交給orderer
    `--tls: 通信時是否使用tls加密
    `--cafile: 當前orderer節點pem格式的tls證書文件, 要使用絕對路徑.
# orderer節點pem格式的tls證書文件路徑參考: 
crypto-config/ordererOrganizations/itcast.com/orderers/orderer.itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem

$ peer channel update -o orderer節點地址:端口 -c 通道名 -f 錨節點更新文件 --tls true --cafile orderer節點pem格式的證書文件

5 鏈碼初始化**

```shell
$ peer chaincode instantiate [flags], 常用參數爲:
    `-C,--channelID:當前命令運行的通道,默認值是“testchainid"。
    `-c, --ctor:JSON格式的構造參數,默認值是“{}"
    `-l,--lang:編寫Chaincode的編程語言,默認值是golang
    `-n,--name:Chaincode的名字。
    `-P,--policy:當前Chaincode的背書策略。
    `-v,--version:當前操作的Chaincode的版本,適用於install/instantiate/upgrade等命令
    `--tls: 通信時是否使用tls加密
    `--cafile: 當前orderer節點pem格式的tls證書文件, 要使用絕對路徑.
$ peer chaincode instantiate -o orderer節點地址:端口 --tls true --cafile orderer節點pem格式的證書文件 -C 通道名稱 -n 鏈碼名稱 -l 鏈碼語言 -v 鏈碼版本 -c 鏈碼Init函數調用 -P 背書策略
peer chaincode instantiate -o orderer.itcast.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/itcast.com/msp/tlscacerts/tlsca.itcast.com-cert.pem -C itcastchannel -n testcc -l golang -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "AND ('OrgGoMSP.member', 'OrgCppMSP.member')"

至此、我們已經手動組件了fabric網絡。

智能合約

格式:

 -鏈代碼的**包名**的指定

  //xxx爲鏈代碼名,必須使用main 
  xxx.go
  package main
  ```

- 必須要引入的包

   // go get github.com/hyperledger/fabric/core/chaincode/shim
  //go get github.com/hyperledger/fabric/protos/peer
  //若無法下載,可以clone一個完整的fabric後,自己拖文件到GOPATH中
  import (
      // 客戶端需要和 Fabric框架通信
      "github.com/hyperledger/fabric/core/chaincode/shim"
      pb "github.com/hyperledger/fabric/protos/peer"
  )

- 鏈碼的書寫要求

  ```go
  // 自定義一個結構體 - 類, 基於這個類實現一些接口函數
  type Test struct {
      // 空着即可
  }
  func (t* Test) Init(stub ChaincodeStubInterface) pb.Response;
  func (t* Test) Invoke(stub ChaincodeStubInterface) pb.Response;

鏈碼 API 查詢地址:

https://pkg.go.dev/github.com/hyperledger/fabric/core/chaincode/shim?tab=doc

示例

package main

import (
	"fmt"
	"strconv"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	fmt.Println("ex02 Init")
	_, args := stub.GetFunctionAndParameters()
	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var err error

	if len(args) != 4 {
		return shim.Error("Incorrect number of arguments. Expecting 4")
	}

	// Initialize the chaincode
	A = args[0]
	Aval, err = strconv.Atoi(args[1])
	if err != nil {
		return shim.Error("Expecting integer value for asset holding")
	}
	B = args[2]
	Bval, err = strconv.Atoi(args[3])
	if err != nil {
		return shim.Error("Expecting integer value for asset holding")
	}
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return shim.Error(err.Error())
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	fmt.Println("ex02 Invoke")
	function, args := stub.GetFunctionAndParameters()
	if function == "invoke" {
		// Make payment of X units from A to B
		return t.invoke(stub, args)
	} else if function == "delete" {
		// Deletes an entity from its state
		return t.delete(stub, args)
	} else if function == "query" {
		// the old "Query" is now implemtned in invoke
		return t.query(stub, args)
	}

	return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}

// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var X int          // Transaction value
	var err error

	if len(args) != 3 {
		return shim.Error("Incorrect number of arguments. Expecting 3")
	}

	A = args[0]
	B = args[1]

	// Get the state from the ledger
	// TODO: will be nice to have a GetAllState call to ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		return shim.Error("Failed to get state")
	}
	if Avalbytes == nil {
		return shim.Error("Entity not found")
	}
	Aval, _ = strconv.Atoi(string(Avalbytes))

	Bvalbytes, err := stub.GetState(B)
	if err != nil {
		return shim.Error("Failed to get state")
	}
	if Bvalbytes == nil {
		return shim.Error("Entity not found")
	}
	Bval, _ = strconv.Atoi(string(Bvalbytes))

	// Perform the execution
	X, err = strconv.Atoi(args[2])
	if err != nil {
		return shim.Error("Invalid transaction amount, expecting a integer value")
	}
	Aval = Aval - X
	Bval = Bval + X
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state back to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return shim.Error(err.Error())
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

// Deletes an entity from state
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	A := args[0]

	// Delete the key from the state in ledger
	err := stub.DelState(A)
	if err != nil {
		return shim.Error("Failed to delete state")
	}

	return shim.Success(nil)
}

// query callback representing the query of a chaincode
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var A string // Entities
	var err error

	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
	}

	A = args[0]

	// Get the state from the ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
		return shim.Error(jsonResp)
	}

	if Avalbytes == nil {
		jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
		return shim.Error(jsonResp)
	}

	jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
	fmt.Printf("Query Response:%s\n", jsonResp)
	return shim.Success(Avalbytes)
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章