序言
通过第一篇博客区块链笔记(1)-fabric1.4环境搭建的学习,初步搭建了fabric的基础环境并运行了官方的案例。但是官方End-2-End案例把执行过程集成,通过一条命令即可完成全部操作,初学者通过这些操作只能了解Fabric网络搭建成功与否,对Fabric网络的执行细节还是会感到迷惑。因此打算通过手动的方式搭建一个Orderer、一个Org和一个Peer的Solo排序的Fabric网络。把配置独立出来,形成Orderer和Peer配置的单个yaml配置文件,通过手动执行Orderer和Peer搭建Fabric网络。
相关源码可点击下载本文全部文件,,由于本人没有积分,有时候下载资源需要付费,迫于无奈设置5积分下载,实在抱歉。
1、创建helloworld目录
# cd $GOPATH/src/github.com/hyperledger/fabric
# mkdir helloworld
# cd helloworld
# cd $GOPATH/src/github.com/hyperledger/fabric
2、获取生成工具
解压第一篇博客中附带的hyperledger-fabric-ca-linux-amd64-1.4.6.tar
压缩包资源,解压后把bin
目录复制到helloworld目录下。修改bin
目录的权限
# chmod -R 777 ./bin
3、准备生成证书和区块配置文件
-
crypto-config.yaml:生成证书配置文件,配置如下。(其实就是
/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/basic-network
目录下crypto-config.yaml
的文件内容,直接拷贝来即可)OrdererOrgs: ## 定义Orderer组织结构 - Name: Orderer ## Orderer的名称 Domain: example.com ## 组织的命名域 # "Specs" - 有关完整说明,请参阅下面的PeerOrgs Specs: - Hostname: orderer # hostname + Domain的值组成Orderer节点的完整域名 #在crypto-config/ordererOrganizations/example.com/orderers 目录下生成orderer.example.com目录 # "PeerOrgs" - 管理Peer节点的组织的定义 PeerOrgs: - Name: Org1 ## 组织名称 组织 1 Domain: org1.example.com ## 组织域 EnableNodeOUs: true ## 如果设置了EnableNodeOUs,就在msp下生成config.yaml文件 Template: ## 允许定义从模板顺序创建的1个或多个主机。 Count: 1 ## 表示生成几个Peer Users: Count: 1 ## 表示生成几个普通User,除Admin之外的用户帐户数量
-
configtx.yaml:生成区块及通道配置文件,配置如下。(其实就是修改一下
/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/first-network
目录下configtx.yaml
的文件内容)Organizations: ##定义Orderer组织 - &OrdererOrg Name: OrdererOrg ID: OrdererMSP MSPDir: crypto-config/ordererOrganizations/example.com/msp Policies: Readers: Type: Signature Rule: "OR('OrdererMSP.member')" Writers: Type: Signature Rule: "OR('OrdererMSP.member')" Admins: Type: Signature Rule: "OR('OrdererMSP.admin')" ##定义Peer组织 1 - &Org1 Name: Org1MSP ID: Org1MSP MSPDir: crypto-config/peerOrganizations/org1.example.com/msp Policies: Readers: Type: Signature Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')" Writers: Type: Signature Rule: "OR('Org1MSP.admin', 'Org1MSP.client')" Admins: Type: Signature Rule: "OR('Org1MSP.admin')" AnchorPeers: ## 定义组织锚节点 用于跨组织 Gossip 通信 - Host: peer0.org1.example.com Port: 7051 Capabilities: Channel: &ChannelCapabilities V1_4_3: true V1_3: false V1_1: false Orderer: &OrdererCapabilities V1_4_2: true V1_1: false Application: &ApplicationCapabilities # V1.1 for Application is a catchall flag for behavior which has been # determined to be desired for all peers running v1.0.x, but the # modification of which would cause incompatibilities. Users should # leave this flag set to true. V1_4_2: true V1_3: false V1_2: false V1_1: false #Application应用通道相关配置,主要包括 参与应用网络的可用组织信息 Application: &ApplicationDefaults Organizations: Policies: Readers: Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" Capabilities: <<: *ApplicationCapabilities #Orderer系统通道相关配置,包括 Orderer 服务配置和参与Orderer 服务的可用组织 Orderer: &OrdererDefaults OrdererType: solo Addresses: - orderer.example.com:7050 BatchTimeout: 2s BatchSize: ## 区块打包的最大包含交易数 MaxMessageCount: 10 AbsoluteMaxBytes: 99 MB PreferredMaxBytes: 512 KB Kafka: Brokers: - 127.0.0.1:9092 ## kafka的 brokens 服务地址 允许有多个 Organizations: ## 参与维护 Orderer 的组织,默认为空 Policies: Readers: Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" BlockValidation: Type: ImplicitMeta Rule: "ANY Writers" Capabilities: <<: *OrdererCapabilities #Channel系统通道相关配置 Channel: &ChannelDefaults Policies: Readers: Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" Capabilities: <<: *ChannelCapabilities #一系列通道配置模板,包括Orderer 系统通道模板 和 应用通道类型模板 Profiles: ##Orderer的系统通道模板 必须包括 Orderer、 Consortiums 两部分 OneOrgsOrdererGenesis: <<: *ChannelDefaults Orderer: <<: *OrdererDefaults Organizations: - *OrdererOrg Consortiums: SampleConsortium: Organizations: - *Org1 OneOrgsChannel: Consortium: SampleConsortium Application: <<: *ApplicationDefaults Organizations: - *Org1
-
生成公私钥和证书,执行该命令后会生成一个
crypto-config
文件夹# ./bin/cryptogen generate --config=./crypto-config.yaml
-
生成创世区块
# mkdir channel-artifacts # ./bin/configtxgen -profile OneOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
-
生成通道配置区块
# ./bin/configtxgen -profile OneOrgsChannel -outputCreateChannelTx ./channel-artifacts/mychannel.tx -channelID mychannel
上述操作见截图
4、准备Docker配置文件
配置docker-orderer.yaml和 docker-peer.yaml文件,复制到helloworld目录下。序言说过本例子是一个Orderer、一个Org和一个Peer的Solo排序的Fabric网络,这两个配置文件其实是修改了/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/basic-network
目录下的docker-compose.yml
文件
先看docker-orderer.yaml
文件
version: '2'
services:
orderer.example.com:
container_name: orderer.example.com
image: hyperledger/fabric-orderer
environment:
- ORDERER_GENERAL_LOGLEVEL=debug
- 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/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls
ports:
- 7050:7050
再看docker-peer.yaml
文件
version: '2'
services:
peer0.org1.example.com:
container_name: peer0.org1.example.com
image: hyperledger/fabric-peer
environment:
- GOPATH=/opt/gopath
- CORE_PEER_ID=peer0.org1.example.com
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- 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=helloworld_default
#- CORE_LOGGING_LEVEL=ERROR
- 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
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
- ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
ports:
- 7051:7051
- 7052:7052
- 7053:7053
cli:
container_name: cli
image: hyperledger/fabric-tools
tty: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_ID=cli
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_TLS_ENABLED=true
- 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/Admin@org1.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
volumes:
- /var/run/:/host/var/run/
- ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/helloworld/chaincode/go
- ./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:
- peer0.org1.example.com
5、准备部署智能合约
在helloworld
目录新建chaincode/go/helloworld
多级目录,编写智能合约文件到该目录下。该目录有两个文件,一个是cmd/main.go
文件,一个是chaincode.go
文件
cmd
目录下的main.go
文件:
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/helloworld/chaincode/go/helloworld"
)
func main() {
err := shim.Start(new(helloworld.SimpleChaincode))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}
chaincode.go
文件
package helloworld
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
// SimpleChaincode implements a simple chaincode to manage an asset
type SimpleChaincode struct {
}
// 链码实例化时,调用Init函数初始化数据
// 链码升级时,也会调用此函数重置或迁移数据
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
// 获取交易提案中的参数
args := stub.GetStringArgs()
if len(args) != 2 {
return shim.Error("Incorrect arguments. Expecting a key and a value")
}
// 通过调用stub.PutState()设置变量和数值
// 在账本上设置key和value
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
}
return shim.Success(nil)
}
// 调用Invoke函数进行资产交易
// 每笔交易通过get或set操作Init函数创建的key和value
// 通过set可以创建新的key和value
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
// 获取交易提案中的函数和参数
fn, args := stub.GetFunctionAndParameters()
var result string
var err error
if fn == "set" {
result, err = set(stub, args)
} else { // assume 'get' even if fn is nil
result, err = get(stub, args)
}
if err != nil {
return shim.Error(err.Error())
}
// Return the result as success payload
return shim.Success([]byte(result))
}
// 保存key和value到账本上
// 如果key存在,覆盖原有的value
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
if len(args) != 2 {
return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")
}
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return "", fmt.Errorf("Failed to set asset: %s", args[0])
}
return args[1], nil
}
// 获取key对应的value
func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
if len(args) != 1 {
return "", fmt.Errorf("Incorrect arguments. Expecting a key")
}
value, err := stub.GetState(args[0])
if err != nil {
return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
}
if value == nil {
return "", fmt.Errorf("Asset not found: %s", args[0])
}
return string(value), nil
}
6、启动Fabric网络
-
启动orderer
docker-compose -f docker-orderer.yaml up -d
-
启动peer
docker-compose -f docker-peer.yaml up -d
-
启动cli容器
docker exec -it cli bash
-
创建Channel
# ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem # peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/mychannel.tx --tls --cafile $ORDERER_CA
-
Peer加入Channel
peer channel join -b mychannel.block
7、安装与运行智能合约
-
安装智能合约
peer chaincode install -n mycc -p github.com/hyperledger/fabric/helloworld/chaincode/go/helloworld/cmd -v 1.0
-
实例化智能合约
peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C mychannel -n mycc -v 1.0 -c '{"Args":["a","helloworld"]}' -P "OR ('Org1MSP.peer')"
-
Peer上查询A,显示Helloworld
peer chaincode query -C mychannel -n mycc -c '{"Args":["get","a"]}'
-
若想修改
a
的值,可以调用set
方法peer chaincode invoke -C mychannel -n mycc -c '{"Args":["set","a","helloha"]}' --tls --cafile $ORDERER_CA #由helloworld变成了helloha peer chaincode query -C mychannel -n mycc -c '{"Args":["get","a"]}'
-
退出,清除网络
docker stop $(docker ps -aq) docker rm $(docker ps -aq)
操作截图,最后显示helloworld则表示成功
-
智能合约操作命令参数说明
参数n 说明 -n 链码名称 -v 版本 -p(小写) 链码本地路径 -P(大写) 指定链码所关联的背书策略 -c(小写) 指定链码的初始化参数值 -C(大写) 指定通道名称 –tls 是否启动TLS与Orderer通信 –cafile $ORDERER_CA 指定Orderer服务的TLS证书,TLS启动时有效