fabric-sdk-java demo

01/21 08:54
阅读数 137

借鉴网上的一篇博文,实现向fabric区块链上存入数据摘要并查询最新的数据记录。

使用的fabric1.4.1单机单节点网络,采用solo共识(多机kafka共识环境也可使用);采用docker部署;关闭TLS;chaincode采用Java编写;fabric状态数据库为couchdb使用了数据库索引;fabric-sdk-java依赖版本为1.4.1。

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

笔者使用的fabric的单机单节点网络实例://download.csdn.net/download/weixin_43562234/12116307

博客园不支持资源上传,非常抱歉~~~~~

代码部分:

代码结构:

在这里插入图片描述

代码正文

1.App.class

package com.richfit.fabric;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import com.alibaba.fastjson.JSONObject;
import org.hyperledger.fabric.sdk.*;
import org.hyperledger.fabric.sdk.BlockEvent.TransactionEvent;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.hyperledger.fabric.sdk.security.CryptoSuite;

/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) throws Exception {
        Configurations configurations = new Configurations();
        HFClient client = HFClient.createNewInstance();
        Channel channel = initChannel(client,configurations);

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

        //insert
        /*for (int i = 0; i <3; 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("test");
            business.setCount(i);
            business.setRequestID("test");

            //Thread.sleep(1000);
            System.out.println("messageCount:  "+i);

            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);
        }
    }

    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");

        Collection<ProposalResponse> responses = channel.sendTransactionProposal(request);
        CompletableFuture<TransactionEvent> transactionEvent =  channel.sendTransaction(responses);
        TransactionEvent event = transactionEvent.get();
        System.out.println(event.getTransactionID());
        System.out.println(event.isValid());
    }

    /**
    * @description
    * @params [client, configurations]
    * @return  org.hyperledger.fabric.sdk.Channel
    * @author  adder
    * @date  2020/1/20 14:27
    *
    */
    private static Channel initChannel(HFClient client,Configurations configurations) throws Exception {
        //create user object
        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");
        FabricUser user = new FabricUser(userName, mspId, keyFile, certFile);
        client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
        client.setUserContext(user);

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

        //create peer
        Peer peer = client.newPeer(peerName, peerURL);
        channel.addPeer(peer);

        //orderer
        Orderer orderer = client.newOrderer(ordererName, ordererURL);
        channel.addOrderer(orderer);

        channel.initialize();
        return channel;
    }


    /**
    * @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;

import lombok.Data;

@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;

import org.yaml.snakeyaml.Yaml;

import javax.json.Json;
import javax.json.JsonObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Map;

public class Configurations {
    public  JsonObject loadConfigurations() throws FileNotFoundException {
        String configPath = "src/main/java/com/richfit/fabric/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;

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

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;

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;
    }
}

5.configure.yml

options:
  user_id: "Admin@org1.gzjg.com"
  msp_id: "Org1MSP"
  channel_id: "mychannel"
  chaincode_id: "mycc"
  peer_url: "grpc://192.168.43.66:7051"
  orderer_url: "grpc://192.168.43.66:7050"

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

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

6.fabric-chaincode-java

package org.hyperledger.fabric.example;

import java.io.UnsupportedEncodingException;
import java.util.*;

import com.alibaba.fastjson.JSON;
import com.google.protobuf.ByteString;
import io.netty.handler.ssl.OpenSsl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.fabric.shim.ChaincodeBase;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.hyperledger.fabric.shim.ledger.KeyValue;
import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata;

import static java.nio.charset.StandardCharsets.UTF_8;

public class SimpleChaincode extends ChaincodeBase {

    private static Log _logger = LogFactory.getLog(SimpleChaincode.class);

    @Override
    public Response init(ChaincodeStub stub) {
        try {
            _logger.info("Init java simpleS chaincode");
            String func = stub.getFunction();
            if (!func.equals("init")) {
                return newErrorResponse("function other than init is not supported");
            }
            List<String> args = stub.getParameters();
            String account1Key = args.get(0);
            System.out.println(account1Key);
            String account1Value = args.get(1);
            System.out.println(account1Value);
            _logger.info(String.format("account %s, value = %s", account1Key, account1Value));
            return newSuccessResponse();
        } catch (Throwable e) {
            return newErrorResponse(e);
        }
    }

    @Override
    public Response invoke(ChaincodeStub stub) {
        try {
            _logger.info("Invoke java simple chaincode");
            String func = stub.getFunction();
            List<String> params = stub.getParameters();

            if (func.equals("invoke")) {
                return invoke(stub, params);
            }
            if (func.equals("delete")) {
                return delete(stub, params);
            }
            if (func.equals("query")) {
                return query(stub, params);
            }

            if (func.equals("insert")) {
                return insert(stub, params);
            }

            return newErrorResponse(
                    "Invalid invoke function name. Expecting one of: [\"invoke\", \"delete\", \"query\"]");
        } catch (Throwable e) {
            return newErrorResponse(e);
        }
    }

    private Response insert(ChaincodeStub stub, List<String> args) throws UnsupportedEncodingException {
        String msgkey = UUID.randomUUID().toString();
        // String msgKey =args.get(0);
        String msgValue = args.get(0);
        stub.putState(msgkey, msgValue.getBytes(UTF_8));
        return newSuccessResponse("insert finished successfully",
                ByteString.copyFrom(msgkey + ": " + msgValue, UTF_8).toByteArray());
    }

    private Response invoke(ChaincodeStub stub, List<String> args) {
        String msgKey = args.get(0);
        String msgValue = args.get(1);

        stub.putStringState(msgKey, msgValue);

        return newSuccessResponse("invoke finished successfully",
                ByteString.copyFrom(msgKey + ": " + msgValue, UTF_8).toByteArray());
    }

    // Deletes an entity from state
    private Response delete(ChaincodeStub stub, List<String> args) {
        if (args.size() != 1) {
            return newErrorResponse("Incorrect number of arguments. Expecting 1");
        }
        String key = args.get(0);
        // Delete the key from the state in ledger
        stub.delState(key);
        return newSuccessResponse();
    }

    /*
     * query callback representing the query of a chaincode rich query
     */
    private Response query(ChaincodeStub stub, List<String> args) {
        System.out.println("agrs: "+args);
        try {
            long start = System.currentTimeMillis();

            if (args.size() != 2) {
                return newErrorResponse(
                        "Incorrect number of arguments. Expecting name of the person to query");
            }
            // SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
            String args1 = args.get(0);
            String args2 = args.get(1);

            // test
            String sql = String.format(
                    "{\"selector\":{\"bizUUID\": \"%s\",\"bizType\":\"%s\"},\"sort\":[{\"blockTimeTamp\":\"desc\"}]}",
                    args.get(0), args.get(1));

            _logger.info("sql: " + sql);
            // QueryResultsIterator<KeyValue> dataResult = stub.getQueryResult(sql);

            QueryResultsIteratorWithMetadata<KeyValue> dataResult = stub.getQueryResultWithPagination(sql,
                    50, "");

            _logger.info("query 1: " + (System.currentTimeMillis() - start));

            System.out.println("dataResult.iterator().hasNext(): " + dataResult.iterator().hasNext());

            if (dataResult.iterator().hasNext()) {

                List<String> dataList = new ArrayList();

                while (dataResult.iterator().hasNext()) {

                    KeyValue dr = dataResult.iterator().next();

                    String drKey = dr.getKey();
                    String drValue = dr.getStringValue();

                    System.out.println("drKey: " + drKey + " \n" + "drValue: " + drValue);

                    dataList.add(drValue);
                }
                _logger.info("query 2: " + (System.currentTimeMillis() - start));

                _logger.info("dataList.size(): " + dataList.size());

                _logger.info("query 3: " + (System.currentTimeMillis() - start));

                _logger.info("dataList: " + dataList.get(0));

                Map<String, String> resultMap = new HashMap<>();

                resultMap.put("returnCode", "success");

                resultMap.put("result", dataList.get(0));

                String jsonString = JSON.toJSONString(resultMap);

                _logger.info(String.format("Query Response:\n %s", jsonString));

                return newSuccessResponse(String.valueOf(jsonString),
                        ByteString.copyFrom(String.valueOf(jsonString), UTF_8).toByteArray());

            } else {
                String result = String.format("State for [bizUUID= %s , bizType= %s] is null", args1,
                        args2);

                Map<String, String> resulMap = new HashMap<>();

                resulMap.put("returnCode", "no data");

                resulMap.put("result", result);

                String jsonString = JSON.toJSONString(resulMap);

                return newSuccessResponse(String.valueOf(jsonString),
                        ByteString.copyFrom(String.valueOf(jsonString), UTF_8).toByteArray());
            }
        } catch (Exception e) {
            return newErrorResponse("query error : " + e);
        }
    }

    public static void main(String[] args) {
        System.out.println("OpenSSL avaliable: " + OpenSsl.isAvailable());
        new SimpleChaincode().start(args);
    }
}
展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部