前言
fabric官方提供的java sdk包含两个项目fabric-sdk-java
和fabric-gateway-java
,前者用于与fabric网络交互的低级API(比如创建channel、加入channel、安装chaincode等),fabric-sdk-java
还包含了fabric-ca client
的实现,后者为高级API(主要针对chaincode的调用),fabric-gateway-java
使用了fabric-sdk-java
的api。
1 环境准备
环境配置 | 版本 |
Windows | 10 |
Fabric | 2.0 |
Java SDK | 8/1.8 |
Maven | 3.6.3 |
2 新建Maven工程
在pom.xml文件中添加如下依赖
<dependency>
<groupId>org.hyperledger.fabric</groupId>
<artifactId>fabric-gateway-java</artifactId>
<version>2.0.0</version>
</dependency>
3 新建resources资源根
3.1 新建connection.json文件
connection.json文件的作用主要是为了连接Linux中的fabric网络,主要包括客户端、通道、组织、排序节点、节点以及证书的描述。这里是官方编写模板
json文件结构如下图所示:
各部分的作用如下表所示:
参数名 | 描述 |
name | 自定义网络名称 |
version | 自定义网络版本 |
client | 客户端相关信息 |
channels | 通道信息 |
organizations | 组织信息 |
orderers | 排序节点信息 |
peer | peer节点信息 |
certificateAuthorities | ca信息 |
注意,connection.json文件中的IP要与虚拟机或者服务器的IP相一致,通道名也要与网络中的通道名相一致等等。
3.2 新建crypto-config文件夹
此文件夹主要用来存放fabric网络的证书配置。
这一步我是从first-network
案例中的crypto-config
直接拷贝过来的。
3.3 文件夹架构
最终resources资源根的架构如下图所示:
4 编写主程序
在src/main/java
目录下编写主程序
4.1 创建网关账户
网关账户就是相当于连接fabric网络的fabric用户对象。
//使用org1中的user1初始化一个网关wallet账户用于连接网络
Wallet wallet = Wallets.newInMemoryWallet();
Path certificatePath = credentialPath.resolve(Paths.get("signcerts", "User1@org1.example.com-cert.pem"));
certificate = readX509Certificate(certificatePath);
Path privateKeyPath = credentialPath.resolve(Paths.get("keystore", "priv_sk"));
privateKey = getPrivateKey(privateKeyPath);
//放进wallet
wallet.put("user",Identities.newX509Identity("Org1MSP",certificate,privateKey));
账户对象都可以存放到wallet
里面,方便存取。
证书对象使用的是org1的user私钥,证书。
4.2 创建网关
通过onnectionProfile
以及网关账户创建网关。
//根据connection-org1.json 获取Fabric网络连接对象
GatewayImpl.Builder builder = (GatewayImpl.Builder) Gateway.createBuilder();
builder.identity(wallet, "user").networkConfig(NETWORK_CONFIG_PATH);
NETWORK_CONFIG_PATH
: connectionProfile
文件路径
4.3 连接网关
//连接网关
gateway = builder.connect();
//获取mychannel通道
Network network = gateway.getNetwork("mychannel");
//获取合约对象
Contract contract = network.getContract("mycc");
网关连接后getNetwork
:可以根据通道名称获取Fabric具体通道网络。network.getContrac
:可以根据合约名称获取部署到对应通道的智能合约对象。
4.4 交易
基于上一部分的内容,最后a的最终值是110
4.4.1 首先我们对合约对象a当前的值进行查询
//查询合约对象evaluateTransaction
byte[] queryAResultBefore = contract.evaluateTransaction("query","a");
System.out.println("交易前:"+new String(queryAResultBefore, StandardCharsets.UTF_8));
4.4.2 然后调用addTen进行a+10
// 创建并且提交交易
byte[] invokeResult = contract.createTransaction("addTen")
.setEndorsingPeers(network.getChannel().getPeers(EnumSet.of(Peer.PeerRole.ENDORSING_PEER)))
.submit("a");
System.out.println(new String(invokeResult, StandardCharsets.UTF_8));
此处setEndorsingPeers
设置背书节点,这里选择了通道中背书权限节点集合
4.4.3 交易完成后再次进行查询
//查询合约对象evaluateTransaction
byte[] queryAResultAfter = contract.evaluateTransaction("query","a");
System.out.println("交易后:"+new String(queryAResultAfter, StandardCharsets.UTF_8));
5 工程架构图
最终工程架构如下图所示:
6 执行程序
由于执行了两遍,所以最后在110的基础上进行了两次addTen
操作,结果如下图所示:
7 总结
在调用交易方面,通过网关这种确实简单了很多,后面应用程序进行设计的时候,可以将网关这个包单独封装,应用程序再进行调用,可以基于网关这层保障应用程序的业务稳定性。而再创建通道、加入通道、部署合约等操作应该还是SDK那套,后续章节也将继续实践。