Hyperledger Fabric Java App Demo

Hyperledger Fabric Java App Demo

編寫一個應用程序來連接到 fabrc 網絡中,通過調用智能合約來訪問賬本.

fabric gateway

fabric gateway 有兩個項目,一個是 fabric-gateway-java , 一個是 fabric-gateway

fabric-gateway-java 是比較早的項目,使用起來較爲麻煩需要提供一個 connection.json 配置文件,該配置文件中要詳細配置網絡中的各個節點的信息。

fabric-gateway 使用起來較爲簡單,不在需要connection.json 配置文件,只需要指定網絡中的一個節點連接就可以了。

fabric 官方建議如果是 fabrc 2.4 或者之後的版本建議使用fabric-gateway

本篇內容基於 fabric-gateway 講解 , fabric 版本 v2.4.1


使用 fabric-gateway

Fabric Gateway是Hyperledger Fabric區塊鏈網絡的核心組件,代表客戶端應用程序協調提交事務和查詢分類賬狀態所需的操作。通過使用Gateway,客戶端應用程序只需要連接到Fabric網絡中的單個端點。

官方示例: https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-events https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic

fabric-gateway 依賴

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

連接 fabric 網絡

application.properties 配置文件:

# 應用名稱
spring.application.name=hyperledger-fabric-app-java-demo
# 應用服務 WEB 訪問端口
server.port=8080

fabric.networkConnectionConfigPath=src/main/resources/org1ProdNetworkConnection.json
fabric.mspId=Org1MSP
fabric.certificatePath=src/main/resources/crypto-config/prod-network/peerOrganizations/org1.example.com/users/[email protected]/msp/signcerts/[email protected]
fabric.privateKeyPath=src/main/resources/crypto-config/prod-network/peerOrganizations/org1.example.com/users/[email protected]/msp/keystore/priv_sk
fabric.tlsCertPath=src/main/resources/crypto-config/prod-network/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
fabric.channel=businesschannel

logging.level.org.hyperledger=trace

src/main/resources/crypto-config/prod-network 路徑下存放的是身份信息文件.

初始化 Gateway , Network , Contract 對象

import io.grpc.ManagedChannel;
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hyperledger.fabric.client.CallOption;
import org.hyperledger.fabric.client.Contract;
import org.hyperledger.fabric.client.Gateway;
import org.hyperledger.fabric.client.Network;
import org.hyperledger.fabric.client.identity.Identities;
import org.hyperledger.fabric.client.identity.Signers;
import org.hyperledger.fabric.client.identity.X509Identity;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

/**
 * author he peng
 * date 2022/1/22 21:21
 */

@Configuration
@AllArgsConstructor
@Slf4j
public class HyperLedgerFabricGatewayConfig {


    final HyperLedgerFabricProperties hyperLedgerFabricProperties;

    @Bean
    public Gateway gateway() throws Exception {


        BufferedReader certificateReader = Files.newBufferedReader(Paths.get(hyperLedgerFabricProperties.getCertificatePath()), StandardCharsets.UTF_8);

        X509Certificate certificate = Identities.readX509Certificate(certificateReader);

        BufferedReader privateKeyReader = Files.newBufferedReader(Paths.get(hyperLedgerFabricProperties.getPrivateKeyPath()), StandardCharsets.UTF_8);

        PrivateKey privateKey = Identities.readPrivateKey(privateKeyReader);

        Gateway gateway = Gateway.newInstance()
                .identity(new X509Identity(hyperLedgerFabricProperties.getMspId() , certificate))
                .signer(Signers.newPrivateKeySigner(privateKey))
                .connection(newGrpcConnection())
                .evaluateOptions(CallOption.deadlineAfter(5, TimeUnit.SECONDS))
                .endorseOptions(CallOption.deadlineAfter(15, TimeUnit.SECONDS))
                .submitOptions(CallOption.deadlineAfter(5, TimeUnit.SECONDS))
                .commitStatusOptions(CallOption.deadlineAfter(1, TimeUnit.MINUTES))
                .connect();

        log.info("=========================================== connected fabric gateway {} " , gateway);

        return gateway;
    }

    private ManagedChannel newGrpcConnection() throws IOException, CertificateException {
        Reader tlsCertReader = Files.newBufferedReader(Paths.get(hyperLedgerFabricProperties.getTlsCertPath()));
        X509Certificate tlsCert = Identities.readX509Certificate(tlsCertReader);

        return NettyChannelBuilder.forTarget("peer0.org1.example.com:7051")
                .sslContext(GrpcSslContexts.forClient().trustManager(tlsCert).build())
                .overrideAuthority("peer0.org1.example.com")
                .build();
    }

    @Bean
    public Network network(Gateway gateway) {
        return gateway.getNetwork(hyperLedgerFabricProperties.getChannel());
    }

    @Bean
    public Contract catContract(Network network) {
        return network.getContract("hyperledger-fabric-contract-java-demo" , "CatContract");
    }

    @Bean
    public ChaincodeEventListener chaincodeEventListener(Network network) {
        return new ChaincodeEventListener(network);
    }
}

鏈碼事件監聽

用來監聽交易完成之後通知的事件,事件中可以攜帶數據。

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.hyperledger.fabric.client.ChaincodeEvent;
import org.hyperledger.fabric.client.CloseableIterator;
import org.hyperledger.fabric.client.Network;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;

/**
 * @author he peng
 * @date 2022/3/4
 */

@Slf4j
public class ChaincodeEventListener implements Runnable {

    final Network network;

    public ChaincodeEventListener(Network network) {
        this.network = network;

        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setDaemon(true);
                thread.setName(this.getClass() + "chaincode_event_listener");
                return thread;
            }
        });

        executor.execute(this);
    }

    @Override
    public void run() {
        CloseableIterator<ChaincodeEvent> events = network.getChaincodeEvents("hyperledger-fabric-contract-java-demo");
        log.info("chaincodeEvents {} " , events);


        while (events.hasNext()) {
            ChaincodeEvent event = events.next();

            log.info("receive chaincode event {} , block number {} , payload {} "
                    , event.getEventName() , event.getBlockNumber() , JSONArray.toJSONString(Base64.decodeBase64(event.getPayload())));

        }
    }
}

異步調用合約

    @PutMapping("/async")
    public Map<String, Object> createCatAsync(@RequestBody CatDTO cat) throws Exception {
        Map<String, Object> result = Maps.newConcurrentMap();

        contract.newProposal("createCat")
                .addArguments(cat.getKey(), cat.getName(), String.valueOf(cat.getAge()), cat.getColor(), cat.getBreed())
                .build()
                .endorse()
                .submitAsync();

        result.put("status", "ok");

        return result;
    }

完整示例代碼項目:https://gitee.com/kernelHP/hyperledger-fabric-app-java-demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章