fabric-sdk-java demo(TLS-enabled)

Posted adderhuang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了fabric-sdk-java demo(TLS-enabled)相关的知识,希望对你有一定的参考价值。

fabric-sdk-java demo(TLS-enabled)

使用fabric-sdk-java,实现向fabric区块链上存入数据摘要并查询最新的数据记录。

本实例使用单机fabric1.4.1网络,采用raft共识;拥有五个orderer节点,四个peer节点;使用docker部署;开启TLS;chaincode采用Java编写;fabric状态数据库为couchdb,使用了数据库索引;fabric-sdk-java依赖版本为1.4.1。

采用的fabric网络实例地址://download.csdn.net/download/weixin_43562234/12118778

采用https://blog.csdn.net/weixin_43562234/article/details/104053966这篇博文中的solo单机单节点网络,开启TLS也可以。

建议有一定fabric基础的同学食用。

借鉴IBM的相关说明:
https://developer.ibm.com/tutorials/hyperledger-fabric-java-sdk-for-tls-enabled-fabric-network/

如果使用过程中出现问题,可以在评论区留言。

注意事项

1.依赖
除需要添加必要的fabric-sdk-java的依赖之外,还需要添加以下依赖

<dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-tcnative</artifactId>
      <version>1.1.33.Fork15</version>
      <classifier>${os.detected.classifier}</classifier>
      <scope>compile</scope>
      <optional>true</optional>
    </dependency>

properties属性中添加:
<os.detected.classifier>windows-x86_64</os.detected.classifier>
我的pom.xml文件:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <properties>
    <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
    <java.version>1.8</java.version>
    <grpc.version>1.11.0</grpc.version>
    <httpclient.version>4.5.5</httpclient.version>
    <os.detected.classifier>windows-x86_64</os.detected.classifier>
  </properties>
  <groupId>com.richfit</groupId>
  <artifactId>fabric-sdk-java</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>8</source>
          <target>8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <name>fabric-sdk-java</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.16</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.16</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hyperledger.fabric-sdk-java/fabric-sdk-java -->
    <dependency>
      <groupId>org.hyperledger.fabric-sdk-java</groupId>
      <artifactId>fabric-sdk-java</artifactId>
      <version>1.4.1</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.47</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client -->
    <dependency>
      <groupId>com.rabbitmq</groupId>
      <artifactId>amqp-client</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>runtime</scope>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>org.junit.vintage</groupId>
          <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <!--&lt;!&ndash; https://mvnrepository.com/artifact/io.netty/netty-tcnative &ndash;&gt;
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-tcnative</artifactId>
      <version>2.0.25.Final</version>
    </dependency>-->

    <!-- https://mvnrepository.com/artifact/io.netty/netty-tcnative -->
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-tcnative</artifactId>
      <version>1.1.33.Fork15</version>
      <classifier>${os.detected.classifier}</classifier>
      <scope>compile</scope>
      <optional>true</optional>
    </dependency>
  </dependencies>
</project>

2.域名
windows中需要修改hosts文件,不能直接使用虚拟机ip
hosts位置:
技术图片
我添加了以下内容

192.168.43.66   peer0.org1.richfit.com
192.168.43.66   peer1.org1.richfit.com
192.168.43.66   peer0.org2.richfit.com
192.168.43.66   peer1.org2.richfit.com
192.168.43.66   orderer.richfit.com
192.168.43.66   orderer0.richfit.com
192.168.43.66   orderer1.richfit.com
192.168.43.66   orderer2.richfit.com
192.168.43.66   orderer3.richfit.com
192.168.43.66   orderer4.richfit.com

## 代码部分

代码结构

技术图片

代码正文

1.App.class

package com.richfit.fabric.tls;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.richfit.fabric.tls.Business;
import org.hyperledger.fabric.sdk.BlockEvent.TransactionEvent;
import org.hyperledger.fabric.sdk.*;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.hyperledger.fabric.sdk.security.CryptoSuite;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author adder
 * @date 2020/1/20 15:43
 */
public class App {

    private static SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) throws Exception {
        Configurations configurations = new Configurations();
        HFClient client = HFClient.createNewInstance();

        //load parameters
        String keyDir = configurations.loadConfigurations().getJsonObject("options").getString("privateKeyFolder");
        String keyFile = getKeyFilesInDir(new File(keyDir)).toString();
        String certFile = configurations.loadConfigurations().getJsonObject("options").getString("signedCert");
        String userName = configurations.loadConfigurations().getJsonObject("options").getString("user_id");
        String mspId = configurations.loadConfigurations().getJsonObject("options").getString("msp_id");
        String channelName = configurations.loadConfigurations().getJsonObject("options").getString("channel_id");
        String peerName = configurations.loadConfigurations().getJsonObject("options").getString("peer_server_hostname");
        String peerURL = configurations.loadConfigurations().getJsonObject("options").getString("peer_url");
        String ordererName = configurations.loadConfigurations().getJsonObject("options").getString("orderer_server_hostname");
        String ordererURL = configurations.loadConfigurations().getJsonObject("options").getString("orderer_url");

        //create user object
        FabricUser user = new FabricUser(userName, mspId, keyFile, certFile);

        //encryption suite
        client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
        client.setUserContext(user);

        //create channel object
        Channel channel = client.newChannel(channelName);

        //create peer
        String peerTLSCert = configurations.loadConfigurations().getJsonObject("options").getString("peer_tls_cacerts");
        Properties peer_properties = new Properties();
        peer_properties.put("pemBytes", Files.readAllBytes(Paths.get(peerTLSCert)));
        peer_properties.setProperty("sslProvider", "openSSL");
        peer_properties.setProperty("negotiationType", "TLS");
        Peer peer = client.newPeer(peerName, peerURL,peer_properties);
        channel.addPeer(peer);

        /*//create EvenHub
        String event_url = "grpcs://peer0.org1.richfit.com:7051"; // ensure that port is of event hub
        EventHub eventHub = client.newEventHub(peerName, event_url, peer_properties);
        channel.addEventHub(eventHub);*/

        //orderer
        String ordererTLSCert = configurations.loadConfigurations().getJsonObject("options").getString("orderer_tls_cacerts");
        Properties orderer_properties = new Properties();
        orderer_properties.put("pemBytes", Files.readAllBytes(Paths.get(ordererTLSCert)));
        orderer_properties.setProperty("sslProvider", "openSSL");
        orderer_properties.setProperty("negotiationType", "TLS");
        Orderer orderer = client.newOrderer(ordererName, ordererURL,orderer_properties);
        channel.addOrderer(orderer);

        //init channel
        channel.initialize();

        //query
        queryByChaincode(client,configurations,channel);

        //insert
        /*for (int i = 0; i <1; i++) {
            Business business = new Business();
            business.setBizUUID("test");
            business.setBizType("test");
            business.setFillPerson("test");
            business.setSubmissionTim("test");
            business.setReviewer("test");
            business.setReviewOpinion("test");
            business.setReviewPass("test");
            business.setToGzwTime("test");
            business.setRequestTime(time.format(new Date()));
            business.setCount(i);
            business.setRequestID("test");

            String json = JSON.toJSONString(business);
            insertBlockChain(client,configurations,channel,json);
        }*/
    }


    /**
    * @description query
    * @params [client, configurations, channel]
    * @return  void
    * @author  adder
    * @date  2020/1/20 14:23
    *
    */
    public static void queryByChaincode(HFClient client,Configurations configurations,Channel channel) throws FileNotFoundException, ProposalException, InvalidArgumentException, UnsupportedEncodingException {
        String chaincodeName = configurations.loadConfigurations().getJsonObject("options").getString("chaincode_id");
        ChaincodeID chaincodeID = ChaincodeID.newBuilder().setName(chaincodeName).build();
        
        //build args
        ArrayList<String> argsList = new ArrayList<>();
        argsList.add("test");
        argsList.add("test");

        //build query request
        QueryByChaincodeRequest request = client.newQueryProposalRequest();
        request.setChaincodeID(chaincodeID);
        request.setFcn("query");
        request.setArgs(argsList);
        Collection<ProposalResponse> responses = channel.queryByChaincode(request);
        ProposalResponse response = (ProposalResponse) responses.toArray()[0];

        //analyse response
        if (response.getStatus().toString().equals("SUCCESS")){
            System.out.println(response.getChaincodeActionResponseStatus());
            String result = new String(response.getChaincodeActionResponsePayload(), StandardCharsets.UTF_8);
            System.out.println(result);
            JSONObject json = JSONObject.parseObject(result);
            String returnCode = (String) json.get("returnCode");
            System.out.println(returnCode);
        }
    }

    /**
    * @description
    * @params [client, configurations, channel, message]
    * @return  void
    * @author  adder
    * @date  2020/1/21 15:42
    *
    */
    public static void insertBlockChain(HFClient client,Configurations configurations,Channel channel,String message) throws FileNotFoundException, InvalidArgumentException, ProposalException, ExecutionException, InterruptedException {
        String chaincodeName = configurations.loadConfigurations().getJsonObject("options").getString("chaincode_id");
        ChaincodeID chaincodeID = ChaincodeID.newBuilder().setName(chaincodeName).build();
        JSONObject  msgJson = JSONObject.parseObject(message);
        msgJson.put("blockTimeTamp",System.currentTimeMillis());

        //build args
        ArrayList<String> argsList = new ArrayList<>();
        argsList.add(msgJson.toJSONString());

        //build insert request
        TransactionProposalRequest request = client.newTransactionProposalRequest();
        request.setChaincodeLanguage(TransactionRequest.Type.JAVA);
        request.setChaincodeID(chaincodeID);
        request.setArgs(argsList);
        request.setFcn("insert");
        request.setProposalWaitTime(3000);

        Collection<ProposalResponse> responses = channel.sendTransactionProposal(request);
        for (ProposalResponse response : responses) {
            if (response.getChaincodeActionResponseStatus()==200){
                System.out.println("Successfully sent Proposal and received ProposalResponse: status:"+response.getChaincodeActionResponseStatus()+",TransactionInformation: "+response.getProposalResponse().getResponse().getPayload().toStringUtf8());
            }
        }
        CompletableFuture<TransactionEvent> transactionEvent =  channel.sendTransaction(responses);
        TransactionEvent event = transactionEvent.get();

        System.out.println("TransationID: "+event.getTransactionID());
        if (event.isValid()){
            System.out.println("Successfully committed the change to the ledger by the peer "+event.getPeer());
        }
    }



    /**
    * @description get private key from key dir
    * @params [filePath]
    * @return  java.io.File
    * @author  adder
    * @date  2020/1/20 11:02
    *
    */
    private static File getKeyFilesInDir(File filePath) {
        File keyFile = null;
        File[] listFiles = filePath.listFiles();
        if(listFiles != null) {
            for(File file:listFiles) {
                if(file.isFile()) {
                    if(file.getName().endsWith("_sk")) {
                        keyFile = file;
                        break;
                    }
                }
            }
        }
        return keyFile;
    }
}

2.Business.class

package com.richfit.fabric.tls;

import lombok.Data;

/**
 * @author adder
 * @date 2020/1/20 15:43
 */
@Data
public class Business {
    public String getRequestID() {
        return requestID;
    }

    public void setRequestID(String requestID) {
        this.requestID = requestID;
    }

    private String requestID;
    private String bizUUID;
    private String bizType;
    private String fillPerson;
    private String submissionTim;
    private String reviewer;
    private String reviewOpinion;
    private String reviewPass;
    private String toGzwTime;
    private int count;
    private String requestTime;

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }


    public String getBizUUID() {
        return bizUUID;
    }

    public void setBizUUID(String bizUUID) {
        this.bizUUID = bizUUID;
    }

    public String getBizType() {
        return bizType;
    }

    public void setBizType(String bizType) {
        this.bizType = bizType;
    }

    public String getFillPerson() {
        return fillPerson;
    }

    public void setFillPerson(String fillPerson) {
        this.fillPerson = fillPerson;
    }

    public String getSubmissionTim() {
        return submissionTim;
    }

    public void setSubmissionTim(String submissionTim) {
        this.submissionTim = submissionTim;
    }

    public String getReviewer() {
        return reviewer;
    }

    public void setReviewer(String reviewer) {
        this.reviewer = reviewer;
    }

    public String getReviewOpinion() {
        return reviewOpinion;
    }

    public void setReviewOpinion(String reviewOpinion) {
        this.reviewOpinion = reviewOpinion;
    }

    public String getReviewPass() {
        return reviewPass;
    }

    public void setReviewPass(String reviewPass) {
        this.reviewPass = reviewPass;
    }

    public String getToGzwTime() {
        return toGzwTime;
    }

    public void setToGzwTime(String toGzwTime) {
        this.toGzwTime = toGzwTime;
    }

    public String getRequestTime() {
        return requestTime;
    }

    public void setRequestTime(String requestTime) {
        this.requestTime = requestTime;
    }
}

3.Configurations.class

package com.richfit.fabric.tls;

import org.yaml.snakeyaml.Yaml;

import javax.json.Json;
import javax.json.JsonObject;
import java.io.*;
import java.util.Map;

/**
 * @author adder
 * @date 2020/1/20 15:43
 */
public class Configurations {

    /**
    * @description
    * @params []
    * @return  javax.json.JsonObject
    * @author  adder
    * @date  2020/1/24 13:03
    *
    */
    public  JsonObject loadConfigurations() throws FileNotFoundException {
        String configPath = "src/main/java/com/richfit/fabric/tls/configure/configure.yml";
        InputStream stream = new FileInputStream(new File(configPath));
        Yaml yaml = new Yaml();
        Map<String,Object> configYaml = yaml.load(stream);
        JsonObject configJSON = Json.createObjectBuilder(configYaml).build();
        return configJSON;
    }
}

4.FabricUser.class

package com.richfit.fabric.tls;

import org.hyperledger.fabric.sdk.Enrollment;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.identity.X509Enrollment;
import org.hyperledger.fabric.sdk.security.CryptoPrimitives;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.util.Set;


/**
 * @author adder
 * @date 2020/1/20 15:43
 */
public class FabricUser implements User {
    private String name;
    private String mspId;
    private Enrollment enrollment;
    private String keyFile;
    private String certFile;

    FabricUser(String name, String mspId, String keyFile, String certFile) {
        this.name = name;
        this.mspId = mspId;
        this.keyFile=keyFile;
        this.certFile=certFile;

        try{
            enrollment=loadFromPemFile(keyFile, certFile);
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }

    private Enrollment loadFromPemFile(String keyFile,String certFile) throws Exception{
        byte[] keyPem = Files.readAllBytes(Paths.get(keyFile));     //load private key text
        byte[] certPem = Files.readAllBytes(Paths.get(certFile));   //load certificate text
        CryptoPrimitives suite = new CryptoPrimitives();            //load the cryptography suite
        PrivateKey privateKey = suite.bytesToPrivateKey(keyPem);    //convert private key text to object
        return new X509Enrollment(privateKey,new String(certPem));  //create X509Enrollment object
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getMspId() {
        return mspId;
    }

    @Override
    public Enrollment getEnrollment() {
        return enrollment;
    }

    @Override
    public String getAccount() {
        return null;
    }

    @Override
    public String getAffiliation() {
        return null;
    }

    @Override
    public Set<String> getRoles() {
        return null;
    }

    public String getKeyFile() {
        return keyFile;
    }

    public void setKeyFile(String keyFile) {
        this.keyFile = keyFile;
    }

    public String getCertFile() {
        return certFile;
    }

    public void setCertFile(String certFile) {
        this.certFile = certFile;
    }

}

6.configure.yml

options:
  user_id: "Admin@org1.richfit.com"
  msp_id: "Org1MSP"
  channel_id: "mychannel"
  chaincode_id: "mycc"
  peer_url: "grpcs://peer0.org1.richfit.com:7051"

  orderer_url: "grpcs://orderer0.richfit.com:8050"

  privateKeyFolder: "src/main/java/com/richfit/fabric/tls/configure/crypto-config/peerOrganizations/org1.richfit.com/users/Admin@org1.richfit.com/msp/keystore"
  signedCert: "src/main/java/com/richfit/fabric/tls/configure/crypto-config/peerOrganizations/org1.richfit.com/users/Admin@org1.richfit.com/msp/signcerts/Admin@org1.richfit.com-cert.pem"

  peer_tls_cacerts: "src/main/java/com/richfit/fabric/tls/configure/crypto-config/peerOrganizations/org1.richfit.com/peers/peer0.org1.richfit.com/tls/ca.crt"
  orderer_tls_cacerts: "src/main/java/com/richfit/fabric/tls/configure/crypto-config/ordererOrganizations/richfit.com/orderers/orderer0.richfit.com/tls/ca.crt"
  peer_server_hostname: "peer0.org1.richfit.com"
  orderer_server_hostname: "orderer0.richfit.com"

以上是关于fabric-sdk-java demo(TLS-enabled)的主要内容,如果未能解决你的问题,请参考以下文章

Hyperledger Fabric 1.0 从零开始——fabric-sdk-java应用

WIN10 X64下通过TLS实现反调试

iOS 9适配技巧(更新版)

需要用 perl 解析 utf8 邮件

TLS 详解

在高级设置中启用 TLS 1.0、TLS 1.1 和 TLS 1.2,