fabric + java 链码测试(一)
所有节点既是客户端,又是客户端(节点对等)
Fabric 开发
一、区块链技术
p2p网络通信协议
所有节点既是客户端,又是客户端(节点对等)
密码学
哈希(hash):满足正向快速、逆向困难;输入敏感;防止哈希碰撞
加解密:非对称加(RSA、椭圆曲线)
共识算法(分布式一致性)
-
强一致性
-
最终一致性
CAP原理
一致性、可用性、分区容忍性(三者选二)
ACID原理
原子性、一致性、隔离性、持久性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MzxeYAQ0-1682322393388)(C:\Users\王涛\AppData\Roaming\Typora\typora-user-images\image-20230406103854943.png)]
智能合约
生命周期:1、打包;2、安装;3、实例化(执行 Init() );4、升级;5、交互;
交互流程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1DQR9Rkk-1682322315197)(C:\Users\王涛\AppData\Roaming\Typora\typora-user-images\image-20230410162231402.png)]
系统链码:
- LSCC(管理链码的生命的周期,主要是安装、实例化、升级)
- CSCC(配置)
- QSCC(管理账本)
- ESCC(交易背书)
- VSCC(交易验证)
编程接口:
- Init():只执行一次主要负责初始化的操作
- Invoke():应用程序链码交互的接口
链码的SDK接口:
- 参数解析
- 交易信息
- 状态的操作
- 链码的互操作
- 事件发送
- 其他
链码编程的禁忌:
- 分布式系统、多节点隔离执行
- 随机函数
- 系统时间
- 不稳定的外部依赖
网络搭建
1、配置文件的准备
- crypto-config.yaml
- configtx.yaml
2、创世配置构造
- MSP证书
- Orderer创世区块
- Channel创世交易(区块)
- 组织主节点配置文件
3、启动网络
- 创建Channel
- 加入Channel
- 安装Chaincode
- 实例化Chaincode
- Chaincode交互测试
fabric新特性
多个组织必须同意链码的参数:
在Fabric的1.x版本中,一个组织可以为所有其他渠道成员设置链码的参数(例如,认可策略)。新的Fabric链码生命周期更加灵活,因为它既支持集中式信任模型(例如先前生命周期模型的模型),也支持分散模型,这些模型需要足够数量的组织才能在背书策略上生效。
-
**更安全的链码升级过程:**在先前的链码生命周期中,升级事务可能由单个组织发出,这给尚未安装新链码的渠道成员带来了风险。新模型仅在足够数量的组织批准升级后才允许升级链码。
-
**更容易的认可策略更新:**Fabric生命周期允许您更改认可策略,而无需重新打包或重新安装链码。用户还可以利用新的默认策略,该策略需要频道中大多数成员的认可。在从渠道中添加或删除组织时,该策略会自动更新。
-
**可检查的链代码包:**Fabric生命周期将链码打包在易于阅读的tar文件中。这使得检查链码包和协调跨多个组织的安装变得更加容易。
-
**使用一个程序包在通道上启动多个链码:**上一个生命周期使用安装链码包时指定的名称和版本定义了通道上的每个链码。现在,您可以使用单个chaincode程序包,并在相同或不同的通道上以不同的名称多次部署它。
二、实战开发
2.1、实践测试
安装智能合约,首先需要将合约打包为 .tar.gz
peer lifecycle chaincode --help
# help相关解释
# 智能合约操作合集
Perform chaincode operations: package|install|queryinstalled|getinstalledpackage|approveformyorg|checkcommitreadiness|commit|querycommitted
Usage:
peer lifecycle chaincode [command]
Available Commands:
approveformyorg 同意智能合约定义
checkcommitreadiness 检查合约是否在通道上已经定义
commit 提交合约定义到指定通道
getinstalledpackage 从节点中获取已经安装的链码包
install 部署链码
package 打包链码
querycommitted 查询节点上已提交的链码定义
queryinstalled 查询节点已经安装的链码
由于要打包合约此处我们使用 peer lifecycle chaincode package
在容器内部执行命令
peer lifecycle chaincode package mycc2.tar.gz --path github.com/hyperledger/fabric-samples/chaincode/abstore/go/ --lang golang --label mycc_2
三、java链码开发
3.1、java合约
springboot + fabric 2.2.10
pom文件的相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<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>org.example</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<fabric.version>2.2.10</fabric.version>
</properties>
<repositories>
<repository>
<id>aliyun</id>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://www.jitpack.io</url>
</repository>
<repository>
<id>artifactory</id>
<url>https://hyperledger.jfrog.io/hyperledger/fabric-maven</url>
</repository>
</repositories>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.4.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish/jakarta.el -->
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>4.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hyperledger.fabric-chaincode-java/fabric-chaincode-shim -->
<dependency>
<groupId>org.hyperledger.fabric-chaincode-java</groupId>
<artifactId>fabric-chaincode-shim</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.hyperledger.fabric-chaincode-java</groupId>
<artifactId>fabric-chaincode-protos</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.11.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.79</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</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>org.hyperledger.fabric.contract.ContractRouter</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>
实体 Cat
package org.example.demo;
import lombok.Data;
import lombok.experimental.Accessors;
import org.hyperledger.fabric.contract.annotation.DataType;
import org.hyperledger.fabric.contract.annotation.Property;
/**
* @Author: kingtao
* @Date: 2023-04-21-19:31
* @Description: 猫
*/
@Data
@DataType
@Accessors(chain = true)
public class Cat {
@Property
private String name;
@Property
private Integer age;
@Property
private String color;
@Property
private String breed;
}
合约类
package org.example.demo;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.contract.ContractInterface;
import org.hyperledger.fabric.contract.annotation.*;
import org.hyperledger.fabric.shim.ChaincodeStub;
import java.util.Random;
/**
* @Author: kingtao
* @Date: 2023-04-21-19:32
* @Description:
*/
@Contract(
name = "Cat",
info = @Info(
title = "Cat contract",
description = "The hyperlegendary car contract",
version = "0.0.1-SNAPSHOT",
license = @License(
name = "Apache 2.0 License",
url = "http://www.apache.org/licenses/LICENSE-2.0.html"),
contact = @Contact(
email = "f.carr@example.com",
name = "F Carr",
url = "https://hyperledger.example.com")))
@Default
public class CatContract implements ContractInterface {
/**
* 初始化 10 只猫
*
* @param ctx
*/
@Transaction
public void initLedger(final Context ctx) {
ChaincodeStub stub = ctx.getStub();
for (int i = 0; i < 10; i++) {
Cat cat = new Cat().setName("cat-" + i)
.setAge(new Random().nextInt())
.setBreed("橘猫")
.setColor("橘黄色");
stub.putStringState(cat.getName(), JSON.toJSONString(cat));
}
}
@Transaction
public Cat queryCat(final Context ctx, final String key) {
ChaincodeStub stub = ctx.getStub();
String catState = stub.getStringState(key);
if (StringUtils.isBlank(catState)) {
String error = String.format("姓名为 cat-%s 的猫不存在", key);
System.out.println(error);
throw new ClassCastException(error);
}
return JSON.parseObject(catState, Cat.class);
}
@Transaction
public Cat createCat(final Context ctx, final String key, String name, Integer age, String color, String breed) {
ChaincodeStub stub = ctx.getStub();
String catState = stub.getStringState(key);
if (StringUtils.isNotBlank(catState)) {
String error = String.format("姓名为 cat-%s 的猫存在", key);
System.out.println(error);
throw new ClassCastException(error);
}
Cat cat = new Cat();
cat.setAge(age);
cat.setName(name);
cat.setBreed(breed);
cat.setColor(color);
return cat;
}
@Transaction
public Cat updateCat(final Context ctx, final String key, String name, Integer age, String color, String breed) {
ChaincodeStub stub = ctx.getStub();
String catState = stub.getStringState(key);
if (StringUtils.isBlank(catState)) {
String error = String.format("姓名为 cat-%s 的猫不存在", key);
System.out.println(error);
throw new ClassCastException(error);
}
Cat cat = new Cat();
cat.setAge(age);
cat.setName(name);
cat.setBreed(breed);
cat.setColor(color);
stub.putStringState(key, JSON.toJSONString(cat));
return cat;
}
@Transaction
public Cat updateCat(final Context ctx, final String key, Cat cat) {
ChaincodeStub stub = ctx.getStub();
String catState = stub.getStringState(key);
if (StringUtils.isBlank(catState)) {
String error = String.format("姓名为 cat-%s 的猫不存在", key);
System.out.println(error);
throw new ClassCastException(error);
}
stub.putStringState(key, JSON.toJSONString(cat));
return cat;
}
@Transaction
public Cat deleteCat(final Context ctx, final String key) {
ChaincodeStub stub = ctx.getStub();
String catState = stub.getStringState(key);
if (StringUtils.isBlank(catState)) {
String error = String.format("姓名为 cat-%s 的猫不存在", key);
System.out.println(error);
throw new ClassCastException(error);
}
stub.delState(key);
return JSON.parseObject(catState, Cat.class);
}
@Override
public void beforeTransaction(Context ctx) {
System.out.println("****************************** 交易开始前 ***************************************");
// log.info("*************************************** beforeTransaction ***************************************");
}
@Override
public void afterTransaction(Context ctx, Object result) {
System.out.println("****************************** 交易开始后 ***************************************");
// log.info("*************************************** afterTransaction ***************************************");
System.out.println("result --------> " + result);
}
}
3.2、部署到网络上
./network.sh up creatChannel
# 创建链码
peer lifecycle chaincode package demo.tar.gz --path /opt/code/java-chaincode-demo/ --lang java --label demo_1
命令解释:此命令将在当前目录中创建一个名为 demo.tar.gz的软件包。
-–lang 标签用于指定链码语言
-–path 标签提供智能合约代码的位置,该路径必须是标准路径或相对于当前工作目录的路径
-–label 标签用于指定一个链码标签,该标签将在安装链码后对其进行标识。建议您的标签包含链码名称和版本。
# 安装链码
打包 hyperledger-fabric-contract-java-demo 智能合约后,我们可以在peer节点上安装链码。需要在将认可交易的每个peer节点上安装链码。因为我们将设置背书策略以要求来自Org1和Org2的背书,所以我们需要在两个组织的peer节点上安装链码:peer0.org1.example.com和peer0.org2.example.com
# Org1 peer节点安装链码
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/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
[root@localhost test-network]# peer lifecycle chaincode install demo.tar.gz
2023-04-21 20:42:52.672 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nGdemo_1:cf6d39b12007ca0c0a70fffd14e778006481571d1f85d15a54b81572d6cd1715\022\006demo_1" >
2023-04-21 20:42:52.673 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: demo_1:cf6d39b12007ca0c0a70fffd14e778006481571d1f85d15a54b81572d6cd1715
# Org2 peer节点安装链码
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_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/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
[root@localhost test-network]# peer lifecycle chaincode install demo.tar.gz
2023-04-21 20:47:19.704 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nGdemo_1:cf6d39b12007ca0c0a70fffd14e778006481571d1f85d15a54b81572d6cd1715\022\006demo_1" >
2023-04-21 20:47:19.705 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: demo_1:cf6d39b12007ca0c0a70fffd14e778006481571d1f85d15a54b81572d6cd1715
# 注意:安装链码时,链码由peer节点构建。如果智能合约代码有问题,install命令将从链码中返回所有构建错误。
# 因为安装 java 链码的时候需要经过 maven 构建以及下载依赖包的过程这个过程有可能会较慢,所以 install 命令有可能会返回一个超时错误:。但是其实链码的 docker 容器内此时还在执行构建任务没有完成。等到构建成功了链码包也就安装成功了。
安装链码包后,需要通过组织的链码定义。该定义包括链码管理的重要参数,例如名称,版本和链码认可策略。
如果组织已在其peer节点上安装了链码,则他们需要在其组织通过的链码定义中包括包ID。包ID用于将peer节点上安装的链码与通过的链码定义相关联,并允许组织使用链码来认可交易。
# 查询包ID
peer lifecycle chaincode queryinstalled
包ID是链码标签和链码二进制文件的哈希值的组合。每个peer节点将生成相同的包ID。你应该看到类似于以下内容的输出:
@localhost test-network]# peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: demo_1:cf6d39b12007ca0c0a70fffd14e778006481571d1f85d15a54b81572d6cd1715, Label: demo_1
通过链码时,我们将使用包ID,因此,将包ID保存为环境变量。将返回的包ID粘贴到下面的命令中。
[root@localhost test-network]# export CC_PACKAGE_ID=demo_1:f2b97d99993b57d40b48d55f1f706cb47447ba3b6cf2ef39f5f9108101dbafd0
# Org2 通过链码定义
# 因为已经设置了环境变量为peer CLI作为Orig2管理员进行操作,所以我们可以以Org2组织级别将 hyperledger-fabric-contract-java-demo 的链码定义通过。使用 peer lifecycle chaincode approveformyorg命令通过链码定义:
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name demo --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
# Org1 通过链码定义
# 设置以下环境变量以Org1管理员身份运行:
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_ADDRESS=localhost:7051
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name demo --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
# 使用peer lifecycle chaincode checkcommitreadiness命令来检查通道成员是否已批准相同的链码定义:
[root@localhost test-network]# peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name demo --version 1.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json
{
"approvals": {
"Org1MSP": true,
"Org2MSP": true
}
}
由于作为通道成员的两个组织都同意了相同的参数,因此链码定义已准备好提交给通道。你可以使用peer lifecycle chaincode commit命令将链码定义提交到通道。commit命令还需要由组织管理员提交。
peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name demo --version 1.0 --sequence 1 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --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
可以使用peer lifecycle chaincode querycommitted命令来确认链码定义已提交给通道。
peer lifecycle chaincode querycommitted --channelID mychannel --name demo --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
如果将链码成功提交给通道,该querycommitted命令将返回链码定义的顺序和版本:
Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true]
3.3、调用链码
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 mychannel -n demo --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":"createCat","Args":["cat-0" , "tom" , "3" , "蓝色" , "大懒猫"]}'
peer chaincode query -C mychannel -n demo -c '{"Args":["queryCat" , "cat-0"]}'
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 mychannel -n demo --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":"updateCat","Args":["cat-0" , "tom" , "3" , "白色" , "超级大懒猫"]}'
peer chaincode query -C mychannel -n demo -c '{"Args":["queryCat" , "cat-0"]}'
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 mychannel -n demo --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":"deleteCat","Args":["cat-0"]}'
peer chaincode query -C mychannel -n demo -c '{"Args":["queryCat" , "cat-0"]}'
3.4、链码升级测试
peer lifecycle chaincode package demo.tar.gz --path /opt/code/java-chaincode-demo/ --lang java --label demo_2
export CC_PACKAGE_ID=demo_2:xxxx
# 参考上面对俩个组织安装链码
....
# 分别对两个组织的管理员进行定义通过
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name demo --version 1.1 --package-id $CC_PACKAGE_ID --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
# 链码提交到通道
peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name demo --version 1.1 --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --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
更多推荐
所有评论(0)