Hyperledger Fabric实践:供应链金融案例

背景描述:

在供应链金融产品中,供应商、核心企业、银行、金融机构等多方并存,共同参与交易完成。由于参与方众多,其中涉及很多清算和结算功能,如果采用传统方案解决会产生很多中间环节,导致效率低下。区块链的出现给供应链金融的实现提供了新的解决方案。

案例描述:

案例实现的是简单的“应收账款融资”场景。

业务流程:

1、核心企业与供应商线下签订合同并发货
2、供应商在链上发起供货交易
3、核心企业和金融机构确认并签名交易
4、金融机构发起放款请求给供应商
以上每一笔交易都需要所有参与方认同。

环境配置

演示为三个组织——核心企业、供应商、金融机构。
使用环境为fabric v1.1

IP节点域名组织名称
10.254.186.164ordererorderer.gyl.com排序节点
10.254.186.164peerpeer0.org1.gyl.com供应商
10.254.247.165peerpeer0.org2.gyl.com金融机构
10.254.207.154peerpeer0.org3.gyl.com核心企业

合约部分

package main

import (
	"fmt"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/lib/cid"
	"crypto/x509"
	"encoding/base64"
	"strconv"
)

var asset_time = "asset_name_a"
type scfinancechaincode struct {}

/**
	系统初始化
 */

// Init callback representing the invocation of a chaincode
func (t *scfinancechaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	fmt.Println("Init success! ")
	return shim.Success([]byte("Init success !!!!!"))
}

/**
系统Invoke方法
 */

func (t *scfinancechaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	function, args := stub.GetFunctionAndParameters()
	switch function {
	case "putvalue":
		if len(args) != 2 {
			return shim.Error("putvalue params num err!")
		}
		return t.putvalue(stub, args[0], args[1])
	case "getlastvalue":
		if len(args) != 1 {
			return shim.Error("getlastvalue params num err!")
		}
		return t.getlastvalue(stub,args[0])
	case "gethistory":
		if len(args) != 1 {
			return shim.Error("gethistory params num err!")
		}
		return t.gethistory(stub,args[0])
	case "creator": //返回调用者信息
		return t.creator(stub,args)
	case "creator2"://返回调用者信息,方法2
		return t.creator2(stub,args)
	case "getattr"://获取用户的属性
	    return t.getattr(stub,args)
	case "setquota"://给公司设置贷款最大额度
		return t.setquota(stub,args)
	case "checkquota"://查看现在还剩多少信用额度
	    return t.checkquota(stub,args[0])
	case "loan"://执行贷款逻辑
	    return t.loan(stub,args)
	case "queryloan"://企业申请贷款
		return t.queryloan(stub,args)
	default:
		return shim.Error("Invalid invoke function name.")
	}
}

//申请贷款
//args: 0:项目(公司)名  1:贷款时长  2:贷款额度
func (t *scfinancechaincode) queryloan(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 3 {
		return shim.Error("setquota params num err!")
	}
	projectName := args[0]
	loanTime := args[1]
	loanNum := args[2]
	loanItem := &LoanItem{
		ProjectName:projectName,
		LoanTime:loanTime,
		LoanNum:loanNum,
	}
	loanItemStr,e := json.Marshal(loanItem)
	if e != nil {
		return shim.Error("queryloan error, json Marshal error")
	}
	resp1 := t.putvalue(stub,"query_loan_"+projectName,string(loanItemStr))
	if resp1.Status != shim.OK {
		return shim.Error("setquota fail ")
	}
	return shim.Success([]byte("success queryloan: " + string(loanItemStr)))
}


//设置公司或者项目贷款配额,如果已经设置,则不能再设置了
func (t *scfinancechaincode) setquota(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 2 {
		return shim.Error("setquota params num err!")
	}
	key := args[0]
	value := args[1]
	fmt.Printf("setquota %s, value is %s\n", key, value)
	bytes, err := stub.GetState(key)
	if err != nil {
		return shim.Error("query fail " + err.Error())
	}
	if string(bytes) != "" {
		return shim.Success([]byte("key: " + key + " has been seted quota and the remaining quota is : " + string(bytes)))
	}

	resp1 := t.putvalue(stub,key,value)
	if resp1.Status != shim.OK {
		return shim.Error("setquota fail ")
	}
	return shim.Success([]byte("success setquota key: " + key + ", value: " + value))
}

//查看quota还有多少
//key为项目名或者公司名
func (t *scfinancechaincode) checkquota(stub shim.ChaincodeStubInterface, key string) pb.Response {
	fmt.Printf("checkquota %s\n", key)
	resp := t.getlastvalue(stub,key)
	if resp.Status != shim.OK {
		return shim.Error("checkquota fail ")
	}
	return shim.Success(resp.Payload)
}

//银行放款给企业
//args: 0:项目名 1:合同ID 2:贷款时长 3:贷款额度
type LoanItem struct {
	ProjectName string
	LoanId  string
	LoanTime string
	LoanNum string
}

func (t *scfinancechaincode) loan(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 4 {
		return shim.Error("loan params number error")
	}
	projectName := args[0]
	loanId := args[1]
	loanTime := args[2]
	loanNum := args[3]
	loanItem := &LoanItem{
		ProjectName:projectName,
		LoanTime:loanTime,
		LoanId:loanId,
		LoanNum:loanNum,
	}
	//先查看是否有额度
	qutaRemaining := t.checkquota(stub,projectName)
	if qutaRemaining.Status != shim.OK{
		return shim.Error("loan error")
	}
	quta, err1 := strconv.ParseInt(string(qutaRemaining.Payload), 10, 64)
	loanN, err2 := strconv.ParseInt(loanNum, 10, 64)
	if err1 != nil || err2 != nil {
		return shim.Error("loan error, type error")
	}
	//贷款额度超过配额
	if loanN - quta > 0 {
		return shim.Success([]byte("quta is not enough, can loan " + string(qutaRemaining.Payload) + " at most"))
	}

	resp1 := t.putvalue(stub,"loan_" + projectName,loanNum)
	if resp1.Status != shim.OK {
		return shim.Error("loan putvalue fail ")
	}
	remainingquta := strconv.FormatInt(quta-loanN,10)
	resp2 := t.putvalue(stub,projectName,remainingquta)
	if resp2.Status != shim.OK {
		return shim.Error("loan putvalue fail ")
	}

	loanItemStr,e := json.Marshal(loanItem)
	if e != nil {
		return shim.Error("loan error, json Marshal error")
	}

	return shim.Success(loanItemStr)
}

func (t *scfinancechaincode) putvalue(stub shim.ChaincodeStubInterface, key, value string) pb.Response {
	fmt.Printf("putvalue %s, value is %s\n", key, value)
	if err := stub.PutState(key, []byte(value)); err != nil {
		return shim.Error("putvalue fail " + err.Error())
	}
	return shim.Success([]byte("success put key: " + key + ", value: " + value))
}

func (t *scfinancechaincode) gethistory(stub shim.ChaincodeStubInterface, key string) pb.Response {
	fmt.Printf("history %s\n", key)
	iter, err := stub.GetHistoryForKey(key)
	defer iter.Close()
	if err != nil {
		return shim.Error("query fail " + err.Error())
	}

	values := make(map[string]string)

	for iter.HasNext() {
		fmt.Printf("next\n")
		if kv, err := iter.Next(); err == nil {
			fmt.Printf("id: %s value: %s\n", kv.TxId, kv.Value)
			values[kv.TxId] = string(kv.Value)
		}
		if err != nil {
			return shim.Error("iterator history fail: " + err.Error())
		}
	}

	bytes, err := json.Marshal(values)
	if err != nil {
		return shim.Error("json marshal fail: " + err.Error())
	}

	return shim.Success(bytes)
}

func (t *scfinancechaincode) getlastvalue(stub shim.ChaincodeStubInterface, key string) pb.Response {
	fmt.Printf("query %s\n", key)
	bytes, err := stub.GetState(key)
	if err != nil {
		return shim.Error("query fail " + err.Error())
	}
	return shim.Success(bytes)
}

func (t *scfinancechaincode) getattr(stub shim.ChaincodeStubInterface, args []string) pb.Response{
	if len(args) != 1 {
		return shim.Error("parametes's number is wrong")
	}
	fmt.Println("get attr: ", args[0])
	value, ok, err := cid.GetAttributeValue(stub, args[0])
	if err != nil {
		return shim.Error("get attr error: " + err.Error())
	}

	if ok == false {
		value = "not found"
	}
	bytes, err := json.Marshal(value)
	if err != nil {
		return shim.Error("json marshal error: " + err.Error())
	}
	return shim.Success(bytes)
}

func (t *scfinancechaincode) creator(stub shim.ChaincodeStubInterface, args []string) pb.Response{
	fmt.Println("creator: ", args)
	bytes, err := stub.GetCreator()
	if err != nil {
		return shim.Error("get creator error: " + err.Error())
	}

	return shim.Success(bytes)
}
func (t *scfinancechaincode) creator2(stub shim.ChaincodeStubInterface, args []string) pb.Response{
	var cinfo struct {
		ID   string
		ORG  string
		CERT *x509.Certificate
	}

	fmt.Println("creator2: ", args)

	id, err := cid.GetID(stub)
	if err != nil {
		return shim.Error("getid error: " + err.Error())
	}

	id_readable, err := base64.StdEncoding.DecodeString(id)
	if err != nil {
		return shim.Error("base64 decode error: " + err.Error())
	}
	cinfo.ID = string(id_readable)

	mspid, err := cid.GetMSPID(stub)
	if err != nil {
		return shim.Error("getmspid error: " + err.Error())
	}
	cinfo.ORG = mspid

	cert, err := cid.GetX509Certificate(stub)
	if err != nil {
		return shim.Error("getX509Cert error: " + err.Error())
	}
	cinfo.CERT = cert

	bytes, err := json.Marshal(cinfo)
	if err != nil {
		return shim.Error("json marshal error: " + err.Error())
	}
	return shim.Success(bytes)
}
func main() {
	err := shim.Start(new(scfinancechaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

client部分

var path = require('path');
var fs = require('fs');
var util = require('util');
var hfc = require('fabric-client');
var Peer = require('fabric-client/lib/Peer.js');
var EventHub = require('fabric-client/lib/EventHub.js');
var User = require('crypto');
var FabricCAService = require('fabric-ca-client');

//var log4js = require('log4js');
//var logger = log4js.getLogger('Helper');
//logger.setLevel('DEBUG');

var tempdir = "/home/dc2-user/kongli/fabric-client-js-kvs";

let client = new hfc();
let tls_cacerts_content_orderer = fs.readFileSync('./orderer/tls/ca.crt');
let opt_orderer = {
    pem: Buffer.from(tls_cacerts_content_orderer).toString(),
    'ssl-target-name-override':'orderer.gyl.com'
};
//peer1
let tls_cacerts_content_peer1 = fs.readFileSync('./peer1/tls/ca.crt');
let opt_peer1 = {
    pem: Buffer.from(tls_cacerts_content_peer1).toString(),
    'ssl-target-name-override':'peer0.org1.gyl.com'
};
//peer2
let tls_cacerts_content_peer2 = fs.readFileSync('./peer2/tls/ca.crt');
let opt_peer2 = {
    pem: Buffer.from(tls_cacerts_content_peer2).toString(),
    'ssl-target-name-override':'peer0.org2.gyl.com'
};
//peer3
let tls_cacerts_content_peer3 = fs.readFileSync('./peer3/tls/ca.crt');
let opt_peer3 = {
    pem: Buffer.from(tls_cacerts_content_peer3).toString(),
    'ssl-target-name-override':'peer0.org3.gyl.com'
};

var channel = client.newChannel('gylchannel');
var order = client.newOrderer('grpcs://10.254.186.164:7050',opt_orderer);
channel.addOrderer(order);
var peer1 = client.newPeer('grpcs://10.254.186.164:7051',opt_peer1);
var peer2 = client.newPeer('grpcs://10.254.247.165:7051',opt_peer2);
var peer3 = client.newPeer('grpcs://10.254.207.154:7051',opt_peer3);
channel.addPeer(peer1);
channel.addPeer(peer2);
channel.addPeer(peer3);

var event_url = 'grpcs://10.254.186.164:7053';
/**
    发起交易
    @returns {Promis.<TResult>}
*/
var sendTransaction = function(chaincodeid, func, chaincode_args, channelId) {
    var tx_id = null;
    var payload;
    return getOrgUser4Local().then((user)=>{
        tx_id = client.newTransactionID();
        var request = {
            chaincodeId: chaincodeid,
            fcn: func,
            args: chaincode_args,
            chainId: channelId,
            txId: tx_id
        };
        return channel.sendTransactionProposal(request);
    },(err)=>{
        console.log('error',err);
    }).then((chaincodeinvokresult)=>{
        var proposalResponses = chaincodeinvokresult[0];
        var proposal = chaincodeinvokresult[1];
        var header = chaincodeinvokresult[2];
        var all_good = true;
        for (var i in proposalResponses) {
            let one_good = false;
            //成功
            if (proposalResponses && proposalResponses[0].response && proposalResponses[0].response.status == 200) {
                one_good = true;
                console.info('transaction proposal was good');
            }else {
                console.error('transaction proposal was bad');
            }
            all_good = all_good & one_good;
        }

        if (all_good) {
            console.info(util.format(
                'Successfully sent proposal and received proposalResponses: Status - %s, message - "%s", metadate - "%s", endorsement signature :%s',
                proposalResponses[0].response.status,proposalResponses[0].response.message,
                proposalResponses[0].response.payload,proposalResponses[0].endorsement.signature));
            payload = proposalResponses[0].response.payload
            var request = {
                proposalResponses: proposalResponses,
                proposal: proposal,
                orderer: order,
                txId: tx_id,
        header:header
            };

            var transactionID = tx_id.getTransactionID();
        var eventPromises = [];
        let eh = client.newEventHub();
        //接下来设置EventHub,用于监听Transaction是否成功写入,这里也是启用了TLS
        eh.setPeerAddr(event_url,opt_peer1);
            eh.connect();
            let txPromise = new Promise((resolve, reject) => {
                let handle = setTimeout(() => {
                    eh.disconnect();
                    reject();
                }, 30000);
            //向EventHub注册事件的处理办法
                eh.registerTxEvent(transactionID, (tx, code) => {
                    clearTimeout(handle);
                    eh.unregisterTxEvent(transactionID);
                    eh.disconnect();

                    if (code !== 'VALID') {
                            console.error(
                            'The transaction was invalid, code = ' + code);
                            reject();
                    } else {
                            console.log(
                            'The transaction has been committed on peer ' +
                            eh._ep._endpoint.addr);
                            resolve();
                    }
                });
            });
            eventPromises.push(txPromise);
            //把背书后的结果发到orderer排序
            var sendPromise = channel.sendTransaction(request);
        return Promise.all([sendPromise].concat(eventPromises)).then((results) => {
                console.log(' event promise all complete and testing complete');
                return results[0]; // the first returned value is from the 'sendPromise' which is from the 'sendTransaction()' call
            }).catch((err) => {
                console.error(
                    'Failed to send transaction and get notifications within the timeout period.'
                );
                return 'Failed to send transaction and get notifications within the timeout period.';
           });
         } else {
             console.error(
                'Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...'
             );
            return 'Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...';
        }
    },(err)=>{
        console.log('error',err);
    }).then((response)=>{
    if (response.status === 'SUCCESS') {
            console.log('Successfully sent transaction to the orderer.');
            return util.format("%s",payload);
        } else {
            console.error('Failed to order the transaction. Error code: ' + response.status);
            return 'Failed to order the transaction. Error code: ' + response.status;
        }
    },(err)=>{
        console.log('error',err);
    });
}


/**
    根据cryptogen模块生成的账号通过Fabric接口进行相关操作
    @returns {Promise.<TResult>}
*/
function getOrgUser4Local(){
    var keyPath = "./users/keystore";
    var keyPEM = Buffer.from(readAllFiles(keyPath)[0]).toString();
    var certPath = "./users/signcerts";
    var certPEM = readAllFiles(certPath)[0].toString();

    return hfc.newDefaultKeyValueStore({
        path: tempdir
    }).then((store)=>{
        client.setStateStore(store);

        return client.createUser({
            username: 'user87',
            mspid: 'GylOrg1MSP',
            cryptoContent: {
                privateKeyPEM: keyPEM,
                signedCertPEM: certPEM
            }
        });
    });
};

function readAllFiles(dir) {
    var files = fs.readdirSync(dir);
    var certs = [];
    files.forEach((file_name)=>{
        let file_path = path.join(dir,file_name);
        let data = fs.readFileSync(file_path);
        certs.push(data);
    });
    return certs;
}

/**
    获取channel的区块信息
    @returns {Promise.<TResult>}
*/
var getBlockChainInfo = function() {
    return getOrgUser4Local().then((user)=>{
        return channel.queryInfo(peer1);
    },(err)=>{
        console.log('error',err);
    })
}

/**
    根据区块链的编号获取详细信息
    @param blocknum
    @returns {Promise.<TResult>}
*/
var getblockInfobyNum = function(blocknum) {
    return getOrgUser4Local().then((user)=>{
        return channel.queryBlock(blocknum,peer1,null);
    },(err)=>{
        console.log('error',err);
    })
}

/**
    根据区块链的哈希值获取区块详细信息
    @param blockhash
    @returns {Promise.<TResult>}
*/
var getblockInfobyHash = function(blockHash) {
    return getOrgUser4Local().then((user)=>{
        return channel.queryBlockByHash(new Buffer(blockHash,"hex"),peer1);
    },(err)=>{
        console.log('error',err);
    })
}
/**
    获取当前节点加入的通道信息
    @returns {Promise.<TResult>}
*/
var getPeerChannel = function() {
    return getOrgUser4Local().then((user)=>{
        return client.queryChannels(peer1);
    },(err)=>{
        console.log('error',err);
    })
}

/**
    查询指定peer节点已经install的chaincode
    @returns {Promise.<TResult>}
*/
var getPeerInstallCc = function() {
    return getOrgUser4Local().then((user)=>{
        return client.queryInstalledChaincodes(peer1);
    },(err)=>{
        console.log('error',err);
    })
}

/**
    查询指定channel中已实例化的chaincode
    @returns {Promise.<TResult>}
*/
var getPeerInstantiatedCc = function() {
    return getOrgUser4Local().then((user)=>{
        return channel.queryInstantiatedChaincodes(peer1);
    },(err)=>{
        console.log('error',err);
    })
}

/**
    查询指定交易所在区块信息
    @param txId
    @returns {Promis.<TResult>}
 */
var getBlockByTxID = function(TxID) {
    return getOrgUser4Local().then((user)=>{
        return channel.queryBlockByTxID(TxID,peer1);
    },(err)=>{
        console.log('error',err);
    })
}

/**
    查询指定交易所在区块信息
    @param txId
    @returns {Promis.<TResult>}
 */
var getTransaction = function(TxID) {
    return getOrgUser4Local().then((user)=>{
        return channel.queryTransaction(TxID,peer1);
    },(err)=>{
        console.log('error',err);
    })
}

exports.sendTransaction = sendTransaction;
exports.getBlockChainInfo = getBlockChainInfo;
exports.getblockInfobyNum = getblockInfobyNum;
exports.getblockInfobyHash = getblockInfobyHash;
exports.getPeerChannel = getPeerChannel;
exports.getPeerInstantiatedCc = getPeerInstantiatedCc;
exports.getPeerInstallCc = getPeerInstallCc;
exports.getBlockByTxID = getBlockByTxID;
exports.getTransaction = getTransaction;

浏览器部分

var co = require('co');
var fabricservice = require('./fabricservice.js');
var express = require('express');

var app = express();

var channelid = "gylchannel";
var chaincodeid = "gyl";

//供应商发起供货交易
app.get('/sendTransaction1',function(req,res){
    co(function * () {
        var k = req.query.k;
        var v = req.query.v;
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"putvalue",[k,v],channelid);
         res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
});

//核心企业发起确认
app.get('/sendTransaction2',function(req,res){
    co(function * () {
        var k = req.query.k;
        var v = req.query.v;
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"putvalue",[k,v],channelid);
        res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//金融机构审核并放款
app.get('/sendTransaction3',function(req,res){
    co(function * () {
        var k = req.query.k;
        var v = req.query.v;
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"putvalue",[k,v],channelid);
         res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//企业申请贷款
app.get('/queryloan',function(req,res){
    co(function * () {
        var project = req.query.project;
        var times = req.query.time;
        var number = req.query.number
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"queryloan",[project,times,number],channelid);
         res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//给公司设置贷款最大额度
app.get('/setquota',function(req,res){
    co(function * () {
        var project = req.query.project;
        var number = req.query.number;
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"setquota",[project,number],channelid);
         res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//执行贷款逻辑
app.get('/loan',function(req,res){
    co(function * () {
        var project = req.query.project;
        var loanID = req.query.loanID;
        var times = req.query.time;
        var number = req.query.number;
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"loan",[project,loanID,times,number],channelid);
         res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//查看现在还剩多少信用额度
app.get('/checkquota',function(req,res){
    co(function * () {
        var project = req.query.project;
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"checkquota",[project],channelid);
         res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})


//查询交易记录
app.get('/queryhistory',function(req,res){
    co(function * () {
        var k = req.query.k;
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"gethistory",[k],channelid);
         res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})


//查询最新结果
app.get('/getlastvalue',function(req,res){
    co(function * () {
        var k = req.query.k;
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"getlastvalue",[k],channelid);
         res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//查看调用者信息1
app.get('/creator',function(req,res){
    co(function * () {
        var k = req.query.k;
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"creator",[],channelid);
         res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//查看调用者信息2
app.get('/creator2',function(req,res){
    co(function * () {
        var k = req.query.k;
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"creator2",[],channelid);
         res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//查看调用者信息属性
app.get('/getattr',function(req,res){
    co(function * () {
        var k = req.query.k;
        var blockinfo = yield fabricservice.sendTransaction(chaincodeid,"getattr",[],channelid);
         res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//获取当前通道块儿高度
app.get('/getchannelheight',function(req,res){
    co(function * () {
        var blockinfo = yield fabricservice.getBlockChainInfo();
        res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//根据区块编号获取区块信息
app.get('/getblockInfobyNum',function(req,res){
    co(function * () {
        var param = parseInt(req.query.params);
        var blockinfo = yield fabricservice.getblockInfobyNum(param);
        res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//根据区块Hash值获取区块信息
app.get('/getblockInfobyHash',function(req,res){
    co(function * () {
        var param = req.query.params;
        var blockinfo = yield fabricservice.getblockInfobyHash(param);
        res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//获取指定peer节点加入的通道数
app.get('/getPeerChannel',function(req,res){
    co(function * () {
        var blockinfo = yield fabricservice.getPeerChannel();
        res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})


//获取channel已经安装的链码
app.get('/getPeerInstallCc',function(req,res){
    co(function * () {
        var blockinfo = yield fabricservice.getPeerInstallCc();
        res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})


//获取指定channel已经实例化的链码
app.get('/getPeerInstantiatedCc',function(req,res){
    co(function * () {
        var blockinfo = yield fabricservice.getPeerInstantiatedCc();
        res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//通过交易ID获取区块信息
app.get('/getBlockByTxID',function(req,res){
    co(function * () {
        var param = req.query.TxID;
        var blockinfo = yield fabricservice.getBlockByTxID(param);
        res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//通过交易ID获取交易信息
app.get('/getTransaction',function(req,res){
    co(function * () {
        var param = req.query.TxID;
        var blockinfo = yield fabricservice.getTransaction(param);
        res.send(JSON.stringify(blockinfo));
    }).catch((err)=>{
        res.send(err);
    })
})

//启动http服务
var server = app.listen(3000,function(){
    var host = server.address().address;
    var port = server.address().port;
    console.log('Example app listen at http://%s:%s',host,port);
});

//注册异常处理器
process.on('unhandleRejection',function(err){
    console.error(err.stack);
});

process.on('uncaughtException',console.error);

流程

1、供应商发起供货交易调用,如:
http://116.85.10.181:3000/sendTransaction1?k=food&v=1
2、核心企业发起确认,如:
http://116.85.10.181:3000/sendTransaction2?k=food&v=2
3、银行审核后确认放款,如:
http://116.85.10.181:3000/sendTransaction3?k=food&v=3

目前链码写的比较简单,最好每个组织有自己的链码,组织间约定好操作内容。即使采用同样的链码,由于账本中会记录调用者的身份信息(组织以及签名等),所以假如供应商直接调用http://116.85.10.181:3000/sendTransaction3?k=food&v=3 虽然通过但是账本会记录调用者不是银行机构,可以认定无效。

贷款流程:
1、核心企业abc执行申请贷款10000元:
http://116.85.10.181:3000/queryloan?project=abc&time=20181205&number=10000

2、银行背景审查后给予最大贷款额度20000元:
http://116.85.10.181:3000/setquota?project=abc&number=20000

3、银行执行贷款流程:
http://116.85.10.181:3000/loan?project=abc&loanID=00001&time=20181206&number=10000

注意:

1、需要准备npm环境,fabric-client 需要在v.1.1.0 grpc为v.1.10.1
可以使用npm list xxx 来查看版本信息。
2、使用浏览器访问需要开通端口访问权限。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值