【Hyperledger Fabric】Fabric 2.2 手动安装
本文内容介绍在Centos7.9系统下手动安装v2.2版本Fabric的过程。
相关过程配置可参考 fabric-samples
截至2023.09,HyperLedger Fabric最新长期支持版本是v2.5,其次是v2.2和v1.4。
下一待发行版本是v3.0,v3.0将提供了基于SmartBFT共识库的BFT排序服务,
是继v1.4版本之后(v2.x版本仅提供Raft和Solo共识排序)再一次支持拜占庭排序,实现完全去中心化。
0.前置条件
参照 https://hyperledger-fabric.readthedocs.io/en/release-2.2/prereqs.html 安装 Git、cURL、Docker、Docker-Compose;
安装 Go(1.16.7版本以上);安装 jq。
下载命令文件
创建一个保存命令工具的目录
进入目录下载 fabric(v2.2.4) 包和 fabric-ca(v1.5.2) 包,下载连接:
https://github.com/hyperledger/fabric/releases
https://github.com/hyperledger/fabric-ca/releases
解压在本目录:
.
├── bin
│ ├── configtxgen
│ ├── configtxlator
│ ├── cryptogen
│ ├── discover
│ ├── fabric-ca-client
│ ├── fabric-ca-server
│ ├── ledgerutil
│ ├── orderer
│ ├── osnadmin
│ └── peer
├── builders
│ └── ccaas
│ └── bin
│ ├── build
│ ├── detect
│ └── release
├── config
│ ├── configtx.yaml
│ ├── core.yaml
│ └── orderer.yaml
├── hyperledger-fabric-ca-linux-amd64-1.5.2.tar.gz
└── hyperledger-fabric-linux-amd64-2.2.4.tar.gz
将bin目录添加值PATH
打开 /etc/profile 文件,
在末尾(unset i 之前)将 所创建目录/bin 添加到PATH,如:
pathmunge /root/go/src/github.com/hyperledger/fabric2.2/bin after
unset i
unset -f pathmunge
执行 source /etc/profile 使之生效
执行 fabric-ca-client version 验证有效
fabric-ca-client:
Version: 1.5.2
Go version: go1.16.7
OS/Arch: linux/amd64
1.身份证书
创建用于保存配置文件的目录,进入目录,创建并配置 crypto-config.yaml 以生成加密材料。后续文件都将保存在该目录下。
展开 crypto-config.yaml
# ---------------------------------------------------------------------------
# "OrdererOrgs" - Definition of organizations managing orderer nodes
# ---------------------------------------------------------------------------
OrdererOrgs:
# ---------------------------------------------------------------------------
# Orderer
# ---------------------------------------------------------------------------
- Name: Orderer
Domain: example.com
EnableNodeOUs: true
# ---------------------------------------------------------------------------
# "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
EnableNodeOUs: true
# ---------------------------------------------------------------------------
# "CA"
# ---------------------------------------------------------------------------
# Uncomment this section to enable the explicit definition of the CA for this
# organization. This entry is a Spec. See "Specs" section below for details.
# ---------------------------------------------------------------------------
# CA:
# Hostname: ca # implicitly ca.org1.example.com
# Country: US
# Province: California
# Locality: San Francisco
# OrganizationalUnit: Hyperledger Fabric
# StreetAddress: address for org # default nil
# PostalCode: postalCode for org # default nil
# ---------------------------------------------------------------------------
# "Specs"
# ---------------------------------------------------------------------------
# Uncomment this section to enable the explicit definition of hosts in your
# configuration. Most users will want to use Template, below
#
# Specs is an array of Spec entries. Each Spec entry consists of two fields:
# - Hostname: (Required) The desired hostname, sans the domain.
# - CommonName: (Optional) Specifies the template or explicit override for
# the CN. By default, this is the template:
#
# "{{.Hostname}}.{{.Domain}}"
#
# which obtains its values from the Spec.Hostname and
# Org.Domain, respectively.
# - SANS: (Optional) Specifies one or more Subject Alternative Names
# to be set in the resulting x509. Accepts template
# variables {{.Hostname}}, {{.Domain}}, {{.CommonName}}. IP
# addresses provided here will be properly recognized. Other
# values will be taken as DNS names.
# NOTE: Two implicit entries are created for you:
# - {{ .CommonName }}
# - {{ .Hostname }}
# ---------------------------------------------------------------------------
# Specs:
# - Hostname: foo # implicitly "foo.org1.example.com"
# CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
# SANS:
# - "bar.{{.Domain}}"
# - "altfoo.{{.Domain}}"
# - "{{.Hostname}}.org6.net"
# - 172.16.10.31
# - Hostname: bar
# - Hostname: baz
# ---------------------------------------------------------------------------
# "Template"
# ---------------------------------------------------------------------------
# Allows for the definition of 1 or more hosts that are created sequentially
# from a template. By default, this looks like "peer%d" from 0 to Count-1.
# You may override the number of nodes (Count), the starting index (Start)
# or the template used to construct the name (Hostname).
#
# Note: Template and Specs are not mutually exclusive. You may define both
# sections and the aggregate nodes will be created for you. Take care with
# name collisions
# ---------------------------------------------------------------------------
Template:
Count: 1
# Start: 5
# Hostname: {{.Prefix}}{{.Index}} # default
# SANS:
# - "{{.Hostname}}.alt.{{.Domain}}"
# ---------------------------------------------------------------------------
# "Users"
# ---------------------------------------------------------------------------
# Count: The number of user accounts _in addition_ to Admin
# ---------------------------------------------------------------------------
Users:
Count: 1
# ---------------------------------------------------------------------------
# Org2: See "Org1" for full specification
# ---------------------------------------------------------------------------
- Name: Org2
Domain: org2.example.com
EnableNodeOUs: true
Template:
Count: 1
Users:
Count: 1
crypto-config.yaml 可通过 cryptogen 生成模板,自行修改:
cryptogen showtemplate > crypto-config.yaml
生成身份数字证书、MSP等文件:
cryptogen generate --config=crypto-config.yaml
2.通道配置
创建并编写 configx.yaml 配置权限策略和网络规格
展开 configx.yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
---
################################################################################
#
# 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
# Policies defines the set of policies at this level of the config tree
# For organization policies, their canonical path is usually
# /Channel///
Policies:
Readers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
Writers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
Admins:
Type: Signature
Rule: "OR('OrdererMSP.admin')"
OrdererEndpoints:
- orderer.example.com:7050
- &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
# Policies defines the set of policies at this level of the config tree
# For organization policies, their canonical path is usually
# /Channel///
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')"
Endorsement:
Type: Signature
Rule: "OR('Org1MSP.peer')"
# 有改过“-”
AnchorPeers:
- 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
# Policies defines the set of policies at this level of the config tree
# For organization policies, their canonical path is usually
# /Channel///
Policies:
Readers:
Type: Signature
Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')"
Writers:
Type: Signature
Rule: "OR('Org2MSP.admin', 'Org2MSP.client')"
Admins:
Type: Signature
Rule: "OR('Org2MSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('Org2MSP.peer')"
AnchorPeers:
- Host: peer0.org2.example.com
Port: 9051
################################################################################
#
# SECTION: Capabilities
#
# - This section defines the capabilities of fabric network. This is a new
# concept as of v1.1.0 and should not be utilized in mixed networks with
# v1.0.x peers and orderers. Capabilities define features which must be
# present in a fabric binary for that binary to safely participate in the
# fabric network. For instance, if a new MSP type is added, newer binaries
# might recognize and validate the signatures from this type, while older
# binaries without this support would be unable to validate those
# transactions. This could lead to different versions of the fabric binaries
# having different world states. Instead, defining a capability for a channel
# informs those binaries without this capability that they must cease
# processing transactions until they have been upgraded. For v1.0.x if any
# capabilities are defined (including a map with all capabilities turned off)
# then the v1.0.x peer will deliberately crash.
#
################################################################################
Capabilities:
# Channel capabilities apply to both the orderers and the peers and must be
# supported by both.
# Set the value of the capability to true to require it.
Channel: &ChannelCapabilities
# V2_0 capability ensures that orderers and peers behave according
# to v2.0 channel capabilities. Orderers and peers from
# prior releases would behave in an incompatible way, and are therefore
# not able to participate in channels at v2.0 capability.
# Prior to enabling V2.0 channel capabilities, ensure that all
# orderers and peers on a channel are at v2.0.0 or later.
V2_0: true
# Orderer capabilities apply only to the orderers, and may be safely
# used with prior release peers.
# Set the value of the capability to true to require it.
Orderer: &OrdererCapabilities
# V2_0 orderer capability ensures that orderers behave according
# to v2.0 orderer capabilities. Orderers from
# prior releases would behave in an incompatible way, and are therefore
# not able to participate in channels at v2.0 orderer capability.
# Prior to enabling V2.0 orderer capabilities, ensure that all
# orderers on channel are at v2.0.0 or later.
V2_0: true
# Application capabilities apply only to the peer network, and may be safely
# used with prior release orderers.
# Set the value of the capability to true to require it.
Application: &ApplicationCapabilities
# V2_0 application capability ensures that peers behave according
# to v2.0 application capabilities. Peers from
# prior releases would behave in an incompatible way, and are therefore
# not able to participate in channels at v2.0 application capability.
# Prior to enabling V2.0 application capabilities, ensure that all
# peers on channel are at v2.0.0 or later.
V2_0: true
################################################################################
#
# SECTION: Application
#
# - This section defines the values to encode into a config transaction or
# genesis block for application related parameters
#
################################################################################
Application: &ApplicationDefaults
# Organizations is the list of orgs which are defined as participants on
# the application side of the network
Organizations:
# Policies defines the set of policies at this level of the config tree
# For Application policies, their canonical path is
# /Channel/Application/
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
LifecycleEndorsement:
Type: ImplicitMeta
Rule: "MAJORITY Endorsement"
Endorsement:
Type: ImplicitMeta
Rule: "MAJORITY Endorsement"
Capabilities:
<<: *ApplicationCapabilities
################################################################################
#
# SECTION: Orderer
#
# - This section defines the values to encode into a config transaction or
# genesis block for orderer related parameters
#
################################################################################
Orderer: &OrdererDefaults
# Orderer Type: The orderer implementation to start
OrdererType: etcdraft
# Addresses used to be the list of orderer addresses that clients and peers
# could connect to. However, this does not allow clients to associate orderer
# addresses and orderer organizations which can be useful for things such
# as TLS validation. The preferred way to specify orderer addresses is now
# to include the OrdererEndpoints item in your org definition
Addresses:
- orderer.example.com:7050
EtcdRaft:
Consenters:
- Host: orderer.example.com
Port: 7050
ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
# Batch Timeout: The amount of time to wait before creating a batch
BatchTimeout: 2s
# Batch Size: Controls the number of messages batched into a block
BatchSize:
# Max Message Count: The maximum number of messages to permit in a batch
MaxMessageCount: 10
# Absolute Max Bytes: The absolute maximum number of bytes allowed for
# the serialized messages in a batch.
AbsoluteMaxBytes: 99 MB
# Preferred Max Bytes: The preferred maximum number of bytes allowed for
# the serialized messages in a batch. A message larger than the preferred
# max bytes will result in a batch larger than preferred max bytes.
PreferredMaxBytes: 512 KB
# Organizations is the list of orgs which are defined as participants on
# the orderer side of the network
Organizations:
# Policies defines the set of policies at this level of the config tree
# For Orderer policies, their canonical path is
# /Channel/Orderer/
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
# BlockValidation specifies what signatures must be included in the block
# from the orderer for the peer to validate it.
BlockValidation:
Type: ImplicitMeta
Rule: "ANY Writers"
################################################################################
#
# CHANNEL
#
# This section defines the values to encode into a config transaction or
# genesis block for channel related parameters.
#
################################################################################
Channel: &ChannelDefaults
# Policies defines the set of policies at this level of the config tree
# For Channel policies, their canonical path is
# /Channel/
Policies:
# Who may invoke the 'Deliver' API
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
# Who may invoke the 'Broadcast' API
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
# By default, who may modify elements at this config level
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
# Capabilities describes the channel level capabilities, see the
# dedicated Capabilities section elsewhere in this file for a full
# description
Capabilities:
<<: *ChannelCapabilities
################################################################################
#
# Profile
#
# - Different configuration profiles may be encoded here to be specified
# as parameters to the configtxgen tool
#
################################################################################
Profiles:
TwoOrgsOrdererGenesis:
<<: *ChannelDefaults
Orderer:
<<: *OrdererDefaults
Organizations:
- *OrdererOrg
Capabilities:
<<: *OrdererCapabilities
Consortiums:
SampleConsortium:
Organizations:
- *Org1
- *Org2
TwoOrgsChannel:
Consortium: SampleConsortium
<<: *ChannelDefaults
Application:
<<: *ApplicationDefaults
Organizations:
- *Org1
- *Org2
Capabilities:
<<: *ApplicationCapabilities
configx.yaml 模板配置可参考 https://github.com/hyperledger/fabric-samples/tree/release-2.2/test-network/configtx
随后通过 configtxgen 创建相关构件,cryptogen命令工具介绍: https://hyperledger-fabric.readthedocs.io/en/latest/commands/configtxgen.html
创建创世块文件
configtxgen \
-profile TwoOrgsOrdererGenesis \
-outputBlock ./channel-artifacts/genesis.block \
-channelID fabric-channel
profile 配置项 configx.yaml 配置文件Profiles第一部分
outputBlock 创世块输出路径
channelID 创世块文件channalID,需要与后面通道channelID不同
CST 0001 INFO [common.tools.configtxgen] main -> Loading configuration
CST 0002 INFO [common.tools.configtxgen.localconfig] completeInitialization -> orderer type: etcdraft
CST 0003 INFO [common.tools.configtxgen.localconfig] completeInitialization -> Orderer.EtcdRaft.Options unset, setting to tick_interval:"500ms" election_tick:10 heartbeat_tick:1 max_inflight_blocks:5 snapshot_interval_size:16777216
CST 0004 INFO [common.tools.configtxgen.localconfig] Load -> Loaded configuration: configtx.yaml
CST 0005 INFO [common.tools.configtxgen] doOutputBlock -> Generating genesis block
CST 0006 INFO [common.tools.configtxgen] doOutputBlock -> Creating system channel genesis block
CST 0007 INFO [common.tools.configtxgen] doOutputBlock -> Writing genesis block
生成通道文件
configtxgen \
-profile TwoOrgsChannel \
-outputCreateChannelTx ./channel-artifacts/channel.tx \
-channelID mychannel
CST 0001 INFO [common.tools.configtxgen] main -> Loading configuration
CST 0002 INFO [common.tools.configtxgen.localconfig] Load -> Loaded configuration: configtx.yaml
CST 0003 INFO [common.tools.configtxgen] doOutputChannelCreateTx -> Generating new channel configtx
CST 0004 INFO [common.tools.configtxgen] doOutputChannelCreateTx -> Writing new channel tx
生成组织1和组织2的锚节点文件
configtxgen \
-profile TwoOrgsChannel \
-outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx \
-channelID mychannel \
-asOrg Org1MSP
configtxgen \
-profile TwoOrgsChannel \
-outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx \
-channelID mychannel \
-asOrg Org2MSP
CST 0001 INFO [common.tools.configtxgen] main -> Loading configuration
CST 0002 INFO [common.tools.configtxgen.localconfig] Load -> Loaded configuration: configtx.yaml
CST 0003 INFO [common.tools.configtxgen] doOutputAnchorPeersUpdate -> Generating anchor peer update
CST 0004 INFO [common.tools.configtxgen] doOutputAnchorPeersUpdate -> Writing anchor peer update0001 INFO [common.tools.configtxgen] main -> Loading configuration
CST 0002 INFO [common.tools.configtxgen.localconfig] Load -> Loaded configuration: configtx.yaml
CST 0003 INFO [common.tools.configtxgen] doOutputAnchorPeersUpdate -> Generating anchor peer update
ST 0004 INFO [common.tools.configtxgen] doOutputAnchorPeersUpdate -> Writing anchor peer update
3.生成网络
创建并编写 docker-compose.yaml 配置生成Fabric节点容器
展开 docker-compose.yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
version: '2'
volumes:
orderer.example.com:
peer0.org1.example.com:
peer0.org2.example.com:
networks:
test:
#name:没有网络名称
name: mytest_test
services:
orderer.example.com:
container_name: orderer.example.com
image: hyperledger/fabric-orderer:2.2
environment:
- FABRIC_LOGGING_SPEC=INFO
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
- ORDERER_GENERAL_LISTENPORT=7050
- 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]
- ORDERER_KAFKA_TOPIC_REPLICATIONFACTOR=1
- ORDERER_KAFKA_VERBOSE=true
- ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt
- ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key
- ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
# - ORDERER_GENERAL_BOOTSTRAPMETHOD=none
- ORDERER_GENERAL_GENESISMETHOD=file
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
- ORDERER_CHANNELPARTICIPATION_ENABLED=true
- ORDERER_ADMIN_TLS_ENABLED=true
- ORDERER_ADMIN_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
- ORDERER_ADMIN_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
- ORDERER_ADMIN_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
- ORDERER_ADMIN_TLS_CLIENTROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
- ORDERER_ADMIN_LISTENADDRESS=0.0.0.0:7053
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
- orderer.example.com:/var/hyperledger/production/orderer
ports:
- 7050:7050
- 7053:7053
#保证每个节点network相同,以在一个网络内运行
networks:
- test
peer0.org1.example.com:
container_name: peer0.org1.example.com
image: hyperledger/fabric-peer:2.2
environment:
#Generic peer variables
- 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/
# 路径名_test 不对的话可能报错
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=mytest_test
# - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_test !!!!!
- FABRIC_LOGGING_SPEC=INFO
#- FABRIC_LOGGING_SPEC=DEBUG
- CORE_PEER_TLS_ENABLED=true
- 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
# Peer specific variabes
- CORE_PEER_ID=peer0.org1.example.com
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LISTENADDRESS=0.0.0.0:7051
- CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
# Use Counchdb
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb1:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=adminpw
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock
- ./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
- peer0.org1.example.com:/var/hyperledger/production
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
ports:
- 7051:7051
depends_on:
- couchdb1
networks:
- test
peer0.org2.example.com:
container_name: peer0.org2.example.com
image: hyperledger/fabric-peer:2.2
environment:
#Generic peer variables
- 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=mytest_test
# - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_test !!!!!
- FABRIC_LOGGING_SPEC=INFO
#- FABRIC_LOGGING_SPEC=DEBUG
- CORE_PEER_TLS_ENABLED=true
- 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
# Peer specific variabes
- CORE_PEER_ID=peer0.org2.example.com
- CORE_PEER_ADDRESS=peer0.org2.example.com:9051
- CORE_PEER_LISTENADDRESS=0.0.0.0:9051
- CORE_PEER_CHAINCODEADDRESS=peer0.org2.example.com:9052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:9052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:9051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:9051
- CORE_PEER_LOCALMSPID=Org2MSP
# Use Counchdb
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb2:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=adminpw
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock
- ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp
- ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls:/etc/hyperledger/fabric/tls
- peer0.org2.example.com:/var/hyperledger/production
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
ports:
- 9051:9051
depends_on:
- couchdb2
networks:
- test
# #终端用户 用来操作peer1 peer2
# # 想要避免切换环境变量 可以创建两个 cli 分别控制
# cli:
# container_name: cli
# image: hyperledger/fabric-tools:$IMAGE_TAG
# tty: true
# stdin_open: true
# environment:
# - GOPATH=/opt/gopath
# - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
# - FABRIC_LOGGING_SPEC=INFO
# #- FABRIC_LOGGING_SPEC=DEBUG
# working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
# command: /bin/bash
# volumes:
# - /var/run/:/host/var/run/
# - ../organizations:/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations
# - ../scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
# depends_on:
# - peer0.org1.example.com
# - peer0.org2.example.com
# networks:
# - test
#终端用户 用来操作peer1 peer2
# 想要避免切换环境变量 可以创建两个 cli 分别控制
cli1:
container_name: cli1
image: hyperledger/fabric-tools:2.2
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_ID=cli1
- 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/[email protected]/msp
#- FABRIC_LOGGING_SPEC=DEBUG
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric-cluster/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
networks:
- test
cli2:
container_name: cli2
image: hyperledger/fabric-tools:2.2
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_ID=cli2
- CORE_PEER_ADDRESS=peer0.org2.example.com:9051
- CORE_PEER_LOCALMSPID=Org2MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
#- FABRIC_LOGGING_SPEC=DEBUG
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric-cluster/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
networks:
- test
couchdb1:
container_name: couchdb1
image: couchdb:3.1.1
# Populate the COUCHDB_USER and COUCHDB_PASSWORD to set an admin user and password
# for CouchDB. This will prevent CouchDB from operating in an "Admin Party" mode.
environment:
- COUCHDB_USER=admin
- COUCHDB_PASSWORD=adminpw
# Comment/Uncomment the port mapping if you want to hide/expose the CouchDB service,
# for example map it to utilize Fauxton User Interface in dev environments.
ports:
- "5984:5984"
networks:
- test
couchdb2:
container_name: couchdb2
image: couchdb:3.1.1
# Populate the COUCHDB_USER and COUCHDB_PASSWORD to set an admin user and password
# for CouchDB. This will prevent CouchDB from operating in an "Admin Party" mode.
environment:
- COUCHDB_USER=admin
- COUCHDB_PASSWORD=adminpw
# Comment/Uncomment the port mapping if you want to hide/expose the CouchDB service,
# for example map it to utilize Fauxton User Interface in dev environments.
ports:
- "7984:5984"
networks:
- test
Fabric 默认使用LevelDB存储交易数据,这里 docker-compose.yaml 中配置使用 CouchDB 以支持智能合约进行富查询操作。
执行 docker-compose up -d
命令创建容器:
Creating cli2 ... done
Creating cli1 ... done
Creating couchdb2 ... done
Creating orderer.example.com ... done
Creating couchdb1 ... done
Creating peer0.org2.example.com ... done
Creating peer0.org1.example.com ... done
执行 docker ps
查看容器是否创建成功。
后续若需关闭容器执行:
docker-compose down
关闭服务
docker volume prune
清理数据卷
4.通道操作
进入终端节点
docker exec -it cli1 bash
创建通道
peer channel create \
-o orderer.example.com:7050 \
-c mychannel \
-f ./channel-artifacts/channel.tx \
--tls true \
--cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem
-o 排序节点
-c 通道名
-f 通道文件路径
--tls 使用tls证书
--cafile 证书路径
可在当前目录查看到 mychannel.block 通道文件
UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
UTC [cli.common] readBlock -> INFO 002 Expect block, but got status: &{NOT_FOUND}
UTC [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized
UTC [cli.common] readBlock -> INFO 004 Expect block, but got status: &{SERVICE_UNAVAILABLE}
UTC [channelCmd] InitCmdFactory -> INFO 005 Endorser and orderer connections initialized
UTC [cli.common] readBlock -> INFO 006 Expect block, but got status: &{SERVICE_UNAVAILABLE}
UTC [channelCmd] InitCmdFactory -> INFO 007 Endorser and orderer connections initialized
UTC [cli.common] readBlock -> INFO 008 Expect block, but got status: &{SERVICE_UNAVAILABLE}
UTC [channelCmd] InitCmdFactory -> INFO 009 Endorser and orderer connections initialized
UTC [cli.common] readBlock -> INFO 00a Expect block, but got status: &{SERVICE_UNAVAILABLE}
UTC [channelCmd] InitCmdFactory -> INFO 00b Endorser and orderer connections initialized
UTC [cli.common] readBlock -> INFO 00c Received block: 0
退出容器
exit
复制 mychannel.block
先将 mychannel.block 复制到本地,在复制到cli2,因为两个 cli 需要加入相同的通道,需要添加同样的通道文件。
docker cp cli1:/opt/gopath/src/github.com/hyperledger/fabric/peer/mychannel.block ./
docker cp ./mychannel.block cli2:/opt/gopath/src/github.com/hyperledger/fabric/peer/
进入cli2
docker exec -it cli2 bash
确认复制成功
cli1 cli2 加入通道
peer channel join -b mychannel.block
cli1 cli2 下都进行此操作
UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channelUTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
更新锚节点
组织1:
peer channel update \
-o orderer.example.com:7050 \
-c mychannel \
-f ./channel-artifacts/Org1MSPanchors.tx \
--tls true \
--cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
-o 排序节点
-c 通道名
-f 锚文件路径
--tls 使用tls证书
--cafile 证书路径
UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
组织2:
peer channel update \
-o orderer.example.com:7050 \
-c mychannel \
-f ./channel-artifacts/Org2MSPanchors.tx \
--tls true \
--cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
通道操作完成后俩节点加入到了同一个通道内
5.链码部署
在当前目录下创建 chaincode/go/sacc.go 链码文件。
链码示例1 sacc.go
/*
* Copyright IBM Corp All Rights Reserved
*
* SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"fmt"
"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric-protos-go/peer"
)
// SimpleAsset implements a simple chaincode to manage an asset
type SimpleAsset struct {
}
// Init is called during chaincode instantiation to initialize any
// data. Note that chaincode upgrade also calls this function to reset
// or to migrate data.
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
// Get the args from the transaction proposal
args := stub.GetStringArgs()
if len(args) != 2 {
return shim.Error("Incorrect arguments. Expecting a key and a value")
}
// Set up any variables or assets here by calling stub.PutState()
// We store the key and the value on the ledger
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 is called per transaction on the chaincode. Each transaction is
// either a 'get' or a 'set' on the asset created by Init function. The Set
// method may create a new asset by specifying a new key-value pair.
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
// Extract the function and args from the transaction proposal
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))
}
// Set stores the asset (both key and value) on the ledger. If the key exists,
// it will override the value with the new one
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
}
// Get returns the value of the specified asset key
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
}
// main function starts up the chaincode in the container during instantiate
func main() {
if err := shim.Start(new(SimpleAsset)); err != nil {
fmt.Printf("Error starting SimpleAsset chaincode: %s", err)
}
}
链码示例2 sacc2.go(富查询)
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric-protos-go/peer"
"github.com/hyperledger/fabric-chaincode-go/pkg/cid"
)
// SimpleAsset implements a simple chaincode to manage an asset
type SimpleAsset struct {
}
type outputEvent struct {
EventName string
}
type someAsset struct {
Creator string
Owner string
Value string
// Status string
// Request string
SerialNumber string
CommonName string
StubID string
}
type someAssets []struct {
Key string `json:"Key"`
Record struct {
Creator string `json:"Creator"`
Owner string `json:"Owner"`
Value string `json:"Value"`
SerialNumber string `json:"SerialNumber"`
CommonName string `json:"CommonName"`
StubID string `json:"StubID"`
} `json:"Record"`
}
// Init is called during chaincode instantiation to initialize any
// data. Note that chaincode upgrade also calls this function to reset
// or to migrate data.
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
fmt.Printf("init...")
return shim.Success(nil)
}
// Invoke is called per transaction on the chaincode. Each transaction is
// either a 'get' or a 'set' on the asset created by Init function. The Set
// method may create a new asset by specifying a new key-value pair.
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
// Extract the function and args from the transaction proposal
fn, args := stub.GetFunctionAndParameters()
var result []byte
var err error
switch fn {
case "C":
result, err = create(stub, args)
case "Q":
result, err = queryByOwner(stub, args)
}
if err != nil {
return shim.Error(err.Error())
}
// Return the result as success payload
return shim.Success(result)
}
// 创建
func create(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
//
cert, err := cid.GetX509Certificate(stub)
if err != nil {
return nil, err
}
inkid, err := cid.GetID(stub)
if err != nil {
return nil, err
}
tempAsset := someAsset{
Creator: args[0],
Owner: args[1],
Value: args[2],
SerialNumber: cert.Subject.SerialNumber,
CommonName: cert.Subject.CommonName,
StubID: inkid,
}
tempJSONAsset, err := json.Marshal(&tempAsset)
if err != nil {
return nil, err
}
err = stub.PutState(args[0], tempJSONAsset)
if err != nil {
return nil, err
}
return []byte(args[0]), nil
}
// 根据Creator查询
func queryByOwner(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
queryString := fmt.Sprintf("{\"selector\":{\"Owner\":\"%s\"}}", args[0])
resultsIterator, err := stub.GetQueryResult(queryString)
if err != nil {
return nil, err
}
defer resultsIterator.Close()
buffer, err := constructQueryResponseFromIterator(resultsIterator)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
//
func constructQueryResponseFromIterator(resultsIterator shim.StateQueryIteratorInterface) (*bytes.Buffer, error) {
// buffer is a JSON array containing QueryResults
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"Key\":")
buffer.WriteString("\"")
buffer.WriteString(queryResponse.Key)
buffer.WriteString("\"")
buffer.WriteString(",\"Record\":")
// Record is a JSON object, so we write as-is
buffer.WriteString(string(queryResponse.Value))
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")
return &buffer, nil
}
// main function starts up the chaincode in the container during instantiate
func main() {
if err := shim.Start(new(SimpleAsset)); err != nil {
fmt.Printf("Error starting SimpleAsset chaincode: %s", err)
}
}
可从 https://github.com/hyperledger/fabric-samples/blob/v2.2.13/chaincode/sacc/sacc.go 复制。
目录chaincode/go挂载在容器,因此可进入容器查看:
cli docker exec -it cli1 bash
cd /opt/gopath/src/github.com/hyperledger/fabric-cluster/chaincode/go
打包链码
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GO111MODULE=auto
go mod init
go mod tidy
go mod vendor
提示:这里因为后续Go更新,会因版本问题报错无法构建链码容器:
Error: chaincode install failed with status: 500 - failed to invoke backing implementation of 'InstallChaincode': could not build chaincode: docker build failed: docker image build failed: docker build failed: Error returned from build: 2 ...
所以执行
go mod init
后,可到 https://github.com/hyperledger/fabric-samples/blob/v2.2.13/chaincode/sacc/go.mod 把 require 内容复制过来,在继续执行go mod tidy
等后续步骤。
打包
返回容器工作目录
cd /opt/gopath/src/github.com/hyperledger/fabric/peer
执行
peer lifecycle chaincode package sacc.tar.gz \
--path /opt/gopath/src/github.com/hyperledger/fabric-cluster/chaincode/go/ \
--label sacc_1
得到 sacc.tar.gz,同样退出容器复制到到cli2
docker cp cli1:/opt/gopath/src/github.com/hyperledger/fabric/peer/sacc.tar.gz ./
docker cp ./sacc.tar.gz cli2:/opt/gopath/src/github.com/hyperledger/fabric/peer/
安装链码
peer lifecycle chaincode install chaincode1.tar.gz
cli1 cli2都要安装
UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nGsacc_1:c9a3a1df0a3514d2846306ad101b11abd9db5013ecba454f6552dcd88be56e65\022\006sacc_1"(安装的链码包id) >
UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: sacc_1:c9a3a1df0a3514d2846306ad101b11abd9db5013ecba454f6552dcd88be56e65
返回结果包括 链码包id: c9a3a1df0a3514d2846306ad101b11abd9db5013ecba454f6552dcd88be56e65,需作为链码批准命令的参数。
通道&链码信息查询
peer lifecycle chaincode queryinstalled
peer lifecycle chaincode queryapproved -C "mychannel" -n sacc
peer lifecycle chaincode querycommitted -C "mychannel"
组织批准链码
cl1、cl2都需批准,每个组织都批准之后链码才能安装到通道上
peer lifecycle chaincode approveformyorg \
--channelID mychannel \
--name sacc \
--version 1.0 \
--init-required \
--package-id sacc_1:c9a3a1df0a3514d2846306ad101b11abd9db5013ecba454f6552dcd88be56e65 \
--sequence 1 \
--tls true \
--cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
查看是否真的安装成功
peer lifecycle chaincode checkcommitreadiness \
--channelID mychannel \
--name sacc \
--version 1.0 \
--init-required \
--sequence 1 \
--tls true \
--cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json
提交链码
提交只需要在一个节点上操作
peer lifecycle chaincode commit \
-o orderer.example.com:7050 \
--channelID mychannel \
--name sacc \
--version 1.0 \
--sequence 1 \
--init-required \
--tls true \
--cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
--peerAddresses peer0.org1.example.com:7051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses peer0.org2.example.com:9051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
UTC [chaincodeCmd] ClientWait -> INFO 001 txid [90a60a294b27e39354a48bab101d54973d51badebd760fef5a9be629f13134f0] committed with status (VALID) at peer0.org2.example.com:9051
UTC [chaincodeCmd] ClientWait -> INFO 002 txid [90a60a294b27e39354a48bab101d54973d51badebd760fef5a9be629f13134f0] committed with status (VALID) at peer0.org1.example.com:7051
6.链码调用
链码初始化调用
peer chaincode invoke \
-o orderer.example.com:7050 \
--isInit \
--ordererTLSHostnameOverride orderer.example.com \
--tls true \
--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 mychannel \
-n sacc \
--peerAddresses peer0.org1.example.com:7051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses peer0.org2.example.com:9051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
-c'{"Args":["a","bb"]}'
get链码函数调用
peer chaincode query \
-C mychannel \
-n sacc \
-c'{"Args":["get","a"]}'
bb
set链码函数调用
peer chaincode invoke \
-o orderer.example.com:7050 \
--tls true \
--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 mychannel \
-n sacc \
--peerAddresses peer0.org1.example.com:7051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses peer0.org2.example.com:9051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
-c'{"Args":["set","a","CC"]}'
UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 payload:"CC"
系统链码调用
peer chaincode invoke \
-o orderer.example.com:7050 \
--tls true \
--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 mychannel \
-n qscc \
--peerAddresses peer0.org1.example.com:7051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses peer0.org2.example.com:9051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
-c '{"function":"GetChainInfo","Args":["mychannel"]}'