1.3.0 和 1.2.0 相比有一些变化,主要是权限控制方面的。这篇文档里现在还有一个问题没解决:User 用户的操作权限
为什么是 1.3.0,因为之前做的一个 教程,陆续有同学反映,chaincode跑不通。查看了下,给出的链码引用的是 1.3.0 版本的 fabric。鉴于 fabric 的版本都已经到了 2.X 了,没必要为老旧的 1.x,2.x 写 chaincode,直接做个 1.3.0 的教程吧。
IP地址分别是:192.168.88.10、192.168.88.11、192.168.88.12
在三台服务的 /etc/hosts/中添加下面的内容,这个 faric 链中各成员的域名:
192.168.88.10 orderer.example.com
192.168.88.10 peer0.org1.example.com
192.168.88.11 peer1.org1.example.com
192.168.88.12 peer0.org2.example.com
在三台服务器上安装 docker,并下载 hyperledger fabric 1.3.0 用到的镜像:
yum install -y docker
systemctl start docker
docker pull hyperledger/fabric-ccenv:1.3.0
docker pull hyperledger/fabric-baseos:0.4.21
为了方便后续的操作,让 192.168.88.10 可以免密码登陆 192.168.88.11 和 192.168.88.12。后面会在 192.168.88.10 上准备好所有文件,然后分别拷贝到 192.168.10.11 和 192.168.10.12。
$ ssh-keygen <回车到结束>
$ ssh-copy-id [email protected]
$ ssh-copy-id [email protected]
在 192.168.88.10 上准备好每个机器上的部署文件,准备工作目录:
mkdir ~/fabric-deploy
cd ~/fabric-deploy
下载 fabric 二进制文件:
wget https://github.com/hyperledger/fabric/releases/download/v1.3.0/hyperledger-fabric-linux-amd64-1.3.0.tar.gz
tar -xvf hyperledger-fabric-linux-amd64-1.3.0.tar.gz
创建文件 crypto-config.yaml,内容如下:
OrdererOrgs:
- Name: Orderer
Domain: example.com
Specs:
- Hostname: orderer
PeerOrgs:
- Name: Org1
Domain: org1.example.com
EnableNodeOUs: true
Template:
Count: 2
Users:
Count: 1
- Name: Org2
Domain: org2.example.com
EnableNodeOUs: true
Template:
Count: 2
Users:
Count: 1
执行下面的命令生成证书:
./bin/cryptogen generate --config=crypto-config.yaml --output ./certs
mkdir orderer.example.com
cp bin/orderer orderer.example.com/
cp -rf certs/ordererOrganizations/example.com/orderers/orderer.example.com/* orderer.example.com/
mkdir orderer.example.com/data
创建 orderer 的配置文件 orderer.example.com/orderer.yaml,内容如下:
General:
LedgerType: file
ListenAddress: 0.0.0.0
ListenPort: 7050
TLS:
Enabled: true
PrivateKey: ./tls/server.key
Certificate: ./tls/server.crt
RootCAs:
- ./tls/ca.crt
# ClientAuthEnabled: false
# ClientRootCAs:
LogLevel: debug
LogFormat: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}'
# GenesisMethod: provisional
GenesisMethod: file
GenesisProfile: SampleInsecureSolo
GenesisFile: ./genesisblock
LocalMSPDir: ./msp
LocalMSPID: OrdererMSP
Profile:
Enabled: false
Address: 0.0.0.0:6060
BCCSP:
Default: SW
SW:
Hash: SHA2
Security: 256
FileKeyStore:
KeyStore:
FileLedger:
Location: /opt/app/fabric/orderer/data
Prefix: hyperledger-fabric-ordererledger
RAMLedger:
HistorySize: 1000
Kafka:
Retry:
ShortInterval: 5s
ShortTotal: 10m
LongInterval: 5m
LongTotal: 12h
NetworkTimeouts:
DialTimeout: 10s
ReadTimeout: 10s
WriteTimeout: 10s
Metadata:
RetryBackoff: 250ms
RetryMax: 3
Producer:
RetryBackoff: 100ms
RetryMax: 3
Consumer:
RetryBackoff: 2s
Verbose: false
TLS:
Enabled: false
PrivateKey:
#File: path/to/PrivateKey
Certificate:
#File: path/to/Certificate
RootCAs:
#File: path/to/RootCAs
Version:
mkdir peer0.org1.example.com
cp bin/peer peer0.org1.example.com/
cp -rf certs/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/* peer0.org1.example.com/
mkdir peer0.org1.example.com/data
创建 peer 的配置文件 peer0.org1.example.com/core.yaml:
logging:
peer: debug
cauthdsl: warning
gossip: warning
ledger: info
msp: warning
policies: warning
grpc: error
format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}'
peer:
id: peer0.org1.example.com
networkId: dev
listenAddress: 0.0.0.0:7051
address: 0.0.0.0:7051
addressAutoDetect: false
gomaxprocs: -1
gossip:
bootstrap: 127.0.0.1:7051
bootstrap: peer0.org1.example.com:7051
useLeaderElection: true
orgLeader: false
endpoint:
maxBlockCountToStore: 100
maxPropagationBurstLatency: 10ms
maxPropagationBurstSize: 10
propagateIterations: 1
propagatePeerNum: 3
pullInterval: 4s
pullPeerNum: 3
requestStateInfoInterval: 4s
publishStateInfoInterval: 4s
stateInfoRetentionInterval:
publishCertPeriod: 10s
skipBlockVerification: false
dialTimeout: 3s
connTimeout: 2s
recvBuffSize: 20
sendBuffSize: 200
digestWaitTime: 1s
requestWaitTime: 1s
responseWaitTime: 2s
aliveTimeInterval: 5s
aliveExpirationTimeout: 25s
reconnectInterval: 25s
externalEndpoint: peer0.org1.example.com:7051
election:
startupGracePeriod: 15s
membershipSampleInterval: 1s
leaderAliveThreshold: 10s
leaderElectionDuration: 5s
events:
address: 0.0.0.0:7053
buffersize: 100
timeout: 10ms
tls:
enabled: true
cert:
file: ./tls/server.crt
key:
file: ./tls/server.key
rootcert:
file: ./tls/ca.crt
serverhostoverride:
fileSystemPath: /opt/app/fabric/peer/data
BCCSP:
Default: SW
SW:
Hash: SHA2
Security: 256
FileKeyStore:
KeyStore:
mspConfigPath: msp
localMspId: Org1MSP
profile:
enabled: true
listenAddress: 0.0.0.0:6060
handlers:
authFilters:
-
name: DefaultAuth
-
name: ExpirationCheck # This filter checks identity x509 certificate expiration
decorators:
-
name: DefaultDecorator
endorsers:
escc:
name: DefaultEndorsement
library:
validators:
vscc:
name: DefaultValidation
library:
vm:
endpoint: unix:///var/run/docker.sock
docker:
tls:
enabled: false
ca:
file: docker/ca.crt
cert:
file: docker/tls.crt
key:
file: docker/tls.key
attachStdout: false
hostConfig:
NetworkMode: host
Dns:
# - 192.168.0.1
LogConfig:
Type: json-file
Config:
max-size: "50m"
max-file: "5"
Memory: 2147483648
chaincode:
peerAddress:
id:
path:
name:
builder: $(DOCKER_NS)/fabric-ccenv:$(ARCH)-$(PROJECT_VERSION)
golang:
runtime: $(BASE_DOCKER_NS)/fabric-baseos:$(ARCH)-$(BASE_VERSION)
car:
runtime: $(BASE_DOCKER_NS)/fabric-baseos:$(ARCH)-$(BASE_VERSION)
java:
Dockerfile: |
from $(DOCKER_NS)/fabric-javaenv:$(ARCH)-$(PROJECT_VERSION)
startuptimeout: 300s
executetimeout: 30s
mode: net
keepalive: 0
system:
cscc: enable
lscc: enable
escc: enable
vscc: enable
qscc: enable
logging:
level: info
shim: warning
format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}'
ledger:
blockchain:
state:
stateDatabase: goleveldb
couchDBConfig:
couchDBAddress: 127.0.0.1:5984
username:
password:
maxRetries: 3
maxRetriesOnStartup: 10
requestTimeout: 35s
queryLimit: 10000
history:
enableHistoryDatabase: true
直接用 peer0 的文件修改得到:
cp -rf peer0.org1.example.com/ peer1.org1.example.com/
rm -rf peer1.org1.example.com/msp/
rm -rf peer1.org1.example.com/tls/
cp -rf certs/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/* peer1.org1.example.com/
sed -i "s/peer0.org1.example.com/peer1\.org1\.example.com/g" peer1.org1.example.com/core.yaml
同样通过修改 peer0.org1 的文件得到:
cp -rf peer0.org1.example.com/ peer0.org2.example.com/
rm -rf peer0.org2.example.com/msp/
rm -rf peer0.org2.example.com/tls/
cp -rf certs/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/* peer0.org2.example.com/
sed -i "s/peer0.org1.example.com/peer0\.org2\.example.com/g" peer0.org2.example.com/core.yaml
sed -i "s/Org1MSP/Org2MSP/g" peer0.org2.example.com/core.yaml
在 192.168.88.10 上部署 orderer 和 peer0.org1:
mkdir -p /opt/app/fabric/{orderer,peer}
scp -r orderer.example.com/* [email protected]:/opt/app/fabric/orderer/
scp -r peer0.org1.example.com/* [email protected]:/opt/app/fabric/peer/
在 192.168.88.11 上部署 peer1.org1:
# 192.168.88.11 上执行
mkdir -p /opt/app/fabric/peer
# 192.168.88.10 上执行
scp -r peer1.org1.example.com/* [email protected]:/opt/app/fabric/peer/
在 192.168.88.12 上部署 peer0.org2:
# 192.168.88.12 上执行
mkdir -p /opt/app/fabric/peer
# 192.168.88.10 上执行
scp -r peer0.org2.example.com/* [email protected]:/opt/app/fabric/peer/
在 fabric-deploy 中创建文件 configtx.yaml,内容如下:
Organizations:
- &OrdererOrg
Name: OrdererOrg
ID: OrdererMSP
MSPDir: ./certs/ordererOrganizations/example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
Writers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
Admins:
Type: Signature
Rule: "OR('OrdererMSP.admin')"
- &Org1
Name: Org1MSP
ID: Org1MSP
MSPDir: ./certs/peerOrganizations/org1.example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')"
Writers:
Type: Signature
Rule: "OR('Org1MSP.admin', 'Org1MSP.client')"
Admins:
Type: Signature
Rule: "OR('Org1MSP.admin')"
AnchorPeers:
- Host: peer0.org1.example.com
Port: 7051
- &Org2
Name: Org2MSP
ID: Org2MSP
MSPDir: ./certs/peerOrganizations/org2.example.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')"
Writers:
Type: Signature
Rule: "OR('Org2MSP.admin', 'Org2MSP.client')"
Admins:
Type: Signature
Rule: "OR('Org2MSP.admin')"
AnchorPeers:
- Host: peer0.org2.example.com
Port: 7051
Capabilities:
Channel: &ChannelCapabilities
V1_3: true
Orderer: &OrdererCapabilities
V1_1: true
Application: &ApplicationCapabilities
V1_3: true
V1_2: false
V1_1: false
Application: &ApplicationDefaults
Organizations:
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
Orderer: &OrdererDefaults
OrdererType: solo
Addresses:
- orderer.example.com:7050
BatchTimeout: 2s
BatchSize:
MaxMessageCount: 10
AbsoluteMaxBytes: 99 MB
PreferredMaxBytes: 512 KB
Kafka:
Brokers:
- 127.0.0.1:9092
Organizations:
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
BlockValidation:
Type: ImplicitMeta
Rule: "ANY Writers"
Channel: &ChannelDefaults
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
Capabilities:
<<: *ChannelCapabilities
Profiles:
TwoOrgsOrdererGenesis:
<<: *ChannelDefaults
Orderer:
<<: *OrdererDefaults
Organizations:
- *OrdererOrg
Capabilities:
<<: *OrdererCapabilities
Consortiums:
SampleConsortium:
Organizations:
- *Org1
- *Org2
TwoOrgsChannel:
Consortium: SampleConsortium
Application:
<<: *ApplicationDefaults
Organizations:
- *Org1
- *Org2
Capabilities:
<<: *ApplicationCapabilities
然后执行命令:
./bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./genesisblock
将初始块复制到 192.168.88.10 的 orderer 部署目录中:
scp genesisblock [email protected]:/opt/app/fabric/orderer/
在 192.168.88.10 上启动 orderer 和 peer:
$ cd /opt/app/fabric/orderer/
$ ./orderer > orderer.log &
$ cd /opt/app/fabric/peer
$ ./peer node start >peer.log &
在 192.168.88.11 上启动 peer:
$ cd /opt/app/fabric/peer
$ ./peer node start >peer.log &
在 192.168.88.12 上启动 peer:
$ cd /opt/app/fabric/peer
$ ./peer node start >peer.log &
mkdir [email protected]
cp -rf certs/peerOrganizations/org1.example.com/users/Admin\@org1.example.com/* Admin\@org1.example.com/
cp peer0.org1.example.com/core.yaml Admin\@org1.example.com/
创建脚本,[email protected]/peer.sh,内容如下:
#!/bin/bash
PATH=`pwd`/../bin:$PATH
export FABRIC_CFG_PATH=`pwd`
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_TLS_CERT_FILE=./tls/client.crt
export CORE_PEER_TLS_KEY_FILE=./tls/client.key
export CORE_PEER_MSPCONFIGPATH=./msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID=Org1MSP
export CORE_PEER_TLS_ROOTCERT_FILE=./tls/ca.crt
export CORE_PEER_ID=cli
export CORE_LOGGING_LEVEL=INFO
peer $*
访问 peer 节点,STARTED 为正常:
$ ./peer.sh node status
status:STARTED
2018-04-29 14:32:03.517 CST [main] main -> INFO 001 Exiting.....
在前一个用户的基础上修改得到:
cp -rf Admin\@org1.example.com/ User1\@org1.example.com/
rm -rf User1\@org1.example.com/msp
rm -rf User1\@org1.example.com/tls
cp -rf certs/peerOrganizations/org1.example.com/users/User1\@org1.example.com/* User1\@org1.example.com/
尝试访问 peer,STARTED 是正常:
$ cd User1\@org1.example.com
$ ./peer.sh node status
status:STARTED
2018-04-29 14:37:48.251 CST [main] main -> INFO 001 Exiting.....
这里有问题,会提示 User1 用户没有权限。因该是配置的原因,找时间再查。暂时可以只用 Admin 用户操作。
在前面用户的基础上修改得到:
cp -rf Admin\@org1.example.com/ Admin\@org2.example.com/
rm -rf Admin\@org2.example.com/msp/
rm -rf Admin\@org2.example.com/tls/
cp -rf certs/peerOrganizations/org2.example.com/users/Admin\@org2.example.com/* Admin\@org2.example.com/
cp peer0.org2.example.com/core.yaml Admin\@org2.example.com/
修改 peer.sh:
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID=Org1MSP
修改为:
export CORE_PEER_ADDRESS=peer0.org2.example.com:7051
export CORE_PEER_LOCALMSPID=Org2MSP
验证:
$ cd Admin\@org2.example.com
$ ./peer.sh node status
status:STARTED
2018-04-29 14:44:22.395 CST [main] main -> INFO 001 Exiting.....
生成 channel 文件:
./bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx mychannel.tx -channelID mychannel
./bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
./bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
cp certs/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem Admin\@org1.example.com/
cp certs/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem User1\@org1.example.com/
cp certs/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem Admin\@org2.example.com/
在 [email protected] 目录中执行:
cd Admin\@org1.example.com
./peer.sh channel create -o orderer.example.com:7050 -c mychannel -f ../mychannel.tx --tls true --cafile tlsca.example.com-cert.pem
在 Admin\@org1.example.com 中执行:
cd Admin\@org1.example.com/
./peer.sh channel join -b mychannel.block
因为org1有两个peer,因此需要将peer.sh中peer修改为peer1.org1.example.com后,再添加一次:
./peer.sh channel join -b mychannel.block
在 Admin\@org2.example.com/ 中执行:
cp [email protected]/mychannel.block [email protected]/
cd Admin\@org2.example.com/
./peer.sh channel join -b mychannel.block
查看 peer 所在的 channel:
$ ./peer.sh channel list
2018-04-29 16:37:47.016 CST [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined:
mychannel
2018-04-29 16:37:47.018 CST [main] main -> INFO 002 Exiting.....
指定 anchor peer:
cd Admin\@org1.example.com/
./peer.sh channel update -o orderer.example.com:7050 -c mychannel -f ../Org1MSPanchors.tx --tls true --cafile ./tlsca.example.com-cert.pem
cd Admin\@org2.example.com/
./peer.sh channel update -o orderer.example.com:7050 -c mychannel -f ../Org2MSPanchors.tx --tls true --cafile ./tlsca.example.com-cert.pem
先在 192.168.88.10 上安装 go:
wget https://golang.org/dl/go1.15.2.linux-amd64.tar.gz
tar -xvf go1.15.2.linux-amd64.tar.gz
mkdir gopath
在 ~/.bashrc 中添加:
export PATH=$PATH:/root/fabric-deploy/go/bin
export GOPATH=/root/fabric-deploy/gopath
下载代码:
source ~/.bashrc
yum install -y git gcc
go get github.com/introclass/hyperledger-fabric-chaincodes/demo
以 [email protected] 的身份打包合约:
cd Admin\@org1.example.com/
执行下面命令进行合约打包、签署、安装:
./peer.sh chaincode package demo-pack.out -n demo -v 0.0.1 -s -S -p github.com/introclass/hyperledger-fabric-chaincodes/demo
./peer.sh chaincode signpackage demo-pack.out signed-demo-pack.out
./peer.sh chaincode install ./signed-demo-pack.out
查看 peer 上已经安装的合约:
$ ./peer.sh chaincode list --installed
Get installed chaincodes on peer:
Name: demo, Version: 0.0.1, Path: github.com/introclass/hyperledger-fabric-chaincode/demo, Id: 3d733bd28accf77b06b2bec065d8ce7315bd7c5441c51beea4650982f79eab46
2018-04-29 18:57:54.327 CST [main] main -> INFO 001 Exiting....
将 peer.sh 中的 peer0.org1.example.com 切换为 peer1.org1.example.com 再安装一次:
./peer.sh chaincode install ./signed-demo-pack.out (不需要重新打包签署)
将 signed-demo-pack.out 复制到 [email protected] 中安装一次
cp Admin\@org1.example.com/signed-demo-pack.out Admin\@org2.example.com/
cd Admin\@org2.example.com/
./peer.sh chaincode install ./signed-demo-pack.out
合约初始化:
cd Admin\@org1.example.com/
./peer.sh chaincode instantiate -o orderer.example.com:7050 --tls true --cafile ./tlsca.example.com-cert.pem -C mychannel -n demo -v 0.0.1 -c '{"Args":["init"]}' -P "OR('Org1MSP.member','Org2MSP.member')"
合约调用:
cd Admin\@org2.example.com/
./peer.sh chaincode invoke -o orderer.example.com:7050 --tls true --cafile ./tlsca.example.com-cert.pem -C mychannel -n demo -c '{"Args":["write","key1","key1valueisabc"]}'
合约查询:
cd User1\@org1.example.com/
./peer.sh chaincode query -C mychannel -n demo -c '{"Args":["query","key1"]}'
更新合约:
cd Admin\@org1.example.com/
./peer.sh chaincode package demo-pack-2.out -n demo -v 0.0.2 -s -S -p github.com/introclass/fabric-chaincode-example/demo
./peer.sh chaincode signpackage demo-pack-2.out signed-demo-pack-2.out
./peer.sh chaincode install ./signed-demo-pack-2.out
./peer.sh chaincode upgrade -o orderer.example.com:7050 --tls true --cafile ./tlsca.example.com-cert.pem -C mychannel -n demo -v 0.0.2 -c '{"Args":["init"]}' -P "OR('Org1MSP.member','Org2MSP.member')"
新的合约也需要在每个peer上单独安装,将 peer0.org1.example.com 切换为 peer1.org1.example.com 再安装一次:
./peer.sh chaincode install ./signed-demo-pack-2.out (不需要重新打包签署)
将 signed-demo-pack.out 复制到 [email protected] 中安装一次
cp Admin\@org1.example.com/signed-demo-pack-2.out Admin\@org2.example.com/
cd Admin\@org2.example.com/
./peer.sh chaincode install ./signed-demo-pack-2.out
合约初始化出现错误,plugin with name escc wasn’t found,这是因为 peer 的配置文件 core.yaml 中缺少配置。在每个节点的 /opt/app/fabric/peer/core.yaml 中添加下面配置:
# ... 省略 ...
profile:
enabled: true
listenAddress: 0.0.0.0:6060
#从这里开始添加配置:
handlers:
authFilters:
-
name: DefaultAuth
-
name: ExpirationCheck # This filter checks identity x509 certificate expiration
decorators:
-
name: DefaultDecorator
endorsers:
escc:
name: DefaultEndorsement
library:
validators:
vscc:
name: DefaultValidation
library:
# 到这里结束
vm:
#...省略...
然后重新启动 peer:
peer node start
出现这个问题是因为 core.yaml 是基于 fabric 1.1 的配置文件改写的,换成 1.2/1.3 版本后,配置文件需要填补新版本增加的配置。