Hyperledger Fabric——balance transfer(四)安装和实例化chaincode

详细解析blance transfer示例的安装(install)和实例化(Instantiate)链码(chaincode)的过程。安装chaincode会根据本地的链码文件生成chaincode镜像,实例化chaincode则会启动该镜像,使链码在docker容器中运行。

安装chaincode

1.首先看app.js中的路由函数

app.post('/chaincodes', async function(req, res) {
    var peers = req.body.peers;                             // 目标节点列表
    var chaincodeName = req.body.chaincodeName;             // chaincode名称
    var chaincodePath = req.body.chaincodePath;             // chaincode路径
    var chaincodeVersion = req.body.chaincodeVersion;       // chaincode版本
    var chaincodeType = req.body.chaincodeType;             // chaincode类型    Eg. golong
    /*
       省略了参数校验
    */
    // 安装chaincode
    let message = await install.installChaincode(peers, chaincodeName, chaincodePath, chaincodeVersion, chaincodeType, req.username, req.orgname)
    res.send(message);
});

2.再来看install-chaincode.js

var installChaincode = async function(peers, chaincodeName, chaincodePath,
    chaincodeVersion, chaincodeType, username, org_name) {
    logger.debug('\n\n============ Install chaincode on organizations ============\n');
    helper.setupChaincodeDeploy();
    let error_message = null;
    try {
        // 创建该组织对应的client,该client中包含用户信息_userContext
        var client = await helper.getClientForOrg(org_name, username);
        // admin transactionID
        tx_id = client.newTransactionID(true);
        // 打包请求参数 
        var request = {
            targets: peers,
            chaincodePath: chaincodePath,
            chaincodeId: chaincodeName,
            chaincodeVersion: chaincodeVersion,
            chaincodeType: chaincodeType
        };
        // 调用SDK中的installChaincode()方法,根据request生成交易提案
        // 然后通过sendPeersProposal()方法提交给所有背书节点,该方法获得提案响应的集合
        // 最终返回 生成的交易提案 和 收集到的提案响应集合(内含背书签名)
        // 之后将两者会作为交易的内容发送给orderer服务
        let results = await client.installChaincode(request);
        var proposalResponses = results[0];         // 背书响应集合 
        var proposal = results[1];                  // 交易提案

        // 检查提案响应是否均存在且合格
        var all_good = true;
        for (var i in proposalResponses) {
            let one_good = false;
            if (proposalResponses && proposalResponses[i].response &&
                proposalResponses[i].response.status === 200) {
                one_good = true;
                logger.info('install proposal was good');
            } else {
                logger.error('install proposal was bad %j',proposalResponses.toJSON());
            }
            all_good = all_good & one_good;
        }
        if (all_good) {
            logger.info('Successfully sent install Proposal and received ProposalResponse');
        } else {
            error_message = 'Failed to send install Proposal or receive valid response. Response null or status is not 200'
            logger.error(error_message);
        }
    } 

这一步完成后会生成chiancode镜像,内部包含chaincode源码go文件编译生成的可执行文件。

实例化chaincode

1.首先看app.js中的路由函数

app.post('/channels/:channelName/chaincodes', async function(req, res) {
    var peers = req.body.peers;
    var chaincodeName = req.body.chaincodeName;
    var chaincodeVersion = req.body.chaincodeVersion;
    var channelName = req.params.channelName;
    var chaincodeType = req.body.chaincodeType;
    var fcn = req.body.fcn;
    var args = req.body.args;
    // 实例化chaincode
    let message = await instantiate.instantiateChaincode(peers, channelName, chaincodeName, chaincodeVersion, chaincodeType, fcn, args, req.username, req.orgname);
    res.send(message);
});

2.再来看instantiate-chaincode.js

var instantiateChaincode = async function(peers, channelName, chaincodeName, chaincodeVersion, functionName, chaincodeType, args, username, org_name) {
    var error_message = null;

    try {
        // 创建该组织名对应的client,并为其分配了用户对象
        var client = await helper.getClientForOrg(org_name, username);
        // 获取channel对象
        var channel = client.getChannel(channelName);
        // 获取基于msp管理员的TransactionID,这表示实例化链码的交易提案
        // 需要用到组织管理员的身份进行签名
        var tx_id = client.newTransactionID(true); 

        // 这个transaction ID 会用来登记(register)事件监听
        var deployId = tx_id.getTransactionID();

        // 构造请求结构
        var request = {
            targets : peers,
            chaincodeId: chaincodeName,
            chaincodeType: chaincodeType,
            chaincodeVersion: chaincodeVersion,
            args: args,
            txId: tx_id
        };

        if (functionName)
            request.fcn = functionName;

        let results = await channel.sendInstantiateProposal(request, 60000); 

        // 返回的 交易提案 和 提案相应
        var proposalResponses = results[0];
        var proposal = results[1];

        // 检查提案响应中是否包含正确的背书签名
        var all_good = true;
        for (var i in proposalResponses) {
            let one_good = false;
            if (proposalResponses && proposalResponses[i].response &&
                proposalResponses[i].response.status === 200) {
                one_good = true;
                logger.info('instantiate proposal was good');
            } else {
                logger.error('instantiate proposal was bad');
            }
            all_good = all_good & one_good;
        }
            // 等待channel的eventHub通知我们交易被peer节点提交
            var promises = [];
            let event_hubs = channel.getChannelEventHubsForOrg();
            #event_hubs.forEach((eh) => {
                #let instantiateEventPromise = new Promise((resolve, reject) => {
                    #let event_timeout = setTimeout(() => {
                        let message = 'REQUEST_TIMEOUT:' + eh.getPeerAddr();
                        logger.error(message);
                        eh.disconnect();
                    }, 60000);
                    // 注册交易事件监听
                    #eh.registerTxEvent(deployId, (tx, code, block_num) => {
                        clearTimeout(event_timeout);
                    }, (err) => {
                        clearTimeout(event_timeout);
                        logger.error(err);
                        reject(err);
                    },          
                        {unregister: true, disconnect: true}
                    );
                    eh.connect();
                });
                promises.push(instantiateEventPromise);
            });
            // 构造交易请求,包含交易id、交易提案、提案响应
            var orderer_request = {
                txId: tx_id,            // 组织admin进行签名的交易id
                proposalResponses: proposalResponses,
                proposal: proposal
            };
            // 发送交易请求到Orderer节点,内部通过调用orderer.sendBroadcast(envelope)实现
            var sendPromise = channel.sendTransaction(orderer_request);

        } else {
            error_message = util.format('Failed to send Proposal and receive all good ProposalResponse');
            logger.debug(error_message);
        }
    } catch (error) {
        logger.error('Failed to send instantiate due to error: ' + error.stack ? error.stack : error);
        error_message = error.toString();
    }
};

测试

  • 安装chaincode

    curl -s -X POST \
      http://localhost:4000/chaincodes \
      -H "authorization: Bearer <Token>" \
      -H "content-type: application/json" \
      -d '{
        "peers": ["peer0.org1.example.com","peer1.org1.example.com"],
        "chaincodeName":"mycc",
        "chaincodePath":"github.com/example_cc/go",
        "chaincodeType": "golang",
        "chaincodeVersion":"v0"
    }'

    结果:

    {"success":true,"message":"Successfully install chaincode"}
  • 实例化chaincode

    curl -s -X POST \
      http://localhost:4000/channels/mychannel/chaincodes \
      -H "authorization: Bearer <token>" \
      -H "content-type: application/json" \
      -d '{
        "peers": ["peer0.org1.example.com","peer1.org1.example.com"],
        "chaincodeName":"mycc",
        "chaincodeVersion":"v0",
        "chaincodeType": "golang",
        "args":["a","100","b","200"]
    }'

    结果:

    {"success":true,"message":"Successfully instantiate chaingcode in organization Org1 to the channel 'mychannel'"}
posted @ 2018-05-14 17:18  zhayujie  阅读(160)  评论(0编辑  收藏  举报