fabric java chaincode 开发

链码的开发不部分参考官网demo即可。

本文不会详细介绍开发过程

笔者启动的是一个gradle工程,也就是jar包管理使用的是gradle。

chaincode 源码:

/*
Copyright IBM Corp., DTCC All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.fabric.example;

import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import io.netty.handler.ssl.OpenSsl;
import io.netty.util.internal.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.fabric.example.bean.Factor;
import org.hyperledger.fabric.shim.ChaincodeBase;
import org.hyperledger.fabric.shim.ChaincodeStub;

import java.util.List;

public class FactoringChaincode extends ChaincodeBase {

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

    @Override
    public Response init(ChaincodeStub stub) {
        try {
            _logger.info("Init java factoring chaincode");
            String func = stub.getFunction();
            if (!func.equals("init")) {
                return newErrorResponse("function other than init is not supported");
            }
            _logger.info("begin test keepAlive");
            stub.putStringState("keepAliveTest","keepAliveTestValue");
            _logger.info("end test keepAlive");
            return newSuccessResponse();
        } catch (Throwable e) {
            return newErrorResponse(e);
        }
    }

    @Override
    public Response invoke(ChaincodeStub stub) {
        try {
            _logger.info("Invoke java factoring chaincode");
            String func = stub.getFunction();
            List<String> params = stub.getParameters();
            _logger.debug("Invoke function is "+stub.getFunction()+"Parameter is "+params.toString());
            if(params.isEmpty() || params.size()<1 || params.get(0).length()==0){
                return newErrorResponse("the invoke args not exist  or arg[0] is emptyt");
            }
            if (func.equals("SaveData")) {
                return saveData(stub, params);
            }
            if (func.equals("KeepaliveQuery")) {
                return keepaliveQuery(stub, params);
            }
            if (func.equals("QueryDataByFabricTxId")) {
                return queryDataByFabricTxId(stub, params);
            }
            if (func.equals("QueryDataByBusinessNo")) {
                return queryDataByBusinessNo(stub, params);
            }
            return newErrorResponse("Invalid invoke function name. ");
        } catch (Throwable e) {
            return newErrorResponse(e);
        }
    }

    private Response keepaliveQuery(ChaincodeStub stub, List<String> params) {
        String tarValue = stub.getStringState("keepAliveTest");
        if(!"keepAliveTestValue".equals(tarValue)){
            return newErrorResponse("ERROR! KeepaliveQuery get result is "+tarValue);
        }
        return newSuccessResponse("Reached".getBytes());
    }

    private Response queryDataByBusinessNo(ChaincodeStub stub, List<String> params) {
        String txId =new String(stub.getState(params.get(0)));
        _logger.info("query data by businessNo:"+params.get(0)+",txId is"+txId);
        return this.queryDataByFabricTxId(stub, Lists.newArrayList(txId));
    }

    private Response queryDataByFabricTxId(ChaincodeStub stub, List<String> params) {
        _logger.info("queryData by txId:"+params.get(0));
       byte[] res  =  stub.getState(params.get(0));
       return newSuccessResponse(new String(res),res);
    }

    private Response saveData(ChaincodeStub stub, List<String> args) {
        if(args.isEmpty() ||  args.size()<1){
            return newSuccessResponse("saveData wrong args");
        }try{
            Factor f = JSONArray.toJavaObject(JSONArray.parseObject(args.get(0)),Factor.class);
            String businessNo = f.getBusinessNo();
            if(StringUtil.isNullOrEmpty(businessNo)){
                return newErrorResponse("businessNo must exist");
            }
            String txId = stub.getTxId();
            stub.putState(txId,args.get(0).getBytes());
            stub.putState(businessNo,txId.getBytes());
            _logger.info("save data successfully with txid "+txId+",and businessNo"+businessNo);
        }catch (Exception e){
            return newErrorResponse(e.getMessage());
        }
        return newSuccessResponse();
    }



    public static void main(String[] args) {
        System.out.println("OpenSSL avaliable: " + OpenSsl.isAvailable());
        new FactoringChaincode().start(args);
    }

}
keepaliveQuery方法是为了探活。因为如果某个节点上没有启动链码容器会对交易的速度结果有影响,所以采用这种方式,每个节点都需要调用一次该方法在开始正常业务的调用。

链码的逻辑很简单,需要注意的是,gradle工程的配置文件中,需要制定baseName是 chaincode。因为在节点实例化链码的时候会默认找名称为chaincode的jar包。

shadowJar {
    baseName = 'chaincode'
    version = null
    classifier = null

    manifest {
        attributes 'Main-Class': 'org.hyperledger.fabric.example.FactoringChaincode'
    }
}

mainfest中需要特别指定main方法的java 文件。否则在实例化的时候会报错。

需要注意的是,目前fabric应用的大部分地方场景中的部署环境是没有外网的。如银行,政府企业的环境。这个时候gradle就需要支持离线打包。

在build.gradle的配置文件中添加

dependencies { compile fileTree(dir: 'libs', includes: ['*.jar'])}    项目的根目录,跟Src同级建立一个libs文件夹,把需要的jar包放进去即可。

 

开发完成以后把编写的项目放到服务器上打包:

./peer chaincode package -n factor -l java -p /usr/local/workspace/java_chaincode/ -v 1.0 -s -S -i "AND ('Org1MSP.peer')" factor.out


 -i "AND ('Org1MSP.peer')"表示该链码只能被Org1的peer节点实例化,其他节点实例化的话会报错。如果不指定这个参数,默认的限制是每个组织的admin可以实例化该链码。

打包的文件经过安装实例化就可以正常调用了。

 

附git地址 https://github.com/figo050518/fabric_java_chaincode

posted @ 2019-03-28 15:32  像我这样的人  阅读(918)  评论(0编辑  收藏  举报