美文网首页
Fabric node sdk交互测试

Fabric node sdk交互测试

作者: 攻城老狮 | 来源:发表于2022-12-06 07:58 被阅读0次

    使用 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接口,供上层服务调用。

    相关文章

      网友评论

          本文标题:Fabric node sdk交互测试

          本文链接:https://www.haomeiwen.com/subject/qmmifdtx.html