一、意義:
在本節內容開始之前,我先跟讀者朋友們一起分享一下公鏈、聯盟鏈、私有鏈的優劣勢。
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)
}
}