Hyperledger Fabric2中文文档-链码部署

  • Post author:
  • Post category:其他


翻译官方文档

https://hyperledger-fabric.readthedocs.io/en/latest/deploy_chaincode.html#install-the-chaincode-package

向Channel中部署链码

终端用户通过调用智能合约与区块链账本交互,Hyperledger Fabric的智能合约被称为链代码。想要验证或查询数据的组织需要在他们的peer中安装链代码。在加入channel的peer上安装链代码后,channel成员可以调用链代码并更改账本数据。

Fabric使用lifecycle进程来部署链代码,多个组织之间使用lifecrycle来决定chaincode的部署。例如,各组织之间使用lifecrycle来讨论决定链代码采用何种背书策略。更多关于部署和操作链码的信息,可查看https://hyperledger-fabric.readthedocs.io/en/latest/chaincode_lifecycle.html

本文讲述如何使用lifecrycle的命令工具,来部署链码。理解了lifecrycle的各项参数后,你可以按本文的步骤部署自己的链码。

注意:本文使用Fabric 2.0版本。

开始环境

首先部署一个Farbic的测试网络。开始之前,确保你已经安装了依赖包,实例代码,执行脚本和docker镜像。使用如下的命令,切换到测试代码目录(fabric-samples)

cd fabric-samples/test-network

从统一的初始状态开始,执行下面代码,删除运行中的docker和之前遗留的影响

./network.sh down

执行下述代码开始测试网络

./network.sh up createChannel

上述命令会创建一个通道mychannel和两个组织Org1,Org2.每个组织有一个peer且已经加入通道中。如果成功执行了,会显示如下logs

========= Channel successfully joined ===========

现在可以使用Peer CLI来向通道中部署链代码:

  • 第一步,打包链码
  • 第二步,安装打包的链码
  • 第三步,各组织对链码内容和定义达成一致
  • 第四步,向channel中提交链码

Log设置(可选,回头补)

打包链码

在安装链码之前我们需要对链码打包。下面仅翻译Go部分。

在打包链码之前,我们需要安装链码的依赖包,切换到包含链码的目录中

cd fabric-samples/chaincode/fabcar/go

本例使用 Go module来安装链码的依赖包,查看go.mod文件。

$ cat go.mod
module github.com/hyperledger/fabric-samples/chaincode/fabcar/go

go 1.13

require github.com/hyperledger/fabric-contract-api-go v0.0.0-20191118113407-4c6ff12b4f96

go.mod文件将Fabric contract API引入到链码包中,在fabcar.go中定义的合约接口SmartContract在链码的开头。

// SmartContract provides functions for managing a car
type SmartContract struct {
    contractapi.Contract
}

SmartContract为函数中操作账本数据构建context。

// CreateCar adds a new car to the world state with given details
func (s *SmartContract) CreateCar(ctx contractapi.TransactionContextInterface, carNumber string, make string, model string, colour string, owner string) error {
    car := Car{
        Make:   make,
        Model:  model,
        Colour: colour,
        Owner:  owner,
    }

    carAsBytes, _ := json.Marshal(car)

    return ctx.GetStub().PutState(carNumber, carAsBytes)
}

链码API更多信息

https://github.com/hyperledger/fabric-contract-api-go



https://hyperledger-fabric.readthedocs.io/en/latest/developapps/smartcontract.html

安装链码依赖包,在fabcar/go目录中运行下面命令

GO111MODULE=on go mod vendor

如果执行成功,go包会安装在vendor文件夹中

现在依赖包安装完毕,可以打包链码了。切换回test-network,打包所有相关内容。

cd ../../../test-network

使用peer CLI来打包链码,peer的可执行二级制文件在fabric-sample的bin文件夹中。使用如下命令添加Peer到CLI命令路径中

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

还需要设置指向fabric-samples中core.yaml的FABRIC_CFG_PATH

export FABRIC_CFG_PATH=$PWD/../config/

查看peer版本来确认是否安装成功

peer version

打包链代码

peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/go/ --lang golang --label fabcar_1

此命令会在当前目录下创建fabcar.tar.gz文件,–lang标识链码的编程语言,–path链码路径,–label链码安装后的标签,建议包含链码名称和版本。

我们已经打包了链码,现在可以在peer上安装链码。

安装打包的链码

打包完链码后,就可以在peer上安装。链码需要再所有参与背书的peer上安装。因为我们将要设置的背书策略是,Org1和Org2同时背书,所以Org1和Org2上都要安装链码

  • peer0.org1.example.com
  • peer0.org2.example.com

首先在Org1的peer上安装,通过设置环境变量来指定peer操作的是Org1,CORE_PEER_ADDRESS会设置peer为peer0.org1.example.com

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

运行下面代码在peer上安装链码

peer lifecycle chaincode install fabcar.tar.gz

如果执行成功,会返回链码的标识符package ID,此ID会再下一步审议链码的环节用到。类似于下方的输出

2020-02-12 11:40:02.923 EST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nIfabcar_1:69de748301770f6ef64b42aa6bb6cb291df20aa39542c3ef94008615704007f3\022\010fabcar_1" >
2020-02-12 11:40:02.925 EST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: fabcar_1:69de748301770f6ef64b42aa6bb6cb291df20aa39542c3ef94008615704007f3

下面安装Org2的peer

export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051

peer lifecycle chaincode install fabcar.tar.gz

在安装时会编译链码,如果链码有bug会在此时返回错误。

审议链码定义

安装链码包后,需要组织审议链码的定义。定义包含管理链码的参数如名称、版本,背书策略.

channel内的成员需要在部署链码之前对链码的定义达成一致。使用Application/Channel/lifeycleEndorsement。默认需要大多数成员对链码定义达成一致。这里我们有两个组织Org1和Org2,多数的情况是,两个组织都要达成一致。

如果一个组织内的peer已经安装了链码,那么组织在审议链码定义时需要包含packageID。packageID用于关联peer上安装的链码和审议过的链码定义,且用于组织为交易做背书。可以用下面命令查找peer上的package ID

peer lifecycle chaincode queryinstalled

package ID是链码标签和链码二级制hash值的结合,每个peer会产生相同的packageID,你会看到类似下面的输出

Installed chaincodes on peer:
Package ID: fabcar_1:69de748301770f6ef64b42aa6bb6cb291df20aa39542c3ef94008615704007f3, Label: fabcar_1

在审议链码时会用到packageID,所以我们先把它保存到一个环境变量中,执行下面命令(值为上一步得到的输出)

export CC_PACKAGE_ID=fabcar_1:69de748301770f6ef64b42aa6bb6cb291df20aa39542c3ef94008615704007f3

因为当前设置的是Org2的环境变量,我们可以用Org2来审议链码。审议是组织级别的,所以只需要一个peer节点操作,审议结果会通过gossip协议通知到组织内。审议链码执行以下命令:

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

通过–package-id来标识链码,–sequence是一个整数用来追踪链码定义和升级次数。因为此处是第一次部署链码到channel中,所以sequence是1,当此链码升级的时候,sequence要递增到2。如果你使用的是低版本的链码API,可以使用–init-required来执行链码的初始化init。第一次invoke调用链码时需要使用–isInit来初始化链码,执行init函数。

我们可以对

approveformyorg

命令使用

--signature-policy



--channel-config-policy参数来指定链码的背书策略。背书策略指定需要多个组织内的peer来为交易做背书。此处我们没有指定背书策略,链码会使用默认的背书策略(运行的peer中大多数为交易做背书)。预示着如果新组织加入或删除组织,背书策略会自动升级为需要更多或更少的背书。本文档中,默认策略是需要来自Org1和Org2的2个peer。如果要自定义背书策略,查看文档


https://hyperledger-fabric.readthedocs.io/en/latest/endorsement-policies.html

需要用admin的身份来审议链码定义,因此

CORE_PEER_MSPCONFIGPATH

要执行admin的账户。客户端用户不能审议链码,审议结果会提交给排序服务器,排序服务器验证管理员签名后会将审议结果分发给组织内的peers。

同样Org1也需要进行相同的操作

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

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

我们现在有了大多数成员的同意可以在channel上部署链码了。虽然只需要大多数组织来审议链码定义,但只有审议通过链码的组织,才能安装链码。在某个组织审议链码之前提交的链码定义,此组织不可为交易做背书。因此推荐在所有组织审议链码之后再提交链码定义。

向Channel中提交链码定义

在足够数量的组织为链码定义达成一致后,一个组织可以提交链码定义到Channel中。如果大多数组织同意了链码定义,提交事务会成功执行,且链码定义的参数会在channel中生效。

可以使用

peer lifecycle chaincode checkcommitreadiness

命令来查看哪些成员已经同意了链码定义。

checkcommitreadiness

使用的flag和组织审议链码的flag完全相同。但是不用使用–package-id

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name fabcar --version 1.0 --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json

命令会以json的形式显示输出,组织是否已经同意了

checkcommitreadiness命令中指定的参数。

通道内所有组织都同意了链码定义之后,链码定义就可以提交到channel中,执行以下命令提交提交channel中

peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --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

上述命令使用了–peerAddresses来指定Org1和Org2中的两个节点,提交事务提交给了加入通道peers,可以用来查询链码定义。

这个命令需要有满足部署链码策略的数量peers,因为同意链码定义已经同步到组织内部,所以可以选择组织内任意一个peer。

通道内成员背书的链码定义会提交到排序服务节点上,然后在通道中会创建一个区块。通道上的peers会验证是否有足够的组织同意了链码定义,peer lifecycle chaincode commit会一直等待peers的验证结果。

可以使用

peer lifecycle chaincode querycommitted

来确认链码定义是否已经被提交到通道上。

peer lifecycle chaincode querycommitted --channelID mychannel --name fabcar --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

如果链码成功的提交到通道上,会返回链码的sequence和链码版本号。

Committed chaincode definition for chaincode 'fabcar' on channel 'mychannel':
Version: 1, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true]

调用链码

如果链码定义提交成功,链码会在安装的peer上开始运行。链码已经可以被客户端调用。使用下面的命令初始化创建一组cars数据。注意链码调用需要有满足策略的足够的背书节点。

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n fabcar --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":[]}'

如果调用成功,你会看到如下返回

2020-02-12 18:22:20.576 EST [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200

可以使用query函数来查询数据

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

返回结果如下

[{"Key":"CAR0","Record":{"make":"Toyota","model":"Prius","colour":"blue","owner":"Tomoko"}},
{"Key":"CAR1","Record":{"make":"Ford","model":"Mustang","colour":"red","owner":"Brad"}},
{"Key":"CAR2","Record":{"make":"Hyundai","model":"Tucson","colour":"green","owner":"Jin Soo"}},
{"Key":"CAR3","Record":{"make":"Volkswagen","model":"Passat","colour":"yellow","owner":"Max"}},
{"Key":"CAR4","Record":{"make":"Tesla","model":"S","colour":"black","owner":"Adriana"}},
{"Key":"CAR5","Record":{"make":"Peugeot","model":"205","colour":"purple","owner":"Michel"}},
{"Key":"CAR6","Record":{"make":"Chery","model":"S22L","colour":"white","owner":"Aarav"}},
{"Key":"CAR7","Record":{"make":"Fiat","model":"Punto","colour":"violet","owner":"Pari"}},
{"Key":"CAR8","Record":{"make":"Tata","model":"Nano","colour":"indigo","owner":"Valeria"}},
{"Key":"CAR9","Record":{"make":"Holden","model":"Barina","colour":"brown","owner":"Shotaro"}}]

升级链码

可以使用lifecycle 来升级已经部署的链码。通道中成员可以升级链码:安装新链码包,审议链码定义,新的链码版本,新的sequence(递增一位)。新的链码在提交到channel后可以调用。lifecycle进程使通道内的成员在链码升级时协调一致,并确保在部署新链码之前有足够数量的通道成员已经准备使用新链码。

通道内成员也可以使用升级程序来升级链码的背书策略。通过审议新背书策略的链码定义并提交链码定义到通道中,通道成员可以成员可以更改背书策略而不用安装新的链码。

假设链码升级的场景是,Org1和Org2想安装一般用另一种语言写的链码。使用lifecycle升级链码,并确保每个组织都安装上了新的链码后才激活新链码。

我们一开始在Org1和Org2上安装的是GO语言的版本链码,但为了更合适的开发需要JS写的链码。第一步是打包JS版本的链码。如果你一开始使用的是JS版本链码,这里你可以使用Go或者Java版。

执行test-network目录下如下命令,来安装依赖包

cd ../chaincode/fabcar/javascript
npm install
cd ../../../test-network

执行test-network目录下如下命令来打包链码。并且设置peer CLI的环境变量,以防已经关闭了CLI终端。

export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
peer lifecycle chaincode package fabcar_2.tar.gz --path ../chaincode/fabcar/javascript/ --lang node --label fabcar_2

设置环境变量使用Org1 Admin身份运行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

接下来在Org1的peer上安装新的链码

peer lifecycle chaincode install fabcar_2.tar.gz

新安装的链码会有新的packageID,使用如下命令查询pacage ID

peer lifecycle chaincode queryinstalled

上述命令会返回一个安装在peer上的链码的列表。

Installed chaincodes on peer:
Package ID: fabcar_1:69de748301770f6ef64b42aa6bb6cb291df20aa39542c3ef94008615704007f3, Label: fabcar_1
Package ID: fabcar_2:1d559f9fb3dd879601ee17047658c7e0c84eab732dca7c841102f20e42a9e7d4, Label: fabcar_2

保存新的packageID到环境变量

export NEW_CC_PACKAGE_ID=fabcar_2:1d559f9fb3dd879601ee17047658c7e0c84eab732dca7c841102f20e42a9e7d4

接下来Org1投票链码的定义。

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --package-id $NEW_CC_PACKAGE_ID --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

新的链码定义使用JS版链码的packageID并且升级了链码的版本。因为sequence参数是用来追踪量升级的,所以Org1需要将值从1变到2。如果忘记上个版本的sequence值,可以使用

peer lifecycle chaincode querycommitted

查询。

现在操作Org2

export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051

peer lifecycle chaincode install fabcar_2.tar.gz


peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --package-id $NEW_CC_PACKAGE_ID --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

查询是否达成一致,可以提交到channel中了
peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name fabcar --version 2.0 --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json

如果可以了会有如下输出
    {
            "Approvals": {
                    "Org1MSP": true,
                    "Org2MSP": true
            }
    }

当新的链码定义通过之后,就可以在channel中升级链码了。直到现在,之前版本的链码还在各组织上运行。Org2使用如下命令执行channel中链码升级。

peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 2.0 --sequence 2 --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --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

一个新的交易提交到Fabric后会立即使用新版链码。如果过新的链码定义改变了背书策略,新的策略也会立即生效。

可以使用docker ps命令来验证新的链码已经在peer上启动

$docker ps
CONTAINER ID        IMAGE                                                                                                                                                                   COMMAND                  CREATED             STATUS              PORTS                              NAMES
197a4b70a392        dev-peer0.org1.example.com-fabcar_2-1d559f9fb3dd879601ee17047658c7e0c84eab732dca7c841102f20e42a9e7d4-d305a4e8b4f7c0bc9aedc84c4a3439daed03caedfbce6483058250915d64dd23   "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes                                           dev-peer0.org1.example.com-fabcar_2-1d559f9fb3dd879601ee17047658c7e0c84eab732dca7c841102f20e42a9e7d4
b7e4dbfd4ea0        dev-peer0.org2.example.com-fabcar_2-1d559f9fb3dd879601ee17047658c7e0c84eab732dca7c841102f20e42a9e7d4-9de9cd456213232033c0cf8317cbf2d5abef5aee2529be9176fc0e980f0f7190   "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes                                           dev-peer0.org2.example.com-fabcar_2-1d559f9fb3dd879601ee17047658c7e0c84eab732dca7c841102f20e42a9e7d4
8b6e9abaef8d        hyperledger/fabric-peer:latest                                                                                                                                          "peer node start"        About an hour ago   Up About an hour    0.0.0.0:7051->7051/tcp             peer0.org1.example.com
429dae4757ba        hyperledger/fabric-peer:latest                                                                                                                                          "peer node start"        About an hour ago   Up About an hour    7051/tcp, 0.0.0.0:9051->9051/tcp   peer0.org2.example.com
7de5d19400e6        hyperledger/fabric-orderer:latest   

如果使用了–init-required参数,你需要首先调用Init函数。这里因为不用执行Init,我们可以直接测试新链码。

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 fabcar --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":"createCar","Args":["CAR11","Honda","Accord","Black","Tom"]}'

可以再查一下数据,看有没有新数据。

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

可以看到如下结果

[{"Key":"CAR0","Record":{"make":"Toyota","model":"Prius","colour":"blue","owner":"Tomoko"}},
{"Key":"CAR1","Record":{"make":"Ford","model":"Mustang","colour":"red","owner":"Brad"}},
{"Key":"CAR11","Record":{"color":"Black","docType":"car","make":"Honda","model":"Accord","owner":"Tom"}},
{"Key":"CAR2","Record":{"make":"Hyundai","model":"Tucson","colour":"green","owner":"Jin Soo"}},
{"Key":"CAR3","Record":{"make":"Volkswagen","model":"Passat","colour":"yellow","owner":"Max"}},
{"Key":"CAR4","Record":{"make":"Tesla","model":"S","colour":"black","owner":"Adriana"}},
{"Key":"CAR5","Record":{"make":"Peugeot","model":"205","colour":"purple","owner":"Michel"}},
{"Key":"CAR6","Record":{"make":"Chery","model":"S22L","colour":"white","owner":"Aarav"}},
{"Key":"CAR7","Record":{"make":"Fiat","model":"Punto","colour":"violet","owner":"Pari"}},
{"Key":"CAR8","Record":{"make":"Tata","model":"Nano","colour":"indigo","owner":"Valeria"}},
{"Key":"CAR9","Record":{"make":"Holden","model":"Barina","colour":"brown","owner":"Shotaro"}}]

复原环境

当调用完毕链码,你可以使用下面的命令来删除Logspout tool。

docker stop logspout
docker rm logspout

接下来停止测试网络

./network.sh down

常见错误

1.
Error: failed to create signed transaction: proposal response was not successful, error code 500, msg failed to invoke backing implementation of 'CommitChaincodeDefinition': chaincode definition not agreed to by this org (Org1MSP)

2.
Error: endorsement failure during invoke. response: status:500 message:"make sure the chaincode fabcar has been successfully defined on channel mychannel and try again: chaincode definition for 'fabcar' exists, but chaincode is not installed"

3.
2020-04-07 20:08:23.306 EDT [chaincodeCmd] ClientWait -> INFO 001 txid [5f569e50ae58efa6261c4ad93180d49ac85ec29a07b58f576405b826a8213aeb] committed with status (ENDORSEMENT_POLICY_FAILURE) at localhost:7051
Error: transaction invalidated with status (ENDORSEMENT_POLICY_FAILURE)

常见错误相对简单,暂时先不翻译了