天天看點

使用chaincode dev mode調試智能合約

文章的開頭,先貼一段使用chaincode dev mode調試智能合約的官方文檔。

應用的官網文檔開始

Building Chaincode

Now let’s compile your chaincode.

go get -u github.com/hyperledger/fabric/core/chaincode/shim
go build
           

Assuming there are no errors, now we can proceed to the next step, testing your chaincode.

Testing Using dev mode

Normally chaincodes are started and maintained by peer. However in “dev mode", chaincode is built and started by the user. This mode is useful during chaincode development phase for rapid code/build/run/debug cycle turnaround.

We start “dev mode” by leveraging pre-generated orderer and channel artifacts for a sample dev network. As such, the user can immediately jump into the process of compiling chaincode and driving calls.

Install Hyperledger Fabric Samples

If you haven’t already done so, please :doc:

install

.

Navigate to the

chaincode-docker-devmode

directory of the

fabric-samples

clone:

cd chaincode-docker-devmode
           

Now open three terminals and navigate to your

chaincode-docker-devmode

directory in each.

Terminal 1 - Start the network

docker-compose -f docker-compose-simple.yaml up
           

The above starts the network with the

SingleSampleMSPSolo

orderer profile and launches the peer in “dev mode”. It also launches two additional containers - one for the chaincode environment and a CLI to interact with the chaincode. The commands for create and join channel are embedded in the CLI container, so we can jump immediately to the chaincode calls.

Terminal 2 - Build & start the chaincode

You should see the following:

Now, compile your chaincode:

cd sacc
go build
           

Now run the chaincode:

CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=mycc:0 ./sacc
           

The chaincode is started with peer and chaincode logs indicating successful registration with the peer.

Note that at this stage the chaincode is not associated with any channel. This is done in subsequent steps

using the

instantiate

command.

Terminal 3 - Use the chaincode

Even though you are in

--peer-chaincodedev

mode, you still have to install the chaincode so the life-cycle system chaincode can go through its checks normally.

This requirement may be removed in future when in

--peer-chaincodedev

mode.

We’ll leverage the CLI container to drive these calls.

peer chaincode install -p chaincodedev/chaincode/sacc -n mycc -v 0 
peer chaincode instantiate -n mycc -v 0 -c '{"Args":["a","10"]}' -C myc
           

Now issue an invoke to change the value of “a” to “20”.

peer chaincode invoke -n mycc -c '{"Args":["set", "a", "20"]}' -C myc
           

Finally, query

a

. We should see a value of

20

.

peer chaincode query -n mycc -c '{"Args":["query","a"]}' -C myc
           

Testing new chaincode

By default, we mount only

sacc

. However, you can easily test different chaincodes by adding them to the

chaincode

subdirectory and relaunching your network. At this point they will be accessible in your

chaincode

container.

Chaincode access control

Chaincode can utilize the client (submitter) certificate for access

control decisions by calling the GetCreator() function. Additionally

the Go shim provides extension APIs that extract client identity

from the submitter’s certificate that can be used for access control decisions, whether that is based on client identity itself, or the org identity, or on a client identity attribute.

For example an asset that is represented as a key/value may include the client’s identity as part of the value (for example as a JSON attribute indicating that asset owner), and only this client may be authorized to make updates to the key/value in the future. The client identity library extension APIs can be used within chaincode to retrieve this submitter information to make such access control decisions.

See the `client identity (CID) library documentation for more details.

To add the client identity shim extension to your chaincode as a dependency, see :ref:

vendoring

.

應用官網文檔結束

按照上面的步驟,我在Terminal 1,cli容器就退出了

orderer      | 2019-04-29 07:47:22.284 UTC [comm.grpc.server] 1 -> INFO 3c3 streaming call completed grpc.service=orderer.AtomicBroadcast grpc.method=Broadcast grpc.peer_address=172.18.0.4:53470 grpc.code=OK grpc.call_duration=1.796324ms
orderer      | 2019-04-29 07:47:22.286 UTC [grpc] warningf -> DEBU 3c4 transport: http2Server.HandleStreams failed to read frame: read tcp 172.18.0.2:7050->172.18.0.4:53470: read: connection reset by peer
orderer      | 2019-04-29 07:47:22.286 UTC [grpc] infof -> DEBU 3c5 transport: loopyWriter.run returning. connection error: desc = "transport is closing"
orderer      | 2019-04-29 07:47:22.286 UTC [grpc] infof -> DEBU 3c6 transport: loopyWriter.run returning. connection error: desc = "transport is closing"
orderer      | 2019-04-29 07:47:22.286 UTC [common.deliver] Handle -> WARN 3c7 Error reading from 172.18.0.4:53468: rpc error: code = Canceled desc = context canceled
orderer      | 2019-04-29 07:47:22.286 UTC [orderer.common.server] func1 -> DEBU 3c8 Closing Deliver stream
orderer      | 2019-04-29 07:47:22.286 UTC [comm.grpc.server] 1 -> INFO 3c9 streaming call completed grpc.service=orderer.AtomicBroadcast grpc.method=Deliver grpc.peer_address=172.18.0.4:53468 error="rpc error: code = Canceled desc = context canceled" grpc.code=Canceled grpc.call_duration=5.854975ms
cli exited with code 1
           

一開始試多幾次,總有一次能成功,且還有其他問題(即将介紹),我就先去解決那個問題,後面一直都失敗,逼迫我去尋找解決辦法,

解決辦法:

注釋docker-compose-simple.yaml檔案中cli容器的command字段,cli容器即可正常啟動。

這個腳本用來在cli容器啟動的時候自動建立通道,我們可以後面手動啟動,即在進入cli容器再啟動。

因為我的chaincode需要身份資訊,百度了一翻,看到了CSDN一位同學的代碼,引用了CID包(github.com/hyperledger/fabric/core/chaincode/lib/cid)。

但是這個包沒有被打包到ccenv鏡像(chaincode所用鏡像),在chaincode容器(ccenv鏡像)中go build失敗,在cli容器(tools鏡像)install chaincode的時候報錯:

2019-04-17 08:46:54.280 UTC [chaincode.platform.golang] getCodeFromFS -> DEBU 045 getCodeFromFS chaincodedev/chaincode/billManager
2019-04-17 08:46:54.466 UTC [chaincode.platform.golang] func1 -> DEBU 046 Discarding GOROOT package encoding/json
2019-04-17 08:46:54.466 UTC [chaincode.platform.golang] func1 -> DEBU 047 Discarding GOROOT package fmt
2019-04-17 08:46:54.466 UTC [chaincode.platform.golang] func1 -> DEBU 048 Accepting import: github.com/hyperledger/fabric/core/chaincode/lib/cid
2019-04-17 08:46:54.466 UTC [chaincode.platform.golang] func1 -> DEBU 049 Discarding provided package github.com/hyperledger/fabric/core/chaincode/shim
2019-04-17 08:46:54.466 UTC [chaincode.platform.golang] func1 -> DEBU 04a Discarding provided package github.com/hyperledger/fabric/protos/peer
2019-04-17 08:46:54.466 UTC [chaincode.platform.golang] func1 -> DEBU 04b Discarding GOROOT package strconv
Error: error getting chaincode code bill: error getting chaincode package bytes: Error obtaining dependencies for github.com/hyperledger/fabric/core/chaincode/lib/cid: command <go list -f {{ join .Deps "\n"}} github.com/hyperledger/fabric/core/chaincode/lib/cid>: failed with error: "exit status 1"
can't load package: package github.com/hyperledger/fabric/core/chaincode/lib/cid: cannot find package "github.com/hyperledger/fabric/core/chaincode/lib/cid" in any of:
	/opt/go/src/github.com/hyperledger/fabric/core/chaincode/lib/cid (from $GOROOT)
	/opt/gopath/src/github.com/hyperledger/fabric/core/chaincode/lib/cid (from $GOPATH)

           

分析列印資訊,我覺得列印中的[chaincode.platform.golang]對應于代碼庫,果然在core/chaincode/platform/golang/platform找到了對于的代碼。

// --------------------------------------------------------------------------------------
	// Remove any imports that are provided by the ccenv or system
	// --------------------------------------------------------------------------------------
	var provided = map[string]bool{
		"github.com/hyperledger/fabric/core/chaincode/shim": true,
		"github.com/hyperledger/fabric/protos/peer":         true,
	}
           

這段代碼的作用應該是編譯的時候忽略這些包的檢查,添加CID包應該就可以了

// --------------------------------------------------------------------------------------
	// Remove any imports that are provided by the ccenv or system
	// --------------------------------------------------------------------------------------
	var provided = map[string]bool{
		"github.com/hyperledger/fabric/core/chaincode/shim": true,
		"github.com/hyperledger/fabric/protos/peer":         true,
		"github.com/hyperledger/fabric/core/chaincode/shim/ext/cid": true,
	}
           

然後重新編譯就可以了。

值得注意的是,修改了core裡面的代碼,需要clean之後再編譯,編譯出來的.build裡面的代碼庫才能同步,因為.build的代碼庫用于建立鏡像的代碼庫。

因為對代碼工程不熟,不知道要怎麼改,隻知道要重新編譯鏡像,make all一直有問題,一路過關斬将,注釋掉一些東西,試了十幾遍,最後還是編譯失敗了。

後面才發現可以直接make docker,這才走入了快車道。通過檢視ccenv鏡像的Dockerfile,發現制作鏡像時,fabric庫被打包成goshim.tar.bz2,拷貝到ccenv鏡像中

# Copyright Greg Haskins All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#
FROM _BASE_NS_/fabric-baseimage:_BASE_TAG_
COPY payload/chaintool payload/protoc-gen-go /usr/local/bin/
ADD payload/goshim.tar.bz2 $GOPATH/src/
RUN mkdir -p /chaincode/input /chaincode/output
           

再往上回溯,發現源頭在Makefile上

GOSHIM_DEPS = $(shell ./scripts/goListFiles.sh $(PKGNAME)/core/chaincode/shim)

$(BUILD_DIR)/goshim.tar.bz2: $(GOSHIM_DEPS)
	@echo "Creating $@"
	@tar -jhc -C $(GOPATH)/src $(patsubst $(GOPATH)/src/%,%,$(GOSHIM_DEPS)) > $@
           

修改第一行,以便包含CID的庫

就在我滿懷希望重新make docker,就在我閑逛的時候,我發現CID居然就在shim/ext/cid包裡面,也就是說原來的ccenv鏡像已經包含了CID包,隻是路徑和以前不同。

修改包的路徑,然後在chaincode容器中就能編譯成功了,在cli容器中也能正常安裝chaincode了。

繼續閱讀