Hyperledger Caliper安裝爬坑指南——Deepin15.10

全篇安裝主要參照這篇官方文檔,但中間有很多坑,需要格外注意。本人系統Deepin15.10

必要組件安裝

請參加這位大大的blog,還有這位的,裏面有詳細記錄如何安裝相關組件,建議對照官方文檔中的查看,因爲blog裏面的組件不全。並且,自己親測按照blog中的安裝方法無法適應最新版本,因此建議按照官方的來。注意docker-ce的版本要在18.09以後,否則會報錯;還有就是一定要取消docker必須使用超級賬戶的權限,因爲後續安裝caliper不能用sudo,會報錯。詳情請參見:
最新docker下載請看 http://www.voidcn.com/article/p-zbjykblf-byx.html 需要注意如果要刪除已安裝的docker,尤其是版本裝錯了重裝的,請使用

sudo apt-get remove docker-ce

否則會報錯,說沒有安裝docker
安裝完後改國內源和權限等後續處理請看 https://blog.csdn.net/qq_36148847/article/details/79273591

caliper安裝

由於最新版caliper的原因,很多2019年以前的教程中caliper的用法已經不適用了,因此還是得按照官方的來。
採用官方文檔中 Local NPM install 的安裝方法。 有兩個坑需要注意
1)

npx caliper bind \
    --caliper-bind-sut fabric:1.4.0

這個語句現在已經不能用了,請用下面的語句代替

npx caliper bind \
    --caliper-bind-sut fabric --caliper-bind-sdk 1.4.0

2)

npx caliper launch master \
    --caliper-workspace . \
    --caliper-benchconfig benchmarks/scenario/simple/config.yaml \
    --caliper-networkconfig networks/fabric/fabric-v1.4.1/2org1peergoleveldb/fabric-go.yaml

這個語句現在也執行不了,現在按照

npx caliper benchmark run --caliper-workspace ./ --caliper-benchconfig benchmarks/scenario/simple/config.yaml --caliper-networkconfig networks/fabric/fabric-v1.4.1/2org1peergoleveldb/fabric-go.yaml

來執行了

上面2)中的語句實際就是執行測試的語句了,但是有個前提,必須在caliper官方的workbench目錄下,該目錄配置有很多測試用的文件

git clone https://github.com/hyperledger/caliper-benchmarks.git
cd caliper-benchmarks
git checkout <your Caliper version>

選擇和caliper相同的版本,如本文選擇的是caliper v0.2.0,則這裏也填 v0.2.0
一定要注意切換版本,否則可能出現測試的標準無法識別的情況。我一開始沒有切版本,結果報了一個無法監控cpu的錯誤(其實我也不知道是不是這個原因導致的,反正切了應該沒錯吧)

使用caliper

大部分教程講到測試成功就沒有下文了,這裏多講一點關於怎麼用的問題。首先,從開始執行的測試中可以看到測試的配置文件主要有兩個。網絡方面注意是 networks/fabric/fabric-v1.4.1/2org1peergoleveldb/fabric-go.yaml, 測試配置爲benchmarks/scenario/simple/config.yaml

打開測試配置文件 benchmarks/scenario/simple/config.yaml,可以見到如下語句

---
test:
  clients:
    type: local
    number: 1
  rounds:
  - label: Change car owner.
    txNumber:
    - 100
    rateControl:
    - type: fixed-rate
      opts:
        tps: 50
    arguments:
      assets: 1000
    callback: benchmarks/scenario/fabcar/changeCarOwner.js
  - label: Query all cars.
    txNumber:
    - 100
    rateControl:
    - type: fixed-rate
      opts:
        tps: 50
    arguments:
      assets: 1000
      startKey: '1'
      endKey: '50'
    callback: benchmarks/scenario/fabcar/queryAllCars.js
  - label: Query a car.
    txNumber:
    - 100
    rateControl:
    - type: fixed-rate
      opts:
        tps: 50
    arguments:
      assets: 1000
    callback: benchmarks/scenario/fabcar/queryCar.js
  - label: Create a car.
     txNumber:
    - 100
    rateControl:
    - type: fixed-rate
      opts:
        tps: 50
    arguments:
    callback: benchmarks/scenario/fabcar/createCar.js
monitor:
  type:
  - docker
  - process
  docker:
    name:
    - all
  process:
  - command: node
    arguments: local-client.js
    multiOutput: avg
  interval: 1

test裏面round,每個label對應一個測試項,實例中測試的主要是吞吐量,調用callback裏面的js文件進行測試。隨意打開一個js文件,如示例sample中的open.js:

'use strict';

module.exports.info  = 'opening accounts';

let account_array = [];
let txnPerBatch;
let initMoney;
let bc, contx;
module.exports.init = function(blockchain, context, args) {
    if(!args.hasOwnProperty('money')) {
        return Promise.reject(new Error('simple.open - \'money\' is missed in the arguments'));
    }

    if(!args.hasOwnProperty('txnPerBatch')) {
        args.txnPerBatch = 1;
    }
    initMoney = args.money;
    txnPerBatch = args.txnPerBatch;
    bc = blockchain;
    contx = context;

    return Promise.resolve();
};

const dic = 'abcdefghijklmnopqrstuvwxyz';
/**
 * Generate string by picking characters from dic variable
 * @param {*} number character to select
 * @returns {String} string generated based on @param number
 */
function get26Num(number){
    let result = '';
    while(number > 0) {
        result += dic.charAt(number % 26);
        number = parseInt(number/26);
    }
    return result;
}

let prefix;
/**
 * Generate unique account key for the transaction
 * @returns {String} account key
 */
function generateAccount() {
    // should be [a-z]{1,9}
    if(typeof prefix === 'undefined') {
        prefix = get26Num(process.pid);
    }
    return prefix + get26Num(account_array.length+1);
}

/**
 * Generates simple workload
 * @returns {Object} array of json objects
 */
function generateWorkload() {
    let workload = [];
    for(let i= 0; i < txnPerBatch; i++) {
        let acc_id = generateAccount();
        account_array.push(acc_id);

        if (bc.bcType === 'fabric') {
            workload.push({
                chaincodeFunction: 'open',
                chaincodeArguments: [acc_id, initMoney.toString()],
            });
        } else {
            workload.push({
                'verb': 'open',
                'account': acc_id,
                'money': initMoney
            });
        }
    }
    return workload;
}

module.exports.run = function() {
    let args = generateWorkload();
    return bc.invokeSmartContract(contx, 'simple', 'v0', args, 100);
};

module.exports.end = function() {
    return Promise.resolve();
};

module.exports.account_array = account_array;

關鍵在於module.export.run中,返回的bc.invokeSmartContract即調用鏈碼功能,其中第二項爲鏈碼名,第三項爲版本,第四項即參數,最後一項是啥我還不清楚,後面在研究。
注意參數的設置在generateWorkload裏面,這是用戶自定義的一個函數,但是其實也可以不這麼寫。再看看另外一個測試查詢藉口的代碼query.js:

'use strict';

module.exports.info  = 'querying accounts';


let bc, contx;
let account_array;

module.exports.init = function(blockchain, context, args) {
    const open = require('./open.js');
    bc       = blockchain;
    contx    = context;
    account_array = open.account_array;

    return Promise.resolve();
};

module.exports.run = function() {
    const acc  = account_array[Math.floor(Math.random()*(account_array.length))];

    if (bc.bcType === 'fabric') {
        let args = {
            chaincodeFunction: 'query',
            chaincodeArguments: [acc],
        };

        return bc.bcObj.querySmartContract(contx, 'simple', 'v0', args, 10);
    } else {
        // NOTE: the query API is not consistent with the invoke API
        return bc.queryState(contx, 'simple', 'v0', acc);
    }
};

module.exports.end = function() {
    // do nothing
    return Promise.resolve();
};

看起來似乎要短很多,原因在於這裏沒有隨機生成用戶名字的代碼,轉而從open.js的執行結果中取出了生成名字列表,注意開始init的部分。open.js的列表導出在最後一句

module.exports.account_array = account_array;

這些東西我還沒有摸索清楚,因爲不是很會JavaScript,後面在慢慢弄。
還有一點,所有要測試的鏈碼都要在通道和peer上安裝,不然你是測試不了的。測試代碼會自動安裝,但是需要配置要安裝的鏈碼和鏈碼的路徑。配置文件在 networks/fabric/fabric-v1.4.1/2org1peergoleveldb/fabric-go.yaml裏面。

channels:
  mychannel:
    configBinary: networks/fabric/config_solo/mychannel.tx
    created: false
    orderers:
    - orderer.example.com
    peers:
      peer0.org1.example.com:
        eventSource: true
      peer0.org2.example.com:
        eventSource: true

    chaincodes:
#     - id: marbles
#       version: v0
#       language: golang
#       path: fabric/samples/marbles/go
#       metadataPath: src/fabric/samples/marbles/go/metadata
#     - id: drm
#       version: v0
#       language: golang
#       path: fabric/scenario/drm/go
    - id: simple
      version: v0
      language: golang
      path: fabric/scenario/simple/go
#     - id: smallbank
#       version: v0
#       language: golang
#       path: fabric/scenario/smallbank/go
    - id: abstore
      version: v0
      language: golang
      path: fabric/scenario/abstore/go

chaincodes下面就是配置要安裝的鏈碼的,注意這個path,是從你指定的workspace下src目錄開始算的,即完整地址爲 你的workspace/src/path

大致就這些了,我也就研究了這麼多,後續有進展還會繼續記錄。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章