【25.06】7W个字,教你解决FISCOBCOS和fabric全套安装caliper的问题,附源码加bug解决方案

 前置条件

如果你不想处理也可以去我的资源里拿,或者找我要我的机器,我的机器也有搭建教程,在置顶文档

安装一个Ubuntu20+的镜像


基础环境安装

Git cURL vim jq

sudo apt install -y git curl vim jq

 Docker和Docker-compose

这个命令会自动安装docker 

sudo apt install docker-compose
sudo chmod +x /usr/bin/docker-compose

docker version

docker-compose version
sudo systemctl enable docker
systemctl status docker
sudo usermod -aG docker $USER
docker version

如果出现版本信息就不用重启 如果没有版本信息就需要重启再查看

docker version

完成后给docker 换源 

sudo mkdir -p /etc/docker

vim命令如果没有本文件就会在wq保存之后创建一个这个文件 

sudo vim /etc/docker/daemon.json

这里使用更多的源,因为,目前docker还不是很稳定

{
  "registry-mirrors" : ["https://docker.registry.cyou",
"https://docker-cf.registry.cyou",
"https://dockercf.jsdelivr.fyi",
"https://docker.jsdelivr.fyi",
"https://dockertest.jsdelivr.fyi",
"https://mirror.aliyuncs.com",
"https://dockerproxy.com",
"https://mirror.baidubce.com",
"https://docker.m.daocloud.io",
"https://docker.nju.edu.cn",
"https://docker.mirrors.sjtug.sjtu.edu.cn",
"https://docker.mirrors.ustc.edu.cn",
"https://mirror.iscas.ac.cn",
"https://docker.rainbond.cc",
"https://do.nark.eu.org",
"https://dc.j8.work",
"https://dockerproxy.com",
"https://gst6rzl9.mirror.aliyuncs.com",
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com",
"http://mirrors.ustc.edu.cn/",
"https://mirrors.tuna.tsinghua.edu.cn/",
"http://mirrors.sohu.com/" 
],
 "insecure-registries" : [
    "registry.docker-cn.com",
    "docker.mirrors.ustc.edu.cn"
    ],
"debug": true,
"experimental": false
}
sudo systemctl daemon-reload
sudo systemctl restart docker

查看换源是否成功,他会显示刚才复制进去的一坨内容 

docker info

Golang

这里有两种方案,一种是压缩包安装 一种是apt安装自行选择,我这里选择的是apt安装 版本尽量高于1.18如果apt安装小于这个版本就先执行apt update 和upgrade

sudo apt install golang

安装包安装

wget https://dl.google.com/go/go1.22.4.linux-amd64.tar.gz
sudo tar -C /usr/local -zxvf go1.22.4.linux-amd64.tar.gz
sudo vim ~/.bashrc
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
source ~/.bashrc
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct

查看内容是否生效 

go env

Node.js

使用nvm不要影响到其他应用的node包

git clone https://gitee.com/mirrors/nvm.git ~/.nvm && cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`
./install.sh
vim .bash_profile
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
source .bash_profile
nvm install v16.13.0
node -v && npm -v
nvm use v16.13.0
npm config get registry
npm config list

安装fabric

赋予管理员权限 然后进入根目录

su root && cd ~

这里不需要创建工作目录因为下载下来后就直接是fabric,当然如果你要管理不同版本的fabric那还是可以创一个工作目录

mkdir fabric && cd fabric
git clone https://github.com/hyperledger/fabric.git

目前测试成功的版本是2.4.9 拉下来的是最新版 直接更换文件内容

cd script && vim bootstrap.sh
#!/bin/bash
#
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
 
# if version not passed in, default to latest released version
VERSION=2.4.9
# if ca version not passed in, default to latest released version
CA_VERSION=1.5.5
 
REGISTRY=${FABRIC_DOCKER_REGISTRY:-docker.io/hyperledger}
 
OS=$(uname -s|tr '[:upper:]' '[:lower:]'|sed 's/mingw64_nt.*/windows/')
ARCH=$(uname -m | sed 's/x86_64/amd64/g' | sed 's/aarch64/arm64/g')
PLATFORM=${OS}-${ARCH}
 
# Fabric < 1.2 uses uname -m for architecture.
MARCH=$(uname -m)
 
: ${CONTAINER_CLI:="docker"}
 
printHelp() {
    echo "Usage: bootstrap.sh [version [ca_version]] [options]"
    echo
    echo "options:"
    echo "-h : this help"
    echo "-d : bypass docker image download"
    echo "-s : bypass fabric-samples repo clone"
    echo "-b : bypass download of platform-specific binaries"
    echo
    echo "e.g. bootstrap.sh 2.4.9 1.5.5 -s"
    echo "will download docker images and binaries for Fabric v2.4.9 and Fabric CA v1.5.5"
}
 
# dockerPull() pulls docker images from fabric and chaincode repositories
# note, if a docker image doesn't exist for a requested release, it will simply
# be skipped, since this script doesn't terminate upon errors.
 
dockerPull() {
    #three_digit_image_tag is passed in, e.g. "1.4.7"
    three_digit_image_tag=$1
    shift
    #two_digit_image_tag is derived, e.g. "1.4", especially useful as a local tag for two digit references to most recent baseos, ccenv, javaenv, nodeenv patch releases
    two_digit_image_tag=$(echo "$three_digit_image_tag" | cut -d'.' -f1,2)
    while [[ $# -gt 0 ]]
    do
        image_name="$1"
        echo "====>  ${REGISTRY}/fabric-$image_name:$three_digit_image_tag"
        ${CONTAINER_CLI} pull "${REGISTRY}/fabric-$image_name:$three_digit_image_tag"
        ${CONTAINER_CLI} tag "${REGISTRY}/fabric-$image_name:$three_digit_image_tag" "${REGISTRY}/fabric-$image_name"
        ${CONTAINER_CLI} tag "${REGISTRY}/fabric-$image_name:$three_digit_image_tag" "${REGISTRY}/fabric-$image_name:$two_digit_image_tag"
        shift
    done
}
 
cloneSamplesRepo() {
    # clone (if needed) hyperledger/fabric-samples and checkout corresponding
    # version to the binaries and docker images to be downloaded
    if [ -d test-network ]; then
        # if we are in the fabric-samples repo, checkout corresponding version
        echo "==> Already in fabric-samples repo"
    elif [ -d fabric-samples ]; then
        # if fabric-samples repo already cloned and in current directory,
        # cd fabric-samples
        echo "===> Changing directory to fabric-samples"
        cd fabric-samples
    else
        echo "===> Cloning hyperledger/fabric-samples repo"
        git clone -b main https://github.com/hyperledger/fabric-samples.git && cd fabric-samples
    fi
 
    if GIT_DIR=.git git rev-parse v${VERSION} >/dev/null 2>&1; then
        echo "===> Checking out v${VERSION} of hyperledger/fabric-samples"
        git checkout -q v${VERSION}
    else
        echo "fabric-samples v${VERSION} does not exist, defaulting to main. fabric-samples main branch is intended to work with recent versions of fabric."
        git checkout -q main
    fi
}
 
# This will download the .tar.gz
download() {
    local BINARY_FILE=$1
    local URL=$2
    echo "===> Downloading: " "${URL}"
    curl -L --retry 5 --retry-delay 3 "${URL}" | tar xz || rc=$?
    if [ -n "$rc" ]; then
        echo "==> There was an error downloading the binary file."
        return 22
    else
        echo "==> Done."
    fi
}
 
pullBinaries() {
    echo "===> Downloading version ${FABRIC_TAG} platform specific fabric binaries"
    download "${BINARY_FILE}" "https://github.com/hyperledger/fabric/releases/download/v${VERSION}/${BINARY_FILE}"
    if [ $? -eq 22 ]; then
        echo
        echo "------> ${FABRIC_TAG} platform specific fabric binary is not available to download <----"
        echo
        exit
    fi
 
    echo "===> Downloading version ${CA_TAG} platform specific fabric-ca-client binary"
    download "${CA_BINARY_FILE}" "https://github.com/hyperledger/fabric-ca/releases/download/v${CA_VERSION}/${CA_BINARY_FILE}"
    if [ $? -eq 22 ]; then
        echo
        echo "------> ${CA_TAG} fabric-ca-client binary is not available to download  (Available from 1.1.0-rc1) <----"
        echo
        exit
    fi
}
 
pullDockerImages() {
    command -v ${CONTAINER_CLI} >& /dev/null
    NODOCKER=$?
    if [ "${NODOCKER}" == 0 ]; then
        FABRIC_IMAGES=(peer orderer ccenv tools)
        case "$VERSION" in
        2.*)
            FABRIC_IMAGES+=(baseos)
            shift
            ;;
        esac
        echo "FABRIC_IMAGES:" "${FABRIC_IMAGES[@]}"
        echo "===> Pulling fabric Images"
        dockerPull "${FABRIC_TAG}" "${FABRIC_IMAGES[@]}"
        echo "===> Pulling fabric ca Image"
        CA_IMAGE=(ca)
        dockerPull "${CA_TAG}" "${CA_IMAGE[@]}"
        echo "===> List out hyperledger docker images"
        ${CONTAINER_CLI} images | grep hyperledger
    else
        echo "========================================================="
        echo "${CONTAINER_CLI} not installed, bypassing download of Fabric images"
        echo "========================================================="
    fi
}
 
DOCKER=true
SAMPLES=true
BINARIES=true
 
# Parse commandline args pull out
# version and/or ca-version strings first
if [ -n "$1" ] && [ "${1:0:1}" != "-" ]; then
    VERSION=$1;shift
    if [ -n "$1" ]  && [ "${1:0:1}" != "-" ]; then
        CA_VERSION=$1;shift
        if [ -n  "$1" ] && [ "${1:0:1}" != "-" ]; then
            THIRDPARTY_IMAGE_VERSION=$1;shift
        fi
    fi
fi
 
# prior to 1.2.0 architecture was determined by uname -m
if [[ $VERSION =~ ^1\.[0-1]\.* ]]; then
    export FABRIC_TAG=${MARCH}-${VERSION}
    export CA_TAG=${MARCH}-${CA_VERSION}
    export THIRDPARTY_TAG=${MARCH}-${THIRDPARTY_IMAGE_VERSION}
else
    # starting with 1.2.0, multi-arch images will be default
    : "${CA_TAG:="$CA_VERSION"}"
    : "${FABRIC_TAG:="$VERSION"}"
    : "${THIRDPARTY_TAG:="$THIRDPARTY_IMAGE_VERSION"}"
fi
 
# Prior to fabric 2.5, use amd64 binaries on darwin-arm64
if [[ $VERSION =~ ^2\.[0-4]\.* ]]; then
  PLATFORM=$(echo $PLATFORM | sed 's/darwin-arm64/darwin-amd64/g')
fi
 
BINARY_FILE=hyperledger-fabric-${PLATFORM}-${VERSION}.tar.gz
CA_BINARY_FILE=hyperledger-fabric-ca-${PLATFORM}-${CA_VERSION}.tar.gz
 
# then parse opts
while getopts "h?dsb" opt; do
    case "$opt" in
        h|\?)
            printHelp
            exit 0
            ;;
        d)  DOCKER=false
            ;;
        s)  SAMPLES=false
            ;;
        b)  BINARIES=false
            ;;
    esac
done
 
if [ "$SAMPLES" == "true" ]; then
    echo
    echo "Clone hyperledger/fabric-samples repo"
    echo
    cloneSamplesRepo
fi
if [ "$BINARIES" == "true" ]; then
    echo
    echo "Pull Hyperledger Fabric binaries"
    echo
    pullBinaries
fi
if [ "$DOCKER" == "true" ]; then
    echo
    echo "Pull Hyperledger Fabric docker images"
    echo
    pullDockerImages
fi
./bootstrap.sh

执行 bootstrap.sh 脚本,主要会做以下3步:

1. 克隆 fabric samples 的代码;

2. 下载 fabric 和 fabric-ca 的二进制文件;

3. 拉取 fabric 所需要的一些镜像 image 。由于直接执行 bootstrap.sh 脚本文件很有可能会出现卡死的问题或者由于网络问题而无法连接的问题,第一步一般都没有问题,主要是第二步和第三步,对于第二步,可以采用手动下载的方式,挂个梯子去 github 官网下载 fabric 和 fabric-ca 编译后的压缩包,这样速度就很快,然后将压缩包直接拖入虚拟机中,最后将其存放在当前目录下,即:~/go/src/github.com/hyperledger/fabric/scripts

fabric:

Releases · hyperledger/fabric · GitHub

fabric-ca:

Releases · hyperledger/fabric-ca · GitHub

 

                        

参考链接:https://blog.csdn.net/qq_46380363/article/details/143177862

将这两个压缩包解压到 fabric-samples 目录下:

sudo tar -zxvf hyperledger-fabric-linux-amd64-2.4.9.tar.gz -C ~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples
sudo tar -zxvf hyperledger-fabric-ca-linux-amd64-1.5.5.tar.gz -C ~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples
./bootstrap.sh -sb
在上面命令中,参数 -sb 
s 表示不执行第一步,即不克隆 fabric-samples 的代码
b 表示不执行第二步,即不下载 fabric 和 fabric-ca 的二进制文件
由于在前面的步骤中我们完成了第一步和第二步,所以只需要执行第三步就可以了,即拉取 fabric 所需的一些镜像 image 。
sudo vim ~/.bashrc

你首先使用pwd找一下路径,然后将路径给写进环境变量,如果你按照我的来做的话,那么你的路径应该是 

export FABRIC_BIN=/root/fabric/scripts/fabric-samples/bin
export PATH=$PATH:$FABRIC_BIN
source ~/.bashrc
peer version

启动测试网络

cd fabric-samples/test-network

启动命令 

sudo ./network.sh up

关闭命令 

sudo ./network.sh down

 创建通道命令

sudo ./network.sh createChannel

通道默认的名字是: mychannel ,也可以使用 -c 来指定通道名称,以下命令将创建一个名为 channel1 的通道:

sudo ./network.sh createChannel -c Channel1

注意:确保通道的名称应用以下限制:
仅包含小写 ASCII 字母数字、点 "." 和短划线"_"
少于 250 个字符
以字母开头

首先配置环境变量,修改 ~/.bashrc 文件:

启动链码

vim ~/.bashrc
alias sudo='sudo env PATH=$PATH LD_LIBRARY_PATH=$LD_LIBRARY_PATH'
source ~/.bashrc

cd ../asset-transfer-basic/chaincode-go

这一步就相当于npm i 或者是 mvc install  


go mod vendor
cd ../../test-network
sudo ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go

注意:如果通道名称不是 mychannel ,在命令中添加 -c 通道名称,表示在该通道上部署链码,如下命令就是在名为 channel1 的通道上部署链码:

sudo ./network.sh deployCC -c channel1 -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go

与网络交互

在启用测试网络后,可以使用 peer cli 客户端与网络进行交互,通过 peer cli 客户端可以调用已部署的智能合约,更新通道,或安装和部署新的智能合约。

这里都是临时变量如果需要持久化使用vim去编辑

执行以下命令将 cli 客户端添加到环境变量中:

export PATH=${PWD}/../bin:$PATH

将 fabric-samples 代码库中的 FABRIC_CFG_PATH 设置为指向其中的 core.yaml 文件:

export FABRIC_CFG_PATH=$PWD/../config/

设置允许 org1 操作 peer cli 的环境变量:

export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051

CORE_PEER_TLS_ROOTCERT_FILE 和 CORE_PEER_MSPCONFIGPATH 环境变量指向 Org1 的 organizations 文件夹中的的加密材料。

执行invoke命令用一些资产来初始化账本:

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}'

修改资产所有者,将 asset1 资产的所有者修改为 IDY:

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"TransferAsset","Args":["asset1","IDY"]}'

查看修改后的结果:

peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'

Caliper 0.5.0部署和测试

Caliper安装

 创建Caliper工作区

在 fabric-samples 目录的同一级别创建一个名为 caliper-workspace 的文件夹,然后在 caliper-workspace 文件夹中,分别创建三个名为 networks 、 benchmarks 和 workload 的文件夹:

mkdir -p ../../caliper-workspace/{networks,benchmarks,workload}

初始化项目

如果这个时候你遇到npm不存在的报错请你按照本逻辑再执行一遍

# 切换到root用户
sudo -i

# 为root用户安装nvm
git clone https://gitee.com/mirrors/nvm.git ~/.nvm
cd ~/.nvm
git checkout `git describe --abbrev=0 --tags`
./install.sh

# 使配置生效
source ~/.bashrc

# 安装node
nvm install v16.13.0

执行完后,在当前目录生成了 package.json 文件。

安装caliper-cli

在 caliper-workspace 目录中,使用以下终端命令安装 caliper CLI:

npm install --only=prod @hyperledger/caliper-cli@0.5.0

执行完后,会将依赖下载到当前目录下的 node_modules 文件下。

验证 caliper-cli 是否安装成功:

npx caliper --version

绑定Fabric 2.4

npx caliper bind --caliper-bind-sut fabric:2.4

构建网络配置文件

在低版本中采用的是 .json 文件,而在新版本中需要采用 .yaml 文件,在 networks 文件夹下创建一个名为 networkConfig.yaml 的文件:

cd networks && vim networkConfig.yaml
name: Caliper Benchmarks
version: "2.0.0"
 
caliper:
  blockchain: fabric
 
channels:
  - channelName: mychannel
    contracts:
    - id: basic
 
organizations:
  - mspid: Org1MSP
    identities:
      certificates:
      - name: 'Admin@org1.example.com'
        clientPrivateKey:
          path: '../fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk'
        clientSignedCert:
          path: '../fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem'
    connectionProfile:
      path: '../fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/connection-org1.yaml'
      discover: true

构建测试工作负载模块

在 workload 文件夹中,创建一个名为 readAsset.js 的文件

cd ../workload && vim readAsset.js
'use strict';
 
const { WorkloadModuleBase } = require('@hyperledger/caliper-core');
 
class MyWorkload extends WorkloadModuleBase {
    constructor() {
        super();
    }
    
    async initializeWorkloadModule(workerIndex, totalWorkers, roundIndex, roundArguments, sutAdapter, sutContext) {
        await super.initializeWorkloadModule(workerIndex, totalWorkers, roundIndex, roundArguments, sutAdapter, sutContext);
 
        for (let i=0; i<this.roundArguments.assets; i++) {
            const assetID = `${this.workerIndex}_${i}`;
            console.log(`Worker ${this.workerIndex}: Creating asset ${assetID}`);
            const request = {
                contractId: this.roundArguments.contractId,
                contractFunction: 'CreateAsset',
                invokerIdentity: 'Admin@org1.example.com',
                contractArguments: [assetID,'blue','20','penguin','500'],
                readOnly: false
            };
 
            await this.sutAdapter.sendRequests(request);
        }
    }
    
    async submitTransaction() {
        const randomId = Math.floor(Math.random()*this.roundArguments.assets);
        const myArgs = {
            contractId: this.roundArguments.contractId,
            contractFunction: 'ReadAsset',
            invokerIdentity: 'Admin@org1.example.com',
            contractArguments: [`${this.workerIndex}_${randomId}`],
            readOnly: true
        };
 
        await this.sutAdapter.sendRequests(myArgs);
    }
    
    async cleanupWorkloadModule() {
        for (let i=0; i<this.roundArguments.assets; i++) {
            const assetID = `${this.workerIndex}_${i}`;
            console.log(`Worker ${this.workerIndex}: Deleting asset ${assetID}`);
            const request = {
                contractId: this.roundArguments.contractId,
                contractFunction: 'DeleteAsset',
                invokerIdentity: 'Admin@org1.example.com',
                contractArguments: [assetID],
                readOnly: false
            };
 
            await this.sutAdapter.sendRequests(request);
        }
    }
}
 
function createWorkloadModule() {
    return new MyWorkload();
}
 
module.exports.createWorkloadModule = createWorkloadModule;

构建基准测试配置文件

在 benchmarks 文件夹下创建一个名为 myAssetBenchmark.yaml 的文件:

cd ../benchmarks && vim myAssetBenchmark.yaml
test:
    name: basic-contract-benchmark
    description: test benchmark
    workers:
      type: local
      number: 2
    rounds:
      - label: readAsset
        description: Read asset benchmark
        txDuration: 30
        rateControl: 
          type: fixed-load
          opts:
            transactionLoad: 2
        workload:
          module: workload/readAsset.js
          arguments:
            assets: 10
            contractId: basic
monitors:
  resource:
  - module: docker
    options:
      interval: 5 
      containers:
      - all

运行Caliper基准测试

回退到 ~/fabric/scripts/caliper-workspace

cd ..
npx caliper launch manager --caliper-workspace ./ --caliper-networkconfig networks/networkConfig.yaml --caliper-benchconfig benchmarks/myAssetBenchmark.yaml --caliper-flow-only-test --caliper-fabric-gateway-enabled --caliper-fabric-gateway-discovery

如果出现如下错误:

error [caliper] [caliper-engine] Error while performing "test" step: Error: EACCES: permission denied, open '/home/idy/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk'

这个错误是没有权限,无法打开 priv_sk 文件,执行如下命令授予权限: 

chmod 666 ~/go/src/github.com/hyperledger/fabric/scripts/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk

 执行成功

运行成功之后就可以去文件夹节点开查看相应报告

 

安装FISCOBCOS

第一步. 安装

建立一个工作目录

mkdir benchmarks && cd benchmarks

NPM项目进行初始化,如果公司没有命名需求的话使用

npm init
npm init -y

安装caliper-cli

由于Caliper所有依赖项的安装较为耗时,因此使用--only=prod选项用于指定NPM只安装Caliper的核心组件,而不安装其他的依赖项(如各个区块链平台针对Caliper的适配器)。在部署完成后,可以通过caliper-cli显式绑定需要测试的区块链平台及相应的适配器。

npm install --only=prod @hyperledger/caliper-cli@0.2.0

我这里要适配其他的所以我使用了

npm install @hyperledger/caliper-cli@0.2.0

验证caliper-cli安装成功

npx caliper --version

第二步. 绑定

由于Caliper采用了轻量级的部署方式,因此需要显式的绑定步骤指定要测试的平台及适配器版本,caliper-cli会自动进行相应依赖项的安装。使用npx caliper bind命令进行绑定,命令所需的各项参数可以通过如下命令查看:

root@admin:~/benchmarks$ npx caliper bind --help
Usage:
  caliper bind --caliper-bind-sut fabric --caliper-bind-sdk 1.4.1 --caliper-bind-cwd ./ --caliper-bind-args="-g"

Options:
  --help               Show help  [boolean]
  -v, --version        Show version number  [boolean]
  --caliper-bind-sut   The name of the platform to bind to  [string]
  --caliper-bind-sdk   Version of the platform SDK to bind to  [string]
  --caliper-bind-cwd   The working directory for performing the SDK install  [string]
  --caliper-bind-args  Additional arguments to pass to "npm install". Use the "=" notation when setting this parameter  [string]
其中,

–-caliper-bind-sut :用于指定需要测试的区块链平台,即受测系统(***S***ystem ***u***nder ***T***est); 
–-caliper-bind-sdk:用于指定适配器版本; 
–-caliper-bind-cwd:用于绑定caliper-cli的工作目录,caliper-cli在加载配置文件等场合时均是使用相对于工作目录的相对路径;
--caliper-bind-args:用于指定caliper-cli在安装依赖项时传递给npm的参数,如用于全局安装的-g。

对于FISCO BCOS,可以采用如下方式进行绑定:

npx caliper bind --caliper-bind-sut fisco-bcos --caliper-bind-sdk latest

如果你报这个错请检查是否是因为权限的问题,请选择提权或者是加sudo 

sudo npx caliper bind --caliper-bind-sut fisco-bcos --caliper-bind-sdk latest

第三步. 快速体验FISCO BCOS基准测试


为方便测试人员快速上手,FISCO BCOS已经为Caliper提供了一组预定义的测试样例,测试对象涵盖HelloWorld合约、Solidity版转账合约及预编译版转账合约。同时在测试样例中,Caliper测试脚本会使用docker在本地自动部署及运行4个互连的节点组成的链,因此测试人员无需手工搭链及编写测试用例便可直接运行这些测试样例。

在工作目录下下载预定义测试用例

git clone https://github.com/vita-dounai/caliper-benchmarks.git

注意 若出现网络问题导致的长时间拉取代码失败,则尝试以下方式:

# 拉取gitee代码
git clone https://gitee.com/vita-dounai/caliper-benchmarks.git

执行HelloWorld合约测试

npx caliper benchmark run --caliper-workspace caliper-benchmarks --caliper-benchconfig benchmarks/samples/fisco-bcos/helloworld/config.yaml  --caliper-networkconfig networks/fisco-bcos/4nodes1group/fisco-bcos.json

caliper 运行错误一:

这个错误请按照如下方案解决 

✔ Compiling /root/benchmarks/caliper-benchmarks/src/fisco-bcos/helloworld/HelloWorld.sol ...
2025.06.03-16:20:29.300 error [caliper] [installSmartContract.js] 	Failed to install smart contract helloworld, path=/root/benchmarks/caliper-benchmarks/src/fisco-bcos/helloworld/HelloWorld.sol
2025.06.03-16:20:29.301 error [caliper] [installSmartContract.js] 	Depolying error: TypeError: secp256k1.sign is not a function
2025.06.03-16:20:29.302 error [caliper] [fiscoBcos.js] 	FISCO BCOS smart contract install failed: TypeError: secp256k1.sign is not a function
    at Object.ecsign (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/utils.js:141:29)
    at Transaction.sign (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/transactionObject.js:272:23)
    at signTransaction (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/web3sync.js:42:8)
    at Object.getSignDeployTx (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/web3sync.js:121:12)
    at Object.module.exports.deploy (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/fiscoBcosApi.js:165:27)
2025.06.03-16:20:29.302 error [caliper] [caliper-flow] 	Error: TypeError: secp256k1.sign is not a function
    at Object.ecsign (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/utils.js:141:29)
    at Transaction.sign (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/transactionObject.js:272:23)
    at signTransaction (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/web3sync.js:42:8)
    at Object.getSignDeployTx (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/web3sync.js:121:12)
    at Object.module.exports.deploy (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/fiscoBcosApi.js:165:27)
2025.06.03-16:20:29.303 info  [caliper] [caliper-utils] 	Executing command: cd /root/benchmarks/caliper-benchmarks;docker-compose -f networks/fisco-bcos/4nodes1group/docker-compose.yaml down
Stopping node3 ... 
Stopping node2 ... 
Stopping node1 ... 
Stopping node0 ... 
Stopping node3 ... done
Stopping node2 ... done
Stopping node1 ... done
Stopping node0 ... done
Removing node3 ... 
Removing node2 ... 
Removing node1 ... 
Removing node0 ... 
Removing node3 ... done
Removing node2 ... done
Removing node1 ... done
Removing node0 ... done
Removing network 4nodes1group_default
Benchmark failure
Error: Benchmark failure
    at Function.handler (/root/benchmarks/node_modules/@hyperledger/caliper-cli/lib/benchmark/lib/runBenchmark.js:70:23)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
Command failed

你可以选择修改或替换

修改请按照如下进行修改,我的建议是直接替换

 修改fiscoBcos.js文件

cd /root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib
gedit fiscoBcos.js

 

 

/* 在40行后进行添加 */

        if (this.fiscoBcosSettings.network && this.fiscoBcosSettings.network.authentication) {
            for (let k in this.fiscoBcosSettings.network.authentication) {
                this.fiscoBcosSettings.network.authentication[k] = CaliperUtils.resolvePath(this.fiscoBcosSettings.network.authentication[k], workspace_root);
            }
        }

 

/*在57行进行替换  const fiscoBcosSettings = CaliperUtils.parseYaml(this.configPath)['fisco-bcos'];*/
const fiscoBcosSettings = this.fiscoBcosSettings;

源文档 https://github.com/hyperledger/caliper/pull/677/files


替换fiscoBcos.js文件

cd /root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib
gedit fiscoBcos.js

 

/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

const {
    BlockchainInterface,
    CaliperUtils
} = require('@hyperledger/caliper-core');
const installSmartContractImpl = require('./installSmartContract');
const invokeSmartContractImpl = require('./invokeSmartContract');
const generateRawTransactionImpl = require('./generateRawTransactions');
const Color = require('./common').Color;
const commLogger = CaliperUtils.getLogger('fiscoBcos.js');

/**
 * Implements {BlockchainInterface} for a FISCO BCOS backend.
 */
class FiscoBcos extends BlockchainInterface {
    /**
     * Create a new instance of the {FISCO BCOS} class.
     * @param {string} config_path The absolute path of the FISCO BCOS network configuration file.
     * @param {string} workspace_root The absolute path to the root location for the application configuration files.
     */
    constructor(config_path, workspace_root) {
        super(config_path);
        this.bcType = 'fisco-bcos';
        this.workspaceRoot = workspace_root;
        this.fiscoBcosSettings = CaliperUtils.parseYaml(this.configPath)['fisco-bcos'];
        
        
        if (this.fiscoBcosSettings.network && this.fiscoBcosSettings.network.authentication) {
            for (let k in this.fiscoBcosSettings.network.authentication) {
                this.fiscoBcosSettings.network.authentication[k] = CaliperUtils.resolvePath(this.fiscoBcosSettings.network.authentication[k], workspace_root);
            }
        }
    }

    /**
     * Initialize the {FISCO BCOS} object.
     * @async
     * @return {Promise<object>} The promise for the result of the execution.
     */
    async init() {
        return Promise.resolve();
    }

    /**
     * Deploy the smart contract specified in the network configuration file to all nodes.
     * @async
     */
    async installSmartContract() {
        const fiscoBcosSettings = this.fiscoBcosSettings;
        try {
            await installSmartContractImpl.run(fiscoBcosSettings, this.workspaceRoot);
        } catch (error) {
            commLogger.error(Color.error(`FISCO BCOS smart contract install failed: ${(error.stack ? error.stack : error)}`));
            throw error;
        }
    }

    /**
     * Get a context for subsequent operations
     * 'engine' attribute of returned context object must be reserved for benchmark engine to extend the context
     *  engine = {
     *   submitCallback: callback which must be called once new transaction(s) is submitted, it receives a number argument which tells how many transactions are submitted
     * }
     * @param {String} name name of the context
     * @param {Object} args adapter specific arguments
     * @param {Integer} clientIdx the client index
     * @return {Promise<object>} The promise for the result of the execution.
     */
    async getContext(name, args, clientIdx) {
        return Promise.resolve();
    }

    /**
     * Release a context as well as related resources
     * @param {Object} context adapter specific object
     * @return {Promise<object>} The promise for the result of the execution.
     */
    async releaseContext(context) {
        return Promise.resolve();
    }

    /**
     * Invoke the given smart contract according to the specified options. Multiple transactions will be generated according to the length of args.
     * @param {object} context The FISCO BCOS context returned by {getContext}.
     * @param {string} contractID The name of the smart contract.
     * @param {string} contractVer The version of the smart contract.
     * @param {Array} args Array of JSON formatted arguments for transaction(s). Each element contains arguments (including the function name) passing to the smart contract. JSON attribute named transaction_type is used by default to specify the function name. If the attribute does not exist, the first attribute will be used as the function name.
     * @param {number} timeout The timeout to set for the execution in seconds.
     * @return {Promise<object>} The promise for the result of the execution.
     */
    async invokeSmartContract(context, contractID, contractVer, args, timeout) {
        let promises = [];
        try {
            args.forEach((arg) => {
                let fcn = null;
                let fcArgs = [];

                for (let key in arg) {
                    if (key === 'transaction_type') {
                        fcn = arg[key].toString();
                    } else {
                        fcArgs.push(arg[key].toString());
                    }
                }
                promises.push(invokeSmartContractImpl.run(context, this.fiscoBcosSettings, contractID, fcn, fcArgs, this.workspaceRoot));
            });

            return await Promise.all(promises);
        } catch (error) {
            commLogger.error(Color.error(`FISCO BCOS smart contract invoke failed: ${(error.stack ? error.stack : JSON.stringify(error))}`));
            throw error;
        }
    }

    /**
     * Query state from the ledger
     * @param {Object} context The FISCO BCOS context returned by {getContext}
     * @param {String} contractID Identity of the contract
     * @param {String} contractVer Version of the contract
     * @param {String} key lookup key
     * @param {String} fcn The smart contract query function name
     * @return {Promise<object>} The result of the query.
     */
    async queryState(context, contractID, contractVer, key, fcn) {
        try {
            return invokeSmartContractImpl.run(context, this.fiscoBcosSettings, contractID, fcn, key, this.workspaceRoot, true);
        } catch (error) {
            commLogger.error(Color.error(`FISCO BCOS smart contract query failed: ${(error.stack ? error.stack : error)}`));
            throw error;
        }
    }

    /**
     * Generate an raw transaction and store in local file
     * @param {Object} context The FISCO BCOS context returned by {getContext}
     * @param {String} contractID Identity of the contract
     * @param {Object} arg Arguments of the transaction
     * @param {String} file File path which will be used to store then transaction
     * @return {TaskStatus} Indicates whether the transaction is written to the file successfully or not
     */
    async generateRawTransaction(context, contractID, arg, file) {
        return generateRawTransactionImpl.run(this.fiscoBcosSettings, this.workspaceRoot, context, contractID, arg, file);
    }

    /**
     * Send raw transactions
     * @param {Object} context The FISCO BCOS context returned by {getContext}
     * @param {Array} transactions List of raw transactions
     * @return {Promise} The promise for the result of the execution
     */
    async sendRawTransaction(context, transactions) {
        return sendRawTransactionImpl.run(this.fiscoBcosSettings, context, transactions);
    }
}

module.exports = FiscoBcos;

-----------分割线---------------

 


修改请按照如下进行修改,我的建议是直接替换

修改channelPromise.js

cd /root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib
 gedit channelPromise.js

 

/*替换49行 let emitter = emitters.get(seq).emitter;*/

    let emitter = emitters.get(seq);
    if(!emitter) {
        //Stale message receieved
        return;
    }
    emitter = emitter.emitter;
 gedit fiscoBcos.js

 

cd /root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib
/*替换25行 const Color = require('./common').Color;*/

const fiscoBcosSettings = this.fiscoBcosSettings;

替换channelPromise.js

cd /root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

const tls = require('tls');
const fs = require('fs');
const net = require('net');
const uuidv4 = require('uuid/v4');
const events = require('events');

/**
 * NetworkError exception class thrown in socket connection
 */
class NetworkError extends Error {
    /**
     *
     * @param {String} msg exception message
     */
    constructor(msg) {
        super(msg);
        this.name = 'NetworkError';
    }
}

let emitters = new Map();
let buffers = new Map();
let sockets = new Map();
let lastBytesRead = new Map();

/**
 * Parse response returned by node
 * @param {Buffer} response Node's response
 */
function parseResponse(response) {
    let seq = response.slice(6, 38).toString();
    let result = JSON.parse(response.slice(42).toString());
        let emitter = emitters.get(seq);
    if(!emitter) {
        //Stale message receieved
        return;
    }
    emitter = emitter.emitter;

    if (emitter) {
        let readOnly = Object.getOwnPropertyDescriptor(emitter, 'readOnly').value;
        if (readOnly) {
            if (result.error || result.result !== undefined ) {
                emitter.emit('gotresult', result);
            }
        } else {
            if (result.error || result.status || (result.result && result.result.status)) {
                emitter.emit('gotresult', result);
            } else {
                if (!result.result) {
                    throw new NetworkError(`unknown message receieved, seq=${seq}, data=${response.toString()}`);
                }
            }
        }
    } else {
        throw new NetworkError(`unknown owner message receieved, seq=${seq}, data=${response.toString()}`);
    }
}

/**
 * Create a new TLS socket
 * @param {String} ip IP of channel server
 * @param {Number} port Port of channel server
 * @param {Object} authentication A JSON object contains certificate file path, private key file path and CA file path
 * @return {TLSSocket} A new TLS socket
 */
function createNewSocket(ip, port, authentication) {
    let secureContextOptions = {
        key: fs.readFileSync(authentication.key),
        cert: fs.readFileSync(authentication.cert),
        ca: fs.readFileSync(authentication.ca),
        ecdhCurve: 'secp256k1',
    };

    let secureContext = tls.createSecureContext(secureContextOptions);

    let socket = new net.Socket();
    socket.connect(port, ip);

    let clientOptions = {
        rejectUnauthorized: false,
        secureContext: secureContext,
        socket: socket
    };

    let tlsSocket = tls.connect(clientOptions);

    tlsSocket.on('error', function (error) {
        throw new Error(error);
    });

    let socketID = `${ip}:${port}`;

    lastBytesRead.set(socketID, 0);

    tlsSocket.on('data', function (data) {
        let response = null;
        if (data instanceof Buffer) {
            response = data;
        }
        else {
            response = Buffer.from(data, 'ascii');
        }

        if (!buffers.has(socketID)) {
            // First time to read data from this socket
            let expectedLength = null;
            if (tlsSocket.bytesRead - lastBytesRead.get(socketID) >= 4) {
                expectedLength = response.readUIntBE(0, 4);
            }

            if (!expectedLength || tlsSocket.bytesRead < lastBytesRead.get(socketID) + expectedLength) {
                buffers.set(socketID, {
                    expectedLength: expectedLength,
                    buffer: response
                });
            } else {
                lastBytesRead.set(socketID, lastBytesRead.get(socketID) + expectedLength);
                parseResponse(response);
                buffers.delete(socketID);
            }
        } else {
            // Multiple reading
            let cache = buffers.get(socketID);
            cache.buffer = Buffer.concat([cache.buffer, response]);
            if (!cache.expectedLength && tlsSocket.bytesRead - lastBytesRead.get(socketID) >= 4) {
                cache.expectedLength = cache.buffer.readUIntBE(0, 4);
            }

            if (cache.expectedLength && tlsSocket.bytesRead - lastBytesRead.get(socketID) >= cache.expectedLength) {
                lastBytesRead.set(socketID, lastBytesRead.get(socketID) + cache.expectedLength);
                parseResponse(buffers.get(socketID).buffer);
                buffers.delete(socketID);
            }
        }
    });

    return tlsSocket;
}

/**
 * Prepare the data which will be sent to channel server
 * @param {String} data JSON string of load
 * @return {Object} UUID and packaged data
 */
function packageData(data) {
    const headerLength = 4 + 2 + 32 + 4;

    let length = Buffer.alloc(4);
    length.writeUInt32BE(headerLength + data.length);
    let type = Buffer.alloc(2);
    type.writeUInt16BE(0x12);
    let uuid = uuidv4();
    uuid = uuid.replace(/-/g, '');
    let seq = Buffer.from(uuid, 'ascii');
    let result = Buffer.alloc(4);
    result.writeInt32BE(0);
    let msg = Buffer.from(data, 'ascii');

    return {
        'uuid': uuid,
        'packagedData': Buffer.concat([length, type, seq, result, msg])
    };
}

/**
 * Clear context when a message got response or timeout
 * @param {String} uuid The ID of an `channelPromise`request
 */
function clearContext(uuid) {
    clearTimeout(emitters.get(uuid).timer);
    emitters.delete(uuid);
    buffers.delete(uuid);
}

/**
 * Return channel promise for a request
 * @param {Object} node A JSON object which contains IP and port configuration of channel server
 * @param {Object} authentication A JSON object contains certificate file path, private key file path and CA file path
 * @param {String} data JSON string of load
 * @param {Number} timeout Timeout to wait response
 * @param {Boolean} readOnly Is this request read-only?
 * @return {Promise} a promise which will be resolved when the request is satisfied
 */
function channelPromise(node, authentication, data, timeout, readOnly = false) {
    let ip = node.ip;
    let port = node.channelPort;

    let connectionID = `${ip}${port}`;
    if (!sockets.has(connectionID)) {
        let newSocket = createNewSocket(ip, port, authentication);
        newSocket.unref();
        sockets.set(connectionID, newSocket);
    }
    let tlsSocket = sockets.get(connectionID);

    let dataPackage = packageData(JSON.stringify(data));
    let uuid = dataPackage.uuid;

    tlsSocket.socketID = uuid;
    let packagedData = dataPackage.packagedData;
    let channelPromise = new Promise(async (resolve, reject) => {
        let eventEmitter = new events.EventEmitter();
        Object.defineProperty(eventEmitter, 'readOnly', {
            value: readOnly,
            writable: false,
            configurable: false,
            enumerable: false
        });

        eventEmitter.on('gotresult', (result) => {
            clearContext(uuid);
            if (result.error) {
                reject(result);
            } else {
                resolve(result);
            }
            return; // This `return` is not necessary, but it may can avoid future trap
        });

        eventEmitter.on('timeout', () => {
            clearContext(uuid);
            reject({ 'error': 'timeout' });
            return; // This `return` is not necessary, but it may can avoid future trap
        });

        emitters.set(uuid, {
            emitter: eventEmitter,
            timer: setTimeout(() => {
                eventEmitter.emit('timeout');
            }, timeout)
        });

        tlsSocket.write(packagedData);
    });
    return channelPromise;
}

module.exports = channelPromise;

 

 


-----------分割线---------------


 修改web3sync.js

cd /root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib
 gedit web3sync.js

/*替换27行 uuid = uuid.replace(/-/g, ''); */

    uuid = '0x' + uuid.replace(/-/g, '');
/*替换91行         extraData: ''*/

        extraData: '0x0'
/*替换118行         extraData: ''*/

        extraData: '0x0'

替换 web3sync.js

cd /root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

const uuidv4 = require('uuid/v4');
const utils = require('./utils');
const Transaction = require('./transactionObject').Transaction;

/**
 * Generate a random number via UUID
 * @return {Number} random number
 */
function genRandomID() {
    let uuid = uuidv4();
    uuid = '0x' + uuid.replace(/-/g, '');

    return uuid;
}

/**
 * Sign a transaction with private key and callback
 * @param {String} txData transaction data
 * @param {Buffer} privKey private key
 * @param {callback} callback callback function
 * @return {String} signed transaction data
 */
function signTransaction(txData, privKey, callback) {
    let tx = new Transaction(txData);
    let privateKey = Buffer.from(privKey, 'hex');
    tx.sign(privateKey);

    // Build a serialized hex version of the tx
    let serializedTx = '0x' + tx.serialize().toString('hex');
    if (callback !== null) {
        callback(serializedTx);
    } else {
        return serializedTx;
    }
}

/**
 * get transaction data
 * @param {String} func function name
 * @param {Array} params params
 * @return {String} transaction data
 */
function getTxData(func, params) {
    let r = /^\w+\((.*)\)$/g.exec(func);
    let types = [];
    if (r[1]) {
        types = r[1].split(',');
    }
    return utils.encodeTxData(func, types, params);
}

/**
 * get signed transaction data
 * @param {Number} groupId ID of the group where this transaction will be sent to
 * @param {Buffer} account user account
 * @param {Buffer} privateKey private key
 * @param {Buffer} to target address
 * @param {String} func function name
 * @param {Array} params params
 * @param {Number} blockLimit block limit
 * @return {String} signed transaction data
 */
function getSignTx(groupId, account, privateKey, to, func, params, blockLimit) {
    let txData = getTxData(func, params);

    let postdata = {
        data: txData,
        from: account,
        to: to,
        gas: 1000000,
        randomid: genRandomID(),
        blockLimit: blockLimit,
        chainId: 1,
        groupId: groupId,
        extraData: '0x0'
    };

    return signTransaction(postdata, privateKey, null);
}

/**
 * get signed deploy tx
 * @param {Number} groupId ID of the group where this transaction will be sent to
 * @param {Buffer} account user account
 * @param {Buffer} privateKey private key
 * @param {Buffer} bin contract bin
 * @param {Number} blockLimit block limit
 * @return {String} signed deploy transaction data
 */
function getSignDeployTx(groupId, account, privateKey, bin, blockLimit) {
    let txData = bin.indexOf('0x') === 0 ? bin : ('0x' + bin);

    let postdata = {
        data: txData,
        from: account,
        to: null,
        gas: 1000000,
        randomid: genRandomID(),
        blockLimit: blockLimit,
        chainId: 1,
        groupId: groupId,
        extraData: '0x0'
    };

    return signTransaction(postdata, privateKey, null);
}

module.exports.getSignDeployTx = getSignDeployTx;
module.exports.signTransaction = signTransaction;
module.exports.getSignTx = getSignTx;
module.exports.getTxData = getTxData;

-----------分割线---------------


caliper 运行错误二:

✔ Compiling /root/benchmarks/caliper-benchmarks/src/fisco-bcos/helloworld/HelloWorld.sol ...
2025.06.03-16:29:30.765 error [caliper] [installSmartContract.js] 	Failed to install smart contract helloworld, path=/root/benchmarks/caliper-benchmarks/src/fisco-bcos/helloworld/HelloWorld.sol
2025.06.03-16:29:30.766 error [caliper] [installSmartContract.js] 	Depolying error: TypeError: secp256k1.sign is not a function
2025.06.03-16:29:30.767 error [caliper] [fiscoBcos.js] 	FISCO BCOS smart contract install failed: TypeError: secp256k1.sign is not a function
    at Object.ecsign (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/utils.js:141:29)
    at Transaction.sign (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/transactionObject.js:272:23)
    at signTransaction (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/web3sync.js:42:8)
    at Object.getSignDeployTx (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/web3sync.js:121:12)
    at Object.module.exports.deploy (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/fiscoBcosApi.js:165:27)
2025.06.03-16:29:30.768 error [caliper] [caliper-flow] 	Error: TypeError: secp256k1.sign is not a function
    at Object.ecsign (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/utils.js:141:29)
    at Transaction.sign (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/transactionObject.js:272:23)
    at signTransaction (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/web3sync.js:42:8)
    at Object.getSignDeployTx (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/web3lib/web3sync.js:121:12)
    at Object.module.exports.deploy (/root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos/lib/fiscoBcosApi.js:165:27)

相应开发者原话:

这是一个愚蠢的bug,指定secp256k1依赖包时版本限制没写对,导致在绑定时自动安装了4.0版本的secp256k1包,但是最新的4.0的包API全部变了,导致执行出错。

有一个临时的解决方案,进入node_modules/@hyperledger/caliper-fisco-bcos目录,编辑该目录下的package.json文件,在"dependencies"中添加一项"secp256k1": “^3.8.0”,随后在该目录下执行npm i,更新完成后测试程序就能启动了。

cd /root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos

 替换或者修改

/*34行添加 */

"secp256k1": "^3.8.0"
gedit package.json
{
    "name": "@hyperledger/caliper-fisco-bcos",
    "version": "0.2.0",
    "description": "FISCO BCOS adaptor for Caliper, enabling the running of a performance benchmarks that interact with FISCO BCOS",
    "repository": {
        "type": "git",
        "url": "https://github.com/hyperledger/caliper",
        "directory": "packages/caliper-fisco-bcos"
    },
    "scripts": {
        "pretest": "npm run licchk",
        "licchk": "license-check-and-add",
        "test": "npm run lint",
        "lint": "npx eslint .",
        "nyc": "nyc mocha --recursive -t 10000"
    },
    "engines": {
        "node": ">=8.10.0",
        "npm": ">=5.6.0"
    },
    "dependencies": {
        "@hyperledger/caliper-core": "0.2.0",
        "nconf": "^0.10.0",
        "isarray": "^2.0.4",
        "fs-extra": "^8.0.1",
        "bn.js": "^4.11.8",
        "ethereumjs-util": "^6.1.0",
        "crypto-js": "^3.1.9-1",
        "ora": "^1.2.0",
        "uuid": "^3.3.2",
        "tls": "^0.0.1",
        "chalk": "^1.1.3",
        "request-promise": "^4.2.1",
	"secp256k1": "^3.8.0"
    },
    "devDependencies": {
        "web3": "0.20.7",
        "license-check-and-add": "2.3.6"
    },
    "license-check-and-add-config": {
        "folder": ".",
        "license": "../../LICENSE.txt",
        "exact_paths_method": "EXCLUDE",
        "exact_paths": [
            "node_modules",
            ".nyc_output",
            "coverage",
            ".gitignore",
            "log"
        ],
        "file_type_method": "EXCLUDE",
        "file_types": [
            ".yml",
            ".log"
        ],
        "insert_license": false,
        "license_formats": {
            "js": {
                "prepend": "/*",
                "append": "*/",
                "eachLine": {
                    "prepend": "* "
                }
            },
            "editorconfig": {
                "prepend": "#",
                "append": "#",
                "eachLine": {
                    "prepend": "# "
                }
            }
        }
    },
    "nyc": {
        "exclude": [
            "lib/**"
        ],
        "reporter": [
            "text-summary",
            "html"
        ],
        "all": true,
        "check-coverage": false,
        "statements": 5,
        "branches": 8,
        "functions": 7,
        "lines": 5
    },
    "license": "Apache-2.0"
}

 之后执行下载命令

cd /root/benchmarks/node_modules/@hyperledger/caliper-fisco-bcos && npm i
cd /root/benchmarks/node_modules/@hyperledger && npm i

执行Solidity版转账合约测试

cd /root/benchmarks/caliper-benchmarks
npx caliper benchmark run --caliper-benchconfig benchmarks/samples/fisco-bcos/transfer/solidity/config.yaml  --caliper-networkconfig networks/fisco-bcos/4nodes1group/fisco-bcos.json

执行预编译版转账合约测试 

cd /root/benchmarks/caliper-benchmarks
npx caliper benchmark run --caliper-benchconfig benchmarks/samples/fisco-bcos/transfer/precompiled/config.yaml  --caliper-networkconfig networks/fisco-bcos/4nodes1group/fisco-bcos.json

测试完成后,会在命令行界面中展示测试结果(TPS、延迟等)及资源消耗情况,同时会在caliper-benchmarks目录下生成一份包含上述内容的可视化HTML报告。

caliper benchmark run所需的各项参数可以通过如下命令查看:

root@admin:~/benchmarks$ npx caliper benchmark run --help
caliper benchmark run --caliper-workspace ~/myCaliperProject --caliper-benchconfig my-app-test-config.yaml --caliper-networkconfig my-sut-config.yaml

Options:
  --help                   Show help  [boolean]
  -v, --version            Show version number  [boolean]
  --caliper-benchconfig    Path to the benchmark workload file that describes the test client(s), test rounds and monitor.  [string]
  --caliper-networkconfig  Path to the blockchain configuration file that contains information required to interact with the SUT  [string]
  --caliper-workspace      Workspace directory that contains all configuration information  [string]

其中,

–caliper-workspace:用于指定caliper-cli的工作目录,如果没有绑定工作目录,可以通过该选项动态指定工作目录;

–caliper-benchconfig:用于指定测试配置文件,测试配置文件中包含测试的具体参数,如交易的发送方式、发送速率控制器类型、性能监视器类型等;

–caliper-networkconfig:用于指定网络配置文件,网络配置文件中会指定Caliper与受测系统的连接方式及要部署测试的合约等。

自定义测试用例


本节将会以测试HelloWorld合约为例,介绍如何使用Caliper测试自定义的测试用例。

Caliper前后端分离的设计原则使得只要后端的区块链系统开放了相关网络端口,Caliper便可以对该系统进行测试。

网络配置


使用已有的链对HelloWorld合约测试(webase-deploy)


前提条件:需要先启动webase-deploy,使用webase-deploy的链进行测试。

cd /fisco/webase-deploy/
python3 deploy.py startAll

新建一个名为test-nw的目录,本阶示例中的FISCO BCOS适配器的网络配置文件均会放置于此。新建一个名为fisco-bcos.json的配置文件,文件内容如下:

{
    "caliper": {
        "blockchain": "fisco-bcos"
    },
    "fisco-bcos": {
        "config": {
            "privateKey": "bcec428d5205abe0f0cc8a734083908d9eb8563e31f943d760786edf42ad67dd",
            "account": "0x64fa644d2a694681bd6addd6c5e36cccd8dcdde3"
        },
        "network": {
            "nodes": [
                {
                    "ip": "127.0.0.1",
                    "rpcPort": "8545",
                    "channelPort": "20200"
                },
                {
                    "ip": "127.0.0.1",
                    "rpcPort": "8546",
                    "channelPort": "20201"
                }
            ],
            "authentication": {
                "key": "/fisco/webase-deploy/nodes/127.0.0.1/sdk/node.key",
                "cert": "/fisco/webase-deploy/nodes/127.0.0.1/sdk/node.crt",
                "ca": "/fisco/webase-deploy/nodes/127.0.0.1/sdk/ca.crt"
            },
            "groupID": 1,
            "timeout": 100000
        },
        "smartContracts": [
            {
                "id": "helloworld",
                "path": "src/fisco-bcos/helloworld/HelloWorld.sol",
                "language": "solidity",
                "version": "v0"
            },
            {
                "id": "parallelok",
                "path": "src/fisco-bcos/transfer/ParallelOk.sol",
                "language": "solidity",
                "version": "v0"
            },
            {
                "id": "dagtransfer",
                "address": "0x0000000000000000000000000000000000005002",
                "language": "precompiled",
                "version": "v0"
            }
        ]
    },
    "info": {
        "Version": "2.0.0",
        "Size": "4 Nodes",
        "Distribution": "Single Host"
    }
}

 验证一下 

cd /root/benchmarks/caliper-benchmarks
npx caliper benchmark run --caliper-benchconfig benchmarks/samples/fisco-bcos/helloworld/config.yaml  --caliper-networkconfig networks/fisco-bcos/test-nw/fisco-bcos.json

使用已有的链对HelloWorld合约测试(四节点,单机构,单群组)

前提条件:需要先启动联盟链,使用联盟链进行测试。

cd /root/tools/
bash build_chain.sh -l 127.0.0.1:4 -p 30300,20200,8545 -e ./fisco-bcos -v 2.8.0
bash nodes/127.0.0.1/start_all.sh

新建一个名为test-nw的目录,本阶示例中的FISCO BCOS适配器的网络配置文件均会放置于此。新建一个名为fisco-bcos.json的配置文件,文件内容如下:

{
    "caliper": {
        "blockchain": "fisco-bcos"
    },
    "fisco-bcos": {
        "config": {
            "privateKey": "bcec428d5205abe0f0cc8a734083908d9eb8563e31f943d760786edf42ad67dd",
            "account": "0x0ff8981ebc130c7874ac7093a4d0c0e3d4f36b08"
        },
        "network": {
            "nodes": [
                {
                    "ip": "127.0.0.1",
                    "rpcPort": "8545",
                    "channelPort": "20200"
                },
                {
                    "ip": "127.0.0.1",
                    "rpcPort": "8546",
                    "channelPort": "20201"
                },
                {
                    "ip": "127.0.0.1",
                    "rpcPort": "8547",
                    "channelPort": "20202"
                },
                {
                    "ip": "127.0.0.1",
                    "rpcPort": "8548",
                    "channelPort": "20203"
                }
            ],
            "authentication": {
                "key": "/root/tools/nodes/127.0.0.1/sdk/sdk.key",
                "cert": "/root/tools/nodes/127.0.0.1/sdk/sdk.crt",
                "ca": "/root/tools/nodes/127.0.0.1/sdk/ca.crt"
            },
            "groupID": 1,
            "timeout": 100000
        },
        "smartContracts": [
            {
                "id": "helloworld",
                "path": "src/fisco-bcos/helloworld/HelloWorld.sol",
                "language": "solidity",
                "version": "v0"
            }
	]
    },
    "info": {
        "Version": "2.0.0",
        "Size": "4 Nodes",
        "Distribution": "Single Host"
    }
}
   }
        ]
    },
    "info": {
        "Version": "2.0.0",
        "Size": "4 Nodes",
        "Distribution": "Single Host"
    }
}

 验证一下

cd /root/benchmarks/caliper-benchmarks
npx caliper benchmark run --caliper-benchconfig benchmarks/samples/fisco-bcos/helloworld/config.yaml  --caliper-networkconfig networks/fisco-bcos/test-nw/fisco-bcos.json

使用已有的链对HelloWorld合约测试(四节点,四机构,单群组)

前提条件:需要先启动联盟链,使用联盟链进行测试。

cd /root/tools/

vim ipconf
127.0.0.1 agencyA 1
127.0.0.1 agencyB 1
127.0.0.1 agencyC 1
127.0.0.1 agencyD 1
bash build_chain.sh -f ipconf -e ./fisco-bcos
bash nodes/127.0.0.1/start_all.sh

新建一个名为test-nw的目录,本阶示例中的FISCO BCOS适配器的网络配置文件均会放置于此。新建一个名为fisco-bcos.json的配置文件,文件内容如下:

{
    "caliper": {
        "blockchain": "fisco-bcos"
    },
    "fisco-bcos": {
        "config": {
            "privateKey": "bcec428d5205abe0f0cc8a734083908d9eb8563e31f943d760786edf42ad67dd",
            "account": "0x0ff8981ebc130c7874ac7093a4d0c0e3d4f36b08"
        },
        "network": {
            "nodes": [
                {
                    "ip": "127.0.0.1",
                    "rpcPort": "8545",
                    "channelPort": "20200"
                }
            ],
            "authentication": {
                "key": "/root/tools/nodes/127.0.0.1/node0/conf/node.key",
                "cert": "/root/tools/nodes/127.0.0.1/node0/conf/node.crt",
                "ca": "/root/tools/nodes/127.0.0.1/node0/conf/ca.crt"
            },
            "groupID": 1,
            "timeout": 100000
        },
        "smartContracts": [
            {
                "id": "helloworld",
                "path": "src/fisco-bcos/helloworld/HelloWorld.sol",
                "language": "solidity",
                "version": "v0"
            }
	]
    },
    "info": {
        "Version": "2.0.0",
        "Size": "4 Nodes",
        "Distribution": "Single Host"
    }
}

验证一下

cd /root/benchmarks/caliper-benchmarks

npx caliper benchmark run --caliper-benchconfig benchmarks/samples/fisco-bcos/helloworld/config.yaml  --caliper-networkconfig networks/fisco-bcos/test-nw/fisco-bcos.json

测试配置

测试配置用于指定测试的具体运行方式。测试配置是一个YAML文件,HelloWorld合约的测试配置文件内容如下所示:

---
test:
  name: Hello World
  description: This is a helloworld benchmark of FISCO BCOS for caliper
  clients:
    type: local
    number: 1
  rounds:
  - label: get
    description: Test performance of getting name
    txNumber:
    - 100
    rateControl:
    - type: fixed-rate
      opts:
        tps: 1000
    callback: benchmarks/samples/fisco-bcos/helloworld/get.js
  - label: set
    description: Test performance of setting name
    txNumber:
    - 100
    rateControl:
    - type: fixed-rate
      opts:
        tps: 1000
    callback: benchmarks/samples/fisco-bcos/helloworld/set.js
monitor:
  type:
  - docker
  - process
  docker:
    name:
    - node0
    - node1
    - node2
    - node3
  process:
    - command: node
      arguments: fiscoBcosClientWorker.js
      multiOutput: avg
  interval: 0.5

测试文件中主要包括两部分:

测试内容配置


test项负责对测试内容进行配置。配置主要集中在round字段中指定如何对区块链系统进行测试。每一个测试可以包含多轮,每一轮可以向区块链发起不同的测试请求。具体要HelloWorld合约测试,测试中包含两轮,分别对合约的get接口和set接口进行测试。在每一轮测试中,可以通过txNumber或txDuration字段指定测试的交易发送数量或执行时间,并通过rateControl字段指定交易发送时的速率控制器,在本节的示例中,使用了QPS为1000的匀速控制器,更多速率控制器的介绍可以参考官方文档。

性能监视器配置


如果是在本地搭好的链,则可以添加本地性能监视器,相应地监视器的配置更改如下:

monitor:
  type:
  - process
  process:
    - command: node0
      multiOutput: avg
    - command: node1
      multiOutput: avg
    - command: node2
      multiOutput: avg
    - command: node3
      multiOutput: avg
  interval: 0.1

其中每项配置项的解释如下:

1、monitor.type,需要指定为process,只对进程进行监控;

2、monitor.process,一个包含所有要监视的进称列表,其中每个进程的command属性为一个正则表达式,表示进程名称;每个进程还可以有一个arguments属性(未在上述示例中使用到),表示进程的参数。Caliper会先使用ps命令搜索commad + arguments,然后匹配以得到目标的进程的进程ID及系统资源的使用情况。每个进程的multiOutput属性用于指定结果的输出方式,目前支持平均值(avg)及总和(sum)两种方式;

3、monitor.interval,监视器的采样间隔,单位为秒。

需要注意的是,进程监控目前暂不支持监控进程对网络和磁盘的使用情况。

 

 

参考文献:

这一篇fabric写的真的没毛病,看得出来作者整合了很多内容

Hyperledger Fabric 2.4.9 环境搭建和 Caliper 0.5.0 测试工具部署教程(Ubuntu)_hyperledger fabric 部署-CSDN博客

这一篇是FSICOBCOS

fisco bcos Caliper部署完整教程(报错解析+自定义测试)_caliper安装-CSDN博客

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

向键雄Alvin

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

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

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

打赏作者

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

抵扣说明:

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

余额充值