Hyperledger Fabric 2.x Java區塊鏈應用
一、説明
在上一篇文章中 《Hyperledger Fabric 2.x 自定義智能合約》 分享了智能合約的安裝並使用 cli
客户端進行合約的調用;本文將使用 Java
代碼基於 fabric-gateway-java
進行區塊鏈網絡的訪問與交易,並集成 SpringBoot
框架。
Fabric Gateway SDK
實現Fabric的編程模型,提供了一系列簡單的API給應用程序與Fabric區塊鏈網絡進行交互;
網絡拓撲圖:
應用程序將各自的網絡交互委託給其網關,每個網關都瞭解網絡信道拓撲,包括組織的多個Peer節點和排序節點,使應用程序專注於業務邏輯;Peer節點可以使用gossip協議在組織內部和組織之間相互通信。
二、Mavn依賴
添加網關sdk的依賴:
<dependency>
<groupId>org.hyperledger.fabric</groupId>
<artifactId>fabric-gateway-java</artifactId>
<version>2.2.3</version>
</dependency>
三、準備配置文件
工程的目錄結構如下圖所示:
3.1. 準備網絡證書
創建目錄 crypto-config
把 orderer
和 peer
節點的證書文件複製進來。
證書文件從 fabric-samples
的 test-network
目錄中複製 ordererOrganizations
與 peerOrganizations
文件夾:
3.2. 創建網絡配置
創建文件 connection.json
內容如下:
{
"name": "basic-network",
"version": "1.0.0",
"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/[email protected]/msp/keystore/priv_sk"
},
"signedCertPEM": {
"path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/signcerts/[email protected]"
}
},
"Org2": {
"mspid": "Org2MSP",
"peers": [
"peer0.org2.example.com"
],
"certificateAuthorities": [
"ca-org2"
],
"adminPrivateKeyPEM": {
"path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/keystore/priv_sk"
},
"signedCertPEM": {
"path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/signcerts/[email protected]"
}
}
},
"orderers": {
"orderer.example.com": {
"url": "grpcs://192.168.28.134: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/[email protected]/msp/keystore/priv_sk"
},
"signedCertPEM": {
"path": "src/main/resources/crypto-config/ordererOrganizations/example.com/users/[email protected]/msp/signcerts/[email protected]"
}
}
},
"peers": {
"peer0.org1.example.com": {
"url": "grpcs://192.168.28.134: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://192.168.28.134: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://192.168.28.134: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://192.168.28.134: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
的配置
3.3. SpringBoot配置
在 application.yml
中添加以下內容,用於訪問網關的相關配置:
fabric:
# wallet文件夾路徑(自動創建)
walletDirectory: wallet
# 網絡配置文件路徑
networkConfigPath: connection.json
# 用户證書路徑
certificatePath: crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/signcerts/[email protected]
# 用户私鑰路徑
privateKeyPath: crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/keystore/priv_sk
# 訪問的組織名
mspid: Org1MSP
# 用户名
username: user1
# 通道名字
channelName: mychannel
# 鏈碼名字
contractName: mycc
四、連接合約
分別構建網關、通道和合約的Bean對象,代碼如下:
/**
* 連接網關
*/
@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);
}
五、合約調用
創建controller類,注入Contract對象調用合約方法:
@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;
}
六、測試接口
調用接口 getUser
:
http://127.0.0.1:9001/getUser?userId=1
返回:
{
"money": 300,
"name": "zlt",
"userId": "1"
}
調用接口 addUser
:
http://127.0.0.1:9001/addUser?userId=6&userName=test6&money=600
返回:
2ae291bb6a366b5ba01ad49e4237da8def9e9828cc2c982e8c49d4b763af0157
七、代碼下載
gitee:https://gitee.com/zlt2000/my-fabric-application-java
github:https://github.com/zlt2000/my-fabric-application-java
掃碼關注有驚喜!
- 如何基於Security框架兼容多套用户密碼加密方式
- 基於Kubernetes(k8s)部署Dubbo Nacos服務
- 基於jib-maven-plugin快速構建微服務docker鏡像
- 基於minikube快速搭建單節點環境
- 隱私計算FATE-多分類神經網絡算法測試
- 隱私計算FATE-離線預測
- 隱私計算FATE-模型訓練
- 隱私計算FATE-核心概念與單機部署
- Hyperledger Fabric 核心概念
- Hyperledger Fabric 2.x Java區塊鏈應用
- Hyperledger Fabric 2.x 自定義智能合約
- Hyperledger Fabric 2.x 環境搭建
- Spring Boot 如何熱加載jar實現動態插件?
- 如何基於Security實現OIDC單點登錄?
- 第三方API對接如何設計接口認證?
- 免費正版 IntelliJ IDEA license 詳細指南
- ClickHouse性能優化?試試物化視圖
- 全量同步Elasticsearch方案之Canal
- Canal高可用架構部署
- 大數據量查詢容易OOM?試試MySQL流式查詢