Hyperledger Fabric Java App Demo

原创
03/04 16:40
阅读数 4K

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/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem
fabric.privateKeyPath=src/main/resources/crypto-config/prod-network/peerOrganizations/org1.example.com/users/User1@org1.example.com/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

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部