1. 环境要求
- 主机:VM
- 操作系统:CentOS 7
- CPU:2 core +
- 内存:4G +
- 存储:50G +
2. 环境安装
-
创建项目目录以下命令在项目目录下运行
shellmkdir -p /home/hyperledger/fabric/finance cd /home/hyperledger/fabric/finance
-
安装通用包
shell# 更新软件包 yum -y update # 安装通用包 yum -y install vim tree wget git maven yum -y install epel-release yum -y install jq
-
安装 Chaincode 编程语言环境(JDK / NodeJS / Go)
shell# 安装 JDK yum -y install java-1.8.0-openjdk* # 验证安装 java -version # 安装 nvm git clone git://github.com/nvm-sh/nvm.git ~/nvm echo "source ~/nvm/nvm.sh" >> ~/.bashrc source ~/.bashrc # 验证安装 nvm --version # 安装 NodeJS nvm install v10.16.0 # 验证 NodeJS 和 NPM 版本 node -v npm -v # 安装 Go yum -y install go # 验证安装 go version
NVM:Node Version Manager
NPM:Node Package Manager
-
安装 docker-ce 和 docker-compose
shell# 删除旧版本 Docker yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine # 设置存储库 yum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 安装 docker-ce yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 启动 Docker systemctl start docker # 开启自启动 systemctl enable docker # 验证安装 docker --version
-
下载 docker 镜像
shell# fabric-ca 镜像 docker pull hyperledger/fabric-ca:1.4.9 # fabric-peer 镜像 docker pull hyperledger/fabric-peer:2.4.1 # fabric-orderer 镜像 docker pull hyperledger/fabric-orderer:2.4.1 # fabric-tools 镜像 docker pull hyperledger/fabric-tools:2.4.1 # 编程语言的链码部署镜像(Go | Java | NodeJS) docker pull hyperledger/fabric-ccenv:2.4.1 docker pull hyperledger/fabric-javaenv:2.4.1 docker pull hyperledger/fabric-nodeenv:2.4.1 # 链码运行时的基本操作系统镜像 docker pull hyperledger/fabric-baseos:2.4.1 # CouchDB镜像(一个用于存储账本状态的NOSQL数据库) docker pull couchdb:3.1.1 # 如果下载速度慢,使用以下方式配置代理 vim /etc/systemd/system/docker.service.d/http-proxy.conf [Service] Environment="HTTP_PROXY=http://192.168.31.86:7890/" vim /etc/systemd/system/docker.service.d/https-proxy.conf [Service] Environment="HTTPS_PROXY=http://192.168.31.86:7890" systemctl daemon-reload systemctl restart docker
查看下载的镜像
shelldocker images
-
下载 Fabirc Binaries
shell# Fabric CA wget https://github.com/hyperledger/fabric-ca/releases/download/v1.4.9/hyperledger-fabric-ca-linux-amd64-1.4.9.tar.gz # Fabric wget https://github.com/hyperledger/fabric/releases/download/v2.4.1/hyperledger-fabric-linux-amd64-2.4.1.tar.gz tar zxf hyperledger-fabric-ca-linux-amd64-1.4.9.tar.gz tar zxf hyperledger-fabric-linux-amd64-2.4.1.tar.gz
3. Hyperledger Fabric 跨境支付网络拓扑
网络规划
名称 | 域名 | 端口 |
---|---|---|
Orderer CA | ca.orderer.finance.com | 7054:7054 |
Bank1 CA | ca.bank1.finance.com | 8054:7054 |
Bank2 CA | ca.bank2.finance.com | 9054:7054 |
Orderer | orderer.finance.com | 7050:7050 |
Bank1 Peer1 | peer1.bank1.finance.com | 7051:7051,7052:7052 |
Bank2 Peer1 | peer1.bank2.finance.com | 9051:7051,9052:7052 |
Bank1 Peer1 CouchDB | peer1.bank1.couchdb.com | 5984:5984 |
Bank2 Peer1 CouchDB | peer1.bank2.couchdb.com | 6984:5984 |
修改 /etc/hosts
文件添加以下内容
shell
vim /etc/hosts
127.0.0.1 ca.orderer.finance.com
127.0.0.1 ca.bank1.finance.com
127.0.0.1 ca.bank2.finance.com
127.0.0.1 orderer.finance.com
127.0.0.1 peer1.bank1.finance.com
127.0.0.1 peer1.bank2.finance.com
127.0.0.1 peer1.bank1.couchdb.com
127.0.0.1 peer1.bank2.couchdb.com
4. 部署 CA 服务
创建 docker-compose 存放目录
shell
mkdir docker
编写 docker-compose-ca.yaml
shell
vim docker/docker-compose-ca.yaml
yaml
# docker/docker-compose-ca.yaml
# version: '3.0'
networks:
orderer:
name: orderer
bank1:
name: bank1
bank2:
name: bank2
finance:
name: finance
services:
ca.orderer.finance.com:
hostname: ca.orderer.finance.com
container_name: ca.orderer.finance.com
image: hyperledger/fabric-ca:1.4.9
command: sh -c 'fabric-ca-server start -d -b admin:adminpw --port 7054'
environment:
- FABRIC_CA_SERVER_HOME=/tmp/hyperledger/fabric-ca-server
- FABRIC_CA_SERVER_TLS_ENABLED=true
- FABRIC_CA_SERVER_CSR_HOSTS=ca.orderer.finance.com
- FABRIC_CA_SERVER_DEBUG=true
# - FABRIC_CA_SERVER_DB_TYPE=mysql
# - FABRIC_CA_SERVER_DB_DATASOURCE=root:root@tcp(192.168.0.104:3306)/orderer_ca?parseTime=true
volumes:
- ../organizations/fabric-ca/orderer:/tmp/hyperledger/fabric-ca-server
networks:
- orderer
- finance
ports:
- 7054:7054
ca.bank1.finance.com:
hostname: ca.bank1.finance.com
container_name: ca.bank1.finance.com
image: hyperledger/fabric-ca:1.4.9
command: sh -c 'fabric-ca-server start -d -b admin:adminpw --port 7054'
environment:
- FABRIC_CA_SERVER_HOME=/tmp/hyperledger/fabric-ca-server
- FABRIC_CA_SERVER_TLS_ENABLED=true
- FABRIC_CA_SERVER_CSR_HOSTS=ca.bank1.finance.com
- FABRIC_CA_SERVER_DEBUG=true
# - FABRIC_CA_SERVER_DB_TYPE=mysql
# - FABRIC_CA_SERVER_DB_DATASOURCE=root:root@tcp(192.168.0.104:3306)/bank1_ca?parseTime=true
volumes:
- ../organizations/fabric-ca/bank1:/tmp/hyperledger/fabric-ca-server
networks:
- bank1
- finance
ports:
- 8054:7054
ca.bank2.finance.com:
hostname: ca.bank2.finance.com
container_name: ca.bank2.finance.com
image: hyperledger/fabric-ca:1.4.9
command: sh -c 'fabric-ca-server start -d -b admin:adminpw --port 7054'
environment:
- FABRIC_CA_SERVER_HOME=/tmp/hyperledger/fabric-ca-server
- FABRIC_CA_SERVER_TLS_ENABLED=true
- FABRIC_CA_SERVER_CSR_HOSTS=ca.bank2.finance.com
- FABRIC_CA_SERVER_DEBUG=true
# - FABRIC_CA_SERVER_DB_TYPE=mysql
# - FABRIC_CA_SERVER_DB_DATASOURCE=root:root@tcp(192.168.0.104:3306)/bank2_ca?parseTime=true
volumes:
- ../organizations/fabric-ca/bank2:/tmp/hyperledger/fabric-ca-server
networks:
- bank2
- finance
ports:
- 9054:7054
使用 docker-compose 命令启动 3个 CA 服务器,一个 Orderer 组织的 CA(Orderer CA)和两个银行组织的 CA(Bank1 CA & Bank2 CA)
shell
docker compose -f docker/docker-compose-ca.yaml up -d
启动后查看容器是否启动成功
shell
docker ps -a
查看docker容器内部的启动日志
shell
# 1. docker logs [container id]
# 查看 Orderer CA 日志
docker logs e9ae3e555254
# 查看 Orderer Bank1 CA 日志
docker logs a07c4e9be072
# 查看 Orderer Bank2 CA 日志
docker logs baf413d9215e
# 成功启动容器后,将在 CA 容器的日志中看到以下输出
[INFO] Listening on https://0.0.0.0:7054
# 2. docker compose 查看日志
docker compose -f docker/docker-compose-ca.yaml logs
docker compose -f docker/docker-compose-ca.yaml logs | grep https://0.0.0.0:7054
# ca.bank2.finance.com | 2024/04/29 09:01:58 [INFO] Listening on https://0.0.0.0:7054
# ca.bank1.finance.com | 2024/04/29 09:01:58 [INFO] Listening on https://0.0.0.0:7054
# ca.orderer.finance.com | 2024/04/29 09:01:58 [INFO] Listening on https://0.0.0.0:7054
查看 CA 启动后的目录解构
shell
[root@blockchain finance]# tree organizations/fabric-ca/
organizations/fabric-ca/
├── bank1
│ ├── ca-cert.pem # Bank1 CA 受信的任根证书
│ ├── fabric-ca-server-config.yaml
│ ├── fabric-ca-server.db
│ ├── IssuerPublicKey
│ ├── IssuerRevocationPublicKey
│ ├── msp
│ │ ├── cacerts
│ │ ├── keystore
│ │ │ ├── 02ad9797470eb769c8e9463767d247d8fc45744ebb68dd7c37bf131775c648a2_sk
│ │ │ ├── a1f0a6137fb4247b3f44410a5bc1f3cfb14783953382374f4a7cd7c6bd53f022_sk
│ │ │ ├── IssuerRevocationPrivateKey
│ │ │ └── IssuerSecretKey
│ │ ├── signcerts
│ │ └── user
│ └── tls-cert.pem
├── bank2
│ ├── ca-cert.pem # Bank2 CA 受信的任根证书
│ ├── fabric-ca-server-config.yaml
│ ├── fabric-ca-server.db
│ ├── IssuerPublicKey
│ ├── IssuerRevocationPublicKey
│ ├── msp
│ │ ├── cacerts
│ │ ├── keystore
│ │ │ ├── 34c218016b065dfef8c94ce12424dddb100b13b417ba91eceda3a36e25e841aa_sk
│ │ │ ├── e77175a5fe4ec9e43f3aba4bbe9baa76df0206f105b5f33e38077f91bccb7304_sk
│ │ │ ├── IssuerRevocationPrivateKey
│ │ │ └── IssuerSecretKey
│ │ ├── signcerts
│ │ └── user
│ └── tls-cert.pem
└── orderer
├── ca-cert.pem # Orderer CA 受信的任根证书
├── fabric-ca-server-config.yaml
├── fabric-ca-server.db
├── IssuerPublicKey
├── IssuerRevocationPublicKey
├── msp
│ ├── cacerts
│ ├── keystore
│ │ ├── 72a02120c7d294e6743c452bb74d46be8db7d8dbfd79265d42ea36535823200e_sk
│ │ ├── afabf4617ef6b27e746644bf5679a694a16cd8e0c5d32d1fe6c88c55069ba5ed_sk
│ │ ├── IssuerRevocationPrivateKey
│ │ └── IssuerSecretKey
│ ├── signcerts
│ └── user
└── tls-cert.pem
5. 生成网络中成员的证书文件
1. Orderer 组织
Enroll Orderer CA 管理员
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/orderer/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/ordererOrganizations/finance.com
bin/fabric-ca-client enroll -d -u https://admin:adminpw@ca.orderer.finance.com:7054
# 用于不同组织通信,由于该CA同时充当组织 CA和 TLS CA,因此直接将CA启动时生成的组织根证书复制到组织级 msp 目录中
mkdir -p "${PWD}/organizations/ordererOrganizations/finance.com/msp/tlscacerts"
cp "${PWD}/organizations/fabric-ca/orderer/ca-cert.pem" "${PWD}/organizations/ordererOrganizations/finance.com/msp/tlscacerts/tlsca.finance.com-cert.pem"
编写 config.yaml
创建 Orderer 组织的OU
配置文件
shell
echo 'NodeOUs:
Enable: true
ClientOUIdentifier:
Certificate: cacerts/ca-orderer-finance-com-7054.pem
OrganizationalUnitIdentifier: client
PeerOUIdentifier:
Certificate: cacerts/ca-orderer-finance-com-7054.pem
OrganizationalUnitIdentifier: peer
AdminOUIdentifier:
Certificate: cacerts/ca-orderer-finance-com-7054.pem
OrganizationalUnitIdentifier: admin
OrdererOUIdentifier:
Certificate: cacerts/ca-orderer-finance-com-7054.pem
OrganizationalUnitIdentifier: orderer' > "${PWD}/organizations/ordererOrganizations/finance.com/msp/config.yaml"
Register Orderer
shell
bin/fabric-ca-client register -d --id.name orderer --id.secret ordererpw --id.type orderer -u https://ca.orderer.finance.com:7054
Register Orderer Admin
shell
bin/fabric-ca-client register -d --id.name ordereradmin --id.secret ordereradminpw --id.type admin --id.attrs "hf.Registrar.Roles=*,hf.Registrar.DelegateRoles=*,hf.AffiliationMgr=true,hf.Registrar.Attributes=*,hf.Revoker=true,hf.GenCRL=true,admin=true:ecert" -u https://ca.orderer.finance.com:7054
Enroll Orderer ECert 证书
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/orderer/ca-cert.pem
# 证书会存放在该目录下 ${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/msp
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com
export FABRIC_CA_CLIENT_MSPDIR=msp
bin/fabric-ca-client enroll -d -u https://orderer:ordererpw@ca.orderer.finance.com:7054
# 构造 Orderer MSP 目录
cp "${PWD}/organizations/ordererOrganizations/finance.com/msp/config.yaml" "${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/msp/config.yaml"
Enroll Orderer TLS 证书
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/orderer/ca-cert.pem
# 证书会存放在该目录下 ${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/tls
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com
export FABRIC_CA_CLIENT_MSPDIR=tls
bin/fabric-ca-client enroll -d -u https://orderer:ordererpw@ca.orderer.finance.com:7054 --enrollment.profile tls --csr.hosts "orderer.finance.com,localhost,127.0.0.1"
# 构造 orderer 的 TLS 证书目录并格式化文件名------用于启动 orderer docker 容器
# TLS 根证书
cp "${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/tls/tlscacerts/"* "${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/tls/ca.crt"
# TLS 签名证书
cp "${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/tls/signcerts/"* "${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/tls/server.crt"
# TLS 私钥
cp "${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/tls/keystore/"* "${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/tls/server.key"
mkdir -p "${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/msp/tlscacerts"
cp "${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/tls/tlscacerts/"* "${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/msp/tlscacerts/tlsca.orderer.finance.com-cert.pem"
Enroll Orderer Admin ECert 证书
shell
# 构造Orderer Admin 的msp证书目录,因为不用于组织间通信,所以不用配置tls
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/orderer/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/ordererOrganizations/finance.com/users/Admin@finance.com
export FABRIC_CA_CLIENT_MSPDIR=msp
bin/fabric-ca-client enroll -d -u https://ordereradmin:ordereradminpw@ca.orderer.finance.com:7054
# 构造 Admin MSP 目录
cp "${PWD}/organizations/ordererOrganizations/finance.com/msp/config.yaml" "${PWD}/organizations/ordererOrganizations/finance.com/users/Admin@finance.com/msp/config.yaml"
2. Bank1 组织
Enroll Bank1 CA 管理员
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/bank1/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/bank1.finance.com
bin/fabric-ca-client enroll -d -u https://admin:adminpw@ca.bank1.finance.com:8054
# 用于不同组织通信,由于该CA同时充当组织 CA和 TLS CA,因此直接将CA启动时生成的组织根证书复制到组织级 msp 目录中
mkdir -p "${PWD}/organizations/peerOrganizations/bank1.finance.com/msp/tlscacerts"
cp "${PWD}/organizations/fabric-ca/bank1/ca-cert.pem" "${PWD}/organizations/peerOrganizations/bank1.finance.com/msp/tlscacerts/tlsca.bank1.finance.com-cert.pem"
编写 config.yaml
shell
echo 'NodeOUs:
Enable: true
ClientOUIdentifier:
Certificate: cacerts/ca-bank1-finance-com-8054.pem
OrganizationalUnitIdentifier: client
PeerOUIdentifier:
Certificate: cacerts/ca-bank1-finance-com-8054.pem
OrganizationalUnitIdentifier: peer
AdminOUIdentifier:
Certificate: cacerts/ca-bank1-finance-com-8054.pem
OrganizationalUnitIdentifier: admin
OrdererOUIdentifier:
Certificate: cacerts/ca-bank1-finance-com-8054.pem
OrganizationalUnitIdentifier: orderer' > "${PWD}/organizations/peerOrganizations/bank1.finance.com/msp/config.yaml"
Register Bank1 Peer1
shell
bin/fabric-ca-client register -d --id.name peer1 --id.secret peer1pw --id.type peer -u https://ca.bank1.finance.com:8054
Register Bank1 Admin
shell
bin/fabric-ca-client register -d --id.name bank1admin --id.secret bank1adminpw --id.type admin --id.attrs "hf.Registrar.Roles=*,hf.Registrar.DelegateRoles=*,hf.AffiliationMgr=true,hf.Registrar.Attributes=*,hf.Revoker=true,hf.GenCRL=true,admin=true:ecert" -u https://ca.bank1.finance.com:8054
Register Bank1 User
shell
bin/fabric-ca-client register -d --id.name user --id.secret userpw --id.type user -u https://ca.bank1.finance.com:8054
Enroll Bank1 Peer1 ECert 证书
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/bank1/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com
export FABRIC_CA_CLIENT_MSPDIR=msp
bin/fabric-ca-client enroll -d -u https://peer1:peer1pw@ca.bank1.finance.com:8054
cp "${PWD}/organizations/peerOrganizations/bank1.finance.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/msp/config.yaml"
Enroll Bank1 Peer1 TLS 证书
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/bank1/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com
export FABRIC_CA_CLIENT_MSPDIR=tls
bin/fabric-ca-client enroll -d -u https://peer1:peer1pw@ca.bank1.finance.com:8054 --enrollment.profile tls --csr.hosts "peer1.bank1.finance.com,localhost,127.0.0.1"
# TLS 根证书
cp "${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/tlscacerts/"* "${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt"
# TLS 签名证书
cp "${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/signcerts/"* "${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt"
# TLS 私钥
cp "${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/keystore/"* "${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key"
Enroll Bank1 Admin ECert 证书
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/bank1/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com
export FABRIC_CA_CLIENT_MSPDIR=msp
bin/fabric-ca-client enroll -d -u https://bank1admin:bank1adminpw@ca.bank1.finance.com:8054
cp "${PWD}/organizations/peerOrganizations/bank1.finance.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp/config.yaml"
Enroll Bank1 User ECert 证书
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/bank1/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/User@bank1.finance.com
export FABRIC_CA_CLIENT_MSPDIR=msp
bin/fabric-ca-client enroll -d -u https://user:userpw@ca.bank1.finance.com:8054
cp "${PWD}/organizations/peerOrganizations/bank1.finance.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/bank1.finance.com/users/User@bank1.finance.com/msp/config.yaml"
3. Bank2组织
Enroll Bank2 CA 管理员
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/bank2/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/bank2.finance.com
bin/fabric-ca-client enroll -d -u https://admin:adminpw@ca.bank2.finance.com:9054
# 用于不同组织通信,由于该CA同时充当组织 CA和 TLS CA,因此直接将CA启动时生成的组织根证书复制到组织级 msp 目录中
mkdir -p "${PWD}/organizations/peerOrganizations/bank2.finance.com/msp/tlscacerts"
cp "${PWD}/organizations/fabric-ca/bank2/ca-cert.pem" "${PWD}/organizations/peerOrganizations/bank2.finance.com/msp/tlscacerts/tlsca.bank2.finance.com-cert.pem"
编写 config.yaml
shell
echo 'NodeOUs:
Enable: true
ClientOUIdentifier:
Certificate: cacerts/ca-bank2-finance-com-9054.pem
OrganizationalUnitIdentifier: client
PeerOUIdentifier:
Certificate: cacerts/ca-bank2-finance-com-9054.pem
OrganizationalUnitIdentifier: peer
AdminOUIdentifier:
Certificate: cacerts/ca-bank2-finance-com-9054.pem
OrganizationalUnitIdentifier: admin
OrdererOUIdentifier:
Certificate: cacerts/ca-bank2-finance-com-9054.pem
OrganizationalUnitIdentifier: orderer' > "${PWD}/organizations/peerOrganizations/bank2.finance.com/msp/config.yaml"
Register Bank2 Peer1
shell
bin/fabric-ca-client register -d --id.name peer1 --id.secret peer1pw --id.type peer -u https://ca.bank2.finance.com:9054
Register Bank2 Admin
shell
bin/fabric-ca-client register -d --id.name bank2admin --id.secret bank2adminpw --id.type admin --id.attrs "hf.Registrar.Roles=*,hf.Registrar.DelegateRoles=*,hf.AffiliationMgr=true,hf.Registrar.Attributes=*,hf.Revoker=true,hf.GenCRL=true,admin=true:ecert" -u https://ca.bank2.finance.com:9054
Register Bank2 User
shell
bin/fabric-ca-client register -d --id.name user --id.secret userpw --id.type user -u https://ca.bank2.finance.com:9054
Enroll Bank2 Peer1 ECert 证书
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/bank2/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com
export FABRIC_CA_CLIENT_MSPDIR=msp
bin/fabric-ca-client enroll -d -u https://peer1:peer1pw@ca.bank2.finance.com:9054
cp "${PWD}/organizations/peerOrganizations/bank2.finance.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/msp/config.yaml"
Enroll Bank2 Peer1 TLS 证书
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/bank2/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com
export FABRIC_CA_CLIENT_MSPDIR=tls
bin/fabric-ca-client enroll -d -u https://peer1:peer1pw@ca.bank2.finance.com:9054 --enrollment.profile tls --csr.hosts "peer1.bank2.finance.com,localhost ,127.0.0.1"
# TLS 根证书
cp "${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/tlscacerts/"* "${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt"
# TLS 签名证书
cp "${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/signcerts/"* "${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.crt"
# TLS 私钥
cp "${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/keystore/"* "${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.key"
Enroll Bank2 Admin ECert 证书
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/bank2/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/bank2.finance.com/users/Admin@bank2.finance.com
export FABRIC_CA_CLIENT_MSPDIR=msp
bin/fabric-ca-client enroll -d -u https://bank2admin:bank2adminpw@ca.bank2.finance.com:9054
cp "${PWD}/organizations/peerOrganizations/bank2.finance.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/bank2.finance.com/users/Admin@bank2.finance.com/msp/config.yaml"
Enroll Bank2 User ECert 证书
shell
export FABRIC_CA_CLIENT_TLS_CERTFILES=${PWD}/organizations/fabric-ca/bank2/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/bank2.finance.com/users/User@bank2.finance.com
export FABRIC_CA_CLIENT_MSPDIR=msp
bin/fabric-ca-client enroll -d -u https://user:userpw@ca.bank2.finance.com:9054
cp "${PWD}/organizations/peerOrganizations/bank2.finance.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/bank2.finance.com/users/User@bank2.finance.com/msp/config.yaml"
6. 生成创世区块
编写 configtx.yaml 用于生成创世区块
shell
mkdir configtx
vim configtx/configtx.yaml
:set paste
yaml
# configtx/configtx.yaml
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
---
################################################################################
#
# ORGANIZATIONS
#
# This section defines the organizational identities that can be referenced
# in the configuration profiles.
#
################################################################################
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.
- &Orderer
# Name is the key by which this org will be referenced in channel
# configuration transactions.
# Name can include alphanumeric characters as well as dots and dashes.
Name: Orderer
# SkipAsForeign can be set to true for org definitions which are to be
# inherited from the orderer system channel during channel creation. This
# is especially useful when an admin of a single org without access to the
# MSP directories of the other orgs wishes to create a channel. Note
# this property must always be set to false for orgs included in block
# creation.
SkipAsForeign: false
# ID is the key by which this org's MSP definition will be referenced.
# ID can include alphanumeric characters as well as dots and dashes.
ID: OrdererMSP
# MSPDir is the filesystem path which contains the MSP configuration.
MSPDir: ../organizations/ordererOrganizations/finance.com/msp
# Policies defines the set of policies at this level of the config tree
# For organization policies, their canonical path is usually
# /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
Policies:
Readers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
# If your MSP is configured with the new NodeOUs, you might
# want to use a more specific rule like the following:
# Rule: "OR('SampleOrg.admin', 'SampleOrg.peer', 'SampleOrg.client')"
Writers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
# If your MSP is configured with the new NodeOUs, you might
# want to use a more specific rule like the following:
# Rule: "OR('SampleOrg.admin', 'SampleOrg.client')"
Admins:
Type: Signature
Rule: "OR('OrdererMSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('OrdererMSP.member')"
# OrdererEndpoints is a list of all orderers this org runs which clients
# and peers may to connect to to push transactions and receive blocks respectively.
OrdererEndpoints:
- "orderer.finance.com:7050"
# AnchorPeers defines the location of peers which can be used for
# cross-org gossip communication.
#
# NOTE: this value should only be set when using the deprecated
# `configtxgen --outputAnchorPeersUpdate` command. It is recommended
# to instead use the channel configuration update process to set the
# anchor peers for each organization.
# AnchorPeers:
# - Host: 127.0.0.1
# Port: 7051
- &Bank1
# DefaultOrg defines the organization which is used in the sampleconfig
# of the fabric.git development environment
Name: Bank1
# ID to load the MSP definition as
ID: Bank1MSP
MSPDir: ../organizations/peerOrganizations/bank1.finance.com/msp
# Policies defines the set of policies at this level of the config tree
# For organization policies, their canonical path is usually
# /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
Policies:
Readers:
Type: Signature
Rule: "OR('Bank1MSP.admin', 'Bank1MSP.peer', 'Bank1MSP.client')"
Writers:
Type: Signature
Rule: "OR('Bank1MSP.admin', 'Bank1MSP.client')"
Admins:
Type: Signature
Rule: "OR('Bank1MSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('Bank1MSP.peer')"
# leave this flag set to true.
AnchorPeers:
# AnchorPeers defines the location of peers which can be used
# for cross org gossip communication. Note, this value is only
# encoded in the genesis block in the Application section context
- Host: peer1.bank1.finance.com
Port: 7051
- &Bank2
# DefaultOrg defines the organization which is used in the sampleconfig
# of the fabric.git development environment
Name: Bank2
# ID to load the MSP definition as
ID: Bank2MSP
MSPDir: ../organizations/peerOrganizations/bank2.finance.com/msp
# Policies defines the set of policies at this level of the config tree
# For organization policies, their canonical path is usually
# /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
Policies:
Readers:
Type: Signature
Rule: "OR('Bank2MSP.admin', 'Bank2MSP.peer', 'Bank2MSP.client')"
Writers:
Type: Signature
Rule: "OR('Bank2MSP.admin', 'Bank2MSP.client')"
Admins:
Type: Signature
Rule: "OR('Bank2MSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('Bank2MSP.peer')"
# leave this flag set to true.
AnchorPeers:
# AnchorPeers defines the location of peers which can be used
# for cross org gossip communication. Note, this value is only
# encoded in the genesis block in the Application section context
- Host: peer1.bank2.finance.com
Port: 9051
################################################################################
#
# 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 for Channel is a catchall flag for behavior which has been
# determined to be desired for all orderers and peers running at the v2.0.0
# level, but which would be incompatible with orderers and peers from
# prior releases.
# 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
# V1.1 for Orderer is a catchall flag for behavior which has been
# determined to be desired for all orderers running at the v1.1.x
# level, but which would be incompatible with orderers from prior releases.
# Prior to enabling V2.0 orderer capabilities, ensure that all
# orderers on a 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 for Application enables the new non-backwards compatible
# features and fixes of fabric v2.0.
# Prior to enabling V2.0 orderer capabilities, ensure that all
# orderers on a channel are at v2.0.0 or later.
V2_0: true
################################################################################
#
# APPLICATION
#
# This section defines the values to encode into a config transaction or
# genesis block for application-related parameters.
#
################################################################################
Application: &ApplicationDefaults
ACLs: &ACLsDefault
# This section provides defaults for policies for various resources
# in the system. These "resources" could be functions on system chaincodes
# (e.g., "GetBlockByNumber" on the "qscc" system chaincode) or other resources
# (e.g.,who can receive Block events). This section does NOT specify the resource's
# definition or API, but just the ACL policy for it.
#
# Users can override these defaults with their own policy mapping by defining the
# mapping under ACLs in their channel definition
#---New Lifecycle System Chaincode (_lifecycle) function to policy mapping for access control--#
# ACL policy for _lifecycle's "CheckCommitReadiness" function
_lifecycle/CheckCommitReadiness: /Channel/Application/Writers
# ACL policy for _lifecycle's "CommitChaincodeDefinition" function
_lifecycle/CommitChaincodeDefinition: /Channel/Application/Writers
# ACL policy for _lifecycle's "QueryChaincodeDefinition" function
_lifecycle/QueryChaincodeDefinition: /Channel/Application/Writers
# ACL policy for _lifecycle's "QueryChaincodeDefinitions" function
_lifecycle/QueryChaincodeDefinitions: /Channel/Application/Writers
#---Lifecycle System Chaincode (lscc) function to policy mapping for access control---#
# ACL policy for lscc's "getid" function
lscc/ChaincodeExists: /Channel/Application/Readers
# ACL policy for lscc's "getdepspec" function
lscc/GetDeploymentSpec: /Channel/Application/Readers
# ACL policy for lscc's "getccdata" function
lscc/GetChaincodeData: /Channel/Application/Readers
# ACL Policy for lscc's "getchaincodes" function
lscc/GetInstantiatedChaincodes: /Channel/Application/Readers
#---Query System Chaincode (qscc) function to policy mapping for access control---#
# ACL policy for qscc's "GetChainInfo" function
qscc/GetChainInfo: /Channel/Application/Readers
# ACL policy for qscc's "GetBlockByNumber" function
qscc/GetBlockByNumber: /Channel/Application/Readers
# ACL policy for qscc's "GetBlockByHash" function
qscc/GetBlockByHash: /Channel/Application/Readers
# ACL policy for qscc's "GetTransactionByID" function
qscc/GetTransactionByID: /Channel/Application/Readers
# ACL policy for qscc's "GetBlockByTxID" function
qscc/GetBlockByTxID: /Channel/Application/Readers
#---Configuration System Chaincode (cscc) function to policy mapping for access control---#
# ACL policy for cscc's "GetConfigBlock" function
cscc/GetConfigBlock: /Channel/Application/Readers
# ACL policy for cscc's "GetChannelConfig" function
cscc/GetChannelConfig: /Channel/Application/Readers
#---Miscellaneous peer function to policy mapping for access control---#
# ACL policy for invoking chaincodes on peer
peer/Propose: /Channel/Application/Writers
# ACL policy for chaincode to chaincode invocation
peer/ChaincodeToChaincode: /Channel/Application/Writers
#---Events resource to policy mapping for access control###---#
# ACL policy for sending block events
event/Block: /Channel/Application/Readers
# ACL policy for sending filtered block events
event/FilteredBlock: /Channel/Application/Readers
# Organizations lists the orgs participating 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/<PolicyName>
Policies: &ApplicationDefaultPolicies
LifecycleEndorsement:
Type: ImplicitMeta
Rule: "MAJORITY Endorsement"
Endorsement:
Type: ImplicitMeta
Rule: "MAJORITY Endorsement"
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
# Capabilities describes the application level capabilities, see the
# dedicated Capabilities section elsewhere in this file for a full
# description
Capabilities:
<<: *ApplicationCapabilities
################################################################################
#
# 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.
# Available types are "solo", "kafka" and "etcdraft".
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.finance.com:7050
# 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.
# The orderer views messages opaquely, but typically, messages may
# be considered to be Fabric transactions. The 'batch' is the group
# of messages in the 'data' field of the block. Blocks will be a few kb
# larger than the batch size, when signatures, hashes, and other metadata
# is applied.
BatchSize:
# Max Message Count: The maximum number of messages to permit in a
# batch. No block will contain more than this number of messages.
MaxMessageCount: 500
# Absolute Max Bytes: The absolute maximum number of bytes allowed for
# the serialized messages in a batch. The maximum block size is this value
# plus the size of the associated metadata (usually a few KB depending
# upon the size of the signing identities). Any transaction larger than
# this value will be rejected by ordering.
# It is recommended not to exceed 49 MB, given the default grpc max message size of 100 MB
# configured on orderer and peer nodes (and allowing for message expansion during communication).
AbsoluteMaxBytes: 10 MB
# Preferred Max Bytes: The preferred maximum number of bytes allowed
# for the serialized messages in a batch. Roughly, this field may be considered
# the best effort maximum size of a batch. A batch will fill with messages
# until this size is reached (or the max message count, or batch timeout is
# exceeded). If adding a new message to the batch would cause the batch to
# exceed the preferred max bytes, then the current batch is closed and written
# to a block, and a new batch containing the new message is created. If a
# message larger than the preferred max bytes is received, then its batch
# will contain only that message. Because messages may be larger than
# preferred max bytes (up to AbsoluteMaxBytes), some batches may exceed
# the preferred max bytes, but will always contain exactly one transaction.
PreferredMaxBytes: 2 MB
# Max Channels is the maximum number of channels to allow on the ordering
# network. When set to 0, this implies no maximum number of channels.
MaxChannels: 0
Kafka:
# Brokers: A list of Kafka brokers to which the orderer connects. Edit
# this list to identify the brokers of the ordering service.
# NOTE: Use IP:port notation.
Brokers:
- kafka0:9092
- kafka1:9092
- kafka2:9092
# EtcdRaft defines configuration which must be set when the "etcdraft"
# orderertype is chosen.
EtcdRaft:
# The set of Raft replicas for this network. For the etcd/raft-based
# implementation, we expect every replica to also be an OSN. Therefore,
# a subset of the host:port items enumerated in this list should be
# replicated under the Orderer.Addresses key above.
Consenters:
- Host: orderer.finance.com
Port: 7050
ClientTLSCert: ../organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/tls/server.crt
ServerTLSCert: ../organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/tls/server.crt
# Options to be specified for all the etcd/raft nodes. The values here
# are the defaults for all new channels and can be modified on a
# per-channel basis via configuration updates.
Options:
# TickInterval is the time interval between two Node.Tick invocations.
TickInterval: 500ms
# ElectionTick is the number of Node.Tick invocations that must pass
# between elections. That is, if a follower does not receive any
# message from the leader of current term before ElectionTick has
# elapsed, it will become candidate and start an election.
# ElectionTick must be greater than HeartbeatTick.
ElectionTick: 10
# HeartbeatTick is the number of Node.Tick invocations that must
# pass between heartbeats. That is, a leader sends heartbeat
# messages to maintain its leadership every HeartbeatTick ticks.
HeartbeatTick: 1
# MaxInflightBlocks limits the max number of in-flight append messages
# during optimistic replication phase.
MaxInflightBlocks: 5
# SnapshotIntervalSize defines number of bytes per which a snapshot is taken
SnapshotIntervalSize: 16 MB
# Organizations lists the orgs participating 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/<PolicyName>
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"
# Capabilities describes the orderer level capabilities, see the
# dedicated Capabilities section elsewhere in this file for a full
# description
Capabilities:
<<: *OrdererCapabilities
################################################################################
#
# 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/<PolicyName>
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
################################################################################
#
# PROFILES
#
# Different configuration profiles may be encoded here to be specified as
# parameters to the configtxgen tool. The profiles which specify consortiums
# are to be used for generating the orderer genesis block. With the correct
# consortium members defined in the orderer genesis block, channel creation
# requests may be generated with only the org member names and a consortium
# name.
#
################################################################################
Profiles:
SystemGenesis:
<<: *ChannelDefaults
Orderer:
<<: *OrdererDefaults
Organizations:
- *Orderer
Capabilities:
<<: *OrdererCapabilities
Consortiums:
FinanceConsortium:
Organizations:
- *Bank1
- *Bank2
CrossBorderPaymentChannel:
Consortium: FinanceConsortium
<<: *ChannelDefaults
Application:
<<: *ApplicationDefaults
Organizations:
- *Bank1
- *Bank2
Capabilities:
<<: *ApplicationCapabilities
生成创世区块文件
shell
bin/configtxgen -configPath ./configtx -profile SystemGenesis -channelID system-channel -outputBlock ./system-genesis-block/genesis.block
7. 生成通道文件
shell
bin/configtxgen -configPath ./configtx -profile CrossBorderPaymentChannel -outputCreateChannelTx ./channel-artifacts/cross-border-payment-channel.tx -channelID cross-border-payment-channel
8. 生成锚节点配置更新文件
shell
# Bank1 锚节点配置更新文件
bin/configtxgen -configPath ./configtx -profile CrossBorderPaymentChannel -outputAnchorPeersUpdate ./channel-artifacts/Bank1MSPanchors.tx -channelID cross-border-payment-channel -asOrg Bank1
# Bank2 锚节点配置更新文件
bin/configtxgen -configPath ./configtx -profile CrossBorderPaymentChannel -outputAnchorPeersUpdate ./channel-artifacts/Bank2MSPanchors.tx -channelID cross-border-payment-channel -asOrg Bank2
9. 部署 Orderer 和 Peer 节点
编写 docker-compose-finance.yaml
shell
vim docker/docker-compose-finance.yaml
:set paste
yaml
# docker/docker-compose-finance.yaml
# version: '3.0'
volumes:
orderer.finance.com:
peer1.bank1.finance.com:
peer1.bank2.finance.com:
networks:
orderer:
name: orderer
bank1:
name: bank1
bank2:
name: bank2
finance:
name: finance
services:
orderer.finance.com:
container_name: orderer.finance.com
image: hyperledger/fabric-orderer:2.4.1
restart: always
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
- ORDERER_GENERAL_GENESISMETHOD=file
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
# 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_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]
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: orderer
volumes:
- ../system-genesis-block/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ../organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/msp:/var/hyperledger/orderer/msp
- ../organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/tls:/var/hyperledger/orderer/tls
- orderer.finance.com:/var/hyperledger/production/orderer
ports:
- 7050:7050
networks:
- finance
- orderer
peer1.bank1.finance.com:
container_name: peer1.bank1.finance.com
image: hyperledger/fabric-peer:2.4.1
restart: always
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=bank1
- FABRIC_LOGGING_SPEC=INFO
#- FABRIC_LOGGING_SPEC=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
# Peer specific variabes
- CORE_PEER_ID=peer1.bank1.finance.com
- CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
- CORE_PEER_LISTENADDRESS=0.0.0.0:7051
- CORE_PEER_CHAINCODEADDRESS=peer1.bank1.finance.com:7052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
- CORE_PEER_GOSSIP_BOOTSTRAP=peer1.bank1.finance.com:7051
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.bank1.finance.com:7051
- CORE_PEER_LOCALMSPID=Bank1MSP
- CORE_CHAINCODE_GOLANG_RUNTIME=hyperledger/fabric-baseos:2.4.1
- CORE_CHAINCODE_JAVA_RUNTIME=hyperledger/fabric-javaenv:2.4.1
- CORE_CHAINCODE_NODE_RUNTIME=hyperledger/fabric-nodeenv:2.4.1
volumes:
- /var/run/:/host/var/run/
- ../organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/msp:/etc/hyperledger/fabric/msp
- ../organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls:/etc/hyperledger/fabric/tls
- peer1.bank1.finance.com:/var/hyperledger/production
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
ports:
- 7051:7051
networks:
- finance
- bank1
peer1.bank2.finance.com:
container_name: peer1.bank2.finance.com
image: hyperledger/fabric-peer:2.4.1
restart: always
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=bank2
- FABRIC_LOGGING_SPEC=INFO
#- FABRIC_LOGGING_SPEC=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
# Peer specific variabes
- CORE_PEER_ID=peer1.bank2.finance.com
- CORE_PEER_ADDRESS=peer1.bank2.finance.com:9051
- CORE_PEER_LISTENADDRESS=0.0.0.0:9051
- CORE_PEER_CHAINCODEADDRESS=peer1.bank2.finance.com:9052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:9052
- CORE_PEER_GOSSIP_BOOTSTRAP=peer1.bank2.finance.com:9051
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.bank2.finance.com:9051
- CORE_PEER_LOCALMSPID=Bank2MSP
- CORE_CHAINCODE_GOLANG_RUNTIME=hyperledger/fabric-baseos:2.4.1
- CORE_CHAINCODE_JAVA_RUNTIME=hyperledger/fabric-javaenv:2.4.1
- CORE_CHAINCODE_NODE_RUNTIME=hyperledger/fabric-nodeenv:2.4.1
volumes:
- /var/run/:/host/var/run/
- ../organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/msp:/etc/hyperledger/fabric/msp
- ../organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls:/etc/hyperledger/fabric/tls
- peer1.bank2.finance.com:/var/hyperledger/production
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
ports:
- 9051:9051
networks:
- finance
- bank2
我们知道在 Fabric 中支持两种类型的状态数据库。
- LevelDB 是嵌入对等节点的默认状态数据库。LevelDB 将链码数据存储为简单的键值对,仅支持键、键范围和复合键查询。
- CouchDB 是一个可选的备用状态数据库,它允许您将分类帐上的数据建模为 JSON,并针对数据值而不是键发出丰富的查询。
我们在这里不使用Peer节点嵌入的 LevelDB,而是使用 CouchDB 作为数据库。
编写 docker-compose-couchdb.yaml
shell
vim docker/docker-compose-couchdb.yaml
:set paste
yaml
# docker/docker-compose-couchdb.yaml
# version: '3.0'
networks:
bank1:
name: bank1
bank2:
name: bank2
finance:
name: finance
services:
peer1.bank1.couchdb.com:
hostname: peer1.bank1.couchdb.com
container_name: peer1.bank1.couchdb.com
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:
- finance
- bank1
peer1.bank1.finance.com:
environment:
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=peer1.bank1.couchdb.com:5984
# The CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME and CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD
# provide the credentials for ledger to connect to CouchDB. The username and password must
# match the username and password set for the associated CouchDB.
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=adminpw
depends_on:
- peer1.bank1.couchdb.com
peer1.bank2.couchdb.com:
hostname: peer1.bank2.couchdb.com
container_name: peer1.bank2.couchdb.com
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:
- finance
- bank2
peer1.bank2.finance.com:
environment:
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=peer1.bank2.couchdb.com:5984
# The CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME and CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD
# provide the credentials for ledger to connect to CouchDB. The username and password must
# match the username and password set for the associated CouchDB.
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=adminpw
depends_on:
- peer1.bank2.couchdb.com
使用 docker-compose 命令启动 Orderer、Peer 和 CouchDB
shell
docker compose -f docker/docker-compose-finance.yaml -f docker/docker-compose-couchdb.yaml up -d
10. 创建并加入通道
Bank1 Peer1 创建跨境支付通道
shell
# Bank1 创建通道
export FABRIC_CFG_PATH=${PWD}/config
export ORDERER_ADDRESS=orderer.finance.com:7050
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/msp/tlscacerts/tlsca.orderer.finance.com-cert.pem
export CHANNEL_NAME=cross-border-payment-channel
export CORE_PEER_LOCALMSPID=Bank1MSP
export CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp
cd channel-artifacts
../bin/peer channel create -o ${ORDERER_ADDRESS} -c ${CHANNEL_NAME} -f ${CHANNEL_NAME}.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA
cd ..
Bank1 Peer1 加入通道
shell
export CORE_PEER_LOCALMSPID=Bank1MSP
export CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp
bin/peer channel join -b ./channel-artifacts/${CHANNEL_NAME}.block
Bank2 Peer1 加入通道
shell
export CORE_PEER_LOCALMSPID=Bank2MSP
export CORE_PEER_ADDRESS=peer1.bank2.finance.com:9051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank2.finance.com/users/Admin@bank2.finance.com/msp
bin/peer channel join -b ./channel-artifacts/${CHANNEL_NAME}.block
Bank1 Peer1 更新锚节点
shell
export CORE_PEER_LOCALMSPID=Bank1MSP
export CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp
bin/peer channel update -o ${ORDERER_ADDRESS} -c ${CHANNEL_NAME} -f ./channel-artifacts/Bank1MSPanchors.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA
Bank2 Peer1 更新锚节点
shell
export CORE_PEER_LOCALMSPID=Bank2MSP
export CORE_PEER_ADDRESS=peer1.bank2.finance.com:9051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank2.finance.com/users/Admin@bank2.finance.com/msp
bin/peer channel update -o ${ORDERER_ADDRESS} -c ${CHANNEL_NAME} -f ./channel-artifacts/Bank2MSPanchors.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA
11. 测试网络
测试链码内容
java
@Contract(
name = "Cross Border Payment Contract",
info = @Info(
title = "Cross Border Payment Contract",
description = "Hyperledger FabricCross Border Payment Contract",
version = "1.0.0-SNAPSHOT",
license = @License(
name = "Apache 2.0 License",
url = "http://www.apache.org/licenses/LICENSE-2.0.html"
),
contact = @Contact(
email = "joe@simnectz.com",
name = "Joe",
url = "https://blockchain.simnectz.com"
)
)
)
@Default
public class SimpleContract implements ContractInterface {
private final static Logger log = LoggerFactory.getLogger(SimpleContract.class);
@Transaction(name = "Init", intent = Transaction.TYPE.SUBMIT)
public String init(final Context context) {
ChaincodeStub chaincodeStub = context.getStub();
long transactionTimestamp = chaincodeStub.getTxTimestamp().toEpochMilli();
AccountContext account1 = new AccountContext("CN0000000001", BigDecimal.valueOf(100));
AccountContext account2 = new AccountContext("CN0000000002", BigDecimal.valueOf(100));
chaincodeStub.putStringState(account1.getAccountNumber(), JSON.toJSONString(account1));
chaincodeStub.putStringState(account2.getAccountNumber(), JSON.toJSONString(account2));
return JSON.toJSONString(new ResultUtil<>(
20000, "Chaincode initialization successfully.", transactionTimestamp));
}
@Transaction(name = "Transfer", intent = Transaction.TYPE.SUBMIT)
public String invoke(
final Context context,
final String fromAccountNumber,
final String toAccountNumber,
final String transferAmount
) {
ChaincodeStub chaincodeStub = context.getStub();
long transactionTimestamp = chaincodeStub.getTxTimestamp().toEpochMilli();
// validation fromAccountNumber
if (fromAccountNumber == null || "".equals(fromAccountNumber) ||
fromAccountNumber.length() == 0 || accountNotExists(context, fromAccountNumber)
) {
return JSON.toJSONString(new ResultUtil<>(
40000,
String.format("Wrong account number transferred out: '%s'", fromAccountNumber),
transactionTimestamp
));
}
// validation toAccountNumber
if (toAccountNumber == null || "".equals(toAccountNumber) ||
toAccountNumber.length() == 0 || accountNotExists(context, toAccountNumber)
) {
return JSON.toJSONString(new ResultUtil<>(
40000,
String.format("Wrong account number transferred in: '%s'", toAccountNumber),
transactionTimestamp
));
}
AccountContext fromAccountContext = JSON.parseObject(
chaincodeStub.getStringState(fromAccountNumber), AccountContext.class);
// validation fromAccountNumber balance
BigDecimal transferAmountNumber;
try {
transferAmountNumber = new BigDecimal(transferAmount);
} catch (Exception e) {
e.printStackTrace();
return JSON.toJSONString(new ResultUtil<>(
40000,
String.format("Incorrect transfer amount: '%s'", transferAmount),
transactionTimestamp
));
}
if (fromAccountContext.getBalance().compareTo(transferAmountNumber) < 0) {
return JSON.toJSONString(new ResultUtil<>(
40000,
"Sorry, your credit is running low.",
transactionTimestamp));
}
AccountContext toAccountContext = JSON.parseObject(
chaincodeStub.getStringState(toAccountNumber), AccountContext.class);
// Execute transfer
fromAccountContext.setBalance(fromAccountContext.getBalance().subtract(transferAmountNumber));
toAccountContext.setBalance(toAccountContext.getBalance().add(transferAmountNumber));
chaincodeStub.putStringState(fromAccountContext.getAccountNumber(), JSON.toJSONString(fromAccountContext));
chaincodeStub.putStringState(toAccountContext.getAccountNumber(), JSON.toJSONString(toAccountContext));
return JSON.toJSONString(new ResultUtil<>(
20000,
"Successful Operation",
transactionTimestamp
));
}
@Transaction(name = "QueryBalance", intent = Transaction.TYPE.EVALUATE)
public String invoke(
final Context context,
final String accountNumber
) {
ChaincodeStub chaincodeStub = context.getStub();
long transactionTimestamp = chaincodeStub.getTxTimestamp().toEpochMilli();
// validation toAccountNumber
if (accountNumber == null || "".equals(accountNumber) ||
accountNumber.length() == 0 || accountNotExists(context, accountNumber)
) {
return JSON.toJSONString(new ResultUtil<>(
40000,
String.format("Wrong account number: %s", accountNumber),
transactionTimestamp
));
}
// query account information
AccountContext accountContext = JSON.parseObject(
chaincodeStub.getStringState(accountNumber), AccountContext.class);
return JSON.toJSONString(new ResultUtil<>(
20000,
"Successful Operation",
accountContext, transactionTimestamp
));
}
private boolean accountNotExists(final Context context, final String accountNumber) {
return context.getStub().getStringState(accountNumber) == null;
}
}
创建链码 (chaincode) 存放的目录
shell
mkdir -p chaincode/network-test-chaincode/java
mkdir temp
将我们准备好的测试链码上传到虚拟的的 /home/hyperledger/fabric/finance/chaincode/network-test-chaincode/java
目录下
打包链码
shell
export FABRIC_CFG_PATH=${PWD}/config # 切换到bank1支付通道
export ORDERER_ADDRESS=orderer.finance.com:7050
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/finance.com/orderers/orderer.finance.com/msp/tlscacerts/tlsca.orderer.finance.com-cert.pem
export CHANNEL_NAME=cross-border-payment-channel
export CC_LANG=java
export CC_PATH=${PWD}/chaincode/network-test-chaincode/java
export CC_NAME=network-test-chaincode
export CC_VERSION=v1.0.0
export CC_LABEL=${CC_NAME}_${CC_VERSION}
export CC_SEQ=1
export CC_POLICY="OR('Bank1MSP.peer', 'Bank2MSP.peer')"
bin/peer lifecycle chaincode package ./temp/${CC_LABEL}.tar.gz --path ${CC_PATH} --lang $CC_LANG --label ${CC_LABEL}
安装链码
Bank1 Peer1 安装链码
shell
export CORE_PEER_LOCALMSPID=Bank1MSP
export CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp
bin/peer lifecycle chaincode install ./temp/${CC_LABEL}.tar.gz
Bank2 Peer1 安装链码
shell
export CORE_PEER_LOCALMSPID=Bank2MSP
export CORE_PEER_ADDRESS=peer1.bank2.finance.com:9051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank2.finance.com/users/Admin@bank2.finance.com/msp
bin/peer lifecycle chaincode install ./temp/${CC_LABEL}.tar.gz
Bank1 Peer1 查询链码ID
shell
export CORE_PEER_LOCALMSPID=Bank1MSP
export CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp
bin/peer lifecycle chaincode queryinstalled --output json
批准链码
Bank1 Peer1 批准链码
shell
export CORE_PEER_LOCALMSPID=Bank1MSP
export CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp
### 注意!!!这块的PACKAGE_ID换成上面查出来的package_id
export PACKAGE_ID=network-test-chaincode_v1.0.0:f9a410122444e51da06380b2065db5ca2ac324bec6af75d91384b7543ad80bc5
bin/peer lifecycle chaincode approveformyorg \
-o ${ORDERER_ADDRESS} \
--ordererTLSHostnameOverride orderer.finance.com \
--tls $CORE_PEER_TLS_ENABLED \
--cafile $ORDERER_CA \
--channelID $CHANNEL_NAME \
--name ${CC_NAME} \
--version ${CC_VERSION} \
--init-required \
--package-id ${PACKAGE_ID} \
--sequence $CC_SEQ \
--waitForEvent \
--signature-policy "$CC_POLICY"
Bank1 Peer1查询批准的链码
shell
bin/peer lifecycle chaincode checkcommitreadiness \
--channelID $CHANNEL_NAME \
--name ${CC_NAME} \
--version ${CC_VERSION} \
--sequence $CC_SEQ \
--output json \
--init-required \
--signature-policy "$CC_POLICY"
Bank2 Peer1 批准链码
shell
export CORE_PEER_LOCALMSPID=Bank2MSP
export CORE_PEER_ADDRESS=peer1.bank2.finance.com:9051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank2.finance.com/users/Admin@bank2.finance.com/msp
### 注意!!!这块的PACKAGE_ID换成上面查出来的package_id
export PACKAGE_ID=network-test-chaincode_v1.0.0:f9a410122444e51da06380b2065db5ca2ac324bec6af75d91384b7543ad80bc5
bin/peer lifecycle chaincode approveformyorg \
-o ${ORDERER_ADDRESS} \
--ordererTLSHostnameOverride orderer.finance.com \
--tls $CORE_PEER_TLS_ENABLED \
--cafile $ORDERER_CA \
--channelID $CHANNEL_NAME \
--name ${CC_NAME} \
--version ${CC_VERSION} \
--init-required \
--package-id ${PACKAGE_ID} \
--sequence $CC_SEQ \
--waitForEvent \
--signature-policy "$CC_POLICY"
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
Bank2 Peer1查询批准的链码
shell
bin/peer lifecycle chaincode checkcommitreadiness \
--channelID $CHANNEL_NAME \
--name ${CC_NAME} \
--version ${CC_VERSION} \
--sequence $CC_SEQ \
--output json \
--init-required \
--signature-policy "$CC_POLICY"
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
提交链码
只需要任意一个组织提交即可,这里使用 Bank1 组织提交
shell
export CORE_PEER_LOCALMSPID=Bank1MSP
export CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp
# 提交链码需要两个组织的节点的地址和TLS根证书
export PEER1_BANK1_ADDRESS=peer1.bank1.finance.com:7051
export PEER1_BANK2_ADDRESS=peer1.bank2.finance.com:9051
export PEER1_BANK1_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export PEER1_BANK2_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
bin/peer lifecycle chaincode commit \
-o ${ORDERER_ADDRESS} \
-C $CHANNEL_NAME \
--ordererTLSHostnameOverride orderer.finance.com \
--tls $CORE_PEER_TLS_ENABLED \
--cafile $ORDERER_CA \
--peerAddresses $PEER1_BANK1_ADDRESS \
--tlsRootCertFiles $PEER1_BANK1_TLS_ROOTCERT_FILE \
--peerAddresses $PEER1_BANK2_ADDRESS \
--tlsRootCertFiles $PEER1_BANK2_TLS_ROOTCERT_FILE \
--name ${CC_NAME} \
--version ${CC_VERSION} \
--sequence $CC_SEQ \
--init-required \
--signature-policy "$CC_POLICY"
再次查看 docker 容器,我们会发现会多出来两个环境,这就是两个节点的智能合约运行的容器
调用链码
初始化链码
此操作只需要任意组织完成即可
shell
export FABRIC_CFG_PATH=${PWD}/config
export CHANNEL_NAME=cross-border-payment-channel
export CORE_PEER_LOCALMSPID=Bank1MSP
export CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp
export PEER1_BANK1_ADDRESS=peer1.bank1.finance.com:7051
export PEER1_BANK2_ADDRESS=peer1.bank2.finance.com:9051
export PEER1_BANK1_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export PEER1_BANK2_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
bin/peer chaincode invoke \
-o ${ORDERER_ADDRESS} \
--ordererTLSHostnameOverride orderer.finance.com \
--tls $CORE_PEER_TLS_ENABLED \
--cafile $ORDERER_CA \
-C $CHANNEL_NAME \
-n ${CC_NAME} \
--peerAddresses $PEER1_BANK1_ADDRESS \
--tlsRootCertFiles $PEER1_BANK1_TLS_ROOTCERT_FILE \
--peerAddresses $PEER1_BANK2_ADDRESS \
--tlsRootCertFiles $PEER1_BANK2_TLS_ROOTCERT_FILE \
--isInit \
-c '{"Function":"Init","Args":[]}'
看到上图红色标注的内容说明链码初始化成功
查询初始账户余额 Bank1 Peer1
shell
export CORE_PEER_LOCALMSPID=Bank1MSP
export CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp
export PEER1_BANK1_ADDRESS=peer1.bank1.finance.com:7051
export PEER1_BANK2_ADDRESS=peer1.bank2.finance.com:9051
export PEER1_BANK1_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export PEER1_BANK2_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
# Bank1 Peer1 查询账户 CN0000000001
bin/peer chaincode invoke \
-o ${ORDERER_ADDRESS} \
--ordererTLSHostnameOverride orderer.finance.com \
--tls $CORE_PEER_TLS_ENABLED \
--cafile $ORDERER_CA \
-C $CHANNEL_NAME \
-n ${CC_NAME} \
--peerAddresses $PEER1_BANK1_ADDRESS \
--tlsRootCertFiles $PEER1_BANK1_TLS_ROOTCERT_FILE \
--peerAddresses $PEER1_BANK2_ADDRESS \
--tlsRootCertFiles $PEER1_BANK2_TLS_ROOTCERT_FILE \
-c '{"Function":"QueryBalance","Args":["CN0000000001"]}'
查询初始账户余额 Bank2 Peer1
shell
export CORE_PEER_LOCALMSPID=Bank2MSP
export CORE_PEER_ADDRESS=peer1.bank2.finance.com:9051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank2.finance.com/users/Admin@bank2.finance.com/msp
export PEER1_BANK1_ADDRESS=peer1.bank1.finance.com:7051
export PEER1_BANK2_ADDRESS=peer1.bank2.finance.com:9051
export PEER1_BANK1_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export PEER1_BANK2_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
# Bank2 Peer1 查询账户 CN0000000002
bin/peer chaincode invoke \
-o ${ORDERER_ADDRESS} \
--ordererTLSHostnameOverride orderer.finance.com \
--tls $CORE_PEER_TLS_ENABLED \
--cafile $ORDERER_CA \
-C $CHANNEL_NAME \
-n ${CC_NAME} \
--peerAddresses $PEER1_BANK1_ADDRESS \
--tlsRootCertFiles $PEER1_BANK1_TLS_ROOTCERT_FILE \
--peerAddresses $PEER1_BANK2_ADDRESS \
--tlsRootCertFiles $PEER1_BANK2_TLS_ROOTCERT_FILE \
-c '{"Function":"QueryBalance","Args":["CN0000000002"]}'
执行转账操作
账户:CN0000000001 向 CN0000000002 转账 50
shell
export CORE_PEER_LOCALMSPID=Bank1MSP
export CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp
export PEER1_BANK1_ADDRESS=peer1.bank1.finance.com:7051
export PEER1_BANK2_ADDRESS=peer1.bank2.finance.com:9051
export PEER1_BANK1_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export PEER1_BANK2_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
# 账户:CN0000000001 向 CN0000000002 转账 50
bin/peer chaincode invoke \
-o ${ORDERER_ADDRESS} \
--ordererTLSHostnameOverride orderer.finance.com \
--tls $CORE_PEER_TLS_ENABLED \
--cafile $ORDERER_CA \
-C $CHANNEL_NAME \
-n ${CC_NAME} \
--peerAddresses $PEER1_BANK1_ADDRESS \
--tlsRootCertFiles $PEER1_BANK1_TLS_ROOTCERT_FILE \
--peerAddresses $PEER1_BANK2_ADDRESS \
--tlsRootCertFiles $PEER1_BANK2_TLS_ROOTCERT_FILE \
-c '{"Function":"Transfer","Args":["CN0000000001","CN0000000002","50"]}'
Bank1 Peer1 再次查询账户余额
shell
export CORE_PEER_LOCALMSPID=Bank1MSP
export CORE_PEER_ADDRESS=peer1.bank1.finance.com:7051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank1.finance.com/users/Admin@bank1.finance.com/msp
export PEER1_BANK1_ADDRESS=peer1.bank1.finance.com:7051
export PEER1_BANK2_ADDRESS=peer1.bank2.finance.com:9051
export PEER1_BANK1_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export PEER1_BANK2_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
# Bank1 Peer1 查询账户 CN0000000001
bin/peer chaincode invoke \
-o ${ORDERER_ADDRESS} \
--ordererTLSHostnameOverride orderer.finance.com \
--tls $CORE_PEER_TLS_ENABLED \
--cafile $ORDERER_CA \
-C $CHANNEL_NAME \
-n ${CC_NAME} \
--peerAddresses $PEER1_BANK1_ADDRESS \
--tlsRootCertFiles $PEER1_BANK1_TLS_ROOTCERT_FILE \
--peerAddresses $PEER1_BANK2_ADDRESS \
--tlsRootCertFiles $PEER1_BANK2_TLS_ROOTCERT_FILE \
-c '{"Function":"QueryBalance","Args":["CN0000000001"]}'
Bank2 Peer1 再次查询账户余额
shell
export CORE_PEER_LOCALMSPID=Bank2MSP
export CORE_PEER_ADDRESS=peer1.bank2.finance.com:9051
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/server.key
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/bank2.finance.com/users/Admin@bank2.finance.com/msp
export PEER1_BANK1_ADDRESS=peer1.bank1.finance.com:7051
export PEER1_BANK2_ADDRESS=peer1.bank2.finance.com:9051
export PEER1_BANK1_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank1.finance.com/peers/peer1.bank1.finance.com/tls/ca.crt
export PEER1_BANK2_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/bank2.finance.com/peers/peer1.bank2.finance.com/tls/ca.crt
# Bank2 Peer1 查询账户 CN0000000002
bin/peer chaincode invoke \
-o ${ORDERER_ADDRESS} \
--ordererTLSHostnameOverride orderer.finance.com \
--tls $CORE_PEER_TLS_ENABLED \
--cafile $ORDERER_CA \
-C $CHANNEL_NAME \
-n ${CC_NAME} \
--peerAddresses $PEER1_BANK1_ADDRESS \
--tlsRootCertFiles $PEER1_BANK1_TLS_ROOTCERT_FILE \
--peerAddresses $PEER1_BANK2_ADDRESS \
--tlsRootCertFiles $PEER1_BANK2_TLS_ROOTCERT_FILE \
-c '{"Function":"QueryBalance","Args":["CN0000000002"]}'
到这里我们的网络 Hyperledger Fabric 网络搭建就已经完成了。
感谢大家的观看!!!创作不易,如果觉得我写的好的话麻烦点点赞👍支持一下,谢谢!!!