1、链码操作:Fabric 1.4 vs Fabric 2.0我们将首先快速介绍在HF 1.4和HF 2.0中的整个链码操作过程。9 A! m$ L- ]+ O2 `/ O
链码操作指的是在Hyperledger fabric网络通道上部署链码的操作,这样区块链 之外的应用可以调用或查询链码方法。在链码开发完成并测试后,首先需要 将Fabric链码安装到指定的peer节点。在这个阶段链码还不能使用,直到 链码被提交(Fabric 2.0中的术语)到通道中或在通道上实例化(Fabric 1.4中的 术语),这样链码就可以被授权用户访问了。# F8 i3 |' V& i7 F8 w
下面是两个版本的Hyperledger Fabric中链码操作流程的对比图:
在Hyperledger Fabric 1.4中,链码操作过程包含以下步骤:打包、安装、实例化。 如果链码属于多个参与方,那么就需要打包这一环节。如果不存在多方属主的问题, 那么直接安装链码就可以(其中隐含了打包环节)。在Fabric链码安装时需要指定 要安装链码的目标节点。4 Q% r. j2 K( k* F# n
在这个阶段,安装好的Fabric链码还不能使用,因为它还没有在通道上实例化。 当Fabric链码包被安装在指定的节点上之后,我们就可以执行链码实例化操作, 从而让链码在通道上可用。技术上来说,链码实例化实际上就是调用LSCC系统链码 的方法来初始化通道上的一个链码。) I* I: Y" p7 I: u; K4 w
Fabric链码实例化之后就可以使用了,可以接受通道上的调用或查询请求。
下面我们看在Hyperledger Fabric 2.0中的链码操作步骤有何区别。
宽泛地来讲,在Fabric 2.0中链码操作基本遵循同样的流程,但是在命令和某些 后台处理中做了一些调整。整体的流程可以分为四个步骤:打包、安装、机构审批、 链码提交。大致可以认为前两个环节对应于Fabric 1.4中的链码安装,后面两个 环节对应于Fabric 1.4中的链码实例化,但是实例化(instantiation)这个词不再 用了。
链码打包这一步是创建一个打包文件(tar格式),其中包含Fabric链码以及一些元数据。 虽然不同的机构可以分别进行打包处理,更常见是由一个机构打包然后分发给其他 机构以便确保所有的机构使用相同的链码。
安装步骤是将打包的Fabric链码文件安装在指定的peer节点上。和之前的版本一样, 只有需要接受链码调用的节点才需要安装链码。在这个节点,Fabric链码还不可用, 因为还没有提交到通道中。链码安装的结果是得到一个包标识符,其格式为.。
机构审批是在Hyperledger Fabric 2.0中增加的步骤。在之前的版本中我们可以让 一个机构实例化链码。在Fabric 2.0中,需要机构显式地审批链码。需要多少机构 审批则是由生命周期背书策略来决定,默认情况下设置为需要大多数机构(超过半数)。 如果Fabric网络中包含两个机构,那么就需要这两个机构同时批准。在审批过程中 需要排序节点的参与,因为每次审批都会生成一个新的区块,这意味着所有的peer 节点都了解审批的状态。
当审批环节完成后,我们就需要指定要在哪个通道上部署链码。这需要提交一些信息, 例如背书策略、是否需要执行Init代码等等。在这里也有些与Fabric 1.4不同的地方: 在Fabric 1.4中,当链码实例化时会自动调用链码的Init方法,然而在Fabric 2.0中, 需要在提交链码后显式地调用Init方法。
在批准机构达到指定数量后,链码就可以提交了。我们现在就进入了最后一个步骤: 链码提交。
链码提交可以由任何机构发起。该流程首先需要批准机构的背书,然后交易提交到 排序服务并生成新的区块,最后所有的对等节点在账本中提交该区块。
现在链码就可以使用了。
2、First Network和SACC链码简介出于完整性考虑,下面给出关于First Network和SACC链码的一些信息,这些内容 都来自fabric-samples仓库。
First Network是一个双机构设置,每个机构中包含两个peer节点。通道mychannel 创建后加入所有的4个peer节点。在byfn.sh中完整的实现了First Network的部署, 并包含一些可选的参数。在下面的演示中,我们不使用默认的链码(在Fabric 1.4 中式chaincode_example02,在Fabric 2.0中式abstore),而是使用SACC链码。0 B( x5 K- f" t' _5 k+ H% G' o9 c# a
SACC式Simple Asset ChainCode的缩写,表示简单资产链码。它在账本中模拟一个 键/值存储。当初次部署后,需要一个初始的键/值对。SACC链码定义了两个方法: Set()和Get(),分别用来设置或读取某个键的值。4 b' ?: Z& [. k5 `9 H
好了,现在我们可以开始演示Fabric 1.4和Fabric 2.0中链码操作的不同了。
3、Fabric 1.4.4链码操作演示我们首先以无链码方式(使用-n选项)启动First Network,然后我们再加载 SACC链码以便聚焦链码的生命周期。+ L- @9 p; t* h; S% @% F; S
下面是演示步骤:- S5 M# [* |( H F% U( ~+ b% |% F
无链码方式启动First Network在指定的peer节点上安装SACC链码在mychannel通道上实例化SACC链码并查询结果调用set()设置新值并从另一个peer节点查询结果STEP 1:首先启动First Network:# l6 q0 j. N# [4 z* q3 u
1 2 | cd fabric-samples/first-network ./byfn.sh up -n3 u1 @ g" y- X |
现在我们可以开始链码部署操作。$ a3 c9 X' n" j' I
STEP 2:在指定peer节点上安装链码8 R9 k7 [+ Z! X
这里我们跳过打包环节,直接在目标节点peer.org1和peer0.org2上安装链码, 因为在这个演示中我们只需要这两个节点进行链码调用和查询。, w* S/ V$ |" @( _! Z! h1 b
1 2* y5 ~8 W+ _: a7 G 3 40 h8 F1 {& M& S6 s$ V0 b7 u 5. l% l8 f7 e- `% B5 u; D; O( R 6; t: `, U: Q$ I3 A' c! J* g 79 V/ v* N9 I8 n- i 8 9/ T4 X! w& \. _ 10- i# m) O, j4 H- a | # peer0.org1" x. Q# h/ U+ s* f* g docker exec cli peer chaincode install -n mycc -v 1 \& F' Y0 U4 a$ S& b9 O -p github.com/chaincode/sacc # peer0.org2 docker exec \ -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer chaincode install -n mycc -v 1 -p github.com/chaincode/sacc |
STEP 3:在通道mychannel上实例化链码并查询
注意在sacc链码中有Init()代码。当我们实例化链码时,我们需要 提供Init()所需的参数:* u( D R$ h- w2 \$ O+ `. E
16 Q$ m4 V1 s+ F% i; o 26 y+ C- ~) F" Q) g0 U 30 `4 U% Q. k+ X( z( {" C9 w1 b; w 4 O6 i. G+ w+ b5 A/ W | docker exec cli peer chaincode instantiate -o orderer.example.com:7050 --tls \, H1 y. T* R; \7 L. _ }5 s --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ -C mychannel -n mycc -v 1 -c '{"Args":["name","kc"]}' \ -P "AND ('Org1MSP.peer','Org2MSP.peer')" |
如果现在看看peer节点的日志,我们可以看到出了新区块#3。
在链码实例化之后,我们可以查询:, J, A! Q3 b; z% h; E0 B) |% U+ |1 d
1 | docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}' |
STEP 4:调用set()设置新值并从另一个节点查询! O/ O. [& @1 D
出于演示目的,我们在peer0.org1上调用set(),然后在peer0.org2上 调用get(),以此说明链码是否工作正常。4 c( F3 P! O- u0 H/ P7 ?* I ?
1 27 F3 h& S' T7 z+ i9 r 3 X# `( e9 u. F; S 4 5, o+ A" a# h4 [. t W9 G; ~ 6 7/ G' Q7 o' b3 {# Y 80 ?. m8 a. A; w5 k 9 10: P/ w/ {* m0 ^- q 11 12* N7 N H6 o$ y; v& [ 13 14 | # peer0.org1 docker exec cli peer chaincode invoke -o orderer.example.com:7050 --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \" d: J7 Y# g" ]3 O --peerAddresses peer0.org1.example.com:7051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \, b0 P- _# W5 X3 f3 ]- Q5 s --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ -C mychannel -n mycc -c '{"Args":["set","name","Peter"]}' 2 Z3 v4 n7 K; O U, f) o # peer0.org2" W" y+ p1 ~; H' {8 V. h3 s docker exec -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \2 v5 ? L6 S6 y, @: { -e CORE_PEER_LOCALMSPID="Org2MSP" \4 @' C3 ?& e9 e' |9 Y1 p -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}') z8 m* k ^9 f, o- f |
4、Fabric 2.0链码操作演示类似的,在Fairc 2.0.0中,我们也先以无链码方式启动First Network, 然后再启动SACC链码以便聚焦链码的生命周期。
下面是演示步骤:, ^1 }$ i% P; s7 p( r {
无链码方式启动First Network打包SACC链码在指定peer节点上安装SACC链码包机构审批链码在mychannel通道上提交链码调用SACC链码的Init方法调用SACC链码的set方法并从另一个peer节点查询结果STEP 1:以无链码方式启动First Network:& v6 X* F/ ~, C
1) Y2 H, D: V9 Y% M 2 | cd fabric-samples/first-network ./byfn.sh up -n |
STEP 2:打包SACC链码
首先我们处理依赖问题:
1 2 3/ T+ t& M4 M) q7 C | cd fabric-sample/chaincode/sacc# x- _2 a, e' w |5 K; U# {+ z GO111MODULE=on go mod vendor N- p$ y# \: s( p- q cd fabric-sample/first-network |
1 22 z3 |! j7 `; l! \ 3 | docker exec cli peer lifecycle chaincode package sacc.tar.gz \5 S& L J/ Z% S8 B1 R! j4 z6 T --path github.com/hyperledger/fabric-samples/chaincode/sacc/ \ --label sacc_1 |
STEP 3:在指定peer节点上安装SACC链码包2 f* Q5 O \( n6 X, u$ ?4 D6 T
现在我们在peer0.org1和peer0.org2上安装SACC练马报,因为在这个 演示中我们只需要使用这两个节点进行链码调用和查询。* I6 c R! f( ?: M1 P" i! Y
1 2 3; w) }. ?$ F: `2 { \0 G. n 4 50 U5 B( ^: D. }- ?5 V1 M* w8 k 6 7 8 9 10 p2 T; Z8 r1 w @# H' Q | # peer0.org1$ E. X9 e, N* w; z1 J docker exec cli peer lifecycle chaincode install sacc.tar.gz3 _* F o @: i9 ?" c0 l2 A # peer0.org2 docker exec \ -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer lifecycle chaincode install sacc.tar.gz |
我们会收到链码包的标识符,在下面的链码审批阶段会用到。我们 收到的链码标识符为:sacc_1:bf57…6399。
我们可以使用peer lifecycle chaincode queryinstalled命令随时 检查节点上的链码安装情况,如果我们需要找出链码包的标识ID,这个命令 会很有用。) u* N! s* G5 ~# O! h. Y
1 2 N z% B- M' P+ w1 F0 J: w 3: U5 J6 e8 [/ i! z7 D# F U 4 58 O" }4 D) ^$ r( _+ o' H' X 6 7 8. S6 q) ?; F) j! _( }+ V% m+ P6 U 9% p4 ^6 P- A9 O& N3 J# z4 ]: N2 S 10( {: m% U0 ^& H0 T1 U' G& E g& Y | # peer0.org1( T& V# B( m, V* y5 ^2 x+ ~ docker exec cli peer lifecycle chaincode queryinstalled # peer0.org2 docker exec \# m4 U8 Y. [* h( X! A; X -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \ -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \. `0 E" W& [$ J' c+ ^+ K! S -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \$ ^ T, s& v: s0 }9 M+ T; M' K/ \ cli peer lifecycle chaincode queryinstalled3 @) k' p& V. A6 l1 ~ |
根据默认策略,需要超过半数的机构审批链码后才能向通道提交链码, 具体可参考configtx.yaml中的Application/Policies/LifecycleEndorsement部分。 目前的设置中包含两个机构,因此需要两个机构同时批准链码。
首先是Org1批准链码:) d: p, U) h+ X7 N* H& I. W$ t
1' u9 }$ e2 a7 s- T6 i; E9 E& F 2 34 _1 ^5 M' W% P) H7 l 4" {5 ]* r) w4 M+ O& b1 T$ v 51 n+ K7 j/ {; S1 V- ?6 T t2 a | docker exec cli peer lifecycle chaincode approveformyorg \0 o' A; \; X# F, k$ V --tls \! R# Q; h) t" b6 z0 ?+ z --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \$ W7 W7 \1 ?1 L6 n/ U. m5 G --channelID mychannel --name mycc --version 1 \ --init-required --sequence 1 --waitForEvent --package-id ${PACKAGE_ID} |
如果我们现在看下peer节点的日志,可以看到出了新块#3。! @6 i" W: n. `: i
类似的,我们让Org2批准链码:
14 ?7 A9 C. Y* f% m 2 3 4 5& ~# k4 \) y. I% E9 o. R 6 7 8" t: k& j+ H% R( Q$ @6 F5 t8 A2 T 9; Z! [# ~) M$ m/ g0 ] 102 h, T0 T0 p; O0 t2 a | docker exec \ -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \" ^* o4 C- @. T -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \, u( A$ z+ l( r% m0 } -e CORE_PEER_LOCALMSPID="Org2MSP" \2 q( v" R2 T/ p& ?5 J e# I -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ l8 V* [/ r) M8 K; W2 o H1 O cli peer lifecycle chaincode approveformyorg \ --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \* S+ ]6 s; E% c6 R' p --channelID mychannel --name mycc --version 1 --init-required \ --sequence 1 --waitForEvent --package-id ${PACKAGE_ID}0 N/ R M* [: ] |
不出意外,可以看到出了新块block#4:! x, C8 G) Q; ~& B6 d
注意我们在approval命令中指定了init相关的参数,以便向SACC链码的 Init方法传入所需的参数。
可以随时使用如下命令查看链码的提交状态:
1 2' ~" \) D5 ~8 c' O3 T1 ^7 ` | docker exec cli peer lifecycle chaincode checkcommitreadiness \ --channelID mychannel --name mycc --version 1 --sequence 1 --output json4 m1 V4 t; [' J! f* \0 y4 E- X |
两个机构都已经批准了链码,现在可以提交了。
STEP 5:向通道mychannel提交链码
链码提交可以在一个peer节点上完成:
1. i" `- ^. R. a- Z 28 k# M0 i! o! S6 x 3 45 b" ]" D3 V1 B( R- [7 n5 R1 e 5 65 M5 Q' v0 ^ Q5 x 7 8 | docker exec cli peer lifecycle chaincode commit -o orderer.example.com:7050 \: Y+ ~9 O3 m) K2 E --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \ --peerAddresses peer0.org1.example.com:7051 \" t0 C/ q1 N3 m. l4 N/ ] ? --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \ --peerAddresses peer0.org2.example.com:9051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \* ]9 V! o- |4 }; {& a --channelID mychannel --name mycc --version 1 --sequence 1 --init-required4 F( R& r, e8 J" T( Z0 ]' b |
可以看到出了新块#5:, W( D( }. N I8 H- E
注意我们在commit命令中已经包含了init所需的参数。
同样,我们可以使用querycommited命令来查看链码的提交状态:6 I) N D' b' C
1! D, k# i" g: _5 H | docker exec cli peer lifecycle chaincode querycommitted --channelID mychannel --name mycc9 Q, V# K" v" q3 s# o, M |
在链码提交到通道之后,链码的生命周期就完成了,链码已经可以访问。 现在我们回到链码的调用和查询,这和之前的版本是一致的。
STEP 6:调用链码的Init方法
SACC链码的Init方法需要首先调用。7 E8 v/ X# e" T4 X) ]
1 2: f8 ?# |% e% f/ p ?/ f8 A" X# D 3 49 ]+ L0 W. T, S/ w" v 5. e" @/ \& Z1 d' C% h. B 6 79 C$ ^2 }# Q; j8 Q6 ~ 8, \! N1 V" s. X S3 a: B% h | docker exec cli peer chaincode invoke -o orderer.example.com:7050 \ --tls \ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \# K* C; X9 G1 x5 \ --peerAddresses peer0.org1.example.com:7051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \ --peerAddresses peer0.org2.example.com:9051 \4 L( R, p0 b, y# R( B% E2 _- U8 C --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ -C mychannel -n mycc --isInit -c '{"Args":["name","kc"]}'8 f% x: g$ B5 j. w: ]8 _3 F' i7 W! ] |
现在可以查询 链码:& X4 I0 f3 ?/ L5 e* s
1( c& Y4 M5 k9 B4 @: b( D | docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}' |
STEP 7:调用链码的set()方法并从另一个peer节点查询* l2 l8 H4 f( U3 j! P. o( ]4 Z
和之前一样,我们在peer0.org1上调用链码的set()方法,在peer0.org2上 进行查询:; V, l; e# J; h' O. _
1 26 ^1 u4 D8 H& ]: q 3 4' s$ a2 |5 n0 e' M 5) k! n6 s1 ]' Y) o 6) O- H* ?4 H5 ^1 ~5 ^& R 73 ]; T' {& t) W 8 9 10 e7 ~; a1 ]/ l3 V 11 120 I; n. \$ k# p |; s3 E4 a6 x- k 136 \; H9 G+ f8 s5 z+ s 14 15 16 h4 Q; g' Z N; j# J7 k& h 17/ q3 d5 z: F) v& |- Q 18! l( w2 q0 {. `8 t0 R | # peer0.org1' C- \0 A) z7 I- s2 `7 S6 _7 Z% I docker exec cli peer chaincode invoke \ -o orderer.example.com:7050 \, S+ d/ J8 o; y( X6 X( { --tls \2 ^; f; _/ K7 d* K% _ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \9 @7 @+ e5 u+ b/ e --peerAddresses peer0.org1.example.com:7051 \$ s- G7 i; e) @% d+ l: ^- P --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \ --peerAddresses peer0.org2.example.com:9051 \ --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ -C mychannel -n mycc -c '{"Args":["set","name","Peter"]}' - o- f! C4 ^# |% [ # peer0.org2 docker exec \ y& A! Y# C$ F3 {* I -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \0 z* ]8 f8 t2 y5 N -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \ -e CORE_PEER_LOCALMSPID="Org2MSP" \ -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \ cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'5 Y S1 s+ D4 W( \7 R* L |
一切正常。