搭建流程
环境搭建
一、自行下载虚拟机软件(这里使用VirtualBox)
二、下载iso光盘CentOS Linux release 7.8.2003 (Core)
http://mirrors.aliyun.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2003.iso
三、创建虚拟机,桥接网络,内存4G,硬盘80G,挂载光盘,启动虚拟机。
四、配置linux
# 关闭防火墙
systemctl stop firewalld && systemctl disable firewalld
#CentOS关闭selinux
setenforce 0
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/sysconfig/selinux
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/selinux/config
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/sysconfig/selinux
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/selinux/config
# 修改时区
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 修改系统语言环境
echo 'LANG="en_US.UTF-8"' >> /etc/profile;source /etc/profile
# 设置dns
echo "nameserver 8.8.8.8" > /etc/resolv.conf
# 设置yum源
sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
echo '
[base]
name=CentOS-$releasever - Base - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
#released updates
[updates]
name=CentOS-$releasever - Updates - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
#contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Contrib - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
' > /etc/yum.repos.d/CentOS-Base.repo
# 更新内核与安装包
sudo yum update -y
# 重新缓存
yum clean all && yum makecache
五、安装docker-ce
# 安装docker-ce依赖包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2 bash-completion
# 添加docker-ce yum源地址
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 安装docker-ce
yum -y install docker-ce
# 修改docker配置文件,添加docker镜像加速仓库,存储格式等
mkdir -p /etc/docker
echo '
{
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 5,
"registry-mirrors": ["https://7bezldxe.mirror.aliyuncs.com/"],
"storage-driver": "overlay2",
"storage-opts": ["overlay2.override_kernel_check=true"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
' > /etc/docker/daemon.json
# 启动docker
systemctl start docker
# 检查状态及版本
systemctl status docker
docker version
# 设置开机启动
sudo systemctl enable docker
六、安装git
yum -y install git
七、安装docker-compose
# 安装epel源
yum -y install epel-release
如何不可用vim 一下/etc/yum.repos.d/epel.repo改为如下
[epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch
#metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
[epel-debuginfo]
name=Extra Packages for Enterprise Linux 7 - $basearch - Debug
#baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch/debug
metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-7&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=1
[epel-source]
name=Extra Packages for Enterprise Linux 7 - $basearch - Source
#baseurl=http://download.fedoraproject.org/pub/epel/7/SRPMS
metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-source-7&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=1
#安装python-pip包
yum -y install python-pip
# 对安装好的pip进行升级
pip install --upgrade pip
# 查看
pip -V
# 安装docker-compose
pip --default-timeout=200 install -U docker-compose
# 查看
docker-compose -version
八、git下载fabric源码,并切换master分支
mkdir -p /opt/gopath/src/github.com/hyperledger
cd /opt/gopath/src/github.com/hyperledger
git clone https://github.com/hyperledger/fabric.git
cd /opt/gopath/src/github.com/hyperledger/fabric
git branch
如git clone出现错误:Peer reports incompatible or unsupported protocol version.
请更新yum update -y nss curl libcurl
九、根据源码脚本拉取镜像、二进制文件等
cd /opt/gopath/src/github.com/hyperledger/fabric/scripts
./bootstrap.sh
# 查看
docker images
------------------------------------------------------------------------------------------------
REPOSITORY TAG IMAGE ID CREATED SIZE
hyperledger/fabric-ca 1.4 dbbc768aec79 5 weeks ago 158MB
hyperledger/fabric-ca 1.4.9 dbbc768aec79 5 weeks ago 158MB
hyperledger/fabric-ca latest dbbc768aec79 5 weeks ago 158MB
hyperledger/fabric-tools 2.2 e9b802fadb41 5 weeks ago 519MB
hyperledger/fabric-tools 2.2.1 e9b802fadb41 5 weeks ago 519MB
hyperledger/fabric-tools latest e9b802fadb41 5 weeks ago 519MB
hyperledger/fabric-peer 2.2 ece149884124 5 weeks ago 55MB
hyperledger/fabric-peer 2.2.1 ece149884124 5 weeks ago 55MB
hyperledger/fabric-peer latest ece149884124 5 weeks ago 55MB
hyperledger/fabric-orderer 2.2 78a16ddd2cf4 5 weeks ago 38.4MB
hyperledger/fabric-orderer 2.2.1 78a16ddd2cf4 5 weeks ago 38.4MB
hyperledger/fabric-orderer latest 78a16ddd2cf4 5 weeks ago 38.4MB
hyperledger/fabric-ccenv 2.2 8e554c280cac 5 weeks ago 586MB
hyperledger/fabric-ccenv 2.2.1 8e554c280cac 5 weeks ago 586MB
hyperledger/fabric-ccenv latest 8e554c280cac 5 weeks ago 586MB
hyperledger/fabric-baseos 2.2 0b99d26b26ad 5 weeks ago 6.85MB
hyperledger/fabric-baseos 2.2.1 0b99d26b26ad 5 weeks ago 6.85MB
hyperledger/fabric-baseos latest 0b99d26b26ad 5 weeks ago 6.85MB
------------------------------------------------------------------------------------------------
十、安装Golang
yum -y install golang
# 自定义环境Go环境变量到linux文件
echo '
export PATH=$PATH:/usr/local/go/bin
export GOPATH=/opt/gopath
# 加载
source /etc/profile
' >> /etc/profile
十一、启动区块链网络
cd fabric-samples/test-network
./network.sh up
# 查看 (可以看到两个组织的peer节点与1个order节点)
docker ps
成功够可以看到启动了3个容器:2个peer、1个order节点。
十二、创建channel
./network.sh createChannel -c ch1
十三、在channel上创建chaincode,指定七牛云go依赖包仓库进行下载,这里chaincode默认加载的智能合约程序为/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples下的basic资产程序
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
./network.sh deployCC -c ch1
十四、交互
cd /opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/test-network
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
# 认证Org1
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:7051
# 对账本初始化资产
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C ch1 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}'
# 查看我们添加的资产
peer chaincode query -C ch1 -n basic -c '{"Args":["GetAllAssets"]}'
# 显示的资产列表 [{"ID":"asset1","color":"blue","size":5,"owner":"Tomoko","appraisedValue":300},{"ID":"asset2","color":"red","size":5,"owner":"Brad","appraisedValue":400},{"ID":"asset3","color":"green","size":10,"owner":"Jin Soo","appraisedValue":500},{"ID":"asset4","color":"yellow","size":10,"owner":"Max","appraisedValue":600},{"ID":"asset5","color":"black","size":15,"owner":"Adriana","appraisedValue":700},{"ID":"asset6","color":"white","size":15,"owner":"Michel","appraisedValue":800}]
# 转移资产
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C ch1 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"TransferAsset","Args":["asset6","Christopher"]}'
# 使用Org2认证,进行验证
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:9051
# 查看刚才转移的第六个资产
peer chaincode query -C ch1 -n basic -c '{"Args":["ReadAsset","asset6"]}'
# 关闭区块链网络
./network.sh down
十五、添加新节点
cd addOrg3
./addOrg3.sh generate
./addOrg3.sh up -c ch1
# 使用org3认证
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:11051
# 安装chaincode到org3Chaincode is installed on peer0.org3
peer lifecycle chaincode install basic.tar.gz
# 查询安装是否成功
peer lifecycle chaincode queryinstalled
# 让org3上的链码定义在ch1通道上认可 Chaincode definition approved on peer0.org3 on channel 'ch1'
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID ch1 --name basic --version 1.0 --package-id basic_1.0:4ec191e793b27e953ff2ede5a8bcc63152cecb1e4c3f301a26e22692c61967ad --sequence 1
十六、编写智能合约
# 创建智能合约程序目录并进入
mkdir atcc && cd atcc
# goland开启 go module模式并配置goproxy
![image.png](https://upload-images.jianshu.io/upload_images/10280146-81a5a1ff88b8795e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
# 新建go文件
touch atcc.go
# 编写代码
package main
import (
"encoding/json"
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"log"
)
func main() {
assetChaincode, err := contractapi.NewChaincode(&SmartContract{})
if err != nil {
log.Panicf("Error creating asset-transfer-basic chaincode: %v", err)
}
if err := assetChaincode.Start(); err != nil {
log.Panicf("Error starting asset-transfer-basic chaincode: %v", err)
}
}
// SmartContract provides functions for managing an Asset
type SmartContract struct {
contractapi.Contract
}
// Asset describes basic details of what makes up a simple asset
type Student struct {
ID string `json:"ID"`
Name string `json:"name"`
Age int `json:"age"`
}
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
stus := []Student{
{ID: "a1", Name: "小明", Age: 16},
{ID: "a2", Name: "小花", Age: 15},
{ID: "a3", Name: "小强", Age: 17},
{ID: "a4", Name: "小刚", Age: 16},
{ID: "a5", Name: "小草", Age: 14},
{ID: "a6", Name: "小新", Age: 14},
}
for _, stu := range stus {
assetJSON, err := json.Marshal(stu)
if err != nil {
return err
}
err = ctx.GetStub().PutState(stu.ID, assetJSON)
if err != nil {
return fmt.Errorf("failed to put to world state. %v", err)
}
}
return nil
}
// CreateAsset issues a new asset to the world state with given details.
func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, name string, age int) error {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if exists {
return fmt.Errorf("the asset %s already exists", id)
}
stu := Student{
ID: id,
Name: name,
Age: age,
}
assetJSON, err := json.Marshal(stu)
if err != nil {
return err
}
return ctx.GetStub().PutState(id, assetJSON)
}
// AssetExists returns true when asset with given ID exists in world state
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return false, fmt.Errorf("failed to read from world state: %v", err)
}
return assetJSON != nil, nil
}
// ReadAsset returns the asset stored in the world state with given id.
func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Student, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return nil, fmt.Errorf("failed to read from world state: %v", err)
}
if assetJSON == nil {
return nil, fmt.Errorf("the asset %s does not exist", id)
}
var stu Student
err = json.Unmarshal(assetJSON, &stu)
if err != nil {
return nil, err
}
return &stu, nil
}
func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, name string, age int) error {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("the asset %s does not exist", id)
}
// overwriting original asset with new asset
stu := Student{
ID: id,
Name: name,
Age: age,
}
assetJSON, err := json.Marshal(stu)
if err != nil {
return err
}
return ctx.GetStub().PutState(id, assetJSON)
}
// DeleteAsset deletes an given asset from the world state.
func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("the asset %s does not exist", id)
}
return ctx.GetStub().DelState(id)
}
上面程序主要调用"github.com/hyperledger/fabric-contract-api-go/contractapi"接口的增删改查方法来操作自己的资产。
十七、部署智能合约
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
# 整理go依赖包
go mod tidy
# 使用vendor管理,将依赖包下载到module目录
go mod vendor
登录fabric network机器上,将写好的合约程序上传到/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/personal-demo/位置,mkdir -p /opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/personal-demo
# 初始集群
cd /opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/test-network
./network down
./network up
# 创建通道ch3
./network createChannel -c ch3
# 部署智能合约
./network.sh deployCC -ccp ../personal-demo/atcc -c ch3
# 调用智能合约api
cd /opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/test-network
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
# 认证Org1
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:7051
# 使用智能合约初始化方法
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C ch3 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}'
# 查看我们添加的资产
peer chaincode query -C ch3 -n atcc -c '{"function":"ReadAsset","Args":["a1"]}'
#显示结果{"ID":"a1","name":"小明","age":16}
十八、编写运行App调用智能合约
这里继续使用golang编写,调用智能合约相关sdk包
"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
"github.com/hyperledger/fabric-sdk-go/pkg/gateway"
大体流程:
1.系统环境变量设置是否为本地app运行:true
2.创建钱包,钱包中为身份认证等信息,这里使用[email protected]的身份
3.通过gateway连接智能合约,传入wallet认证信息、通道名称、合约名称
4.获取合约对象后,调用合约方法
5.启动app
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
"github.com/hyperledger/fabric-sdk-go/pkg/gateway"
)
func main() {
log.Println("============ application-golang starts ============")
log.Println("系统环境变量设置是否为本地app运行:true ")
err := os.Setenv("DISCOVERY_AS_LOCALHOST", "true")
if err != nil {
log.Fatalf("Error setting DISCOVERY_AS_LOCALHOST environemnt variable: %v", err)
}
log.Println("创建钱包,钱包中为身份认证等信息,这里使用[email protected]的身份.")
wallet, err := gateway.NewFileSystemWallet("wallet")
if err != nil {
log.Fatalf("Failed to create wallet: %v", err)
}
if !wallet.Exists("appUser") {
err = populateWallet(wallet)
if err != nil {
log.Fatalf("Failed to populate wallet contents: %v", err)
}
}
log.Println("通过gateway连接智能合约,传入通道名称、合约名称.")
ccpPath := filepath.Join(
"..",
"..",
"test-network",
"organizations",
"peerOrganizations",
"org1.example.com",
"connection-org1.yaml",
)
gw, err := gateway.Connect(
gateway.WithConfig(config.FromFile(filepath.Clean(ccpPath))),
gateway.WithIdentity(wallet, "appUser"),
)
if err != nil {
log.Fatalf("Failed to connect to gateway: %v", err)
}
defer gw.Close()
network, err := gw.GetNetwork("ch3")
if err != nil {
log.Fatalf("Failed to get network: %v", err)
}
contract := network.GetContract("basic")
log.Println("--> Submit Transaction: 调用智能合约InitLedger方法初始化所有同学的数据.")
result, err := contract.SubmitTransaction("InitLedger")
if err != nil {
log.Fatalf("Failed to Submit transaction: %v", err)
}
log.Println(string(result))
log.Println("--> Submit Transaction: 调用智能合约CreateAsset方法创建一个同学的信息, id=a8,name=小朵,age=13.")
result, err = contract.SubmitTransaction("CreateAsset", "a8", "小朵", "13")
if err != nil {
log.Fatalf("Failed to Submit transaction: %v", err)
}
log.Println(string(result))
log.Println("--> Evaluate Transaction: 调用智能合约ReadAsset方法读取刚刚创建的同学的信息.")
result, err = contract.EvaluateTransaction("ReadAsset", "a8")
if err != nil {
log.Fatalf("Failed to evaluate transaction: %v\n", err)
}
log.Println(string(result))
log.Println("--> Evaluate Transaction: 调用智能合约AssetExists方法判断刚刚创建的同学信息是否存在.")
result, err = contract.EvaluateTransaction("AssetExists", "a8")
if err != nil {
log.Fatalf("Failed to evaluate transaction: %v\n", err)
}
log.Println(string(result))
log.Println("============ application-golang ends ============")
}
func populateWallet(wallet *gateway.Wallet) error {
log.Println("============ Populating wallet ============")
credPath := filepath.Join(
"..",
"..",
"test-network",
"organizations",
"peerOrganizations",
"org1.example.com",
"users",
"[email protected]",
"msp",
)
certPath := filepath.Join(credPath, "signcerts", "[email protected]")
// read the certificate pem
cert, err := ioutil.ReadFile(filepath.Clean(certPath))
if err != nil {
return err
}
keyDir := filepath.Join(credPath, "keystore")
// there's a single file in this dir containing the private key
files, err := ioutil.ReadDir(keyDir)
if err != nil {
return err
}
if len(files) != 1 {
return fmt.Errorf("keystore folder should have contain one file")
}
keyPath := filepath.Join(keyDir, files[0].Name())
key, err := ioutil.ReadFile(filepath.Clean(keyPath))
if err != nil {
return err
}
identity := gateway.NewX509Identity("Org1MSP", string(cert), string(key))
return wallet.Put("appUser", identity)
}
go run xxx.go
运行该app
十九、test-network目录说明
├── addOrg3 添加新组织相关文件及脚本文件夹
│ ├── addOrg3.sh
│ ├── ccp-generate.sh
│ ├── ccp-template.json
│ ├── ccp-template.yaml
│ ├── configtx.yaml
│ ├── docker
│ ├── fabric-ca
│ ├── org3-crypto.yaml
│ └── README.md
├── channel-artifacts 通道文件
│ ├── ch5.block
│ ├── ch5.tx
│ ├── Org1MSPanchors.tx
│ └── Org2MSPanchors.tx
├── configtx
│ └── configtx.yaml 用于生成系统创世区块的配置文件
├── docker 用于启动docker容器的docker-compose配置文件
│ ├── docker-compose-ca.yaml
│ ├── docker-compose-couch.yaml
│ └── docker-compose-test-net.yaml
├── log.txt
├── network.sh 入口脚本
├── organizations
│ ├── ccp-generate.sh
│ ├── ccp-template.json
│ ├── ccp-template.yaml
│ ├── cryptogen 使用cryptogen tool为组织生成证书、秘钥
│ ├── fabric-ca 使用ca服务器来为每个身份 生成证书、秘钥时,其中包含相关的配置文件
│ │ ├── ordererOrg
│ │ ├── org1
│ │ ├── org2
│ │ └── registerEnroll.sh 生成证书、秘钥的脚本
│ ├── ordererOrganizations order组织的证书文件
│ └── peerOrganizations peer组织的证书文件
├── README.md
├── scripts 子脚本文件夹
│ ├── createChannel.sh createChannel.sh基于configtx/configtx.yaml使用指定的通道名称创建通道,向通道中加入peer0.org1.example.com和peer0.org2.example.com,并将它们更新为锚节点
│ ├── deployCC.sh deployCC.sh在peer0.org1.example.com和peer0.org2.example.com上安装fabric的链码,并在通道中定义chaincode,最后调用chaincode显示结果
│ ├── envVar.sh 系统环境变量
│ └── org3-scripts 添加新组织相关脚本
├── scriptUtils.sh 通用脚本-help等
└── system-genesis-block 系统创世区块文件夹
└── genesis.block 生成的系统创世区块
附录
安装go环境
1.下载go sdk
非科学上网访问:https://studygolang.com/dl
安装后请确认环境变量可用
go version
go env
2.下载Goland
访问:
https://www.jetbrains.com/zh-cn/go/
cryptogen介绍
1.MSP是什么
MSP一个提供虚拟成员操作的管理框架组件
每个节点都有一个MSP账号
每个用户也都有MSP账号
MSP下面有一个管理员账号和证书
验证身份的证书都在MSP下面。
2.cryptogen使用方法
cryptogen --help //查看使用方法
cryptogen generate --help //查看generate后的使用方法
//使用cryptogen generate需要指定模板文件,不然就是默认模板
cryptogen generate --config == 某文件
会生成peer节点和orderer节点文件
根据yaml的模块修改 cryptogen showtemplate //查看模板
使用重定向命令将模板放在别的地方通过修改成自己的
cryptogen showtemplate > a.yaml //一般起名叫crypto-config.yaml
3.模板说明
OrdererOrgs: //排序节点的组织信息,这里不能改
# ---------------------------------------------------------------------------
# Orderer
# ---------------------------------------------------------------------------
- Name: Orderer //排序节点组织的名字,可以修改可以不修改
Domain: example.com //根域名,排序节点组织的根域名,测试的时候随便取
# ---------------------------------------------------------------------------
# "Specs" - See PeerOrgs below for complete description
# ---------------------------------------------------------------------------
Specs: //User去指定
- Hostname: orderer //生成一个子域名,去访问当前唯一排序节点。orderer对应的访问域名应该是:orderer.example.com
Hostname有几个就有几个排序节点,通过队友的域名
排序节点名字.根域名去访问
第二部分:
PeerOrgs: Org1和Org2是指定的默认peer节点的组织可以无限添加
# ---------------------------------------------------------------------------
# Org1
# ---------------------------------------------------------------------------
- Name: Org1 //名字,自己指定
Domain: org1.example.com //域名同样跟orderer的域名一样
EnableNodeOUs: false //是否支持nodejs来编写链码
Template: //模板
Count: 1 //生成的peer节点数,访问的域名peer0.org1.example.com //0对应1,1对2
Users:
Count: 1 //操作节点的普通用户的个数,还会默认生成一个管理员用户
[email protected]
使用template和specs的区别:
使用specs二级域名可以自己指定
使用template二级域名就是默认的peer0这种类似
可以单独也可以混合使用
新增组织
1.新增组织证书配置
echo '
PeerOrgs:
# ---------------------------------------------------------------------------
# Org4
# ---------------------------------------------------------------------------
- Name: Org4
Domain: org4.example.com
EnableNodeOUs: true
Template:
Count: 1
Users:
Count: 1
' > crypto-config.yaml
cryptogen extend --config=./crypto-config.yaml
- 新增组织定义到区块链
echo '
Organizations:
- &Org4
Name: Org4MSP
ID: Org4MSP
MSPDir: crypto-config/peerOrganizations/org4.example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('Org4MSP.admin', 'Org4MSP.peer', 'Org4MSP.client')"
Writers:
Type: Signature
Rule: "OR('Org4MSP.admin', 'Org4MSP.client')"
Admins:
Type: Signature
Rule: "OR('Org4MSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('Org4MSP.peer')"
AnchorPeers:
- Host: peer0.org4.example.com
Port: 7051
' > configtx.yaml
configtxgen -printOrg Org4MSP > ./channel-artifacts/org.json
3.启动新组织容器
docker run -tid \
--name=peer0.org4.example.com \
--restart=always \
-p 7051:7051 \
-p 7052:7052 \
-p 7053:7053 \
-w /opt/gopath/src/github.com/hyperledger/fabric/peer \
-e CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock \
-e CORE_PEER_ID=peer0.org4.example.com \
-e CORE_PEER_ADDRESS=peer0.org4.example.com:7051 \
-e CORE_PEER_LISTENADDRESS=0.0.0.0:7051 \
-e CORE_PEER_CHAINCODEADDRESS=peer0.org4.example.com:7052 \
-e CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 \
-e CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org4.example.com:7051 \
-e CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org4.example.com:7051 \
-e CORE_PEER_LOCALMSPID=Org4MSP \
-e FABRIC_LOGGING_SPEC=INFO \
-e CORE_PEER_TLS_ENABLED=true \
-e CORE_PEER_GOSSIP_USELEADERELECTION=true \
-e CORE_PEER_GOSSIP_ORGLEADER=false \
-e CORE_PEER_PROFILE_ENABLED=true \
-e CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt \
-e CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key \
-e CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt \
-e CORE_CHAINCODE_EXECUTETIMEOUT=300s \
-v /var/run/:/host/var/run/ \
-v /opt/multiple-deployment/crypto-config/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/msp:/etc/hyperledger/fabric/msp \
-v /opt/multiple-deployment/crypto-config/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls:/etc/hyperledger/fabric/tls \
--add-host=orderer0.example.com:10.160.0.122 \
--add-host=orderer1.example.com:10.160.0.115 \
--add-host=orderer2.example.com:10.160.0.200 \
hyperledger/fabric-peer:latest sh -c 'peer node start'
docker run -tid \
--name=peer0.org4.example.com.cli \
--restart=always \
-w /opt/gopath/src/github.com/hyperledger/fabric/peer \
-e GOPATH=/opt/gopath \
-e CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock \
-e FABRIC_LOGGING_SPEC=INFO \
-e CORE_PEER_ID=peer0.org4.example.com \
-e CORE_PEER_ADDRESS=peer0.org4.example.com:7051 \
-e CORE_PEER_LOCALMSPID=Org4MSP \
-e CORE_PEER_TLS_ENABLED=true \
-e CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/server.crt \
-e CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/server.key \
-e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt \
-e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org4.example.com/users/[email protected]/msp \
-v /var/run/:/host/var/run/ \
-v /opt/multiple-deployment/chaincode/go/:/opt/gopath/src/github.com/hyperledger/multiple-deployment/chaincode/go \
-v /opt/multiple-deployment/crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ \
-v /opt/multiple-deployment/channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts \
--add-host=orderer0.example.com:10.160.0.122 \
--add-host=orderer1.example.com:10.160.0.115 \
--add-host=orderer2.example.com:10.160.0.200 \
--add-host=peer0.org1.example.com:10.160.0.122 \
--add-host=peer1.org1.example.com:10.160.0.122 \
--add-host=peer0.org2.example.com:10.160.0.115 \
--add-host=peer1.org2.example.com:10.160.0.115 \
--add-host=peer0.org3.example.com:10.160.0.200 \
--add-host=peer1.org3.example.com:10.160.0.200 \
--add-host=peer0.org4.example.com:10.160.0.162 \
--add-host=peer1.org4.example.com:10.160.0.200 \
hyperledger/fabric-tools:latest /bin/bash
- 更新通道配置
channelName=mychannel
ordererAddr=orderer0.example.com:7050
ordererCa=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
4.1 获取配置 获取最新块
在peer0.org1.cli容器中
docker exec -ti peer0.org1.example.com.cli bash
peer channel fetch config config_block.pb -o orderer0.example.com:7050 -c mychannel --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
4.2 修改配置
将pb文件转json
configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config > config.json
先把之前生成的org.json放进去Org3cli容器
将org.json添加到config.json
jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org4MSP":.[1]}}}}}' config.json ./channel-artifacts/org.json > modified_config.json
将config.json 跟modified_config.json 转pb编码
configtxlator proto_encode --input config.json --type common.Config --output config.pb
configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
计算两个pb差异
configtxlator compute_update --channel_id mychannel --original config.pb --updated modified_config.pb --output org_update.pb
将更新的pb解析为json
configtxlator proto_decode --input org_update.pb --type common.ConfigUpdate | jq . > org_update.json
现在我们有一个解码后的更新文件org_update.json,我们需要将其包装在信封消息中。此步骤将使我们返回之前删除的header字段。我们将这个文件命名为org_update_in_envelope.json:
echo '{"payload":{"header":{"channel_header":{"channel_id":"'mychannel'", "type":2}},"data":{"config_update":'$(cat org_update.json)'}}}' | jq . > org_update_in_envelope.json
转pb编码
configtxlator proto_encode --input org_update_in_envelope.json --type common.Envelope --output org_update_in_envelope.pb
4.3 签名并提交更新配置
peer channel signconfigtx -f org_update_in_envelope.pb
切换环境为org2执行更新配置,因为update也会为当前组织签名,所以不需要再org2签名
docker cp peer0.org1.example.com.cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/org_update_in_envelope.pb ./
scp org_update_in_envelope.pb [email protected]:/opt/multiple-deployment/channel-artifacts
docker exec -ti peer0.org2.example.com.cli bash
peer channel update -f org_update_in_envelope.pb -c mychannel -o orderer0.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
- 新组织加入通道
docker exec -ti peer0.org4.example.com.cli bash
peer channel fetch 0 mychannel.block -o orderer0.example.com:7050 -c mychannel --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
peer channel join -b mychannel.block
peer channel list