Caliper安装与使用

环境安装

1
2
3
yum install nodejs
npm install n
n 8.9.0

一. 安装绑定Caliper

全局安装Cliper Cli

1
npm install -g --only=prod @hyperledger/caliper-cli@0.3.2

绑定SDK

1
caliper bind --caliper-bind-sut fabric:1.4.8 --caliper-bind-args=-g

二. 创建文件夹

Caliper需要两个配置文件

  • 网络配置文件: 描述网络并提供连接要求
  • 基准文件: 包含回调和用户测试文件引用

首先创建caliper-workspace父文件夹,然后在该文件夹下创建networksbenchmarks两个子文件夹。

三. 网络配置文件

网络配置文件是通用连接配置文件的扩展,并为与网络交互的客户端提供了连接要求。该文件可以是YAML或JSON格式,本教程显示JSON格式。

创建文件

network文件夹下创建network_config.json文件,该文件包含8个部分如下面初始文件所示,后续教程将会逐步补充完整。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"caliper" : {
},
"clients" : {
},
"channels" : {
},
"name": {
},
"organization" : {
},
"peers" : {
},
"certificateAuthorities" : {
},
"version" : {
}
}

查找并复制模板

first-sample->first-network->connection-org1.json
将该文件所有内容复制到network_config.json文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
{
"name": "first-network-org1",
"version": "1.0.0",
"client": {
"organization": "Org1",
"connection": {
"timeout": {
"peer": {
"endorser": "300"
}
}
}
},
"organizations": {
"Org1": {
"mspid": "Org1MSP",
"peers": [
"peer0.org1.example.com",
"peer1.org1.example.com"
],
"certificateAuthorities": [
"ca.org1.example.com"
]
}
},
"peers": {
"peer0.org1.example.com": {
"url": "grpcs://localhost:7051",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\nMIICVzCCAf2gAwIBAgIQJ4YZaoAxgNFIlMKJnCK8YzAKBggqhkjOPQQDAjB2MQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEfMB0GA1UEAxMWdGxz\nY2Eub3JnMS5leGFtcGxlLmNvbTAeFw0yMDA5MjQxMzE0MDBaFw0zMDA5MjIxMzE0\nMDBaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH\nEw1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMR8wHQYD\nVQQDExZ0bHNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D\nAQcDQgAEMJdNsNECYe4vnAX1HLFVOlcigcDvW00+pmjxdfpfZZ530ESzzYCOlruO\n9iV/BYcrWMC8ZFv1HYPWH4Z7bkiJ16NtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1Ud\nJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1Ud\nDgQiBCAbL0P+tBNB1AA0/7T7SDBFjlrg3n+7Boc+y0kk5/EJRTAKBggqhkjOPQQD\nAgNIADBFAiEAz+K66R5mn31xPcjcWSDmnhA8DmC//K7j9hy3tpnNar4CIFqvxAqx\nvEzHuvlsU99KGUhPgpfWjgPDS4NppK/zxZse\n-----END CERTIFICATE-----\n"
},
"grpcOptions": {
"ssl-target-name-override": "peer0.org1.example.com",
"hostnameOverride": "peer0.org1.example.com"
}
},
"peer1.org1.example.com": {
"url": "grpcs://localhost:8051",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\nMIICVzCCAf2gAwIBAgIQJ4YZaoAxgNFIlMKJnCK8YzAKBggqhkjOPQQDAjB2MQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEfMB0GA1UEAxMWdGxz\nY2Eub3JnMS5leGFtcGxlLmNvbTAeFw0yMDA5MjQxMzE0MDBaFw0zMDA5MjIxMzE0\nMDBaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH\nEw1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMR8wHQYD\nVQQDExZ0bHNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D\nAQcDQgAEMJdNsNECYe4vnAX1HLFVOlcigcDvW00+pmjxdfpfZZ530ESzzYCOlruO\n9iV/BYcrWMC8ZFv1HYPWH4Z7bkiJ16NtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1Ud\nJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1Ud\nDgQiBCAbL0P+tBNB1AA0/7T7SDBFjlrg3n+7Boc+y0kk5/EJRTAKBggqhkjOPQQD\nAgNIADBFAiEAz+K66R5mn31xPcjcWSDmnhA8DmC//K7j9hy3tpnNar4CIFqvxAqx\nvEzHuvlsU99KGUhPgpfWjgPDS4NppK/zxZse\n-----END CERTIFICATE-----\n"
},
"grpcOptions": {
"ssl-target-name-override": "peer1.org1.example.com",
"hostnameOverride": "peer1.org1.example.com"
}
}
},
"certificateAuthorities": {
"ca.org1.example.com": {
"url": "https://localhost:7054",
"caName": "ca-org1",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\nMIICUDCCAfegAwIBAgIQdgnCSGhuhWkNbc6249Ml3zAKBggqhkjOPQQDAjBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMS5leGFtcGxlLmNvbTAeFw0yMDA5MjQxMzE0MDBaFw0zMDA5MjIxMzE0MDBa\nMHMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMRwwGgYDVQQD\nExNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\na0TCdMmVSOzjTWNimrNe9o22cy5obbyJortbkdZPp663SEX7ZIbb7xD1PrSVOIlV\nlHrxc/NJ+rNzCDE37mWT8KNtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1UdJQQWMBQG\nCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdDgQiBCD6\n2/MOGvcQQO6GCyg7fe4x1I3Oqx3TsobGO4PfqjWHwzAKBggqhkjOPQQDAgNHADBE\nAiAysfOd2AL5pkuJutsG02DHNxCjotuBvj1JyH7shfbMUAIgF++Ya9o5uu1QuzD+\n4llvZ+y1mznyLgXjD4H+bwcRaiw=\n-----END CERTIFICATE-----\n"
},
"httpOptions": {
"verify": false
}
}
}
}

Caliper对象
表示被测试的分布式账本。在文件中添加Caliper对象,该对象包含一个blockchain属性,值为fabric

1
2
3
"caliper": {
"blockchain": "fabric"
},

Client对象

将Clients对象添加到文件中,并添加以网络中的一个标识命名的属性。在该示例中,使用的身份为Admin@org1.example.com。然后将现有Client对象嵌套在标识中。

1
2
3
4
5
6
7
8
9
10
11
12
13
"clients": {
"Admin@org1.example.com": {
"client": {
"connection": {
"timeout": {
"peer": {
"endorser": "300"
}
}
}
}
}
},

在client对象中添加credentialStore属性,在该属性下添加path属性,对应值为指向工作空间中的临时文件的路径
tmp/hfc-kvs/org1。同时,仍然是在credentialStore属性下,添加cryptoStore 属性,在添加的属性下再添加一个path属性执行上述相同的文件,即tmp/hfc-kvs/org1。添加到client的内容如下:

1
2
3
4
5
6
"credentialStore": {
"path": "tmp/hfc-kvs/org1",
"cryptoStore": {
"path": "tmp/hfc-kvs/org1"
}
},

在client对象下添加属性clientPrivateKey ,该属性下包含path属性,对应值指向身份标识私钥
fabric-samples->first-network->crypto-config->peerOrganizations->org1.example.com->users->Admin@org1.example.com->msp->keystore->priv_sk

1
2
3
"clientPrivateKey": {
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/c1967b006168083cade9ddf79932d924a3fa59698b6a5b0e1dc6c087bc79f9a3_sk"
},

仍然是在client对象下添加属性clientSignedCert,该属性下包含path属性,对应值指向身份签名证书。
fabric-samples->first-network->crypto-config->peerOrganizations->org1.example.com->users->Admin@org1.example.com->msp-> signedcerts -> admin@org1.example.com-cert.pem

1
2
3
"clientSignedCert":{
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"
},

client对象所需要添加的所有属性,最终如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"clients": {
"Admin@org1.example.com": {
"client": {
"credentialStore": {
"path": "tmp/hfc-kvs/org1",
"cryptoStore": {
"path": "tmp/hfc-kvs/org1"
}
},
"organization": "Org1",
"clientPrivateKey": {
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/c1967b006168083cade9ddf79932d924a3fa59698b6a5b0e1dc6c087bc79f9a3_sk"
},
"clientSignedCert":{
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"
},
"connection": {
"timeout": {
"peer": {
"endorser": "300"
}
}
}
}
}
},

channel对象

在文件中添加一个channels对象,并在channel之后添加一个名称属性。默认频道名称(本教程中使用的名称)为mychannel。根据频道名称,添加两个属性,分别为created和chaincodes。
设置created为布尔变量true

1
"created":true,

chaincodes作为一个数组,带有两个属性,分别为id和version,id代表的是链码id,在本次例子中为mycc,version指明链码版本,在本次例子中为1.0

1
2
3
4
5
6
"chaincodes": [
{
"id":"mycc",
"version":"1.0"
}
]

最终channels对象如下所示:

1
2
3
4
5
6
7
8
9
10
11
"channels": {
"mychannel": {
"created" : true,
"chaincodes": [
{
"id":"mycc",
"version":"1.0"
}
]
}
},

Organizations 对象

在Organizations 对象中的Org1中添加两个属性:

  • adminPrivateKey :管理员用户私钥路径
  • signedCert :管理员用户签名证书

在本次示例中使用的身份是管理员用户,所以对应路径与上述client对象相同。如果使用不同的身份,对应管理员用户密钥和证书可以在以下路径中查找:
fabric-samples->first-network->crypto-config->peerOrganizations->org1.example.com->users->Admin@org1.example.com->msp

下面内容应该添加到org1中:

1
2
3
4
5
6
"adminPrivateKey": {
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/c1967b006168083cade9ddf79932d924a3fa59698b6a5b0e1dc6c087bc79f9a3_sk"
},
"signedCert": {
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"
}

Organizations对象最后应该包括以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"organizations":{
"Org1": {
"mspid": "Org1MSP",
"peers": [
"peer0.org1.example.com",
"peer1.org1.example.com"
],
"certificateAuthorities": [
"ca.org1.example.com"
],
"adminPrivateKey": {
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/c1967b006168083cade9ddf79932d924a3fa59698b6a5b0e1dc6c087bc79f9a3_sk"
},
"signedCert": {
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"
}
}
},

网络配置文件
最终网络配置文件在补充完整之后,需要仔细确认确保对应密钥和证书的路径是否正确,整个完整文件如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
{
"caliper": {
"blockchain": "fabric"
},
"clients": {
"Admin@org1.example.com": {
"client": {
"credentialStore": {
"path": "tmp/hfc-kvs/org1",
"cryptoStore": {
"path": "tmp/hfc-kvs/org1"
}
},
"organization": "Org1",
"clientPrivateKey": {
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/c1967b006168083cade9ddf79932d924a3fa59698b6a5b0e1dc6c087bc79f9a3_sk"
},
"clientSignedCert":{
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"
},
"connection": {
"timeout": {
"peer": {
"endorser": "300"
}
}
}
}
}
},
"channels": {
"mychannel": {
"created" : true,
"chaincodes": [
{
"id":"mycc",
"version":"1.0"
}
]
}
},
"name": "test-network-org1",
"organizations":{
"Org1": {
"mspid": "Org1MSP",
"peers": [
"peer0.org1.example.com",
"peer1.org1.example.com"
],
"certificateAuthorities": [
"ca.org1.example.com"
],
"adminPrivateKey": {
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/c1967b006168083cade9ddf79932d924a3fa59698b6a5b0e1dc6c087bc79f9a3_sk"
},
"signedCert": {
"path": "../fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"
}
}
},
"peers": {
"peer0.org1.example.com": {
"url": "grpcs://localhost:7051",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\nMIICVzCCAf2gAwIBAgIQJ4YZaoAxgNFIlMKJnCK8YzAKBggqhkjOPQQDAjB2MQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEfMB0GA1UEAxMWdGxz\nY2Eub3JnMS5leGFtcGxlLmNvbTAeFw0yMDA5MjQxMzE0MDBaFw0zMDA5MjIxMzE0\nMDBaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH\nEw1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMR8wHQYD\nVQQDExZ0bHNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D\nAQcDQgAEMJdNsNECYe4vnAX1HLFVOlcigcDvW00+pmjxdfpfZZ530ESzzYCOlruO\n9iV/BYcrWMC8ZFv1HYPWH4Z7bkiJ16NtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1Ud\nJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1Ud\nDgQiBCAbL0P+tBNB1AA0/7T7SDBFjlrg3n+7Boc+y0kk5/EJRTAKBggqhkjOPQQD\nAgNIADBFAiEAz+K66R5mn31xPcjcWSDmnhA8DmC//K7j9hy3tpnNar4CIFqvxAqx\nvEzHuvlsU99KGUhPgpfWjgPDS4NppK/zxZse\n-----END CERTIFICATE-----\n"
},
"grpcOptions": {
"ssl-target-name-override": "peer0.org1.example.com",
"hostnameOverride": "peer0.org1.example.com"
}
},
"peer1.org1.example.com": {
"url": "grpcs://localhost:8051",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\nMIICVzCCAf2gAwIBAgIQJ4YZaoAxgNFIlMKJnCK8YzAKBggqhkjOPQQDAjB2MQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEfMB0GA1UEAxMWdGxz\nY2Eub3JnMS5leGFtcGxlLmNvbTAeFw0yMDA5MjQxMzE0MDBaFw0zMDA5MjIxMzE0\nMDBaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH\nEw1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMR8wHQYD\nVQQDExZ0bHNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D\nAQcDQgAEMJdNsNECYe4vnAX1HLFVOlcigcDvW00+pmjxdfpfZZ530ESzzYCOlruO\n9iV/BYcrWMC8ZFv1HYPWH4Z7bkiJ16NtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1Ud\nJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1Ud\nDgQiBCAbL0P+tBNB1AA0/7T7SDBFjlrg3n+7Boc+y0kk5/EJRTAKBggqhkjOPQQD\nAgNIADBFAiEAz+K66R5mn31xPcjcWSDmnhA8DmC//K7j9hy3tpnNar4CIFqvxAqx\nvEzHuvlsU99KGUhPgpfWjgPDS4NppK/zxZse\n-----END CERTIFICATE-----\n"
},
"grpcOptions": {
"ssl-target-name-override": "peer1.org1.example.com",
"hostnameOverride": "peer1.org1.example.com"
}
}
},
"certificateAuthorities": {
"ca.org1.example.com": {
"url": "https://localhost:7054",
"caName": "ca-org1",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\nMIICUDCCAfegAwIBAgIQdgnCSGhuhWkNbc6249Ml3zAKBggqhkjOPQQDAjBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMS5leGFtcGxlLmNvbTAeFw0yMDA5MjQxMzE0MDBaFw0zMDA5MjIxMzE0MDBa\nMHMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMRwwGgYDVQQD\nExNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\na0TCdMmVSOzjTWNimrNe9o22cy5obbyJortbkdZPp663SEX7ZIbb7xD1PrSVOIlV\nlHrxc/NJ+rNzCDE37mWT8KNtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1UdJQQWMBQG\nCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdDgQiBCD6\n2/MOGvcQQO6GCyg7fe4x1I3Oqx3TsobGO4PfqjWHwzAKBggqhkjOPQQDAgNHADBE\nAiAysfOd2AL5pkuJutsG02DHNxCjotuBvj1JyH7shfbMUAIgF++Ya9o5uu1QuzD+\n4llvZ+y1mznyLgXjD4H+bwcRaiw=\n-----END CERTIFICATE-----\n"
},
"httpOptions": {
"verify": false
}
}
}
}

四. 测试回调文件

测试回调文件与部署的智能合约在基准测试期间交互,每个测试回调函数必须包含3个函数:

  • init - 用于初始化账本以运行会话
  • run - 在基准测试监控阶段用于与智能合约进行交互
  • end - 在run阶段完成之后结束并清理。

创建文件

benchmarks文件夹中创建callbacks子文件夹,在该文件夹中创建文件query.js,后面将对该文件进行补充。

由于本次部署链码为 chaincode_example02 ,可在fabric-samples->chaincode->chaincode_example02中查找

文件设置

Caliper使用以下两个方法与部署的智能合约进行交互:

invokeSmartContract (ctx, contractId, contractVersion, args)
querySmartContract (ctx, contractId, contractVersion, args)

其中:

  • ctx 指用户上下文
  • contractId 为智能合约名称,本示例中为mycc
  • contractVersion 为智能合约版本,本示例中为1.0
  • args 为一个对象,主要包括
    • chaincodeFunction 调用的智能合约函数名称
    • invokerIdentity 调用函数时的用户身份,本示例中为 Admin@org1.example.com
    • chaincodeArguments 函数调用时传递给函数的参数列表

下面是文件基本模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
'use strict';

module.exports.info = 'Template callback';

const contractID = 'mycc';
const version = '1.0';

let bc, ctx, clientArgs, clientIdx;

module.exports.init = async function(blockchain, context, args) {
};

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

module.exports.end = async function() {
};

Init 函数

初始化传递run函数中需要使用到的内容,参数。

本示例中,通过等待invokeSmartContract调用完成。通过区块链对象将上下文,合约名称,合约版本以及包含以下内容的对象:chaincodeFunction设置为query; invokeIdentity设为admin@org.example.com; chaincodeArguments设置为包含的数组a,需要将参数传递给query。

该函数应如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports.init = async function(blockchain, context, args) {
bc = blockchain;
ctx = context;
clientArgs = args;
clientIdx = context.clientIdx.toString();
try {
const myArgs = {
chaincodeFunction: 'query',
invokerIdentity: 'Admin@org1.example.com',
chaincodeArguments: ['a']
};
return bc.bcObj.querySmartContract(ctx, contractID, version, myArgs);
} catch (error) {
console.log(`Smart Contract threw with error: ${error}` );
}
};

Run 函数

本次只测试query函数,所以函数内容与Init函数相同

1
2
3
4
5
6
7
8
module.exports.run = async function() {
const myArgs = {
chaincodeFunction: 'query',
invokerIdentity: 'Admin@org1.example.com'',
chaincodeArguments: ['a']
};
return bc.bcObj.invokeSmartContract(ctx, contractID, version, myArgs);
};

End 函数

此功能用于在测试后清除,因为它会删除该init功能中创建的数据。
如果测试的智能合约没有删除功能,则不使用此功能,此功能将保持为空。

1
2
module.exports.end = async function() {
};

最终文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
'use strict';

module.exports.info = 'Template callback';

const contractID = 'mycc';
const version = '1.0';

let bc, ctx, clientArgs, clientIdx;

module.exports.init = async function(blockchain, context, args) {
bc = blockchain;
ctx = context;
clientArgs = args;
clientIdx = context.clientIdx.toString();
try {
const myArgs = {
chaincodeFunction: 'query',
invokerIdentity: 'Admin@org1.example.com',
chaincodeArguments: ['a']
};
return bc.bcObj.querySmartContract(ctx, contractID, version, myArgs);
} catch (error) {
console.log(`Smart Contract threw with error: ${error}` );
}
};

module.exports.run = async function() {
const myArgs = {
chaincodeFunction: 'query',
invokerIdentity: 'Admin@org1.example.com',
chaincodeArguments: ['a']
};
return bc.bcObj.invokeSmartContract(ctx, contractID, version, myArgs);
};

module.exports.end = async function() {
};

五. 基准配置文件

基准测试配置文件定义基准测试轮数并引用已定义的回调。它将指定生成负载时要使用的测试客户端的数量,测试的轮数,每一轮的持续时间,每一轮中的负载生成方法以及每一轮中要使用的回调。

该文件是YAML文件。YAML文件区分大小写,所有标签均小写。

该文件将具有三个需要填充的根块。如下所示:

1
2
3
4
5
test:

monitor:

observer:

创建文件

benchmarks文件夹下创建一个myAssetBenchmark.yaml文件,后续进行补充。

test

首先添加一个名为test的根块。在此块中添加:

  • name:对应值为my-asset-benchmark
  • description :带有简短描述作为值的键,在此示例中为test benchmark
  • workers具有以下键和值:
    • type: local
    • number: 2

到目前为止看起来应该像这样:

还添加一个名为rounds的块。该块包含每个测试回合,每个回合均以唯一的回合标签为首。回合可用于基准化不同的智能合约方法或以不同的方式对同一方法进行基准测试。

该round块包含以下内容:

  • label -用于回合的唯一标头标签。
  • description -对正在运行的回合的描述。
  • chaincodeId -正在测试的链码ID。
  • txDuration -通过持续时间长度。
  • rateControl -带有选项和类型的速率控制方法。
  • callback -被测试的回调文件的路径,在这种情况下,这是queryAssetBenchmark.js文件。
  • arguments -调用时将传递给回调文件的可选参数数组。

示例如下所示:

1
2
3
4
5
6
7
8
9
10
rounds:
- label: open
description: Query benchmark
chaincodeId: mycc
txDuration: 30
rateControl:
type: fixed-backlog
opts:
unfinished_per_client: 2
callback: benchmarks/callbacks/query.js

monitor

添加名为monitor的根块,其中单个键type的值为none, 因为在本次测试中不进行任何资源监控

示例如下:

1
2
3
monitor:
type:
- none

observer

添加名为observer的根块,其中包含两个键typeinterval,对应的值设置为local5,代表着使用本地统计信息每五秒钟观察一次测试进度。

示例如下:

1
2
3
observer:
type: local
interval: 5

最终文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
test:
name: simple
description: This is an example benchmark for caliper, to test the backend DLT's performance with simple account opening & querying transactions
workers:
type: local
number: 2
rounds:
- label: open
description: Query benchmark
chaincodeId: mycc
txDuration: 30
rateControl:
type: fixed-backlog
opts:
unfinished_per_client: 2
callback: benchmarks/callbacks/query.js

monitor:
type:
- none

observer:
type: local
interval: 5

六. 运行并获取结果

使用上述步骤准备的材料使用Caliper Cli运行性能测试,设置网络配置文件,测试配置文件以及工作空间的路径。如下所示

  • caliper-networkconfig: networks/network_config.json
  • caliper-benchconfig: benchmarks/myAssetBenchmark.yaml
  • caliper-workspace: ./

因为已经安装且实例化链码,因此Caliper唯一需要的操作就是在测试阶段使用启用了发现功能的fabric gateway,因此需要在命令中指明以下标志:

  • caliper-flow-only-test
  • caliper-fabric-gateway-usegateway
  • caliper-fabric-gateway-discovery

运行命令

确认处于caliper-workspace目录

在终端运行以下命令:

1
caliper launch master --caliper-benchconfig benchmarks/myAssetBenchmark.yaml --caliper-networkconfig networks/network_config.json --caliper-workspace ./ --caliper-flow-only-test --caliper-fabric-gateway-usegateway --caliper-fabric-gateway-discovery

问题:

开始命令运行后出现gRPC未安装错误:
进入 /usr/local/lib/node_modules/fabric-network
执行以下命令:

1
npm rebuild

回到caliper-workspace目录,再次执行命令,结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
+------+------+------+-----------------+-----------------+-----------------+-----------------+------------------+
| Name | Succ | Fail | Send Rate (TPS) | Max Latency (s) | Min Latency (s) | Avg Latency (s) | Throughput (TPS) |
|------|------|------|-----------------|-----------------|-----------------|-----------------|------------------|
| open | 42 | 0 | 1.5 | 2.62 | 0.59 | 2.28 | 1.4 |
+------+------+------+-----------------+-----------------+-----------------+-----------------+------------------+

2020.09.26-14:10:07.479 info [caliper] [round-orchestrator] Finished round 1 (open) in 30.324 seconds
2020.09.26-14:10:07.479 info [caliper] [report-builder] ### All test results ###
2020.09.26-14:10:07.481 info [caliper] [report-builder]
+------+------+------+-----------------+-----------------+-----------------+-----------------+------------------+
| Name | Succ | Fail | Send Rate (TPS) | Max Latency (s) | Min Latency (s) | Avg Latency (s) | Throughput (TPS) |
|------|------|------|-----------------|-----------------|-----------------|-----------------|------------------|
| open | 42 | 0 | 1.5 | 2.62 | 0.59 | 2.28 | 1.4 |
+------+------+------+-----------------+-----------------+-----------------+-----------------+------------------+


2020.09.26-14:10:07.498 info [caliper] [report-builder] Generated report with path /opt/gopath/src/github.com/hyperledger/caliper-workspace/report.html
2020.09.26-14:10:07.498 info [caliper] [monitor.js] Stopping all monitors
2020.09.26-14:10:07.499 info [caliper] [worker-orchestrator] Sending exit message to connected workers
2020.09.26-14:10:07.500 info [caliper] [message-handler] Handling "exit" message
2020.09.26-14:10:07.500 info [caliper] [message-handler] Handling "exit" message
2020.09.26-14:10:07.500 info [caliper] [message-handler] Handled "exit" message for worker 1, exiting process
2020.09.26-14:10:07.500 info [caliper] [message-handler] Handled "exit" message for worker 0, exiting process
2020.09.26-14:10:07.501 info [caliper] [round-orchestrator] Benchmark finished in 49.014 seconds. Total rounds: 1. Successful rounds: 1. Failed rounds: 0.
2020.09.26-14:10:07.501 info [caliper] [caliper-engine] Skipping end command due to benchmark flow conditioning
2020.09.26-14:10:07.501 info [caliper] [cli-launch-master] Benchmark successfully finished

在当前目录中可以看到生成一个新的report.html文件。

1
2
3
4
5
6
7
[root@localhost caliper-workspace]# ll
total 112
drwxr-xr-x. 3 root root 50 Sep 26 14:08 benchmarks
-rw-r--r--. 1 root root 103725 Sep 26 14:10 caliper.log
drwxr-xr-x. 2 root root 32 Sep 26 14:07 networks
-rw-r--r--. 1 root root 7290 Sep 26 14:10 report.html
drwxr-xr-x. 3 root root 20 Sep 26 14:00 tmp

最后更新: 2020年09月26日 15:17

原始链接: https://silence-linhl.github.io/blog/2020/09/25/caliper/

× 请我吃糖~
打赏二维码