1、链码操作:Fabric 1.4 vs Fabric 2.0我们将首先快速介绍在HF 1.4和HF 2.0中的整个链码操作过程。/ }4 m4 ^! Q9 V! M& ]5 }, e
链码操作指的是在Hyperledger fabric网络通道上部署链码的操作,这样区块链 之外的应用可以调用或查询链码方法。在链码开发完成并测试后,首先需要 将Fabric链码安装到指定的peer节点。在这个阶段链码还不能使用,直到 链码被提交(Fabric 2.0中的术语)到通道中或在通道上实例化(Fabric 1.4中的 术语),这样链码就可以被授权用户访问了。
下面是两个版本的Hyperledger Fabric中链码操作流程的对比图:% L6 x& |. \% @
在Hyperledger Fabric 1.4中,链码操作过程包含以下步骤:打包、安装、实例化。 如果链码属于多个参与方,那么就需要打包这一环节。如果不存在多方属主的问题, 那么直接安装链码就可以(其中隐含了打包环节)。在Fabric链码安装时需要指定 要安装链码的目标节点。% x" b% T ]& t; G4 G
在这个阶段,安装好的Fabric链码还不能使用,因为它还没有在通道上实例化。 当Fabric链码包被安装在指定的节点上之后,我们就可以执行链码实例化操作, 从而让链码在通道上可用。技术上来说,链码实例化实际上就是调用LSCC系统链码 的方法来初始化通道上的一个链码。
Fabric链码实例化之后就可以使用了,可以接受通道上的调用或查询请求。: X3 }+ |. W; v7 I; x; P) A
下面我们看在Hyperledger Fabric 2.0中的链码操作步骤有何区别。5 O" B( v. i4 e, W
宽泛地来讲,在Fabric 2.0中链码操作基本遵循同样的流程,但是在命令和某些 后台处理中做了一些调整。整体的流程可以分为四个步骤:打包、安装、机构审批、 链码提交。大致可以认为前两个环节对应于Fabric 1.4中的链码安装,后面两个 环节对应于Fabric 1.4中的链码实例化,但是实例化(instantiation)这个词不再 用了。1 [ {% z5 Q0 e( `0 S& b6 m* V Z
链码打包这一步是创建一个打包文件(tar格式),其中包含Fabric链码以及一些元数据。 虽然不同的机构可以分别进行打包处理,更常见是由一个机构打包然后分发给其他 机构以便确保所有的机构使用相同的链码。# O8 ?2 o- m/ Y6 y3 A8 W: b/ K6 E, |
安装步骤是将打包的Fabric链码文件安装在指定的peer节点上。和之前的版本一样, 只有需要接受链码调用的节点才需要安装链码。在这个节点,Fabric链码还不可用, 因为还没有提交到通道中。链码安装的结果是得到一个包标识符,其格式为.。' N V4 `: U: m# G9 `/ d; J, H
机构审批是在Hyperledger Fabric 2.0中增加的步骤。在之前的版本中我们可以让 一个机构实例化链码。在Fabric 2.0中,需要机构显式地审批链码。需要多少机构 审批则是由生命周期背书策略来决定,默认情况下设置为需要大多数机构(超过半数)。 如果Fabric网络中包含两个机构,那么就需要这两个机构同时批准。在审批过程中 需要排序节点的参与,因为每次审批都会生成一个新的区块,这意味着所有的peer 节点都了解审批的状态。
当审批环节完成后,我们就需要指定要在哪个通道上部署链码。这需要提交一些信息, 例如背书策略、是否需要执行Init代码等等。在这里也有些与Fabric 1.4不同的地方: 在Fabric 1.4中,当链码实例化时会自动调用链码的Init方法,然而在Fabric 2.0中, 需要在提交链码后显式地调用Init方法。! K+ I1 ^% L- L C1 B
在批准机构达到指定数量后,链码就可以提交了。我们现在就进入了最后一个步骤: 链码提交。1 X0 v$ F w+ Z* a
链码提交可以由任何机构发起。该流程首先需要批准机构的背书,然后交易提交到 排序服务并生成新的区块,最后所有的对等节点在账本中提交该区块。( o7 k' h! L' c: E6 q. e
现在链码就可以使用了。
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链码。+ ]+ Z+ H* d' X: y N, p9 a( M/ _" j
SACC式Simple Asset ChainCode的缩写,表示简单资产链码。它在账本中模拟一个 键/值存储。当初次部署后,需要一个初始的键/值对。SACC链码定义了两个方法: Set()和Get(),分别用来设置或读取某个键的值。1 r2 G$ H/ U" H% J# i- z
好了,现在我们可以开始演示Fabric 1.4和Fabric 2.0中链码操作的不同了。& U4 d5 V' {+ o- r0 l
3、Fabric 1.4.4链码操作演示我们首先以无链码方式(使用-n选项)启动First Network,然后我们再加载 SACC链码以便聚焦链码的生命周期。7 X/ Z* { n$ T* N7 n
下面是演示步骤:' y% F) E/ u& b% ]
无链码方式启动First Network在指定的peer节点上安装SACC链码在mychannel通道上实例化SACC链码并查询结果调用set()设置新值并从另一个peer节点查询结果STEP 1:首先启动First Network:
1 s% H( T5 [$ N3 R+ x 2 | cd fabric-samples/first-network ./byfn.sh up -n |
现在我们可以开始链码部署操作。3 i/ K* F6 Y u9 ]
STEP 2:在指定peer节点上安装链码
这里我们跳过打包环节,直接在目标节点peer.org1和peer0.org2上安装链码, 因为在这个演示中我们只需要这两个节点进行链码调用和查询。3 [4 t6 @" q, |3 H/ x; ~) p
1# u3 p. F/ H( p 2 3 4& o" D! c n- p0 `8 K5 n( | 5( Z4 ]4 x' c! Z3 e/ h" E+ h' a* z9 i* N 6 7( ?, a# m; s8 N* c; H 8 9 107 v" O9 V( f9 K( { H3 | | # peer0.org16 U! B- \* G9 k! f* ~$ r6 c& J9 l9 E docker exec cli peer chaincode install -n mycc -v 1 \ -p github.com/chaincode/sacc, Z! f |7 P6 i$ H$ R$ T # 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 \, i$ w* m2 R2 x/ i cli peer chaincode install -n mycc -v 1 -p github.com/chaincode/sacc |
STEP 3:在通道mychannel上实例化链码并查询7 u2 P$ P6 o8 J5 r C
注意在sacc链码中有Init()代码。当我们实例化链码时,我们需要 提供Init()所需的参数:# z+ j1 p$ d7 |
17 \0 ], U/ E* L' j$ J N3 u, K 2 3 4 | docker exec cli peer chaincode instantiate -o orderer.example.com:7050 --tls \2 j* g6 E& R0 F) \, X: @, ? --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。9 \* {+ ~$ d1 N# D( V# I
在链码实例化之后,我们可以查询:% I7 p& b. |# |- G
1 | docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}'$ J. r* c+ U3 T. \# X9 |9 F |
STEP 4:调用set()设置新值并从另一个节点查询5 D1 n& @: I" C
出于演示目的,我们在peer0.org1上调用set(),然后在peer0.org2上 调用get(),以此说明链码是否工作正常。
1) ^: h2 E# {; }, B. I- P4 K7 _ 2 3' T. {9 A1 h4 |7 [ 4 5 69 n/ R1 T; D2 n/ H 7; p! e! B& b2 J; F. e- @0 m! f 8 9 10 11 12 13 14 | # peer0.org1& X" R0 | N, y docker exec cli peer chaincode invoke -o orderer.example.com:7050 --tls \) ~: u6 Z' y# x/ T --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 \4 K' Q/ o' f k0 F% O& V* y3 S0 V2 ~ --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 \. h. G. F: ~0 ^+ B -C mychannel -n mycc -c '{"Args":["set","name","Peter"]}'% S* @9 P# N* Y5 R% \6 O1 P # peer0.org21 e% _3 K- Y% r% D3 m 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 \- y& ]& {0 c! P -e CORE_PEER_LOCALMSPID="Org2MSP" \/ ~2 K. O# Y4 r: s5 O -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"]}' |
4、Fabric 2.0链码操作演示类似的,在Fairc 2.0.0中,我们也先以无链码方式启动First Network, 然后再启动SACC链码以便聚焦链码的生命周期。
下面是演示步骤:5 }% |: m. B% L4 Y3 D
无链码方式启动First Network打包SACC链码在指定peer节点上安装SACC链码包机构审批链码在mychannel通道上提交链码调用SACC链码的Init方法调用SACC链码的set方法并从另一个peer节点查询结果STEP 1:以无链码方式启动First Network:
1+ |, y3 h1 U, w9 F# \) _ 2 | cd fabric-samples/first-network ./byfn.sh up -n1 E. j2 Q- |% [3 {2 q! | C+ g |
STEP 2:打包SACC链码/ C' q9 C. E7 r6 U
首先我们处理依赖问题:
1 2 3 | cd fabric-sample/chaincode/sacc+ {; ?) C0 T. [7 X1 e5 m GO111MODULE=on go mod vendor1 p$ Z' u, i( D* p cd fabric-sample/first-network, k! h: I- j. z( e# [7 E4 s |
19 \ E: A" E. S/ ]# B+ z9 W 2: [3 U0 G& E" n2 p 31 ~! t& D* j4 x/ r | docker exec cli peer lifecycle chaincode package sacc.tar.gz \# ]" l+ k M$ ]. L& x, H. r1 R1 y --path github.com/hyperledger/fabric-samples/chaincode/sacc/ \ --label sacc_15 }' ?9 Q) O' c |
STEP 3:在指定peer节点上安装SACC链码包
现在我们在peer0.org1和peer0.org2上安装SACC练马报,因为在这个 演示中我们只需要使用这两个节点进行链码调用和查询。( b* {: q1 N; T$ D, G
1 2 36 \0 a* K \! x 4 5 62 D+ | V0 {0 t8 U: P% c 7* _. a* B/ ~4 i# Y1 _ 8, d8 h, g ?( l6 X 9 10 | # peer0.org1; M1 X5 i/ f+ g: V docker exec cli peer lifecycle chaincode install sacc.tar.gz* J ]/ L6 w, \9 i8 \! V. Q # peer0.org2) M) U" Z+ _# s* b8 K" ~5 \ 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 \2 S: N" [' Z6 K8 P* [ -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \: d& G8 M; \- O( [1 V/ C5 X& I0 F -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。+ s6 T2 ~4 P# F( _9 I' S; u6 a
我们可以使用peer lifecycle chaincode queryinstalled命令随时 检查节点上的链码安装情况,如果我们需要找出链码包的标识ID,这个命令 会很有用。
1 V6 L* n( l# W1 @% H 26 d7 V) O1 i, e# S 3 4 5( U" N2 f8 U9 q! }' k 6) e7 X) Q a3 p( s& \9 ` 7, E7 Z8 X5 w. ^' K v 84 b6 C$ ?; |9 b0 P k/ R" O 9 10 | # peer0.org1* g( l- l( D8 Z5 c+ X0 A6 \- S& t* ? docker exec cli peer lifecycle chaincode queryinstalled # peer0.org2 docker exec \: F" d2 k l8 t3 ~6 z4 ~ -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \4 E8 M9 J! R3 ~* x -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 queryinstalled |
根据默认策略,需要超过半数的机构审批链码后才能向通道提交链码, 具体可参考configtx.yaml中的Application/Policies/LifecycleEndorsement部分。 目前的设置中包含两个机构,因此需要两个机构同时批准链码。
首先是Org1批准链码:
1 2- [( i. S. z; G* m& M 3 4 55 I8 W5 y' {/ x7 M* _' B3 x7 g, @ | docker exec cli peer lifecycle chaincode approveformyorg \& z1 a+ ]( G h; E; b --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 \ --channelID mychannel --name mycc --version 1 \* B0 H7 b- t. L --init-required --sequence 1 --waitForEvent --package-id ${PACKAGE_ID} |
如果我们现在看下peer节点的日志,可以看到出了新块#3。: Y5 d" o1 Y8 T, m+ B7 N% C% Z
类似的,我们让Org2批准链码:
1 2 3& m0 L+ s& R0 X3 v. ^8 S 46 { G( y1 Y. v1 G8 z2 b 5 64 O! u; z& E0 y# d6 ^' ? 7- a# E, G6 q/ S8 j r; w 89 ~; Z5 I6 {: n! M1 Y$ [3 G 9; |: L2 G0 h2 R$ m% F+ W 10. K. v8 ?, N/ C# z$ J4 N | docker exec \$ T& B; G5 T5 N -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \! a6 y3 S( z+ k( U -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \& K3 a/ |$ H5 n2 e9 b -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 approveformyorg \+ j2 O: s! L; p! o8 Z! W --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 \ --channelID mychannel --name mycc --version 1 --init-required \ --sequence 1 --waitForEvent --package-id ${PACKAGE_ID}, o# w7 J: a, N& L |
不出意外,可以看到出了新块block#4:" U5 F1 a2 G8 ]* Y
注意我们在approval命令中指定了init相关的参数,以便向SACC链码的 Init方法传入所需的参数。. b% ?. S! c2 k# E. _- x
可以随时使用如下命令查看链码的提交状态:! `6 Y3 S0 W' ~7 b6 x$ Y5 P# O+ K7 O
1$ }+ _# q& S6 @1 E5 L- V) F 2* A4 L; G# P' T4 t9 J2 r | docker exec cli peer lifecycle chaincode checkcommitreadiness \ --channelID mychannel --name mycc --version 1 --sequence 1 --output json |
两个机构都已经批准了链码,现在可以提交了。
STEP 5:向通道mychannel提交链码
链码提交可以在一个peer节点上完成:0 F! X. O; B% \0 t0 T" c+ M
1$ e9 H8 l! V) r 2 3 4 5 6 7 8 | docker exec cli peer lifecycle chaincode commit -o orderer.example.com:7050 \* `- r7 H- u9 A4 g8 ~" {$ v/ q --tls \% G' f& l; l- B5 h3 d --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 \" o' e3 c1 O0 c& R --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \; ~+ p& P& v, `. ^2 z' S; a0 h --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 \( P; f& p3 B- z5 W5 b; d8 G7 t: A --channelID mychannel --name mycc --version 1 --sequence 1 --init-required& q& Z6 E0 j, f2 @ |
可以看到出了新块#5:
注意我们在commit命令中已经包含了init所需的参数。: e: o; h; o1 A- ^
同样,我们可以使用querycommited命令来查看链码的提交状态:$ H6 W; l; O% ]4 \% g9 k
1 | docker exec cli peer lifecycle chaincode querycommitted --channelID mychannel --name mycc |
在链码提交到通道之后,链码的生命周期就完成了,链码已经可以访问。 现在我们回到链码的调用和查询,这和之前的版本是一致的。: v& B0 u! E3 {) O
STEP 6:调用链码的Init方法/ j, |8 g! a/ |# y- i
SACC链码的Init方法需要首先调用。7 W+ w6 l3 ]0 c+ \
1 21 Q0 w2 T" A3 C) @ 37 L$ K' U5 Q) ]/ W6 u- I* }0 N# p 4 5 62 Z3 r+ q) _( j, N! v, Y1 c9 ?7 Q 7 _( |0 ]) B) J% l! k 8 J" V: z0 L" _6 |) }% ^ | docker exec cli peer chaincode invoke -o orderer.example.com:7050 \+ `6 }1 c" [4 r1 ~# j/ ]. \ --tls \: l8 M9 p8 p- ~ --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \' N% Z9 z9 m4 z7 S --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 \0 V3 s! ?0 ?" L2 C) d+ ^ --peerAddresses peer0.org2.example.com:9051 \0 ~! z X8 M8 R: L0 j' g1 N! I --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"]}'* y- p, q) }1 p, k$ Y |
现在可以查询 链码:
1 | docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["get","name"]}' |
STEP 7:调用链码的set()方法并从另一个peer节点查询
和之前一样,我们在peer0.org1上调用链码的set()方法,在peer0.org2上 进行查询:
1 2 3 4! y$ @+ ]2 l4 Y' X& J 5 6 7 8; j: q4 u' [1 w 9 10+ f7 @$ d( Y5 _/ R! ^1 U 11. N6 \7 K+ A3 Q5 q H' H* s" \ 12% a' o1 ]2 k& d 13% z( `7 G7 }# e% J, ? 144 n0 Y. U% }% p" c2 z; M 15 162 b' D6 V. r: x: F 17, a+ i) @( r2 Y, v" t 18 | # peer0.org12 ^/ `( w/ d4 v E: Z0 |" D docker exec cli peer chaincode invoke \4 L( s5 q) o" U$ M -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 \ --peerAddresses peer0.org1.example.com:7051 \& t# r! ]/ U. w W! 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 \& U% v. l8 O+ M0 S, _9 m i: ~ --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"]}'# P; [, z" C# M Q ! X5 C% @& @3 a; x, I # peer0.org21 v2 V. t0 c: d0 m9 e docker exec \5 `! b2 y1 B6 M. U -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \( [- T; O+ V; B6 F( e9 A- K -e CORE_PEER_ADDRESS=peer0.org2.example.com:9051 \+ ?* I3 U1 c& N -e CORE_PEER_LOCALMSPID="Org2MSP" \$ r- x- l C3 U, s' t -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"]}' |
一切正常。