Fabric Gateway SDK 实现Fabric的编程模型,提供了一系列简单的API给应用程序与Fabric区块链网络进行交互

应用程序将各自的网络交互委托给其网关,每个网关都了解网络信道拓扑,包括组织的多个Peer节点和排序节点,使应用程序专注于业务逻辑;Peer节点可以使用gossip协议在组织内部和组织之间相互通信。

Maven依赖

<dependency>
<groupId>org.hyperledger.fabric</groupId>
<artifactId>fabric-gateway-java</artifactId>
<version>2.2.3</version>
</dependency>

准备网络证书

创建目录 crypto-config 把 orderer 和 peer 节点的证书文件复制进来。

证书文件从 fabric-samples 的 test-network 目录中复制 ordererOrganizations 与 peerOrganizations 文件夹

springboot工程结构如下:

准备网络证书

创建文件 connection.json 内容如下:

{
"name": "basic-network",
"version": "1.0.0",
"dependencies": {
},
"client": {
"organization": "Org1",
"connection": {
"timeout": {
"peer": {
"endorser": "300"
},
"orderer": "300"
}
}
},
"channels": {
"mychannel": {
"orderers": [
"orderer.example.com"
],
"peers": {
"peer0.org1.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"ledgerQuery": true,
"eventSource": true
},
"peer0.org2.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"ledgerQuery": true,
"eventSource": true
}
}
}
},
"organizations": {
"Org1": {
"mspid": "Org1MSP",
"peers": [
"peer0.org1.example.com"
],
"certificateAuthorities": [
"ca-org1"
],
"adminPrivateKeyPEM": {
"path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk"
},
"signedCertPEM": {
"path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"
}
},
"Org2": {
"mspid": "Org2MSP",
"peers": [
"peer0.org2.example.com"
],
"certificateAuthorities": [
"ca-org2"
],
"adminPrivateKeyPEM": {
"path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/priv_sk"
},
"signedCertPEM": {
"path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts/Admin@org2.example.com-cert.pem"
}
}
},
"orderers": {
"orderer.example.com": {
"url": "grpcs://127.0.0.1:7050",
"mspid": "OrdererMSP",
"grpcOptions": {
"ssl-target-name-override": "orderer.example.com",
"hostnameOverride": "orderer.example.com"
},
"tlsCACerts": {
"path": "src/main/resources/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt"
},
"adminPrivateKeyPEM": {
"path": "src/main/resources/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/msp/keystore/priv_sk"
},
"signedCertPEM": {
"path": "src/main/resources/crypto-config/ordererOrganizations/example.com/users/Admin@example.com/msp/signcerts/Admin@example.com-cert.pem"
}
}
},
"peers": {
"peer0.org1.example.com": {
"url": "grpcs://127.0.0.1:7051",
"grpcOptions": {
"ssl-target-name-override": "peer0.org1.example.com",
"hostnameOverride": "peer0.org1.example.com",
"request-timeout": 120001
},
"tlsCACerts": {
"path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
}
},
"peer0.org2.example.com": {
"url": "grpcs://127.0.0.1:9051",
"grpcOptions": {
"ssl-target-name-override": "peer0.org2.example.com",
"hostnameOverride": "peer0.org2.example.com",
"request-timeout": 120001
},
"tlsCACerts": {
"path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
}
}
},
"certificateAuthorities": {
"ca-org1": {
"url": "https://127.0.0.1:7054",
"grpcOptions": {
"verify": true
},
"tlsCACerts": {
"path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem"
},
"registrar": [
{
"enrollId": "admin",
"enrollSecret": "adminpw"
}
]
},
"ca-org2": {
"url": "https://127.0.0.1:8054",
"grpcOptions": {
"verify": true
},
"tlsCACerts": {
"path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem"
},
"registrar": [
{
"enrollId": "admin",
"enrollSecret": "adminpw"
}
]
}
}
}

需按实际情况修改url中的地址,内容中分别包含了 channels、organizations、orderers、peers、ca 的配置

SpringBoot配置

在 application.yml 中添加以下内容,用于访问网关的相关配置:

fabric:
# wallet文件夹路径(自动创建)
walletDirectory: wallet
# 网络配置文件路径
networkConfigPath: connection.json
# 用户证书路径
certificatePath: crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem
# 用户私钥路径
privateKeyPath: crypto-config/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/priv_sk
# 访问的组织名
mspid: Org1MSP
# 用户名
username: user1
# 通道名字
channelName: mychannel
# 链码名字
contractName: mycc

连接合约

分别构建网关、通道和合约的Bean对象,代码如下:

import lombok.extern.slf4j.Slf4j;
import org.hyperledger.fabric.gateway.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; @Slf4j
@Configuration
public class GatewayConfig {
/**
* wallet文件夹路径
*/
@Value("${fabric.walletDirectory}")
private String walletDirectory;
/**
* 网络配置文件路径
*/
@Value("${fabric.networkConfigPath}")
private String networkConfigPath;
/**
* 用户证书路径
*/
@Value("${fabric.certificatePath}")
private String certificatePath;
/**
* 用户私钥路径
*/
@Value("${fabric.privateKeyPath}")
private String privateKeyPath;
/**
* 访问的组织名
*/
@Value("${fabric.mspid}")
private String mspid;
/**
* 用户名
*/
@Value("${fabric.username}")
private String username;
/**
* 通道名字
*/
@Value("${fabric.channelName}")
private String channelName;
/**
* 链码名字
*/
@Value("${fabric.contractName}")
private String contractName; /**
* 连接网关
*/
@Bean
public Gateway connectGateway() throws IOException, InvalidKeyException, CertificateException {
//使用org1中的user1初始化一个网关wallet账户用于连接网络
Wallet wallet = Wallets.newFileSystemWallet(Paths.get(this.walletDirectory));
X509Certificate certificate = readX509Certificate(Paths.get(this.certificatePath));
PrivateKey privateKey = getPrivateKey(Paths.get(this.privateKeyPath));
wallet.put(username, Identities.newX509Identity(this.mspid, certificate, privateKey)); //根据connection.json 获取Fabric网络连接对象
Gateway.Builder builder = Gateway.createBuilder()
.identity(wallet, username)
.networkConfig(Paths.get(this.networkConfigPath));
//连接网关
return builder.connect();
} /**
* 获取通道
*/
@Bean
public Network network(Gateway gateway) {
return gateway.getNetwork(this.channelName);
} /**
* 获取合约
*/
@Bean
public Contract contract(Network network) {
return network.getContract(this.contractName);
} private static X509Certificate readX509Certificate(final Path certificatePath) throws IOException, CertificateException {
try (Reader certificateReader = Files.newBufferedReader(certificatePath, StandardCharsets.UTF_8)) {
return Identities.readX509Certificate(certificateReader);
}
} private static PrivateKey getPrivateKey(final Path privateKeyPath) throws IOException, InvalidKeyException {
try (Reader privateKeyReader = Files.newBufferedReader(privateKeyPath, StandardCharsets.UTF_8)) {
return Identities.readPrivateKey(privateKeyReader);
}
}
}

合约的调用

创建controller类,注入Contract对象调用合约方法:

import org.hyperledger.fabric.gateway.Contract;
import org.hyperledger.fabric.gateway.ContractException;
import org.hyperledger.fabric.gateway.Network;
import org.hyperledger.fabric.sdk.Peer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.chenyi.fabric.common.Result; import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
import java.util.concurrent.TimeoutException; @RestController
public class TestController {
@Resource
private Contract contract; @Resource
private Network network; @GetMapping("/getUser")
public String getUser(String userId) throws ContractException {
byte[] queryAResultBefore = contract.evaluateTransaction("getUser",userId);
return new String(queryAResultBefore, StandardCharsets.UTF_8);
} @GetMapping("/addUser")
public String addUser(String userId, String userName, String money) throws ContractException, InterruptedException, TimeoutException {
byte[] invokeResult = contract.createTransaction("addUser")
.setEndorsingPeers(network.getChannel().getPeers(EnumSet.of(Peer.PeerRole.ENDORSING_PEER)))
.submit(userId, userName, money);
String txId = new String(invokeResult, StandardCharsets.UTF_8);
return txId;
}
}

测试接口

启动springboot工程,调用对应接口即可

Hyperledger Fabric - 区块链应用的更多相关文章

  1. 区块链学习7:超级账本项目Fabric中的背书、背书节点、背书策略、背书签名

    ☞ ░ 前往老猿Python博文目录 ░ 在Hyperledger Fabric区块链中,有背书节点进行背书,Hyperledger Fabric 使用背书策略来定义哪些节点需要执行交易. Hyper ...

  2. Hyperledger Fabric Membership Service Providers (MSP)——成员服务

    Membership Service Providers (MSP) 本文将介绍有关MSPs的设置和最佳实践的详细方案. Membership Service Providers (MSP)是一个旨在 ...

  3. Hyperledger Fabric 账本结构解析

    前言 现在很多人都在从事区块链方面的研究,作者也一直在基于Hyperledger Fabric做一些开发工作.为了方便后来人更快的入门,本着“开源”的精神,在本文中向大家讲解一下Hyperledger ...

  4. Hyperledger Fabric 中channel配置相关数据结构

    channel Configuration Transaction Hyperledger Fabric区块链网络中的配置存储在一个configuration-transaction的集合中,每个ch ...

  5. Hyperledger Fabric 2.x Java区块链应用

    一.说明 在上一篇文章中 <Hyperledger Fabric 2.x 自定义智能合约> 分享了智能合约的安装并使用 cli 客户端进行合约的调用:本文将使用 Java 代码基于 fab ...

  6. Hyperledger Fabric链码之一

    什么是链码(Chaincode)? 我们知道区块链有3个发展阶段:区块链1.0,区块链2.0,区块链3.0.其中区块链2.0就是各种区块链平台百花齐放的阶段,区块链2.0最大的特点就是智能合约,我们接 ...

  7. HyperLedger/Fabric JAVA-SDK with 1.1

    HyperLedger/Fabric JAVA-SDK with 1.1 该项目可直接在github上访问. 该项目介绍如何使用fabric-sdk-java框架,基于fabric-sdk-java ...

  8. Hyperledger Fabric(v1.2.0)代码分析1——channel创建

    Hyperledger Fabric(v1.2.0)代码分析1--channel创建 0. e2e_cli Hyperledger Fabric提供了一个e2e的例子,该例中创建了一个基础的区块链网络 ...

  9. hyperledger fabric 1.0.5 分布式部署 (七)

    fabric 使用 fabric-ca 服务 准备部分 首先需要用户从github上download fabric-ca 的工程代码 cd $GOPATH/src/github.com/hyperle ...

  10. Hyperledger Fabric(4)链码ChainCode

    智能合约,是一个抽象的概念,智能合约的历史可以追溯到 1990s 年代.它是由尼克萨博(Nick Szabo)提出的理念,几乎与互联网同龄. 我们这里所说的智能合约只狭义的指区块链中.它能够部署和运行 ...

随机推荐

  1. token、jwt、oauth2、session对比总结

    什么是认证(Authentication) 通俗地讲就是验证当前用户的身份,证明"你是你自己"(比如:你每天上下班打卡,都需要通过指纹打卡,当你的指纹和系统里录入的指纹相匹配时,就 ...

  2. 图解红黑树RBT

    rotation:

  3. el-table关于选择行的三个常用事件

    变量声明 data(){ return{ selectList: [], } } 事件绑定 <el-table @select-all="selectAllChange" @ ...

  4. 一个简易socket通信结构

    服务端 基本的结构 工作需要又需要用到socketTCP通讯,这么多年了,终于稍微能写点了.让我说其实也说不出个啥来,看了很多的异步后稍微对异步socket的导流 endreceive后 再begin ...

  5. 云数据库MySQL多人协同开发实践

    本文分享自天翼云开发者社区<云数据库MySQL多人协同开发实践>,作者:不知不觉 随着云计算技术的快速发展,云数据库作为云计算的重要组成部分,为企业提供了高效.灵活和可靠的数据存储和管理服 ...

  6. 同步工具-Oceanus打通mysql到Iceberg

    一.服务配置 已配置好gt_oneline_2,其它集群还需按照下面方式特殊配置 1.需要腾讯Oceanus同学在后端修改高途flink集群配置core-site.xml文件,增加如下配置.只能绑定一 ...

  7. Java 将 RTF 转换为Word、PDF、HTML、图片

    RTF文档因其跨平台兼容性而广泛使用,但有时在不同的应用场景可能需要特定的文档格式.例如,Word文档适合编辑和协作,PDF文档适合打印和分发,HTML文档适合在线展示,图片格式则适合社交媒体分享.因 ...

  8. 多线程之lamda表达式

    代码简化过程  public class TestLambda1 { ​     //3.静态内部类     static class Like2 implements ILike{          ...

  9. 『Python底层原理』--Python整数为什么可以无限大

    整数类型是编程中最常见的数据类型之一,但它的实现细节却鲜为人知. 与其他语言不同,Python 的整数是任意精度的,这意味着它们可以无限大,仅受限于内存. 这种特性使得 Python 在处理大整数时非 ...

  10. QT5笔记: 32. QPainter 基本绘制