Fabric node sdk交互测试

使用 Fabric 完成基础的网络配置和链码的编写和部署后,还需要我们进一步通过上层应用服务,完成对底层Fabric搭建的联盟链的调用。本文提供使用 nodejs 编写的上层 sdk 完成对链码的调用操作。当然,也可以使用 go 语言,异曲同工。enjoy!

1 基础 chaincode 编写

  1. 在 chaincode 文件夹中创建nodejs环境
# 1.进入 chaincode 目录
cd $GOPATH/src/github.com/hyperledger/fabric/scripts/fabric-samples/chaincode
# 2.创建我们自己的chaincode目录
mkdir helloworldcc
# 3.初始化npm
npm init
# 4.下载fabric 链码的必要依赖
npm install fabric-shim
# 5.编写链码,并保存至 helloworld.js 文件中

# 6.修改 package.json 文件,指定容器启动时候执行的js程序
vim package.json
"scripts": {
    "start": "node helloworld.js"
},
  1. 编写链码 helloworld.js
//导入环境依赖
const shim = require('fabric-shim');
const Chaincode = class{
    //链码初始化操作
    async Init(stub){
        //获取当前方法的名字和参数
        var ret = stub.getFunctionAndParameters();
        var args  = ret.params;
        var a = args[0];
        var aValue = args[1];
        var b = args[2];
        var bValue = args[3];
        await  stub.putState(a,Buffer.from(aValue));
        await  stub.putState(b,Buffer.from(bValue));
        return shim.success(Buffer.from('chaincod init successs'));
    }

    async Invoke(stub){
        let ret = stub.getFunctionAndParameters();
        let fcn = this[ret.fcn];
        return fcn(stub,ret.params);
    }
    //查询操作
    async query(stub,args){
        let a = args[0];
        let balance = await stub.getState(a);
        return shim.success(balance);
    }

};
shim.start(new Chaincode());

2 基础网络环境搭建与链码安装

  1. 基础网络配置
# 根据fabric提供的基础网络环境配置网络
cd $GOPATH/src/github.com/hyperledger/fabric/scripts/fabric-samples/
cp -r basic-network helloworld-network
  1. node sdk环境创建
# 创建webapp的工作目录
cd $GOPATH/src/github.com/hyperledger/fabric/scripts/fabric-samples/
mkdir helloworld-webapp
cd helloworld-webapp
# 初始化环境,安装依赖
npm init
npm install fabric-ca-client fabric-client
  1. 编写cli安装链码脚本 startFabric.sh
#!/bin/bash

set -e

export MSYS_NO_PATHCONV=1

starttime=$(date +%s)

# 启动 helloworld 的网络环境,创建 channel 并将 peer 节点加入网络
cd ../helloworld-network
./start.sh

# 启动 cli 容器,用于安装,实例化链码
docker-compose -f ./docker-compose.yml up -d cli

# 安装链码
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode install -l node -n helloworld -v v1.0 -p /opt/gopath/src/github.com/helloworldcc/

# 实例化链码
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n helloworld -v v1.0 -c '{"args":["init","yorick","200","tom","100"]}' -P "OR ('Org1MSP.member','Org2MSP.member')"

# 等待
sleep 10

# 测试链码调用
docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n helloworld -c '{"args":["query","yorick"]}'

printf "\nTotal setup execution time : $(($(date +%s) - starttime)) secs ...\n\n\n"
chmod +x startFabric.sh
  1. 执行脚本,完成网络部署 and 链码安装并调用测试
./startFabric.sh
  • result
# 创建 channel 完毕
2022-12-06 11:44:03.909 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2022-12-06 11:44:03.922 UTC [cli.common] readBlock -> INFO 002 Received block: 0
# peer加入 channel 完毕
2022-12-06 11:44:04.014 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2022-12-06 11:44:04.090 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
# cli docker容器创建完毕
Creating cli ... done
# 链码安装,实例化,调用
2022-12-06 11:44:05.289 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2022-12-06 11:44:05.289 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2022-12-06 11:44:05.319 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
2022-12-06 11:44:05.425 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2022-12-06 11:44:05.425 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
# 成功获取到 yorick 的 200 数据
2022-12-06 11:44:16.778 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 payload:"200"

Total setup execution time : 38 secs ...

3 CA 创建用户

  1. 编写 node 程序enrollAdmin.js,使用 ca 创建admin账户
'use strict';
var Fabric_Client = require('fabric-client');
var Fabric_CA_Client = require('fabric-ca-client');

var path = require('path');
var util = require('util');
var os = require('os');


var fabric_client = new Fabric_Client();
var fabric_ca_client = null;
var admin_user = null;
var member_user = null;
var store_path = path.join(__dirname, 'hfc-key-store');
console.log(' Store path:'+store_path);

// 创建 key-value-store,用于保存用户的身份信息(公私钥)
// promise 风格
Fabric_Client.newDefaultKeyValueStore({ path: store_path
}).then((state_store) => {
    // 设置存储区块链网络状态的目录路径,比如智能合约的状态和交易的状态
    fabric_client.setStateStore(state_store);
    var crypto_suite = Fabric_Client.newCryptoSuite();
    // 设置存储组织、节点和用户的密钥的目录路径(两个目前使用相同的目录存储)
    var crypto_store = Fabric_Client.newCryptoKeyStore({path: store_path});
    crypto_suite.setCryptoKeyStore(crypto_store);
    fabric_client.setCryptoSuite(crypto_suite);
    var tlsOptions = {
        trustedRoots: [],
        verify: false
    };
    // be sure to change the http to https when the CA is running TLS enabled
    // 设置 ca 客户端
    fabric_ca_client = new Fabric_CA_Client('http://localhost:7054', tlsOptions , 'ca.example.com', crypto_suite);

    // 首次获取admin账户,查看是否已经登记
    return fabric_client.getUserContext('admin', true);
}).then((user_from_store) => {
    // 已经登记admin,无需ca再创建
    if (user_from_store && user_from_store.isEnrolled()) {
        console.log('Successfully loaded admin from persistence');
        admin_user = user_from_store;
        return null;
    } else {
        // 需要 ca 服务端完成admin账户创建
        // 输入 ca 的id和password,在docker-compose中已经指定
        return fabric_ca_client.enroll({
          enrollmentID: 'admin',
          enrollmentSecret: 'adminpw'
        }).then((enrollment) => {
          console.log('Successfully enrolled admin user "admin"');
          // 创建 admin 账户
          return fabric_client.createUser(
              {username: 'admin',
                  mspid: 'Org1MSP',
                  cryptoContent: { privateKeyPEM: enrollment.key.toBytes(), signedCertPEM: enrollment.certificate }
              });
        }).then((user) => {
          // 给 fabric 客户端设置 admin
          admin_user = user;
          return fabric_client.setUserContext(admin_user);
        }).catch((err) => {
          console.error('Failed to enroll and persist admin. Error: ' + err.stack ? err.stack : err);
          throw new Error('Failed to enroll admin');
        });
    }
}).then(() => {
    console.log('Assigned the admin user to the fabric client ::' + admin_user.toString());
}).catch((err) => {
    console.error('Failed to enroll admin: ' + err);
});
  1. 执行 enrollAdmin.js 程序,得到ca给其办法的证书,hfc-key-store中存有admin用户的公私钥信息
$ node enrollAdmin.js
 Store path:/opt/go-project/src/github.com/hyperledger/fabric/scripts/fabric-samples/helloworld-webapp/hfc-key-store
Successfully enrolled admin user "admin"
Assigned the admin user to the fabric client ::{"name":"admin","mspid":"Org1MSP","roles":null,"affiliation":"","enrollmentSecret":"","enrollment":{"signingIdentity":"bee3c03e36a357f52a80434a542e8d1e574d576c1f7ad93f95cae78b968ce980","identity":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICATCCAaigAwIBAgIUSQqYMOL+H6y2I8vVFhAOfQ1G2wYwCgYIKoZIzj0EAwIw\nczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT\nE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMjIxMjA2MTE0ODAwWhcNMjMxMjA2MTE1\nMzAwWjAhMQ8wDQYDVQQLEwZjbGllbnQxDjAMBgNVBAMTBWFkbWluMFkwEwYHKoZI\nzj0CAQYIKoZIzj0DAQcDQgAEvkFbiPCqKdeljnWzEuBwVXa87V4l3Dak3mVbyOO6\nQ75OIpdisxulZHxgNmpNYhMyb1pW3sRtqUP/LPXebnq4yKNsMGowDgYDVR0PAQH/\nBAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFB9QLZbsSi5gX4Ew0ctTPN4g\nSxAqMCsGA1UdIwQkMCKAIEI5qg3NdtruuLoM2nAYUdFFBNMarRst3dusalc2Xkl8\nMAoGCCqGSM49BAMCA0cAMEQCIELJMJjIk2Qz19XZh1VmF0tJPshSiU9+KHjAltYq\nOANdAiABN0jioRUQBHlvUNONZP3tm798/Vj7akqs0kHCz1/dzQ==\n-----END CERTIFICATE-----\n"}}}
  1. 编写 node 程序registerUser.js,使用刚刚生成的admin用户,注册user1用户
'use strict';
/*
* Copyright IBM Corp All Rights Reserved
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
 * Register and Enroll a user
 */

var Fabric_Client = require('fabric-client');
var Fabric_CA_Client = require('fabric-ca-client');

var path = require('path');
var util = require('util');
var os = require('os');

//
var fabric_client = new Fabric_Client();
var fabric_ca_client = null;
var admin_user = null;
var member_user = null;
var store_path = path.join(__dirname, 'hfc-key-store');
console.log(' Store path:'+store_path);

// create the key value store as defined in the fabric-client/config/default.json 'key-value-store' setting
Fabric_Client.newDefaultKeyValueStore({ path: store_path
}).then((state_store) => {
    // assign the store to the fabric client
    fabric_client.setStateStore(state_store);
    var crypto_suite = Fabric_Client.newCryptoSuite();
    // use the same location for the state store (where the users' certificate are kept)
    // and the crypto store (where the users' keys are kept)
    var crypto_store = Fabric_Client.newCryptoKeyStore({path: store_path});
    crypto_suite.setCryptoKeyStore(crypto_store);
    fabric_client.setCryptoSuite(crypto_suite);
    var tlsOptions = {
        trustedRoots: [],
        verify: false
    };
    // be sure to change the http to https when the CA is running TLS enabled
    fabric_ca_client = new Fabric_CA_Client('http://localhost:7054', null , '', crypto_suite);

    // first check to see if the admin is already enrolled
    return fabric_client.getUserContext('admin', true);
}).then((user_from_store) => {
    // 创建 user1 普通用户前,必须已经有 admin 账户,否则抛异常
    if (user_from_store && user_from_store.isEnrolled()) {
        console.log('Successfully loaded admin from persistence');
        admin_user = user_from_store;
    } else {
        throw new Error('Failed to get admin.... run enrollAdmin.js');
    }

    // at this point we should have the admin user
    // first need to register the user with the CA server
    return fabric_ca_client.register({enrollmentID: 'user1', affiliation: 'org1.department1'}, admin_user);
}).then((secret) => {
    // next we need to enroll the user with CA server
    console.log('Successfully registered user1 - secret:'+ secret);

    return fabric_ca_client.enroll({enrollmentID: 'user1', enrollmentSecret: secret});
}).then((enrollment) => {
  console.log('Successfully enrolled member user "user1" ');
  return fabric_client.createUser(
     {username: 'user1',
     mspid: 'Org1MSP',
     cryptoContent: { privateKeyPEM: enrollment.key.toBytes(), signedCertPEM: enrollment.certificate }
     });
}).then((user) => {
     member_user = user;

     return fabric_client.setUserContext(member_user);
}).then(()=>{
     console.log('User1 was successfully registered and enrolled and is ready to intreact with the fabric network');

}).catch((err) => {
    console.error('Failed to register: ' + err);
    if(err.toString().indexOf('Authorization') > -1) {
        console.error('Authorization failures may be caused by having admin credentials from a previous CA instance.\n' +
        'Try again after deleting the contents of the store directory '+store_path);
    }
});
  1. 执行 registerUser.js 程序,hfc-key-store中存有user1用户的公私钥信息
$ node registerUser.js
 Store path:/opt/go-project/src/github.com/hyperledger/fabric/scripts/fabric-samples/helloworld-webapp/hfc-key-store
Successfully loaded admin from persistence
Successfully registered user1 - secret:PbjicGKZoMwV
Successfully enrolled member user "user1"
User1 was successfully registered and enrolled and is ready to intreact with the fabric network
  1. 编写 node 程序 query.js ,调用helloworld链码的query函数,查询“yorick”的值
'use strict';
/*
* Copyright IBM Corp All Rights Reserved
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
 * Chaincode query
 */

var Fabric_Client = require('fabric-client');
var path = require('path');
var util = require('util');
var os = require('os');

//
var fabric_client = new Fabric_Client();

// setup the fabric network
var channel = fabric_client.newChannel('mychannel');
var peer = fabric_client.newPeer('grpc://localhost:7051');
channel.addPeer(peer);

//
var member_user = null;
var store_path = path.join(__dirname, 'hfc-key-store');
console.log('Store path:'+store_path);
var tx_id = null;

// 获取操作链码的用户身份信息
Fabric_Client.newDefaultKeyValueStore({ path: store_path
}).then((state_store) => {
    // assign the store to the fabric client
    fabric_client.setStateStore(state_store);
    var crypto_suite = Fabric_Client.newCryptoSuite();
    // use the same location for the state store (where the users' certificate are kept)
    // and the crypto store (where the users' keys are kept)
    var crypto_store = Fabric_Client.newCryptoKeyStore({path: store_path});
    crypto_suite.setCryptoKeyStore(crypto_store);
    fabric_client.setCryptoSuite(crypto_suite);

    // get the enrolled user from persistence, this user will sign all requests
    return fabric_client.getUserContext('user1', true);
}).then((user_from_store) => {
    if (user_from_store && user_from_store.isEnrolled()) {
        console.log('Successfully loaded user1 from persistence');
        member_user = user_from_store;
    } else {
        throw new Error('Failed to get user1.... run registerUser.js');
    }

    // 查询请求构建
    const request = {
        chaincodeId: 'helloworld',
        fcn: 'query',
        args: ['yorick']
    };

    // 向peer节点发送请求提案
    return channel.queryByChaincode(request);
}).then((query_responses) => {
    console.log("Query has completed, checking results");
    // query_responses could have more than one  results if there multiple peers were used as targets
    if (query_responses && query_responses.length == 1) {
        if (query_responses[0] instanceof Error) {
            console.error("error from query = ", query_responses[0]);
        } else {
      // 打印查询的结果
            console.log("Response is ", query_responses[0].toString());
        }
    } else {
        console.log("No payloads were returned from query");
    }
}).catch((err) => {
    console.error('Failed to query successfully :: ' + err);
});
  1. 执行 query.js 程序,使用hfc-key-store中存有user1用户作为身份凭证调用链码,获取yorick的值信息
$ node query.js
Store path:/opt/go-project/src/github.com/hyperledger/fabric/scripts/fabric-samples/helloworld-webapp/hfc-key-store
Successfully loaded user1 from persistence
Query has completed, checking results
Response is  200

至此,完成了通过 node sdk 的方式调用链码。后续可以对sdk进一步封装,对外提供相关访问请求crud接口,供上层服务调用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻城老湿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值