Fabric First-Network
官方bynf
在安装好前期的依赖后,我们运行官方的byfn.sh
,进行官方的Example的测试
# 在fabric-exsamples/first-network下执行
# 按照配置文件初始化
./byfn.sh -m generate
# 启动第一个测试网络
./byfn.sh up
启动后根据环境的不同,会出现所谓的panic
如果一切顺利,会输出这样的日志信息
========= All GOOD, BYFN execution completed ===========
_____ _ _ ____
| ____| | \ | | | _ \
| _| | \| | | | | |
| |___ | |\ | | |_| |
|_____| |_| \_| |____/
此时只需要执行
# 关闭测试网络
./byfn.sh down
当然,我们可以部署不同语言的链码
# 使用Java语言编写的链码启动
./byfn.sh up -l java
注意:此处一定要先执行一下
./byfn.sh down
把现有的网络给清除,两种语言的链码不能共存
My First-Network
自己动手配置一个网络
简述一下项目文件结构,由tree
命令打印出的项目目录如下
├── basic-network
│ ├── README.md
│ ├── config
│ ├── configtx.yaml
│ ├── connection.yaml
│ ├── crypto-config
│ ├── crypto-config.yaml
│ ├── docker-compose.yml
│ ├── generate.sh
│ ├── init.sh
│ ├── start.sh
│ ├── stop.sh
│ └── teardown.sh
├── chaincode
│ ├── hyperledger
│ └── test1
└── startup.sh
其中basic-network
中是保存的和网络相关的文件
chaincode
中保存的是链码
配置一个简单的Fabric网络
从fabric-samples
中获取一个基础网络的例子,我们可以基于这个例子对网络进行配置
配置身份信息文件
身份信息配置文件为crypto-config.yaml
OrdererOrgs:
- Name: Orderer
Domain: example.com
Specs:
- Hostname: orderer
PeerOrgs:
- Name: Org1
Domain: org1.example.com
Template:
Count: 1
Users:
Count: 1
配置身份信息主要用于以后的认证,这里配置了一个Orderer
和一个Organization
,其中这个组织只有一个Peer一个User
配置交易文件
交易配置文件为configtx.yaml
Organizations:
# 基本组织信息的配置,主要是身份信息的认证
- &OrdererOrg
Name: OrdererOrg
ID: OrdererMSP
MSPDir: crypto-config/ordererOrganizations/example.com/msp
- &Org1
Name: Org1MSP
ID: Org1MSP
MSPDir: crypto-config/peerOrganizations/org1.example.com/msp
AnchorPeers:
- Host: peer0.org1.example.com
Port: 7051
Application: &ApplicationDefaults
Organizations:
Orderer: &OrdererDefaults
# Orderer排序节点的配置信息
# Orderer Type: The orderer implementation to start
# Available types are "solo" and "kafka"
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:
# 创世区块的配置
OneOrgOrdererGenesis:
Orderer:
<<: *OrdererDefaults
Organizations:
- *OrdererOrg
Consortiums:
SampleConsortium:
Organizations:
- *Org1
# channel的配置
OneOrgChannel:
Consortium: SampleConsortium
Application:
<<: *ApplicationDefaults
Organizations:
- *Org1
这里主要配置和网络交易相关的信息,包括排序节点,创世区块,Channel的配置,都可以在这个里面进行。
生成配置文件
我们可以一步一步来生成这个配置文件
执行这个步骤时,请务必保证
first-network
中的bin
目录已经加入$PATH
中了
生成证书等身份信息文件
cryptogen generate --config=./crypto-config.yaml
根据配置文件生成对应的证书
生成创世区块
mkdir config
configtxgen -profile OneOrgOrdererGenesis -outputBlock ./config/genesis.block
创世区块的生成在当前目录的/config
目录下,执行这个命令之前需要执行新建目录执行
生成Channel
相关文件
configtxgen -profile OneOrgChannel -outputCreateChannelTx ./config/channel.tx -channelID $CHANNEL_NAME
这里的
$CHANNEL_NAME
在实际应用中可以修改,但是需要保持文件之间的一致性
生成锚节点相关文件
configtxgen -profile OneOrgChannel -outputAnchorPeersUpdate ./config/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
使用一个脚本来代替刚刚的步骤
当然我们不会手动去一个一个执行这个命令,一个脚本能解决大部分问题
#!/bin/sh
export PATH=$GOPATH/src/github.com/hyperledger/fabric/build/bin:${PWD}/../bin:${PWD}:$PATH
export FABRIC_CFG_PATH=${PWD}
CHANNEL_NAME=fishchannel
# remove previous crypto material and config transactions
rm -fr config/*
rm -fr crypto-config/*
mkdir config
# generate crypto material
cryptogen generate --config=./crypto-config.yaml
if [ "$?" -ne 0 ]; then
echo "Failed to generate crypto material..."
exit 1
fi
# generate genesis block for orderer
configtxgen -profile OneOrgOrdererGenesis -outputBlock ./config/genesis.block
if [ "$?" -ne 0 ]; then
echo "Failed to generate orderer genesis block..."
exit 1
fi
# generate channel configuration transaction
configtxgen -profile OneOrgChannel -outputCreateChannelTx ./config/channel.tx -channelID $CHANNEL_NAME
if [ "$?" -ne 0 ]; then
echo "Failed to generate channel configuration transaction..."
exit 1
fi
# generate anchor peer transaction
configtxgen -profile OneOrgChannel -outputAnchorPeersUpdate ./config/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
if [ "$?" -ne 0 ]; then
echo "Failed to generate anchor peer update for Org1MSP..."
exit 1
fi
配置docker-compose.yml
这关乎我们能否成功搭建网络,我们需要通过这个文件来启动网络,这个的核心就是配置一些参数和映射,要保持和刚刚的几个文件相对应,后面如果出现错误有可能是这个没有对应上导致的
#
# Copyright IBM Corp All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#
version: '2'
networks:
basic:
services:
ca.example.com:
image: hyperledger/fabric-ca
environment:
- FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
- FABRIC_CA_SERVER_CA_NAME=ca.example.com
- FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem
- FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/26c967a4ac4d03185e92b58c0b01c580715890605e0627b5319ca0be78da80e2_sk
# 主要注意这里的FABRIC_CA_SERVER_CA_KEYFILE,和对应目录下的CA密钥要能对应上
ports:
- "7054:7054"
command: sh -c 'fabric-ca-server start -b admin:adminpw'
volumes:
- ./crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config/msp/keystore
container_name: ca.example.com
networks:
- basic
orderer.example.com:
container_name: orderer.example.com
image: hyperledger/fabric-orderer
environment:
- FABRIC_LOGGING_SPEC=info
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
- ORDERER_GENERAL_GENESISMETHOD=file
- ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/genesis.block
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP
- ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/msp/orderer/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/orderer
command: orderer
ports:
- 7050:7050
volumes:
- ./config/:/etc/hyperledger/configtx
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/:/etc/hyperledger/msp/orderer
- ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/:/etc/hyperledger/msp/peerOrg1
networks:
- basic
peer0.org1.example.com:
container_name: peer0.org1.example.com
image: hyperledger/fabric-peer
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer0.org1.example.com
- FABRIC_LOGGING_SPEC=info
- CORE_CHAINCODE_LOGGING_LEVEL=info
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/peer/
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
# # the following setting starts chaincode containers on the same
# # bridge network as the peers
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_basic
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
# command: peer node start
command: peer node start --peer-chaincodedev=true
ports:
- 7051:7051
- 7053:7053
volumes:
- /var/run/:/host/var/run/
- ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/msp/peer
- ./crypto-config/peerOrganizations/org1.example.com/users:/etc/hyperledger/msp/users
- ./config:/etc/hyperledger/configtx
depends_on:
- orderer.example.com
- couchdb
networks:
- basic
couchdb:
container_name: couchdb
image: hyperledger/fabric-couchdb
# 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=
- COUCHDB_PASSWORD=
ports:
- 5984:5984
networks:
- basic
cli:
container_name: cli
image: hyperledger/fabric-tools
tty: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=info
- CORE_PEER_ID=cli
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
- CORE_CHAINCODE_KEEPALIVE=10
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ./../chaincode/:/opt/gopath/src/github.com/
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
networks:
- basic
编写启动脚本
#!/bin/bash
#
# Copyright IBM Corp All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#
# Exit on first error, print all commands.
set -ev
# don't rewrite paths for Windows Git Bash users
export MSYS_NO_PATHCONV=1
# 关闭正在运行的容器
docker-compose -f docker-compose.yml down
# 启动容器
docker-compose -f docker-compose.yml up -d ca.example.com orderer.example.com peer0.org1.example.com couchdb cli
docker ps -a
# wait for Hyperledger Fabric to start
# incase of errors when running later commands, issue export FABRIC_START_TIMEOUT=<larger number>
export FABRIC_START_TIMEOUT=10
#echo ${FABRIC_START_TIMEOUT}
sleep ${FABRIC_START_TIMEOUT}
# 创建频道
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp" peer0.org1.example.com peer channel create -o orderer.example.com:7050 -c fishchannel -f /etc/hyperledger/configtx/channel.tx
# Join peer0.org1.example.com to the channel.
# 加入频道
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp/users/Admin@org1.example.com/msp" peer0.org1.example.com peer channel join -b fishchannel.block
至此,总体上的网络配置基本结束
Trouble Shooting
一个成功的配置后的输出中所有镜像都是正常运行的
其中包括
- Fabric-ca
- peer
- orderer
- couchdb
- cli
如果有缺少的,那么需要通过修改配置 ,或者根据提示信息修改
在启动网络前,请务必清理干净docker容器中的镜像
使用
docker stop $(docker ps -aq)
和docker rm $(docker ps -aq)
移除全部镜像
编写一个简单的链码
网上的教程大多都是基于Gradle
的,我使用maven
较多,其实官方的例子里是有maven的例子的,我们拷贝下来就可以了
附上网址: https://github.com/hyperledger/fabric-chaincode-java
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>my_java_chaincode</groupId>
<artifactId>my_java_chaincode</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- fabric-chaincode-java -->
<fabric-chaincode-java.version>1.4.4</fabric-chaincode-java.version>
<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
<!-- Test -->
<junit.version>4.11</junit.version>
</properties>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://www.jitpack.io</url>
</repository>
<repository>
<id>nexus</id>
<url>https://nexus.hyperledger.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<!-- fabric-chaincode-java -->
<dependency>
<groupId>org.hyperledger.fabric-chaincode-java</groupId>
<artifactId>fabric-chaincode-shim</artifactId>
<version>${fabric-chaincode-java.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hyperledger.fabric-chaincode-java</groupId>
<artifactId>fabric-chaincode-protos</artifactId>
<version>${fabric-chaincode-java.version}</version>
<scope>compile</scope>
</dependency>
<!-- fabric-sdk-java -->
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Test Artifacts -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.2</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>chaincode</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>chaincode.example.SimpleChaincode</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<!-- filter out signature files from signed dependencies, else repackaging fails with security ex -->
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
这里我就添加了一个Jackson
依赖,主要用于处理Json数据
编写链码
模型实体
/**
* @author lucasgao
*/
public class Fish {
private String vessel;
private String location;
private String time;
private String holder;
public Fish(String vessel, String location, String time, String holder) {
this.vessel = vessel;
this.location = location;
this.time = time;
this.holder = holder;
}
public String getVessel() {
return vessel;
}
public void setVessel(String vessel) {
this.vessel = vessel;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getHolder() {
return holder;
}
public void setHolder(String holder) {
this.holder = holder;
}
@Override
public String toString() {
return "Fish{" +
"vessel='" + vessel + '\'' +
", location='" + location + '\'' +
", time=" + time +
", holder='" + holder + '\'' +
'}';
}
}
这个当然是可以更换的,这里因为以渔业数据上链为背景
链码主体
/**
* @author lucasgao
*/
public class SimpleChaincode extends ChaincodeBase {
//日志
private static Log _logger = LogFactory.getLog(SimpleChaincode.class);
//Jackson核心对象
public ObjectMapper objectMapper = new ObjectMapper();
//初始化方法
@Override
public Response init(ChaincodeStub stub) {
_logger.info("Init java simple ChainCode");
//生成三条鱼
ArrayList<Fish> fishList = new ArrayList<Fish>();
fishList.add(new Fish("a1","67,-70","2020-9-1","111"));
fishList.add(new Fish("b2","64,-70","2020-9-5","222"));
fishList.add(new Fish("c3","67,-20","2020-9-2","333"));
try {
//逐个放入世界状态中
for (int i = 0; i < fishList.size(); i++) {
_logger.info("put:"+fishList.get(i));
//这个是核心方法,根据键值的方式放入世界状态
stub.putStringState("fish"+i, objectMapper.writeValueAsString(fishList.get(i)));
}
}catch (Exception e){
e.printStackTrace();
}
//作出回应
return newSuccessResponse("init success!!!");
}
@Override
public Response invoke(ChaincodeStub stub) {
//invoke方法,调用链码的时候会使用这个方法
try {
_logger.info("Invoke java simple ChainCode");
//获取方法名
String func = stub.getFunction();
//获取参数
List<String> params = stub.getParameters();
//方法分发
if ("invoke".equals(func)) {
return invoke(stub, params);
}
if ("delete".equals(func)) {
return delete(stub, params);
}
if ("query".equals(func)) {
return query(stub, params);
}
return newErrorResponse("Invalid invoke function name. Expecting one of: [\"invoke\", \"delete\", \"query\"]");
} catch (Throwable e) {
return newErrorResponse(e+"\t function name:"+stub.getFunction());
}
}
//重载方法,在世界状态中存入鱼
private Response invoke(ChaincodeStub stub, List<String> args) {
if (args.size() < 5) {
return newErrorResponse("Incorrect number of arguments. Expecting 5, Invoke fail");
}
Fish fish = new Fish(args.get(1), args.get(2), args.get(3), args.get(4));
_logger.info("add: "+fish);
try {
stub.putStringState(args.get(0), objectMapper.writeValueAsString(fish));
}catch (Exception e){
e.printStackTrace();
}
return newSuccessResponse("invoke finished successfully");
}
// Deletes an entity from state
// 删除鱼
private Response delete(ChaincodeStub stub, List<String> args) {
if (args.size() != 1) {
return newErrorResponse("Incorrect number of arguments. Expecting 1");
}
String key = args.get(0);
// Delete the key from the state in ledger
stub.delState(key);
return newSuccessResponse("delete success");
}
// query callback representing the query of a chaincode
// 查询鱼
private Response query(ChaincodeStub stub, List<String> args) {
if (args.size() < 1) {
return newErrorResponse("Incorrect number of arguments. Expecting 1");
}
String fishId = args.get(0);
//从世界状态中查询
String fishString = stub.getStringState(fishId);
Fish fish = null;
try{
fish = objectMapper.readValue(fishString,Fish.class);
}catch (Exception e){
e.printStackTrace();
}
_logger.info("query response: "+fish);
String val = "queryId:"+fishId+" result:"+fishString+"";
return newSuccessResponse("query success", ByteString.copyFrom(val, UTF_8).toByteArray());
}
public static void main(String[] args) {
new SimpleChaincode().start(args);
}
}
代码也是比较简单的,链码所写的就是业务逻辑相关的一些信息,区块链就像一个数据库可以实现查询,删除等操作
部署链码
我们可以编写一个脚本部署链码,但是在此之前,我建议先手动部署一下链码试试看
首先先进入cli中
docker exec -it cli bash
然后先安装链码,因为我们只有一个peer结点,只需要安装一遍
peer chaincode install -p /opt/gopath/src/github.com/test1 -v 1.0 -n mycc -l java
其中-p
后面的跟路径的,-v
是版本,-n
是链码名称,-l
是语言
然后我们实例化链码,这一步等待的时间可能比较长
peer chaincode instantiate -n mycc -v 1.0 -c '{"Args":[]}' -C fishchannel -o orderer.example.com:7050
然后我们就可以去测试一下链码了
peer chaincode invoke -n mycc -c '{"Args":["query","fish0"]}' -C fishchannel
如果没有报错,那么就成功了
编写一个类似byfn.sh
的脚本
#!/bin/bash
#
# Copyright IBM Corp All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#
# Exit on first error
set -e
# don't rewrite paths for Windows Git Bash users
export MSYS_NO_PATHCONV=1
starttime=$(date +%s)
CC_SRC_LANGUAGE=java
CC_SRC_LANGUAGE=`echo "$CC_SRC_LANGUAGE" | tr [:upper:] [:lower:]`
CC_RUNTIME_LANGUAGE=java
CC_SRC_PATH=/opt/gopath/src/github.com/test1
# clean the keystore
rm -rf ./hfc-key-store
# launch network; create channel and join peer to channel
cd basic-network
echo y | ./stop.sh
./start.sh
CONFIG_ROOT=/opt/gopath/src/github.com/hyperledger/fabric/peer
ORG1_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
ORG1_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
ORG2_MSPCONFIGPATH=${CONFIG_ROOT}/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
ORG2_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
ORDERER_TLS_ROOTCERT_FILE=${CONFIG_ROOT}/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
set -x
echo "Installing smart contract on peer0.org1.example.com"
docker exec \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \
-e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \
-e CORE_PEER_TLS_ROOTCERT_FILE=${ORG1_TLS_ROOTCERT_FILE} \
cli \
peer chaincode install \
-n mycc \
-v 1.0 \
-p "$CC_SRC_PATH" \
-l "$CC_RUNTIME_LANGUAGE"
sleep 20
echo "Instantiating smart contract on mychannel"
docker exec \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \
cli \
peer chaincode instantiate \
-o orderer.example.com:7050 \
-C fishchannel \
-n mycc \
-l "$CC_RUNTIME_LANGUAGE" \
-v 1.0 \
-c '{"Args":[]}'
echo "Waiting for instantiation request to be committed ..."
# sleep 10
echo "Submitting initLedger transaction to smart contract on mychannel"
echo " "
sleep 10
docker exec \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \
cli \
peer chaincode invoke \
-o orderer.example.com:7050 \
-C fishchannel \
-n mycc \
-c '{"function":"query","Args":["fish0"]}'
set +x
echo " "
docker exec \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \
cli \
peer chaincode invoke \
-o orderer.example.com:7050 \
-C fishchannel \
-n mycc \
-c '{"function":"query","Args":["fish1"]}'
set +x
echo " "
docker exec \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \
cli \
peer chaincode invoke \
-o orderer.example.com:7050 \
-C fishchannel \
-n mycc \
-c '{"function":"query","Args":["fish2"]}'
set +x
# 测试向世界状态写数据
docker exec \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \
cli \
peer chaincode invoke \
-o orderer.example.com:7050 \
-C fishchannel \
-n mycc \
-c '{"function":"invoke","Args":["fish4","d4","90,23","2020-9-9","lucas"]}'
set +x
echo " "
sleep 30
docker exec \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_MSPCONFIGPATH=${ORG1_MSPCONFIGPATH} \
cli \
peer chaincode invoke \
-o orderer.example.com:7050 \
-C fishchannel \
-n mycc \
-c '{"function":"query","Args":["fish4"]}'
set +x
cat <<EOF
Total setup execution time : $(($(date +%s) - starttime)) secs ...
all good!!!!!!!!!!!
EOF
总结
在编写Fabric的时候遇到了很多坑,因为很多错误都不能人性化地显示出来,我们只能逐个去分析,先保证这个网络能跑通,再去部署链码