Repository: securekey/fabric-examples Branch: master Commit: 600b6db41b10 Files: 63 Total size: 310.4 KB Directory structure: gitextract_8xm2cptt/ ├── .gitignore ├── .gitreview ├── README.md └── fabric-cli/ ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── cmd/ │ └── fabric-cli/ │ ├── action/ │ │ ├── action.go │ │ └── svcproviderfactory.go │ ├── chaincode/ │ │ ├── chaincodecmd.go │ │ ├── getinfocmd.go │ │ ├── installcmd.go │ │ ├── instantiatecmd.go │ │ ├── invokecmd.go │ │ ├── invokeerror/ │ │ │ └── invokeerror.go │ │ ├── invoketask/ │ │ │ └── invoketask.go │ │ ├── multitask/ │ │ │ └── multitask.go │ │ ├── querycmd.go │ │ ├── querytask/ │ │ │ └── querytask.go │ │ ├── task/ │ │ │ └── task.go │ │ ├── upgradecmd.go │ │ └── utils/ │ │ ├── test.json │ │ ├── util.go │ │ └── util_test.go │ ├── channel/ │ │ ├── channelcmd.go │ │ ├── channelcreatecmd.go │ │ └── channeljoincmd.go │ ├── cmd/ │ │ └── fabric-cli.go │ ├── config/ │ │ └── config.go │ ├── event/ │ │ ├── eventcmd.go │ │ ├── inputevent.go │ │ ├── listenblockcmd.go │ │ ├── listencccmd.go │ │ ├── listenfilteredblockcmd.go │ │ └── listentxcmd.go │ ├── executor/ │ │ ├── executor.go │ │ └── worker/ │ │ ├── worker.go │ │ └── workerpool.go │ ├── fabric-cli.go │ ├── go.mod │ ├── go.sum │ ├── printer/ │ │ ├── blockprinter.go │ │ ├── formatter.go │ │ ├── printer.go │ │ ├── protoutils.go │ │ └── writer.go │ └── query/ │ ├── queryblockcmd.go │ ├── querychannelscmd.go │ ├── querycmd.go │ ├── queryinfocmd.go │ ├── queryinstalledcmd.go │ ├── querylocalpeerscmd.go │ ├── querypeerscmd.go │ └── querytxcmd.go └── test/ ├── fixtures/ │ ├── config/ │ │ ├── config_test_local.yaml │ │ └── pvtdatacollection.json │ └── testdata/ │ └── src/ │ ├── github.com/ │ │ └── securekey/ │ │ ├── example2_cc/ │ │ │ └── example2_cc.go │ │ └── example_cc/ │ │ └── example_cc.go │ ├── go.mod │ └── go.sum └── integration/ ├── fabric-cli_test.go ├── go.mod └── go.sum ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # # Copyright SecureKey Technologies Inc. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # *.db *report.xml .DS_Store .vscode debug.test vendor/ .idea/ /fabric-cli/cmd/fabric-cli/fabric-cli ================================================ FILE: .gitreview ================================================ [gerrit] host=gerrit.securekey.com port=29418 project=fabric-examples ================================================ FILE: README.md ================================================ fabric-examples ================================================ FILE: fabric-cli/.gitignore ================================================ # # Copyright SecureKey Technologies Inc. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # vendor/ fabric-sdk-go/ ================================================ FILE: fabric-cli/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: fabric-cli/Makefile ================================================ # # Copyright SecureKey Technologies Inc. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # # Supported Targets: # # populate-sdk: retrieves all fabric-sdk-files required for tests # fabric-sdk-go-pin: populates only upstream files (not included in git) # example-network: start the example fabric network # example-network-clean: stops any running network and cleans up the artifacts # clean: removes all generated artifacts # # Tool commands (overridable) GO_CMD ?= go GO_DEP_CMD ?= dep DOCKER_CMD ?= docker DOCKER_COMPOSE_CMD ?= docker-compose # fabric-sdk-go version (overridable) FABRIC_SDK_GO_BRANCH ?= master FABRIC_SDK_GO_COMMIT ?= 8f3d32c9d1a66f88d405c9f5335870c5277f773a # Test fixture paths FIXTURE_DOCKERENV_PATH := fabric-sdk-go/test/fixtures/dockerenv .PHONY: polulate-sdk populate-sdk: fabric-sdk-go-pin fabric-sdk-go-populate .PHONY: fabric-sdk-go-pin fabric-sdk-go-pin: @echo "Pinning fabric-sdk-go ..." @UPSTREAM_COMMIT=$(FABRIC_SDK_GO_COMMIT) UPSTREAM_BRANCH=$(FABRIC_SDK_GO_BRANCH) scripts/fabric-sdk-go/apply_upstream.sh .PHONY: fabric-sdk-go-populate fabric-sdk-go-populate: @scripts/fabric-sdk-go/populate.sh .PHONY: clean clean: example-network-clean rm -Rf vendor rm -Rf fabric-sdk-go .PHONY: example-network example-network: @cd ./fabric-sdk-go && \ make dockerenv-stable-up .PHONY: example-network-clean example-network-clean: @DOCKER_CMD=$(DOCKER_CMD) scripts/fabric-sdk-go/example-network-clean.sh ================================================ FILE: fabric-cli/README.md ================================================ # Fabric CLI Sample Application Fabric CLI is a sample command-line interface built using Fabric SDK GO. It provides the following functionality: Channel: - Create - Create a channel - Join - Join a peer to a channel Query: - Info - Displays information about the block, including the block height - Block - Displays the contents of a given block - Tx - Displays the contents of a transaction within a block - Channels - Displays all channels for a peer - Installed - Displays the chaincodes installed on a peer - Peers - Displays the discovered peers on a channel - Local Peers - Displays the discovered local peers in an org Chaincode: - Install - Installs chaincode - Instantiate - Instantiates chaincode - Upgrade - Upgrades chaincode - Invoke - Invokes chaincode with a transaction proposal and a commit - Query - Invokes chaincode without a commit - Info - Retrieves details about the chaincode Events: - Listen Block - Listens for block events and displays the block when a new block is created - Listen Filtered Block - Listens for filtered block events and displays the filtered block when a new block is created - Listen TX - Listens for transaction events - Listen CC - Listens for chaincode events for a specified chaincode ## Running NOTE: If using Go 1.11 or 1.12, you'll need to set the following environment variable: ```bash export GO111MODULE=on ``` Run the client: ```bash go run fabric-cli.go [options] ``` To display the available commands/options: ```bash go run fabric-cli.go ``` ## Compatability This example is compatible with the following Hyperledger Fabric/SDK commit levels: - fabric: v1.3.0, v1.4, v2.0 - fabric-sdk-go: master:33f4504ff8f169ebddd822443eadbe1bf4b96887 ### Quick Tour Start the example HLF network locally ```bash make populate-sdk make example-network ``` Open another shell and go to the CLI directory ```bash cd $GOPATH/src/github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli ``` Create channel 'orgchannel' and add anchor peers ```bash go run fabric-cli.go channel create --cid orgchannel --txfile ../../fabric-sdk-go/test/fixtures/fabric/v1.4/channel/orgchannel.tx --config ../../test/fixtures/config/config_test_local.yaml go run fabric-cli.go channel create --cid orgchannel --txfile ../../fabric-sdk-go/test/fixtures/fabric/v1.4/channel/orgchannelOrg1MSPanchors.tx --config ../../test/fixtures/config/config_test_local.yaml --orgid org1 go run fabric-cli.go channel create --cid orgchannel --txfile ../../fabric-sdk-go/test/fixtures/fabric/v1.4/channel/orgchannelOrg2MSPanchors.tx --config ../../test/fixtures/config/config_test_local.yaml --orgid org2 ``` Join all peers to channel 'orgchannel' ```bash go run fabric-cli.go channel join --cid orgchannel --config ../../test/fixtures/config/config_test_local.yaml ``` Install ExampleCC chaincode on all peers ```bash go run fabric-cli.go chaincode install --ccp=github.com/securekey/example_cc --ccid=ExampleCC --v v0 --gopath ../../test/fixtures/testdata --config ../../test/fixtures/config/config_test_local.yaml ``` Instantiate ExampleCC chaincode with endorsement policy AND('Org1MSP.member','Org2MSP.member') ```bash go run fabric-cli.go chaincode instantiate --cid orgchannel --ccp=github.com/securekey/example_cc --ccid ExampleCC --v v0 --args '{"Args":["A","1","B","2"]}' --policy "AND('Org1MSP.member','Org2MSP.member')" --config ../../test/fixtures/config/config_test_local.yaml ``` Query ExampleCC chaincode on a set of peers ```bash go run fabric-cli.go chaincode query --cid orgchannel --ccid ExampleCC --args '{"Func":"query","Args":["A"]}' --peer localhost:7051,localhost:8051 --payload --config ../../test/fixtures/config/config_test_local.yaml ``` Listen for block events: ```bash go run fabric-cli.go event listenblock --cid orgchannel --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` Then invoke ExampleCC chaincode in another shell and observe block events in the first shell. ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=ExampleCC --args '{"Func":"move","Args":["A","B","1"]}' --peer localhost:7051,localhost:8051 --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` To clean up example network artifacts run ```bash make example-network-clean ``` To clean up all generated artifacts run ```bash make clean ``` ## CLI examples ### Channel #### Create a channel ```bash go run fabric-cli.go channel create --cid orgchannel --txfile ../../fabric-sdk-go/test/fixtures/fabric/v1.4/channel/orgchannel.tx --config ../../test/fixtures/config/config_test_local.yaml ``` #### Update anchor peers ```bash go run fabric-cli.go channel create --cid orgchannel --txfile ../../fabric-sdk-go/test/fixtures/fabric/v1.4/channel/orgchannelOrg1MSPanchors.tx --orgid=org1 --config ../../test/fixtures/config/config_test_local.yaml go run fabric-cli.go channel create --cid orgchannel --txfile ../../fabric-sdk-go/test/fixtures/fabric/v1.4/channel/orgchannelOrg2MSPanchors.tx --orgid=org2 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Join a peer to a channel ```bash go run fabric-cli.go channel join --cid orgchannel --peer localhost:7051 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Join all peers in org1 to a channel ```bash go run fabric-cli.go channel join --cid orgchannel --orgid org1 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Join all peers to a channel ```bash go run fabric-cli.go channel join --cid orgchannel --config ../../test/fixtures/config/config_test_local.yaml ``` ### Query #### Query info ```bash go run fabric-cli.go query info --cid orgchannel --config ../../test/fixtures/config/config_test_local.yaml ``` #### Query block by block number ```bash go run fabric-cli.go query block --cid orgchannel --num 0 --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Query block by hash (replace the example hash with a valid hash, e.g. using the output from query info) ```bash go run fabric-cli.go query block --cid orgchannel --hash BNNsxK_Xyz2d3Yj2g6M2t3aOYkHCxvoPeIGmTWdOJ9w --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Query block output in JSON format ```bash go run fabric-cli.go query block --cid orgchannel --num 0 --format json --config ../../test/fixtures/config/config_test_local.yaml ``` #### Query transaction (replace txid with a valid transaction, e.g. using the output from query block) ```bash go run fabric-cli.go query tx --cid orgchannel --txid 0ed409872e0e6a6aa745df10d5e71e33d7e160b84519c2ad89281e65b6561364 --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Query channels joined by a peer ```bash go run fabric-cli.go query channels --peer localhost:7051 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Query installed chaincodes on a peer ```bash go run fabric-cli.go query installed --peer localhost:7051 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Query discovered peers on a channel ```bash go run fabric-cli.go query peers --cid orgchannel --config ../../test/fixtures/config/config_test_local.yaml ``` #### Query discovered peers in an org ```bash go run fabric-cli.go query localpeers --orgid org1 --config ../../test/fixtures/config/config_test_local.yaml ``` ## Chaincode ### Install Chaincode #### Install chaincode on a peer ```bash go run fabric-cli.go chaincode install --peer localhost:7051 --ccp=github.com/securekey/example_cc --gopath ../../test/fixtures/testdata --ccid=examplecc --v v0 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Install chaincode on all peers of org1 ```bash go run fabric-cli.go chaincode install --orgid org1 --ccp=github.com/securekey/example_cc --gopath ../../test/fixtures/testdata --ccid=examplecc --v v0 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Install chaincode on all peers ```bash go run fabric-cli.go chaincode install --ccp=github.com/securekey/example_cc --gopath ../../test/fixtures/testdata --ccid=examplecc --v v0 --config ../../test/fixtures/config/config_test_local.yaml ``` ### Instantiate and Upgrade Chaincode #### Instantiate chaincode with default endorsement policy (any one) ```bash go run fabric-cli.go chaincode instantiate --cid orgchannel --ccp github.com/securekey/example_cc --ccid examplecc --v v0 --args='{"Args":["A","1","B","2"]}' --config ../../test/fixtures/config/config_test_local.yaml ``` #### Instantiate chaincode with specified endorsement policy ```bash go run fabric-cli.go chaincode instantiate --cid orgchannel --ccp github.com/securekey/example_cc --ccid examplecc --v v0 --args='{"Args":["A","1","B","2"]}' --policy "AND('Org1MSP.member','Org2MSP.member')" --config ../../test/fixtures/config/config_test_local.yaml ``` #### Instantiate chaincode with specified private data collection configuration (Fabric 1.2 and greater) ```bash go run fabric-cli.go chaincode install --ccp=github.com/securekey/example2_cc --gopath ../../test/fixtures/testdata --ccid=example2cc --v v0 --config ../../test/fixtures/config/config_test_local.yaml go run fabric-cli.go chaincode instantiate --cid orgchannel --ccp github.com/securekey/example2_cc --ccid example2cc --v v0 --policy "AND('Org1MSP.member','Org2MSP.member')" --collconfig ../../test/fixtures/config/pvtdatacollection.json --config ../../test/fixtures/config/config_test_local.yaml ``` #### Upgrade chaincode ```bash go run fabric-cli.go chaincode install --cid=orgchannel --ccp=github.com/securekey/example_cc --gopath ../../test/fixtures/testdata --ccid=examplecc --v v1 --config ../../test/fixtures/config/config_test_local.yaml go run fabric-cli.go chaincode upgrade --cid orgchannel --ccp github.com/securekey/example_cc --ccid examplecc --v v1 --args='{"Args":["A","1","B","2"]}' --policy "OutOf(2,'Org1MSP.member','Org2MSP.member')" --config ../../test/fixtures/config/config_test_local.yaml ``` ### Chaincode Info #### Retrieve chaincode deployment info ```bash go run fabric-cli.go chaincode info --cid orgchannel --ccid examplecc --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` ### Query Chaincode #### Query chaincode on a set of peers ```bash go run fabric-cli.go chaincode query --cid orgchannel --ccid=examplecc --args='{"Func":"query","Args":["A"]}' --peer localhost:7051,localhost:8051 --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Query chaincode and view payloads only ```bash go run fabric-cli.go chaincode query --cid orgchannel --ccid=examplecc --args='{"Func":"query","Args":["A"]}' --peer localhost:7051,localhost:8051 --payload --config ../../test/fixtures/config/config_test_local.yaml ``` ### Invoke Chaincode #### Invoke chaincode on all peers in org1 ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=examplecc --args='{"Func":"move","Args":["A","B","1"]}' --orgid org1 --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Invoke chaincode using a 'dynamic' selection provider that chooses a minimal set of peers required to satisfy the endorsement policy of the chaincode ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=examplecc --args='{"Func":"move","Args":["A","B","1"]}' --selectprovider=dynamic --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Invoke chaincode using Fabric's discovery service to choose a minimal set of peers required to satisfy the endorsement policy of the chaincode (Requires Fabric >=1.2) ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=examplecc --args='{"Func":"move","Args":["A","B","1"]}' --selectprovider=fabric --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Invoke chaincode using a selection provider automatically determined from channel capabilities ('dynamic' for v1.1; 'fabric' for >=v1.2) ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=examplecc --args='{"Func":"move","Args":["A","B","1"]}' --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Invoke chaincode 5 times ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=examplecc --args='{"Func":"move","Args":["A","B","1"]}' --iterations 5 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Invoke chaincode 100 times in 8 Go routines with a maximum of 5 attempts for each invocation (in case the invocation fails) ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=examplecc --args='{"Func":"move","Args":["A","B","1"]}' --iterations 100 --concurrency 8 --attempts 5 --backoff 1000 --backofffactor 1.5 --maxbackoff 5000 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Invoke chaincode with two sets of args, 100 times each in 8 Go routines with 3 attempts for each invocation (in case the invocation fails) ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=examplecc --args='[{"Func":"move","Args":["A","B","1"]},{"Func":"move","Args":["B","A","1"]}]' --iterations 100 --concurrency 8 --attempts=3 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Invoke chaincode 100 times in 8 Go routines using randomly generated keys, values, and variables ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=example2cc --args='[{"Func":"putprivate","Args":["$set(coll,coll1)","$set(key,Key_$rand(500))","Val_$rand(1000)"]},{"Func":"getprivate","Args":["${coll}","${key}"]}]' --iterations 100 --concurrency 8 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Invoke chaincode 100 times in 8 Go routines using sequentially generated keys and large values ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=example2cc --args='{"Func":"putprivate","Args":["coll1","Key_$seq()","Val_$pad(500,X)"]}' --iterations 100 --concurrency 8 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Invoke chaincode 100 times in 8 Go routines using randomly generated keys and random size values ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=example2cc --args='{"Func":"putprivate","Args":["coll1","Key_$rand(500)","Val_$pad($rand(500),X)"]}' --iterations 100 --concurrency 8 --config ../../test/fixtures/config/config_test_local.yaml ``` #### Invoke a chaincode using the contents of a file as a value ```bash go run fabric-cli.go chaincode invoke --cid orgchannel --ccid=example2cc --args='{"Func":"put","Args":["coll1","Key_1","$file(./chaincode/utils/test.json)"]}' --config ../../test/fixtures/config/config_test_local.yaml ``` ## Event ### Block Events ### Listen for block events on a specific peer (output in JSON) ```bash go run fabric-cli.go event listenblock --cid orgchannel --peer localhost:7051 --format json --config ../../test/fixtures/config/config_test_local.yaml ``` ### Listen for block events starting from block number 20 ```bash go run fabric-cli.go event listenblock --cid orgchannel --peer localhost:7051 --seek from --num 20 --base64 --config ../../test/fixtures/config/config_test_local.yaml ``` ### Listen for filtered block events (output in JSON) ```bash go run fabric-cli.go event listenfilteredblock --cid orgchannel --format json --config ../../test/fixtures/config/config_test_local.yaml ``` ### Listen for chaincode events ```bash go run fabric-cli.go event listencc --cid orgchannel --ccid=examplecc --event=.* --config ../../test/fixtures/config/config_test_local.yaml ``` ### Listen for tx event ```bash go run fabric-cli.go event listentx --cid orgchannel --txid --config ../../test/fixtures/config/config_test_local.yaml ``` ================================================ FILE: fabric-cli/cmd/fabric-cli/action/action.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package action import ( "encoding/json" "math/rand" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/core" "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk/factory/defcore" "github.com/pkg/errors" "strings" "io" "fmt" "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" "github.com/hyperledger/fabric-sdk-go/pkg/client/event" "github.com/hyperledger/fabric-sdk-go/pkg/client/ledger" "github.com/hyperledger/fabric-sdk-go/pkg/client/msp" "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" "github.com/hyperledger/fabric-sdk-go/pkg/common/logging" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" mspapi "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/msp" contextImpl "github.com/hyperledger/fabric-sdk-go/pkg/context" cryptosuiteimpl "github.com/hyperledger/fabric-sdk-go/pkg/core/cryptosuite/bccsp/multisuite" "github.com/hyperledger/fabric-sdk-go/pkg/fab/orderer" "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/printer" "github.com/spf13/pflag" ) const ( defaultUser = "User1" // pre-enrolled user adminUser = "Admin" ) // ArgStruct is used for marshalling arguments to chaincode invocations type ArgStruct struct { Func string `json:"Func"` Args []string `json:"Args"` } // Action is the base implementation of the Action interface. type Action struct { flags *pflag.FlagSet sdk *fabsdk.FabricSDK endpointConfig fab.EndpointConfig peersByOrg map[string][]fab.Peer peers []fab.Peer orgIDByPeer map[string]string printer printer.Printer initError error Writer io.Writer sessions map[string]context.ClientProvider } // Initialize initializes the action using the given flags func (action *Action) Initialize(flags *pflag.FlagSet) error { action.sessions = make(map[string]context.ClientProvider) action.flags = flags if err := cliconfig.InitConfig(flags); err != nil { return err } var opts []fabsdk.Option if cliconfig.Config().SelectionProvider() != cliconfig.AutoDetectSelectionProvider { svcPackage, err := newServiceProviderFactory() if err != nil { return err } opts = append(opts, fabsdk.WithServicePkg(svcPackage)) } opts = append(opts, fabsdk.WithCorePkg(&cryptoSuiteProviderFactory{})) sdk, err := fabsdk.New(cliconfig.Provider(), opts...) if err != nil { return errors.Errorf("Error initializing SDK: %s", err) } action.sdk = sdk ctx, err := sdk.Context()() if err != nil { return errors.WithMessage(err, "Error creating anonymous provider") } action.endpointConfig = ctx.EndpointConfig() networkConfig := action.endpointConfig.NetworkConfig() level := levelFromName(cliconfig.Config().LoggingLevel()) logging.SetLevel("", level) action.orgIDByPeer = make(map[string]string) var allPeers []fab.Peer allPeersByOrg := make(map[string][]fab.Peer) for orgID := range networkConfig.Organizations { peersConfig, ok := action.endpointConfig.PeersConfig(orgID) if !ok { return errors.Errorf("failed to get peer configs for org [%s]", orgID) } cliconfig.Config().Logger().Debugf("Peers for org [%s]: %v\n", orgID, peersConfig) var peers []fab.Peer for _, p := range peersConfig { endorser, err := ctx.InfraProvider().CreatePeerFromConfig(&fab.NetworkPeer{PeerConfig: p}) if err != nil { return errors.Wrapf(err, "failed to create peer from config") } peers = append(peers, endorser) action.orgIDByPeer[endorser.URL()] = orgID } allPeersByOrg[orgID] = peers allPeers = append(allPeers, peers...) } if cliconfig.Config().IsLoggingEnabledFor(logging.DEBUG) { cliconfig.Config().Logger().Debug("All Peers:") for orgID, peers := range allPeersByOrg { cliconfig.Config().Logger().Debugf("Org: %s\n", orgID) for i, peer := range peers { cliconfig.Config().Logger().Debugf("-- Peer[%d]: MSPID: %s, URL: %s\n", i, peer.MSPID(), peer.URL()) } } } // Filter peers by specified peers/orgs peers, err := action.getPeers(allPeers, cliconfig.Config().PeerURLs(), cliconfig.Config().OrgIDs()) if err != nil { return err } // Organize peers by orgs peersByOrg := make(map[string][]fab.Peer) cliconfig.Config().Logger().Debugf("Selected Peers:\n") for _, peer := range peers { cliconfig.Config().Logger().Debugf("- URL: %s\n", peer.URL()) orgID := action.orgIDByPeer[peer.URL()] if orgID == "" { return errors.Errorf("unable to find org for peer: %s", peer.URL()) } peersByOrg[orgID] = append(peersByOrg[orgID], peer) } action.peers = peers action.peersByOrg = peersByOrg action.printer = printer.NewBlockPrinterWithOpts( printer.AsOutputFormat(cliconfig.Config().PrintFormat()), printer.AsWriterType(cliconfig.Config().Writer()), &printer.FormatterOpts{Base64Encode: cliconfig.Config().Base64()}) return nil } // Terminate closes any open connections. This function should be called at the end of every command invocation. func (action *Action) Terminate() { if action.sdk != nil { cliconfig.Config().Logger().Info("Closing SDK") action.sdk.Close() } } // Flags returns the flag-set func (action *Action) Flags() *pflag.FlagSet { return action.flags } // EndpointConfig returns the endpoint configuration func (action *Action) EndpointConfig() fab.EndpointConfig { return action.endpointConfig } // ChannelClient creates a new channel client func (action *Action) ChannelClient(...channel.ClientOption) (*channel.Client, error) { user, err := action.User() if err != nil { return nil, errors.Errorf("error getting user: %s", err) } session, err := action.context(user) if err != nil { return nil, errors.Errorf("error getting session for user [%s,%s]: %v", user.Identifier().MSPID, user.Identifier().ID, err) } channelProvider := func() (context.Channel, error) { return contextImpl.NewChannel(session, cliconfig.Config().ChannelID()) } return channel.New(channelProvider) } // OrgAdminChannelClient creates a new channel client for the given org in order to perform administrative functions func (action *Action) OrgAdminChannelClient(orgID string) (*channel.Client, error) { channelID := cliconfig.Config().ChannelID() cliconfig.Config().Logger().Debugf("Creating new channel client for channel [%s] and org [%s] ...", channelID, orgID) user, err := action.OrgAdminUser(orgID) if err != nil { return nil, err } channelClient, err := action.ClientForUser(channelID, user) if err != nil { return nil, errors.Errorf("error creating fabric client: %s", err) } return channelClient, nil } // AdminChannelClient creates a new channel client for performing administrative functions func (action *Action) AdminChannelClient() (*channel.Client, error) { return action.OrgAdminChannelClient(action.OrgID()) } // Printer returns the Printer func (action *Action) Printer() printer.Printer { return action.printer } // LocalContext creates a new local context func (action *Action) LocalContext() (context.Local, error) { user, err := action.User() if err != nil { return nil, errors.Errorf("error getting user: %s", err) } contextProvider, err := action.context(user) if err != nil { return nil, errors.Errorf("error getting context for user [%s,%s]: %v", user.Identifier().MSPID, user.Identifier().ID, err) } return contextImpl.NewLocal(contextProvider) } // ChannelProvider returns the ChannelProvider func (action *Action) ChannelProvider() (context.ChannelProvider, error) { channelID := cliconfig.Config().ChannelID() user, err := action.User() if err != nil { return nil, err } cliconfig.Config().Logger().Debugf("creating channel provider for user [%s] in org [%s]...", user.Identifier().ID, user.Identifier().MSPID) clientContext, err := action.context(user) if err != nil { return nil, errors.Errorf("error getting client context for user [%s,%s]: %v", user.Identifier().MSPID, user.Identifier().ID, err) } channelProvider := func() (context.Channel, error) { return contextImpl.NewChannel(clientContext, channelID) } return channelProvider, nil } // EventClient returns the event hub. func (action *Action) EventClient(opts ...event.ClientOption) (*event.Client, error) { channelProvider, err := action.ChannelProvider() if err != nil { return nil, errors.Errorf("error creating channel provider: %v", err) } c, err := event.New(channelProvider, opts...) if err != nil { return nil, errors.Errorf("error creating new event client: %v", err) } return c, nil } // LedgerClient returns the Fabric client for the current user func (action *Action) LedgerClient() (*ledger.Client, error) { channelProvider, err := action.ChannelProvider() if err != nil { return nil, errors.Errorf("error creating channel provider: %v", err) } c, err := ledger.New(channelProvider) if err != nil { return nil, errors.Errorf("error creating new ledger client: %v", err) } return c, nil } // Peer returns the first peer in the list of selected peers func (action *Action) Peer() fab.Peer { if len(action.peers) == 0 { return nil } return action.peers[0] } // Peers returns the peers func (action *Action) Peers() []fab.Peer { return action.peers } // PeersByOrg returns the peers mapped by organization func (action *Action) PeersByOrg() map[string][]fab.Peer { return action.peersByOrg } // OrgOfPeer returns the organization ID of the given peer func (action *Action) OrgOfPeer(peerURL string) (string, error) { orgID, ok := action.orgIDByPeer[peerURL] if !ok { return "", errors.Errorf("org not found for peer %s", peerURL) } return orgID, nil } // Client returns the Fabric client for the current user func (action *Action) Client(channelID string) (*channel.Client, error) { user, err := action.User() if err != nil { return nil, err } return action.ClientForUser(channelID, user) } // ResourceMgmtClient returns a resource management client for the current user func (action *Action) ResourceMgmtClient() (*resmgmt.Client, error) { return action.ResourceMgmtClientForOrg(action.OrgID()) } // ResourceMgmtClientForOrg returns a resource management client for the given org func (action *Action) ResourceMgmtClientForOrg(orgID string) (*resmgmt.Client, error) { user, err := action.OrgAdminUser(orgID) if err != nil { return nil, err } return action.ResourceMgmtClientForUser(user) } // ClientForUser returns the Channel client for the given user func (action *Action) ClientForUser(channelID string, user mspapi.SigningIdentity) (*channel.Client, error) { cliconfig.Config().Logger().Debugf("create resmgmt client for user [%s] in org [%s]...", user.Identifier().ID, user.Identifier().MSPID) session, err := action.context(user) if err != nil { return nil, errors.Errorf("error getting session for user [%s,%s]: %v", user.Identifier().MSPID, user.Identifier().ID, err) } channelProvider := func() (context.Channel, error) { return contextImpl.NewChannel(session, channelID) } c, err := channel.New(channelProvider) if err != nil { return nil, errors.Errorf("error creating new resmgmt client for user [%s,%s]: %v", user.Identifier().MSPID, user.Identifier().ID, err) } return c, nil } // ResourceMgmtClientForUser returns the Fabric client for the given user func (action *Action) ResourceMgmtClientForUser(user mspapi.SigningIdentity) (*resmgmt.Client, error) { cliconfig.Config().Logger().Debugf("create resmgmt client for user [%s] in org [%s]...", user.Identifier().ID, user.Identifier().MSPID) session, err := action.context(user) if err != nil { return nil, errors.Errorf("error getting session for user [%s,%s]: %v", user.Identifier().MSPID, user.Identifier().ID, err) } c, err := resmgmt.New(session) if err != nil { return nil, errors.Errorf("error creating new resmgmt client for user [%s,%s]: %v", user.Identifier().MSPID, user.Identifier().ID, err) } return c, nil } // ChannelMgmtClientForUser returns the Fabric client for the given user func (action *Action) ChannelMgmtClientForUser(channelID string, user mspapi.SigningIdentity) (*channel.Client, error) { cliconfig.Config().Logger().Debugf("create channel client for user [%s] in org [%s]...", user.Identifier().ID, user.Identifier().MSPID) session, err := action.context(user) if err != nil { return nil, errors.Errorf("error getting session for user [%s,%s]: %v", user.Identifier().MSPID, user.Identifier().ID, err) } channelProvider := func() (context.Channel, error) { return contextImpl.NewChannel(session, channelID) } c, err := channel.New(channelProvider) if err != nil { return nil, errors.Errorf("error creating new channel client for user [%s,%s]: %v", user.Identifier().MSPID, user.Identifier().ID, err) } return c, nil } func (action *Action) context(user mspapi.SigningIdentity) (context.ClientProvider, error) { key := user.Identifier().MSPID + "_" + user.Identifier().ID session := action.sessions[key] if session == nil { session = action.sdk.Context(fabsdk.WithIdentity(user)) cliconfig.Config().Logger().Debugf("Created session for user [%s] in org [%s]", user.Identifier().ID, user.Identifier().MSPID) action.sessions[key] = session } return session, nil } // OrgID returns the organization ID of the first peer in the list of peers func (action *Action) OrgID() string { if len(action.Peers()) == 0 { // This shouldn't happen since we should already have passed validation panic("no peers to choose from!") } peer := action.Peers()[0] orgID, err := action.OrgOfPeer(peer.URL()) if err != nil { // This shouldn't happen since we should already have passed validation panic(err) } return orgID } // GetOrgID returns the organization ID for the given MSP ID func (action *Action) GetOrgID(mspID string) (string, error) { networkConfig := action.endpointConfig.NetworkConfig() for orgID, orgConfig := range networkConfig.Organizations { if mspID == orgConfig.MSPID { return orgID, nil } } return "", errors.Errorf("unable to find org ID for MSP [%s]", mspID) } // User returns the enrolled user. If the user doesn't exist then a new user is enrolled. func (action *Action) User() (mspapi.SigningIdentity, error) { userName := cliconfig.Config().UserName() if userName == "" { userName = defaultUser } return action.OrgUser(action.OrgID(), userName) } func (action *Action) newUser(orgID, username, pwd string) (mspapi.SigningIdentity, error) { cliconfig.Config().Logger().Infof("Enrolling user %s...\n", username) mspClient, err := msp.New(action.sdk.Context(), msp.WithOrg(orgID)) if err != nil { return nil, errors.Errorf("error creating MSP client: %s", err) } cliconfig.Config().Logger().Infof("Creating new user %s...\n", username) err = mspClient.Enroll(username, msp.WithSecret(pwd)) if err != nil { return nil, errors.Errorf("Enroll returned error: %v", err) } user, err := mspClient.GetSigningIdentity(username) if err != nil { return nil, errors.Errorf("GetSigningIdentity returned error: %v", err) } cliconfig.Config().Logger().Infof("Returning user [%s], MSPID [%s]\n", user.Identifier().ID, user.Identifier().MSPID) return user, nil } // OrgUser returns an already enrolled user for the given organization func (action *Action) OrgUser(orgID, username string) (mspapi.SigningIdentity, error) { if username == "" { return nil, errors.Errorf("no username specified") } mspClient, err := msp.New(action.sdk.Context(), msp.WithOrg(orgID)) if err != nil { return nil, errors.Errorf("error creating MSP client: %s", err) } user, err := mspClient.GetSigningIdentity(username) if err != nil { return nil, errors.Errorf("GetSigningIdentity returned error: %v", err) } cliconfig.Config().Logger().Infof("Returning user [%s], MSPID [%s]\n", user.Identifier().ID, user.Identifier().MSPID) return user, nil } // OrgAdminUser returns the pre-enrolled administrative user for the given organization func (action *Action) OrgAdminUser(orgID string) (mspapi.SigningIdentity, error) { userName := cliconfig.Config().UserName() if userName == "" { userName = adminUser } return action.OrgUser(orgID, userName) } // PeerFromURL returns the peer for the given URL func (action *Action) PeerFromURL(url string) (fab.Peer, bool) { for _, peer := range action.peers { if url == peer.URL() { return peer, true } } return nil, false } // Orderers returns all Orderers from the set of configured Orderers func (action *Action) Orderers() ([]fab.Orderer, error) { ordererConfigs := action.endpointConfig.OrderersConfig() ordererURL := cliconfig.Config().OrdererURL() var orderers []fab.Orderer for _, ordererConfig := range ordererConfigs { if ordererURL == "" || ordererConfig.URL == ordererURL { newOrderer, err := orderer.New(action.endpointConfig, orderer.FromOrdererConfig(&ordererConfig)) if err != nil { return nil, errors.WithMessage(err, "creating orderer failed") } orderers = append(orderers, newOrderer) } } return orderers, nil } // RandomOrderer chooses a random Orderer from the set of configured Orderers func (action *Action) RandomOrderer() (fab.Orderer, error) { orderers, err := action.Orderers() if err != nil { return nil, err } if len(orderers) == 0 { return nil, errors.New("No orders found") } return orderers[rand.Intn(len(orderers))], nil } // ArgsArray returns an array of args used in chaincode invocations func ArgsArray() ([]ArgStruct, error) { var argsArray []ArgStruct argBytes := []byte(cliconfig.Config().Args()) if strings.HasPrefix(cliconfig.Config().Args(), "[") { if err := json.Unmarshal(argBytes, &argsArray); err != nil { return nil, errors.Errorf("Error unmarshaling JSON arg string: %v", err) } } else { args := ArgStruct{} if err := json.Unmarshal(argBytes, &args); err != nil { return nil, errors.Errorf("Error unmarshaling JSON arg string: %v", err) } argsArray = append(argsArray, args) } return argsArray, nil } func levelFromName(levelName string) logging.Level { switch levelName { case "CRITICAL": return logging.CRITICAL case "ERROR": return logging.ERROR case "WARNING": return logging.WARNING case "INFO": return logging.INFO case "DEBUG": return logging.DEBUG default: return logging.ERROR } } func (action *Action) getPeers(allPeers []fab.Peer, peerURLs []string, orgIDs []string) ([]fab.Peer, error) { selectAll := false if len(peerURLs) == 0 && len(orgIDs) == 0 { selectAll = true } var selectedPeers []fab.Peer var allPeerURLs []string for _, peer := range allPeers { allPeerURLs = append(allPeerURLs, peer.URL()) orgID := action.orgIDByPeer[peer.URL()] if selectAll || containsString(peerURLs, peer.URL()) || len(peerURLs) == 0 && containsString(orgIDs, orgID) { selectedPeers = append(selectedPeers, peer) } } for _, url := range peerURLs { if !containsString(allPeerURLs, url) { return nil, fmt.Errorf("invalid peer URL: %s", url) } } return selectedPeers, nil } // PeerConfig returns the PeerConfig for the first peer in the current org func (action *Action) PeerConfig() (*fab.PeerConfig, error) { peersConfig, ok := action.endpointConfig.PeersConfig(action.OrgID()) if !ok { return nil, errors.Errorf("Error reading peers config for %s: %v", action.OrgID()) } peer := action.Peer() for _, p := range peersConfig { if peer.URL() == "" || p.URL == peer.URL() { return &p, nil } } return nil, errors.Errorf("No configuration found for peer %s", peer.URL()) } // CreateDiscoveryService returns a new DiscoveryService for the given channel. // This is an implementation of the DiscoveryProvider interface func (action *Action) CreateDiscoveryService(channelID string) (fab.DiscoveryService, error) { return action, nil } // GetPeers returns the peers in context. // This is an implementation of the DiscoveryService interface func (action *Action) GetPeers() ([]fab.Peer, error) { return action.Peers(), nil } func containsString(sarr []string, s string) bool { for _, str := range sarr { if s == str { return true } } return false } // cryptoSuiteProviderFactory will provide custom cryptosuite (bccsp.BCCSP) type cryptoSuiteProviderFactory struct { defcore.ProviderFactory } // CreateCryptoSuiteProvider returns a new default implementation of BCCSP func (f *cryptoSuiteProviderFactory) CreateCryptoSuiteProvider(config core.CryptoSuiteConfig) (core.CryptoSuite, error) { return cryptosuiteimpl.GetSuiteByConfig(config) } ================================================ FILE: fabric-cli/cmd/fabric-cli/action/svcproviderfactory.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package action import ( "github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/dynamicselection" "github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/fabricselection" "github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/staticselection" "github.com/hyperledger/fabric-sdk-go/pkg/common/options" contextApi "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk/factory/defsvc" "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk/provider/chpvdr" "github.com/pkg/errors" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" ) // serviceProviderFactory is configured with either static or dynamic selection provider type serviceProviderFactory struct { defsvc.ProviderFactory } func newServiceProviderFactory() (*serviceProviderFactory, error) { return &serviceProviderFactory{}, nil } type fabricSelectionChannelProvider struct { fab.ChannelProvider service fab.ChannelService selection fab.SelectionService } type fabricSelectionChannelService struct { fab.ChannelService selection fab.SelectionService } // CreateChannelProvider returns a new default implementation of channel provider func (f *serviceProviderFactory) CreateChannelProvider(config fab.EndpointConfig, opts ...options.Opt) (fab.ChannelProvider, error) { chProvider, err := chpvdr.New(config, opts...) if err != nil { return nil, err } return &fabricSelectionChannelProvider{ ChannelProvider: chProvider, }, nil } type closable interface { Close() } // Close frees resources and caches. func (cp *fabricSelectionChannelProvider) Close() { if c, ok := cp.ChannelProvider.(closable); ok { c.Close() } if cp.selection != nil { if c, ok := cp.selection.(closable); ok { c.Close() } } } type providerInit interface { Initialize(providers contextApi.Providers) error } func (cp *fabricSelectionChannelProvider) Initialize(providers contextApi.Providers) error { if init, ok := cp.ChannelProvider.(providerInit); ok { return init.Initialize(providers) } return nil } // ChannelService creates a ChannelService for an identity func (cp *fabricSelectionChannelProvider) ChannelService(ctx fab.ClientContext, channelID string) (fab.ChannelService, error) { chService, err := cp.ChannelProvider.ChannelService(ctx, channelID) if err != nil { return nil, err } discovery, err := chService.Discovery() if err != nil { return nil, err } if cp.selection == nil { switch cliconfig.Config().SelectionProvider() { case cliconfig.StaticSelectionProvider: cliconfig.Config().Logger().Debugf("Using static selection provider.") cp.selection, err = staticselection.NewService(discovery) case cliconfig.DynamicSelectionProvider: cliconfig.Config().Logger().Debugf("Using dynamic selection provider.") cp.selection, err = dynamicselection.NewService(ctx, channelID, discovery) case cliconfig.FabricSelectionProvider: cliconfig.Config().Logger().Debugf("Using Fabric selection provider.") cp.selection, err = fabricselection.New(ctx, channelID, discovery) default: return nil, errors.Errorf("invalid selection provider: %s", cliconfig.Config().SelectionProvider()) } if err != nil { return nil, err } } return &fabricSelectionChannelService{ ChannelService: chService, selection: cp.selection, }, nil } func (cs *fabricSelectionChannelService) Selection() (fab.SelectionService, error) { return cs.selection, nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/chaincodecmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package chaincode import ( cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" ) var chaincodeCmd = &cobra.Command{ Use: "chaincode", Short: "Chaincode commands", Long: "Chaincode commands", Run: func(cmd *cobra.Command, args []string) { cmd.HelpFunc()(cmd, args) }, } // Cmd returns the chaincode command func Cmd() *cobra.Command { cliconfig.InitChannelID(chaincodeCmd.Flags()) chaincodeCmd.AddCommand(getInstallCmd()) chaincodeCmd.AddCommand(getInstantiateCmd()) chaincodeCmd.AddCommand(getInvokeCmd()) chaincodeCmd.AddCommand(getQueryCmd()) chaincodeCmd.AddCommand(getGetInfoCmd()) chaincodeCmd.AddCommand(getUpgradeCmd()) return chaincodeCmd } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/getinfocmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package chaincode import ( "fmt" "strings" "github.com/golang/protobuf/proto" pb "github.com/hyperledger/fabric-protos-go/peer" "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/core/common/ccprovider" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) const ( lifecycleSCC = "lscc" getCCDataFunc = "getccdata" getCollConfigFunc = "getcollectionsconfig" ) var getInfoCmd = &cobra.Command{ Use: "info", Short: "Get chaincode info", Long: "Retrieves details about the chaincode", Run: func(cmd *cobra.Command, args []string) { if cliconfig.Config().ChaincodeID() == "" { fmt.Printf("\nMust specify the chaincode ID\n\n") cmd.HelpFunc()(cmd, args) return } action, err := newGetInfoAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing getAction: %v", err) return } defer action.Terminate() err = action.invoke() if err != nil { cliconfig.Config().Logger().Errorf("Error while running getAction: %v", err) } }, } func getGetInfoCmd() *cobra.Command { flags := getInfoCmd.Flags() cliconfig.InitPeerURL(flags) cliconfig.InitChannelID(flags) cliconfig.InitChaincodeID(flags) return getInfoCmd } type getInfoAction struct { action.Action } func newGetInfoAction(flags *pflag.FlagSet) (*getInfoAction, error) { action := &getInfoAction{} err := action.Initialize(flags) if len(action.Peers()) == 0 { return nil, errors.New("a peer must be specified") } return action, err } func (action *getInfoAction) invoke() error { channelClient, err := action.ChannelClient() if err != nil { return errors.Errorf("error retrieving channel client: %v", err) } ccData, err := action.getCCData(channelClient) if err != nil { return errors.WithMessagef(err, "error querying for chaincode data") } collConfig, err := action.getCollConfig(channelClient) if err != nil { if !strings.Contains(errors.Cause(err).Error(), "collections config not defined for chaincode") { return errors.WithMessagef(err, "error querying for collection config") } } action.Printer().PrintChaincodeData(ccData, collConfig) return nil } func (action *getInfoAction) getCCData(channelClient *channel.Client) (*ccprovider.ChaincodeData, error) { var args [][]byte args = append(args, []byte(cliconfig.Config().ChannelID())) args = append(args, []byte(cliconfig.Config().ChaincodeID())) peer := action.Peer() fmt.Printf("querying chaincode info for %s on peer: %s...\n", cliconfig.Config().ChaincodeID(), peer.URL()) response, err := channelClient.Query( channel.Request{ChaincodeID: lifecycleSCC, Fcn: getCCDataFunc, Args: args}, channel.WithTargetEndpoints(peer.URL())) if err != nil { return nil, errors.Errorf("error querying for chaincode info: %v", err) } ccData := &ccprovider.ChaincodeData{} err = proto.Unmarshal(response.Payload, ccData) if err != nil { return nil, errors.Errorf("error unmarshalling chaincode data: %v", err) } return ccData, nil } func (action *getInfoAction) getCollConfig(channelClient *channel.Client) (*pb.CollectionConfigPackage, error) { var args [][]byte args = append(args, []byte(cliconfig.Config().ChaincodeID())) peer := action.Peer() fmt.Printf("querying collections config for %s on peer: %s...\n", cliconfig.Config().ChaincodeID(), peer.URL()) response, err := channelClient.Query( channel.Request{ChaincodeID: lifecycleSCC, Fcn: getCollConfigFunc, Args: args}, channel.WithTargetEndpoints(peer.URL())) if err != nil { return nil, errors.Errorf("error querying for collections config: %v", err) } collConfig := &pb.CollectionConfigPackage{} err = proto.Unmarshal(response.Payload, collConfig) if err != nil { return nil, errors.Errorf("error unmarshalling collections config: %v", err) } return collConfig, nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/installcmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package chaincode import ( "fmt" "net/http" "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" "github.com/hyperledger/fabric-sdk-go/pkg/fab/ccpackager/gopackager" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var installCmd = &cobra.Command{ Use: "install", Short: "Install chaincode.", Long: "Install chaincode", Run: func(cmd *cobra.Command, args []string) { if cliconfig.Config().ChaincodeID() == "" { fmt.Printf("\nMust specify the chaincode ID\n\n") cmd.HelpFunc()(cmd, args) return } if cliconfig.Config().ChaincodePath() == "" { fmt.Printf("\nMust specify the path of the chaincode\n\n") cmd.HelpFunc()(cmd, args) return } action, err := newInstallAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing installAction: %v", err) return } defer action.Terminate() err = action.invoke() if err != nil { cliconfig.Config().Logger().Errorf("Error while running installAction: %v", err) } }, } func getInstallCmd() *cobra.Command { flags := installCmd.Flags() cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to install the chaincode, e.g. localhost:7051") cliconfig.InitChannelID(flags) cliconfig.InitChaincodeID(flags) cliconfig.InitChaincodePath(flags) cliconfig.InitChaincodeVersion(flags) cliconfig.InitGoPath(flags) return installCmd } type installAction struct { action.Action } func newInstallAction(flags *pflag.FlagSet) (*installAction, error) { action := &installAction{} err := action.Initialize(flags) return action, err } func (action *installAction) invoke() error { var lastErr error for orgID, peers := range action.PeersByOrg() { fmt.Printf("Installing chaincode %s on org[%s] peers:\n", cliconfig.Config().ChaincodeID(), orgID) for _, peer := range peers { fmt.Printf("-- %s\n", peer.URL()) } err := action.installChaincode(orgID, peers) if err != nil { lastErr = err } } return lastErr } func (action *installAction) installChaincode(orgID string, targets []fab.Peer) error { resMgmtClient, err := action.ResourceMgmtClientForOrg(orgID) if err != nil { return err } ccPkg, err := gopackager.NewCCPackage(cliconfig.Config().ChaincodePath(), cliconfig.Config().GoPath()) if err != nil { return err } req := resmgmt.InstallCCRequest{ Name: cliconfig.Config().ChaincodeID(), Path: cliconfig.Config().ChaincodePath(), Version: cliconfig.Config().ChaincodeVersion(), Package: ccPkg, } responses, err := resMgmtClient.InstallCC(req, resmgmt.WithTargets(targets...)) if err != nil { return errors.Errorf("InstallChaincode returned error: %v", err) } ccIDVersion := cliconfig.Config().ChaincodeID() + "." + cliconfig.Config().ChaincodeVersion() var errs []error for _, resp := range responses { if resp.Info == "already installed" { fmt.Printf("Chaincode %s already installed on peer: %s.\n", ccIDVersion, resp.Target) } else if resp.Status != http.StatusOK { errs = append(errs, errors.Errorf("installCC returned error from peer %s: %s", resp.Target, resp.Info)) } else { fmt.Printf("...successfuly installed chaincode %s on peer %s.\n", ccIDVersion, resp.Target) } } if len(errs) > 0 { cliconfig.Config().Logger().Warnf("Errors returned from InstallCC: %v\n", errs) return errs[0] } return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/instantiatecmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package chaincode import ( "encoding/json" "fmt" "io/ioutil" "strings" "github.com/hyperledger/fabric-protos-go/common" pb "github.com/hyperledger/fabric-protos-go/peer" "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/cauthdsl" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var instantiateCmd = &cobra.Command{ Use: "instantiate", Short: "Instantiate chaincode.", Long: "Instantiates the chaincode", Run: func(cmd *cobra.Command, args []string) { if cliconfig.Config().ChaincodeID() == "" { fmt.Printf("\nMust specify the chaincode ID\n\n") cmd.HelpFunc()(cmd, args) return } if cliconfig.Config().ChaincodePath() == "" { fmt.Printf("\nMust specify the path of the chaincode\n\n") cmd.HelpFunc()(cmd, args) return } action, err := newInstantiateAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing instantiateAction: %v", err) return } defer action.Terminate() err = action.invoke() if err != nil { cliconfig.Config().Logger().Errorf("Error while running instantiateAction: %v", err) } }, } func getInstantiateCmd() *cobra.Command { flags := instantiateCmd.Flags() cliconfig.InitPeerURL(flags) cliconfig.InitChannelID(flags) cliconfig.InitChaincodeID(flags) cliconfig.InitChaincodePath(flags) cliconfig.InitChaincodeVersion(flags) cliconfig.InitArgs(flags) cliconfig.InitChaincodePolicy(flags) cliconfig.InitCollectionConfigFile(flags) cliconfig.InitTimeout(flags) return instantiateCmd } type instantiateAction struct { action.Action } func newInstantiateAction(flags *pflag.FlagSet) (*instantiateAction, error) { action := &instantiateAction{} err := action.Initialize(flags) if len(action.Peers()) == 0 { return nil, errors.Errorf("a peer must be specified") } return action, err } func (a *instantiateAction) invoke() error { s := cliconfig.Config().Args() argBytes := []byte(s) args := &action.ArgStruct{} if err := json.Unmarshal(argBytes, args); err != nil { return errors.Errorf("Error unmarshalling JSON arg string: %v", err) } resMgmtClient, err := a.ResourceMgmtClient() if err != nil { return err } cliconfig.Config().Logger().Infof("Sending instantiate %s ...\n", cliconfig.Config().ChaincodeID()) chaincodePolicy, err := a.newChaincodePolicy() if err != nil { return err } // Private Data Collection Configuration // - see fixtures/config/pvtdatacollection.json for sample config file var collConfig []*pb.CollectionConfig collConfigFile := cliconfig.Config().CollectionConfigFile() if collConfigFile != "" { collConfig, err = getCollectionConfigFromFile(cliconfig.Config().CollectionConfigFile()) if err != nil { return errors.Wrapf(err, "error getting private data collection configuration from file [%s]", cliconfig.Config().CollectionConfigFile()) } } req := resmgmt.InstantiateCCRequest{ Name: cliconfig.Config().ChaincodeID(), Path: cliconfig.Config().ChaincodePath(), Version: cliconfig.Config().ChaincodeVersion(), Args: utils.AsBytes(utils.NewContext(), args.Args), Policy: chaincodePolicy, CollConfig: collConfig, } _, err = resMgmtClient.InstantiateCC(cliconfig.Config().ChannelID(), req, resmgmt.WithTargets(a.Peer())) if err != nil { if strings.Contains(err.Error(), "chaincode exists "+cliconfig.Config().ChaincodeID()) { // Ignore cliconfig.Config().Logger().Infof("Chaincode %s already instantiated.", cliconfig.Config().ChaincodeID()) fmt.Printf("...chaincode %s already instantiated.\n", cliconfig.Config().ChaincodeID()) return nil } return errors.Errorf("error instantiating chaincode: %v", err) } fmt.Printf("...successfuly instantiated chaincode %s on channel %s.\n", cliconfig.Config().ChaincodeID(), cliconfig.Config().ChannelID()) return nil } func (a *instantiateAction) newChaincodePolicy() (*common.SignaturePolicyEnvelope, error) { if cliconfig.Config().ChaincodePolicy() != "" { // Create a signature policy from the policy expression passed in return newChaincodePolicy(cliconfig.Config().ChaincodePolicy()) } // Default policy is 'signed by any member' for all known orgs return cauthdsl.AcceptAllPolicy, nil } func newChaincodePolicy(policyString string) (*common.SignaturePolicyEnvelope, error) { ccPolicy, err := cauthdsl.FromString(policyString) if err != nil { return nil, errors.Errorf("invalid chaincode policy [%s]: %s", policyString, err) } return ccPolicy, nil } type collectionConfigJSON struct { Name string `json:"name"` Policy string `json:"policy"` RequiredPeerCount int32 `json:"requiredPeerCount"` MaxPeerCount int32 `json:"maxPeerCount"` } func getCollectionConfigFromFile(ccFile string) ([]*pb.CollectionConfig, error) { fileBytes, err := ioutil.ReadFile(ccFile) if err != nil { return nil, errors.Wrapf(err, "could not read file [%s]", ccFile) } cconf := &[]collectionConfigJSON{} if err = json.Unmarshal(fileBytes, cconf); err != nil { return nil, errors.Wrapf(err, "error parsing collection configuration in file [%s]", ccFile) } return getCollectionConfig(*cconf) } func getCollectionConfig(cconf []collectionConfigJSON) ([]*pb.CollectionConfig, error) { ccarray := make([]*pb.CollectionConfig, 0, len(cconf)) for _, cconfitem := range cconf { p, err := cauthdsl.FromString(cconfitem.Policy) if err != nil { return nil, errors.WithMessage(err, fmt.Sprintf("invalid policy %s", cconfitem.Policy)) } cpc := &pb.CollectionPolicyConfig{ Payload: &pb.CollectionPolicyConfig_SignaturePolicy{ SignaturePolicy: p, }, } cc := &pb.CollectionConfig{ Payload: &pb.CollectionConfig_StaticCollectionConfig{ StaticCollectionConfig: &pb.StaticCollectionConfig{ Name: cconfitem.Name, MemberOrgsPolicy: cpc, RequiredPeerCount: cconfitem.RequiredPeerCount, MaximumPeerCount: cconfitem.MaxPeerCount, }, }, } ccarray = append(ccarray, cc) } return ccarray, nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/invokecmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package chaincode import ( "fmt" "strconv" "sync" "time" "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/invoketask" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/multitask" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/task" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/executor" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var invokeCmd = &cobra.Command{ Use: "invoke", Short: "invoke chaincode.", Long: "invoke chaincode", Run: func(cmd *cobra.Command, args []string) { if cliconfig.Config().ChaincodeID() == "" { fmt.Printf("\nMust specify the chaincode ID\n\n") cmd.HelpFunc()(cmd, args) return } action, err := newInvokeAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing invokeAction: %v", err) return } defer action.Terminate() err = action.invoke() if err != nil { cliconfig.Config().Logger().Errorf("Error while running invokeAction: %v", err) } }, } func getInvokeCmd() *cobra.Command { flags := invokeCmd.Flags() cliconfig.InitPeerURL(flags) cliconfig.InitChannelID(flags) cliconfig.InitChaincodeID(flags) cliconfig.InitArgs(flags) cliconfig.InitIterations(flags) cliconfig.InitSleepTime(flags) cliconfig.InitTimeout(flags) cliconfig.InitPrintPayloadOnly(flags) cliconfig.InitConcurrency(flags) cliconfig.InitMaxAttempts(flags) cliconfig.InitInitialBackoff(flags) cliconfig.InitMaxBackoff(flags) cliconfig.InitBackoffFactor(flags) cliconfig.InitVerbosity(flags) cliconfig.InitSelectionProvider(flags) return invokeCmd } type invokeAction struct { action.Action numInvoked uint32 done chan bool } func newInvokeAction(flags *pflag.FlagSet) (*invokeAction, error) { action := &invokeAction{done: make(chan bool)} err := action.Initialize(flags) return action, err } func (a *invokeAction) invoke() error { channelClient, err := a.ChannelClient() if err != nil { return errors.Errorf("Error getting channel client: %v", err) } argsArray, err := action.ArgsArray() if err != nil { return err } executor := executor.NewConcurrent("Invoke Chaincode", cliconfig.Config().Concurrency()) executor.Start() defer executor.Stop(true) success := 0 var errs []error var successDurations []time.Duration var failDurations []time.Duration var targets []fab.Peer if len(cliconfig.Config().PeerURL()) > 0 || len(cliconfig.Config().OrgIDs()) > 0 { targets = a.Peers() } var wg sync.WaitGroup var mutex sync.RWMutex var tasks []task.Task var taskID int for i := 0; i < cliconfig.Config().Iterations(); i++ { ctxt := utils.NewContext() multiTask := multitask.New(wg.Done) for _, args := range argsArray { taskID++ var startTime time.Time cargs := args task := invoketask.New( ctxt, strconv.Itoa(taskID), channelClient, targets, cliconfig.Config().ChaincodeID(), &cargs, executor, retry.Opts{ Attempts: cliconfig.Config().MaxAttempts(), InitialBackoff: cliconfig.Config().InitialBackoff(), MaxBackoff: cliconfig.Config().MaxBackoff(), BackoffFactor: cliconfig.Config().BackoffFactor(), RetryableCodes: retry.ChannelClientRetryableCodes, }, cliconfig.Config().Verbose() || cliconfig.Config().Iterations() == 1, cliconfig.Config().PrintPayloadOnly(), a.Printer(), func() { startTime = time.Now() }, func(err error) { duration := time.Since(startTime) mutex.Lock() defer mutex.Unlock() if err != nil { errs = append(errs, err) failDurations = append(failDurations, duration) } else { success++ successDurations = append(successDurations, duration) } }) multiTask.Add(task) } tasks = append(tasks, multiTask) } wg.Add(len(tasks)) numInvocations := len(tasks) * len(argsArray) done := make(chan bool) go func() { ticker := time.NewTicker(10 * time.Second) for { select { case <-ticker.C: mutex.RLock() if len(errs) > 0 { fmt.Printf("*** %d failed invocation(s) out of %d\n", len(errs), numInvocations) } fmt.Printf("*** %d successfull invocation(s) out of %d\n", success, numInvocations) mutex.RUnlock() case <-done: return } } }() startTime := time.Now() sleepTime := time.Duration(cliconfig.Config().SleepTime()) * time.Millisecond for _, task := range tasks { if err := executor.Submit(task); err != nil { return errors.Errorf("error submitting task: %s", err) } if sleepTime > 0 { time.Sleep(sleepTime) } } // Wait for all tasks to complete wg.Wait() done <- true duration := time.Now().Sub(startTime) var allErrs []error var attempts int for _, task := range tasks { attempts = attempts + task.Attempts() if task.LastError() != nil { allErrs = append(allErrs, task.LastError()) } } if len(errs) > 0 { fmt.Printf("\n*** %d errors invoking chaincode:\n", len(errs)) for _, err := range errs { fmt.Printf("%s\n", err) } } else if len(allErrs) > 0 { fmt.Printf("\n*** %d transient errors invoking chaincode:\n", len(allErrs)) for _, err := range allErrs { fmt.Printf("%s\n", err) } } if numInvocations/len(argsArray) > 1 { fmt.Printf("\n") fmt.Printf("*** ---------- Summary: ----------\n") fmt.Printf("*** - Invocations: %d\n", numInvocations) fmt.Printf("*** - Concurrency: %d\n", cliconfig.Config().Concurrency()) fmt.Printf("*** - Successfull: %d\n", success) fmt.Printf("*** - Total attempts: %d\n", attempts) fmt.Printf("*** - Duration: %2.2fs\n", duration.Seconds()) fmt.Printf("*** - Rate: %2.2f/s\n", float64(numInvocations)/duration.Seconds()) fmt.Printf("*** - Average: %2.2fs\n", average(append(successDurations, failDurations...))) fmt.Printf("*** - Average Success: %2.2fs\n", average(successDurations)) fmt.Printf("*** - Average Fail: %2.2fs\n", average(failDurations)) fmt.Printf("*** - Min Success: %2.2fs\n", min(successDurations)) fmt.Printf("*** - Max Success: %2.2fs\n", max(successDurations)) fmt.Printf("*** ------------------------------\n") } return nil } func average(durations []time.Duration) float64 { if len(durations) == 0 { return 0 } var total float64 for _, duration := range durations { total += duration.Seconds() } return total / float64(len(durations)) } func min(durations []time.Duration) float64 { min, _ := minMax(durations) return min } func max(durations []time.Duration) float64 { _, max := minMax(durations) return max } func minMax(durations []time.Duration) (min float64, max float64) { for _, duration := range durations { if min == 0 || min > duration.Seconds() { min = duration.Seconds() } if max == 0 || max < duration.Seconds() { max = duration.Seconds() } } return } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/invokeerror/invokeerror.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package invokeerror import "github.com/pkg/errors" type ErrorCode int const ( // PersistentError indicates that an unknown error occurred // and a retry of the request would NOT be successful PersistentError ErrorCode = iota // TransientError indicates that a transient error occurred // and a retry of the request could be successful TransientError // TimeoutOnCommit indicates that a timeout occurred while waiting // for a TxStatus event TimeoutOnCommit ) // Error extends error with // additional context type Error interface { error // Status returns the error code ErrorCode() ErrorCode } type invokeError struct { error code ErrorCode } // New returns a new Error func New(code ErrorCode, msg string) Error { return &invokeError{ error: errors.New(msg), code: code, } } // Wrap returns a new Error func Wrap(code ErrorCode, cause error, msg string) Error { return &invokeError{ error: errors.Wrap(cause, msg), code: code, } } // Wrapf returns a new Error func Wrapf(code ErrorCode, cause error, fmt string, args ...interface{}) Error { return &invokeError{ error: errors.Wrapf(cause, fmt, args...), code: code, } } // Errorf returns a new Error func Errorf(code ErrorCode, fmt string, args ...interface{}) Error { return &invokeError{ error: errors.Errorf(fmt, args...), code: code, } } // ErrorCode returns the error code func (e *invokeError) ErrorCode() ErrorCode { return e.code } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/invoketask/invoketask.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package invoketask import ( pb "github.com/hyperledger/fabric-protos-go/peer" "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/invokeerror" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/executor" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/printer" ) // Task is a Task that invokes a chaincode type Task struct { ctxt utils.Context executor *executor.Executor channelClient *channel.Client targets []fab.Peer id string ccID string args *action.ArgStruct retryOpts retry.Opts attempt int lastErr error startedCB func() completedCB func(err error) verbose bool printer printer.Printer txID string payloadOnly bool } // New returns a new Task func New(ctxt utils.Context, id string, channelClient *channel.Client, targets []fab.Peer, ccID string, args *action.ArgStruct, executor *executor.Executor, retryOpts retry.Opts, verbose bool, payloadOnly bool, p printer.Printer, startedCB func(), completedCB func(err error)) *Task { return &Task{ ctxt: ctxt, id: id, channelClient: channelClient, targets: targets, printer: p, ccID: ccID, args: args, executor: executor, retryOpts: retryOpts, startedCB: startedCB, completedCB: completedCB, attempt: 1, verbose: verbose, payloadOnly: payloadOnly, } } // Attempts returns the number of invocation attempts that were made // in order to achieve a successful response func (t *Task) Attempts() int { return t.attempt } // LastError returns the last error that was recorder func (t *Task) LastError() error { return t.lastErr } // Invoke invokes the task func (t *Task) Invoke() { t.startedCB() if err := t.doInvoke(); err != nil { t.lastErr = err t.completedCB(err) } else { cliconfig.Config().Logger().Debugf("(%s) - Successfully invoked chaincode\n", t.id) t.completedCB(nil) } } func (t *Task) doInvoke() error { cliconfig.Config().Logger().Debugf("(%s) - Invoking chaincode: %s, function: %s, args: %+v. Attempt #%d...\n", t.id, t.ccID, t.args.Func, t.args.Args, t.attempt) var opts []channel.RequestOption opts = append(opts, channel.WithRetry(t.retryOpts)) opts = append(opts, channel.WithBeforeRetry(func(err error) { t.attempt++ })) if len(t.targets) > 0 { opts = append(opts, channel.WithTargets(t.targets...)) } response, err := t.channelClient.Execute( channel.Request{ ChaincodeID: t.ccID, Fcn: t.args.Func, Args: utils.AsBytes(t.ctxt, t.args.Args), }, opts..., ) if err != nil { return invokeerror.Errorf(invokeerror.TransientError, "SendTransactionProposal return error: %v", err) } if t.verbose { t.printer.PrintTxProposalResponses(response.Responses, t.payloadOnly) } t.txID = string(response.TransactionID) switch pb.TxValidationCode(response.TxValidationCode) { case pb.TxValidationCode_VALID: cliconfig.Config().Logger().Debugf("(%s) - Successfully committed transaction [%s] ...\n", t.id, response.TransactionID) return nil case pb.TxValidationCode_DUPLICATE_TXID, pb.TxValidationCode_MVCC_READ_CONFLICT, pb.TxValidationCode_PHANTOM_READ_CONFLICT: cliconfig.Config().Logger().Debugf("(%s) - Transaction commit failed for [%s] with code [%s]. This is most likely a transient error.\n", t.id, response.TransactionID, response.TxValidationCode) return invokeerror.Wrapf(invokeerror.TransientError, errors.New("Duplicate TxID"), "invoke Error received from eventhub for TxID [%s]. Code: %s", response.TransactionID, response.TxValidationCode) default: cliconfig.Config().Logger().Debugf("(%s) - Transaction commit failed for [%s] with code [%s].\n", t.id, response.TransactionID, response.TxValidationCode) return invokeerror.Wrapf(invokeerror.PersistentError, errors.New("error"), "invoke Error received from eventhub for TxID [%s]. Code: %s", response.TransactionID, response.TxValidationCode) } } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/multitask/multitask.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package multitask import "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/task" // MultiTask contains a set of Tasks to be invoked synchronously type MultiTask struct { tasks []task.Task completedCB func() } // New creates a new multi task func New(completedCB func()) *MultiTask { return &MultiTask{ completedCB: completedCB, } } // Add adds a task func (m *MultiTask) Add(task task.Task) { m.tasks = append(m.tasks, task) } // Invoke invokes the task func (m *MultiTask) Invoke() { defer m.completedCB() for _, task := range m.tasks { task.Invoke() } } // Attempts returns the number of invocation attempts that were made // in order to achieve a successful response func (m *MultiTask) Attempts() int { var attempts int for _, t := range m.tasks { attempts += t.Attempts() } return attempts } // LastError returns the last error that was recorder func (m *MultiTask) LastError() error { for _, t := range m.tasks { if t.LastError() != nil { return t.LastError() } } return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/querycmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package chaincode import ( "fmt" "strconv" "sync" "time" "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/multitask" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/querytask" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/task" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/executor" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var queryCmd = &cobra.Command{ Use: "query", Short: "Query chaincode.", Long: "Query chaincode", Run: func(cmd *cobra.Command, args []string) { if cliconfig.Config().ChaincodeID() == "" { fmt.Printf("\nMust specify the chaincode ID\n\n") cmd.HelpFunc()(cmd, args) return } action, err := newQueryAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing queryAction: %v", err) return } defer action.Terminate() err = action.query() if err != nil { cliconfig.Config().Logger().Errorf("Error while running queryAction: %v", err) } }, } func getQueryCmd() *cobra.Command { flags := queryCmd.Flags() cliconfig.InitPeerURL(flags) cliconfig.InitChannelID(flags) cliconfig.InitChaincodeID(flags) cliconfig.InitArgs(flags) cliconfig.InitIterations(flags) cliconfig.InitSleepTime(flags) cliconfig.InitTimeout(flags) cliconfig.InitPrintPayloadOnly(flags) cliconfig.InitConcurrency(flags) cliconfig.InitVerbosity(flags) cliconfig.InitSelectionProvider(flags) cliconfig.InitValidate(flags) return queryCmd } type queryAction struct { action.Action numInvoked uint32 done chan bool } func newQueryAction(flags *pflag.FlagSet) (*queryAction, error) { action := &queryAction{done: make(chan bool)} err := action.Initialize(flags) return action, err } func (a *queryAction) query() error { channelClient, err := a.ChannelClient() if err != nil { return errors.Errorf("Error getting channel client: %v", err) } argsArray, err := action.ArgsArray() if err != nil { return err } var targets []fab.Peer if len(cliconfig.Config().PeerURL()) > 0 || len(cliconfig.Config().OrgIDs()) > 0 { targets = a.Peers() } executor := executor.NewConcurrent("Query Chaincode", cliconfig.Config().Concurrency()) executor.Start() defer executor.Stop(true) verbose := cliconfig.Config().Verbose() || cliconfig.Config().Iterations() == 1 var mutex sync.RWMutex var tasks []task.Task var errs []error var wg sync.WaitGroup var taskID int var success int var successDurations []time.Duration var failDurations []time.Duration for i := 0; i < cliconfig.Config().Iterations(); i++ { ctxt := utils.NewContext() multiTask := multitask.New(wg.Done) for _, args := range argsArray { taskID++ var startTime time.Time cargs := args task := querytask.New( ctxt, strconv.Itoa(taskID), channelClient, targets, &cargs, a.Printer(), retry.Opts{ Attempts: cliconfig.Config().MaxAttempts(), InitialBackoff: cliconfig.Config().InitialBackoff(), MaxBackoff: cliconfig.Config().MaxBackoff(), BackoffFactor: cliconfig.Config().BackoffFactor(), RetryableCodes: retry.ChannelClientRetryableCodes, }, verbose, cliconfig.Config().PrintPayloadOnly(), cliconfig.Config().Validate(), func() { startTime = time.Now() }, func(err error) { duration := time.Since(startTime) mutex.Lock() if err != nil { errs = append(errs, err) } else { success++ successDurations = append(successDurations, duration) } mutex.Unlock() }) multiTask.Add(task) } tasks = append(tasks, multiTask) } wg.Add(len(tasks)) numInvocations := len(tasks) * len(argsArray) done := make(chan bool) go func() { ticker := time.NewTicker(3 * time.Second) for { select { case <-ticker.C: mutex.RLock() if len(errs) > 0 { fmt.Printf("*** %d failed query(s) out of %d\n", len(errs), numInvocations) } fmt.Printf("*** %d successfull query(s) out of %d\n", success, numInvocations) mutex.RUnlock() case <-done: return } } }() startTime := time.Now() sleepTime := time.Duration(cliconfig.Config().SleepTime()) * time.Millisecond for _, task := range tasks { if err := executor.Submit(task); err != nil { return errors.Errorf("error submitting task: %s", err) } if sleepTime > 0 { time.Sleep(sleepTime) } } // Wait for all tasks to complete wg.Wait() done <- true duration := time.Now().Sub(startTime) var allErrs []error var attempts int for _, task := range tasks { attempts = attempts + task.Attempts() if task.LastError() != nil { allErrs = append(allErrs, task.LastError()) } } if len(errs) > 0 { fmt.Printf("\n*** %d errors querying chaincode:\n", len(errs)) for _, err := range errs { fmt.Printf("%s\n", err) } } else if len(allErrs) > 0 { fmt.Printf("\n*** %d transient errors querying chaincode:\n", len(allErrs)) for _, err := range allErrs { fmt.Printf("%s\n", err) } } if numInvocations/len(argsArray) > 1 { fmt.Printf("\n") fmt.Printf("*** ---------- Summary: ----------\n") fmt.Printf("*** - Queries: %d\n", numInvocations) fmt.Printf("*** - Concurrency: %d\n", cliconfig.Config().Concurrency()) fmt.Printf("*** - Successfull: %d\n", success) fmt.Printf("*** - Total attempts: %d\n", attempts) fmt.Printf("*** - Duration: %2.2fs\n", duration.Seconds()) fmt.Printf("*** - Rate: %2.2f/s\n", float64(numInvocations)/duration.Seconds()) fmt.Printf("*** - Average: %2.2fs\n", average(append(successDurations, failDurations...))) fmt.Printf("*** - Average Success: %2.2fs\n", average(successDurations)) fmt.Printf("*** - Average Fail: %2.2fs\n", average(failDurations)) fmt.Printf("*** - Min Success: %2.2fs\n", min(successDurations)) fmt.Printf("*** - Max Success: %2.2fs\n", max(successDurations)) fmt.Printf("*** ------------------------------\n") } return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/querytask/querytask.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package querytask import ( "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" "github.com/hyperledger/fabric-sdk-go/pkg/client/channel/invoke" "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/printer" ) // Task is the query task type Task struct { ctxt utils.Context channelClient *channel.Client targets []fab.Peer retryOpts retry.Opts id string args *action.ArgStruct startedCB func() completedCB func(err error) printer printer.Printer verbose bool payloadOnly bool validate bool attempt int lastErr error } // New creates a new query Task func New(ctxt utils.Context, id string, channelClient *channel.Client, targets []fab.Peer, args *action.ArgStruct, printer printer.Printer, retryOpts retry.Opts, verbose bool, payloadOnly bool, validate bool, startedCB func(), completedCB func(err error)) *Task { return &Task{ ctxt: ctxt, id: id, channelClient: channelClient, targets: targets, retryOpts: retryOpts, args: args, startedCB: startedCB, completedCB: completedCB, attempt: 1, printer: printer, verbose: verbose, payloadOnly: payloadOnly, validate: validate, } } // Invoke invokes the query task func (t *Task) Invoke() { t.startedCB() var opts []channel.RequestOption opts = append(opts, channel.WithRetry(t.retryOpts)) opts = append(opts, channel.WithBeforeRetry(func(err error) { t.attempt++ })) if len(t.targets) > 0 { opts = append(opts, channel.WithTargets(t.targets...)) } request := channel.Request{ ChaincodeID: cliconfig.Config().ChaincodeID(), Fcn: t.args.Func, Args: utils.AsBytes(t.ctxt, t.args.Args), } var additionalHandlers []invoke.Handler if t.validate { // Add the validation handlers additionalHandlers = append(additionalHandlers, invoke.NewEndorsementValidationHandler( invoke.NewSignatureValidationHandler(), ), ) } response, err := t.channelClient.InvokeHandler( invoke.NewProposalProcessorHandler( invoke.NewEndorsementHandler(additionalHandlers...), ), request, opts...) if err != nil { cliconfig.Config().Logger().Debugf("(%s) - Error querying chaincode: %s\n", t.id, err) t.lastErr = err t.completedCB(err) } else { cliconfig.Config().Logger().Debugf("(%s) - Chaincode query was successful\n", t.id) if t.verbose { t.printer.PrintTxProposalResponses(response.Responses, t.payloadOnly) } t.completedCB(nil) } } // Attempts returns the number of invocation attempts that were made // in order to achieve a successful response func (t *Task) Attempts() int { return t.attempt } // LastError returns the last error that was recorder func (t *Task) LastError() error { return t.lastErr } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/task/task.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package task // Task is an invocable unit of work type Task interface { // Invoke invokes the task Invoke() // Attempts returns the number of invocation attempts that were made // in order to achieve a successful response Attempts() int // LastError returns the last error that occurred LastError() error } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/upgradecmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package chaincode import ( "encoding/json" "fmt" "strings" fabricCommon "github.com/hyperledger/fabric-protos-go/common" pb "github.com/hyperledger/fabric-protos-go/peer" "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/cauthdsl" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var upgradeCmd = &cobra.Command{ Use: "upgrade", Short: "Upgrade chaincode.", Long: "Upgrades the chaincode", Run: func(cmd *cobra.Command, args []string) { if cliconfig.Config().ChaincodeID() == "" { fmt.Printf("\nMust specify the chaincode ID\n\n") cmd.HelpFunc()(cmd, args) return } if cliconfig.Config().ChaincodePath() == "" { fmt.Printf("\nMust specify the path of the chaincode\n\n") cmd.HelpFunc()(cmd, args) return } action, err := newUpgradeAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing upgradeAction: %v", err) return } defer action.Terminate() err = action.invoke() if err != nil { cliconfig.Config().Logger().Errorf("Error while running upgradeAction: %v", err) } }, } func getUpgradeCmd() *cobra.Command { flags := upgradeCmd.Flags() cliconfig.InitPeerURL(flags) cliconfig.InitChannelID(flags) cliconfig.InitChaincodeID(flags) cliconfig.InitChaincodePath(flags) cliconfig.InitChaincodeVersion(flags) cliconfig.InitArgs(flags) cliconfig.InitChaincodePolicy(flags) cliconfig.InitCollectionConfigFile(flags) cliconfig.InitTimeout(flags) return upgradeCmd } type upgradeAction struct { action.Action } func newUpgradeAction(flags *pflag.FlagSet) (*upgradeAction, error) { action := &upgradeAction{} err := action.Initialize(flags) if len(action.Peers()) == 0 { return nil, errors.Errorf("a peer must be specified") } return action, err } func (a *upgradeAction) invoke() error { argBytes := []byte(cliconfig.Config().Args()) args := &action.ArgStruct{} if err := json.Unmarshal(argBytes, args); err != nil { return errors.Errorf("Error unmarshalling JSON arg string: %v", err) } resMgmtClient, err := a.ResourceMgmtClient() if err != nil { return err } cliconfig.Config().Logger().Infof("Sending upgrade %s ...\n", cliconfig.Config().ChaincodeID()) chaincodePolicy, err := a.newChaincodePolicy() if err != nil { return err } // Private Data Collection Configuration // - see fixtures/config/pvtdatacollection.json for sample config file var collConfig []*pb.CollectionConfig collConfigFile := cliconfig.Config().CollectionConfigFile() if collConfigFile != "" { collConfig, err = getCollectionConfigFromFile(cliconfig.Config().CollectionConfigFile()) if err != nil { return errors.Wrapf(err, "error getting private data collection configuration from file [%s]", cliconfig.Config().CollectionConfigFile()) } } req := resmgmt.UpgradeCCRequest{ Name: cliconfig.Config().ChaincodeID(), Path: cliconfig.Config().ChaincodePath(), Version: cliconfig.Config().ChaincodeVersion(), Args: utils.AsBytes(utils.NewContext(), args.Args), Policy: chaincodePolicy, CollConfig: collConfig, } _, err = resMgmtClient.UpgradeCC(cliconfig.Config().ChannelID(), req, resmgmt.WithTargets(a.Peers()...)) if err != nil { if strings.Contains(err.Error(), "chaincode exists "+cliconfig.Config().ChaincodeID()) { // Ignore cliconfig.Config().Logger().Infof("Chaincode %s already instantiated.", cliconfig.Config().ChaincodeID()) fmt.Printf("...chaincode %s already instantiated.\n", cliconfig.Config().ChaincodeID()) return nil } return errors.Errorf("error instantiating chaincode: %v", err) } fmt.Printf("...successfuly upgraded chaincode %s on channel %s.\n", cliconfig.Config().ChaincodeID(), cliconfig.Config().ChannelID()) return nil } func (a *upgradeAction) newChaincodePolicy() (*fabricCommon.SignaturePolicyEnvelope, error) { if cliconfig.Config().ChaincodePolicy() != "" { // Create a signature policy from the policy expression passed in return newChaincodePolicy(cliconfig.Config().ChaincodePolicy()) } // Default policy is 'signed my any member' for all known orgs var mspIDs []string for _, orgID := range cliconfig.Config().OrgIDs() { orgConfig, ok := a.EndpointConfig().NetworkConfig().Organizations[orgID] if !ok { return nil, errors.Errorf("Unable to get the MSP ID from org ID %s", orgID) } mspIDs = append(mspIDs, orgConfig.MSPID) } return cauthdsl.SignedByAnyMember(mspIDs), nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/utils/test.json ================================================ {"Field1": "Value1"} ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/utils/util.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package utils import ( "fmt" "github.com/pkg/errors" "io/ioutil" "math/rand" "os" "path/filepath" "strconv" "strings" "sync/atomic" "time" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" ) const ( randFunc = "$rand(" padFunc = "$pad(" seqFunc = "$seq(" setFunc = "$set(" fileFunc = "$file(" varExp = "${" ) var ( sequence uint64 ) type Context interface { SetVar(name, value string) GetVar(name string) (string, bool) } // AsBytes converts the string array to an array of byte arrays. // The args may contain functions $rand(n) or $pad(n,chars). // The functions are evaluated before returning. // // Examples: // - "key$rand(3)" -> "key0" or "key1" or "key2" // - "val$pad(3,XYZ) -> "valXYZXYZXYZ" // - "val$pad($rand(3),XYZ) -> "val" or "valXYZ" or "valXYZXYZ" // - "key$seq()" -> "key1", "key2", "key2", ... // - "val$pad($seq(),X)" -> "valX", "valXX", "valXX", "valXXX", ... // - "Key_$set(x,$seq())=Val_${x}" -> Key_1=Val_1, Key_2=Val_2, ... func AsBytes(ctxt Context, args []string) [][]byte { rand := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) bytes := make([][]byte, len(args)) if cliconfig.Config().Verbose() { fmt.Printf("Args:\n") } for i, a := range args { arg := getArg(ctxt, rand, a) if cliconfig.Config().Verbose() { fmt.Printf("- [%d]=%s\n", i, arg) } bytes[i] = []byte(arg) } return bytes } func getArg(ctxt Context, r *rand.Rand, arg string) string { arg = evaluateSeqExpression(arg) arg = evaluateRandExpression(r, arg) arg = evaluatePadExpression(arg) arg = evaluateFileExpression(arg) arg = evaluateSetExpression(ctxt, arg) arg = evaluateVarExpression(ctxt, arg) return arg } // evaluateSeqExpression replaces occurrences of $seq() with a sequential // number starting at 1 and incrementing for each task func evaluateSeqExpression(arg string) string { return evaluateExpression(arg, seqFunc, ")", func(expression string) (string, error) { return strconv.FormatUint(atomic.AddUint64(&sequence, 1), 10), nil }) } // evaluateRandExpression replaces occurrences of $rand(n) with a random // number between 0 and n (exclusive) func evaluateRandExpression(r *rand.Rand, arg string) string { return evaluateExpression(arg, randFunc, ")", func(expression string) (string, error) { n, err := strconv.ParseInt(expression, 10, 64) if err != nil { return "", errors.Errorf("invalid number %s in $rand expression\n", expression) } return strconv.FormatInt(r.Int63n(n), 10), nil }) } // evaluatePadExpression replaces occurrences of $pad(n,chars) with n of the given pad characters func evaluatePadExpression(arg string) string { return evaluateExpression(arg, padFunc, ")", func(expression string) (string, error) { s := strings.Split(expression, ",") if len(s) != 2 { return "", errors.Errorf("invalid $pad expression: '%s'. Expecting $pad(n,chars)", expression) } n, err := strconv.Atoi(s[0]) if err != nil { return "", errors.Errorf("invalid number %s in $pad expression\n", s[0]) } result := "" for i := 0; i < n; i++ { result += s[1] } return result, nil }) } // evaluateFileExpression replaces occurrences of $file(path) with the contents of the file func evaluateFileExpression(arg string) string { return evaluateExpression(arg, fileFunc, ")", func(expression string) (string, error) { return readFile(expression) }) } // evaluateSetExpression sets a variable to the given value using the syntax $set(var,expression). // The variable may be used in a subsequent expression, ${var}. // Example: $set(v,$rand(10)) sets variable "v" to a random value that may be accessed as ${v} func evaluateSetExpression(ctxt Context, arg string) string { return evaluateExpression(arg, setFunc, ")", func(expression string) (string, error) { s := strings.Split(expression, ",") if len(s) != 2 { return "", errors.Errorf("invalid $set expression: '%s'. Expecting $set(var,value)", expression) } variable := s[0] value := s[1] ctxt.SetVar(variable, value) return value, nil }) } // evaluateVarExpression references a variable previously set with the $set(var,expression) expression. // Example: ${someVar} func evaluateVarExpression(ctxt Context, arg string) string { return evaluateExpression(arg, varExp, "}", func(varName string) (string, error) { value, ok := ctxt.GetVar(varName) if !ok { return "", errors.Errorf("variable [%s] not set", varName) } return value, nil }) } func evaluateExpression(expression, funcType, endDelim string, evaluate func(string) (string, error)) string { result := "" for { i := strings.Index(expression, funcType) if i == -1 { result += expression break } j := strings.Index(expression[i:], endDelim) if j == -1 { fmt.Printf("expecting '%s' in expression '%s'", endDelim, expression) result = expression break } j = i + j replacement, err := evaluate(expression[i+len(funcType) : j]) if err != nil { fmt.Printf("%s\n", err) result += expression[0 : j+1] } else { result += expression[0:i] + replacement } expression = expression[j+1:] } return result } func NewContext() Context { return &defaultContext{ vars: make(map[string]string), } } type defaultContext struct { vars map[string]string } func (c *defaultContext) SetVar(k, v string) { c.vars[k] = v } func (c *defaultContext) GetVar(k string) (string, bool) { value, ok := c.vars[k] return value, ok } func readFile(filePath string) (string, error) { fmt.Printf("Reading file: [%s]", filePath) file, err := os.Open(filepath.Clean(filePath)) if err != nil { return "", errors.Wrapf(err, "error opening file [%s]", filePath) } defer func() { fileErr := file.Close() if fileErr != nil { cliconfig.Config().Logger().Errorf("Failed to close file : %s", fileErr) } }() configBytes, err := ioutil.ReadAll(file) if err != nil { return "", errors.Wrapf(err, "error reading config file [%s]", filePath) } return string(configBytes), nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/chaincode/utils/util_test.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package utils import ( "fmt" "github.com/stretchr/testify/assert" "math/rand" "testing" "time" ) func TestEvaluatePadExpression(t *testing.T) { result := evaluatePadExpression("Value_$pad(3,XYZ)!") assert.Equal(t, "Value_XYZXYZXYZ!", result) result = evaluatePadExpression("Value_$pad(3,XYZ)_$pad(2,123)!") assert.Equal(t, "Value_XYZXYZXYZ_123123!", result) } func TestFailEvaluatePadExpression(t *testing.T) { result := evaluatePadExpression("Value_$pad(3,XYZ!") assert.Equal(t, "Value_$pad(3,XYZ!", result) result = evaluatePadExpression("Value_$pad3,XYZ)!") assert.Equal(t, "Value_$pad3,XYZ)!", result) result = evaluatePadExpression("Value_$pad(3)!") assert.Equal(t, "Value_$pad(3)!", result) result = evaluatePadExpression("Value_$pad(3)_$pad(3,X)!") assert.Equal(t, "Value_$pad(3)_XXX!", result) } func TestEvaluateRandExpression(t *testing.T) { rand := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) for i := 0; i < 5; i++ { result := evaluateRandExpression(rand, "Value_$rand(2)!") assert.True(t, result == "Value_0!" || result == "Value_1!") result = evaluateRandExpression(rand, "Value_$rand(2)_$rand(1)!") assert.True(t, result == "Value_0_0!" || result == "Value_1_0!") } } func TestFailEvaluateRandExpression(t *testing.T) { rand := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) result := evaluateRandExpression(rand, "Value_$rand(3,!") assert.Equal(t, "Value_$rand(3,!", result) result = evaluateRandExpression(rand, "Value_$rand3)!") assert.Equal(t, "Value_$rand3)!", result) result = evaluateRandExpression(rand, "Value_$rand(X)!") assert.Equal(t, "Value_$rand(X)!", result) result = evaluateRandExpression(rand, "Value_$rand(X)_$rand(1)!") assert.Equal(t, "Value_$rand(X)_0!", result) } func TestEvaluateSeqExpression(t *testing.T) { assert.Equal(t, "Value_1!", evaluateSeqExpression("Value_$seq()!")) assert.Equal(t, "Value_2!", evaluateSeqExpression("Value_$seq()!")) assert.Equal(t, "Value_3!", evaluateSeqExpression("Value_$seq()!")) } func TestFailEvaluateSeqExpression(t *testing.T) { assert.Equal(t, "Value_$seq(!", evaluateSeqExpression("Value_$seq(!")) } func TestEvaluateFileExpression(t *testing.T) { assert.Equal(t, `{"Field1": "Value1"}`, evaluateFileExpression("$file(./test.json)")) } func TestFailEvaluateFileExpression(t *testing.T) { assert.Equal(t, "$file(./invalid.json)", evaluateSeqExpression("$file(./invalid.json)")) } func TestEvaluateSetExpression(t *testing.T) { ctxt := NewContext() assert.Equal(t, "Value_1000!", evaluateSetExpression(ctxt, "Value_$set(x,1000)!")) assert.Equal(t, "Value_1000!", evaluateVarExpression(ctxt, "Value_${x}!")) } func TestFailEvaluateSetExpression(t *testing.T) { ctxt := NewContext() assert.Equal(t, "Value_$set(x,1000", evaluateSetExpression(ctxt, "Value_$set(x,1000")) assert.Equal(t, "Value_${x", evaluateVarExpression(ctxt, "Value_${x")) // Var not set assert.Equal(t, "Value_${x}", evaluateVarExpression(NewContext(), "Value_${x}")) } func TestGetArg(t *testing.T) { rand := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) result := getArg(NewContext(), rand, "Value_$pad(3,X)!") assert.Equal(t, "Value_XXX!", result) for i := 0; i < 5; i++ { result := getArg(NewContext(), rand, "Value_$rand(2)!") assert.True(t, result == "Value_0!" || result == "Value_1!") } for i := 0; i < 5; i++ { result := getArg(NewContext(), rand, "Value_$pad(3,X)_$rand(2)!") assert.True(t, result == "Value_XXX_0!" || result == "Value_XXX_1!") } for i := 0; i < 5; i++ { result := getArg(NewContext(), rand, "Value_$pad($rand(3),X)!") assert.True(t, result == "Value_!" || result == "Value_X!" || result == "Value_XX!") } n := sequence + 1 for i := n; i <= n+5; i++ { result := getArg(NewContext(), rand, "Value_$seq()!") assert.True(t, result == fmt.Sprintf("Value_%d!", i)) } n = sequence + 1 for i := n; i <= n+5; i++ { ctxt := NewContext() assert.Equal(t, fmt.Sprintf("Key_%d=Val_%d", i, i), getArg(ctxt, rand, "Key_$set(x,$seq())=Val_${x}")) assert.Equal(t, fmt.Sprintf("Value_%d!", i), getArg(ctxt, rand, "Value_${x}!")) } } ================================================ FILE: fabric-cli/cmd/fabric-cli/channel/channelcmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package channel import ( cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" ) var channelCmd = &cobra.Command{ Use: "channel", Short: "Channel commands", Long: "Channel commands", Run: func(cmd *cobra.Command, args []string) { cmd.HelpFunc()(cmd, args) }, } // Cmd returns the channel command func Cmd() *cobra.Command { cliconfig.InitChannelID(channelCmd.Flags()) channelCmd.AddCommand(getChannelCreateCmd()) channelCmd.AddCommand(getChannelJoinCmd()) return channelCmd } ================================================ FILE: fabric-cli/cmd/fabric-cli/channel/channelcreatecmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package channel import ( "fmt" "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/msp" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var channelCreateCmd = &cobra.Command{ Use: "create", Short: "Create Channel", Long: "Create a new channel", Run: func(cmd *cobra.Command, args []string) { action, err := newChannelCreateAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing channelCreateAction: %v", err) return } defer action.Terminate() err = action.invoke() if err != nil { cliconfig.Config().Logger().Errorf("Error while running channelCreateAction: %v", err) } }, } func getChannelCreateCmd() *cobra.Command { flags := channelCreateCmd.Flags() cliconfig.InitChannelID(flags) cliconfig.InitOrdererURL(flags) cliconfig.InitTxFile(flags) return channelCreateCmd } type channelCreateAction struct { action.Action } func newChannelCreateAction(flags *pflag.FlagSet) (*channelCreateAction, error) { a := &channelCreateAction{} err := a.Initialize(flags) return a, err } func (a *channelCreateAction) invoke() error { user, err := a.OrgAdminUser(a.OrgID()) if err != nil { return err } chMgmtClient, err := a.ResourceMgmtClient() if err != nil { return err } fmt.Printf("Attempting to create/update channel: %s\n", cliconfig.Config().ChannelID()) req := resmgmt.SaveChannelRequest{ ChannelID: cliconfig.Config().ChannelID(), ChannelConfigPath: cliconfig.Config().TxFile(), SigningIdentities: []msp.SigningIdentity{user}, } orderer, err := a.RandomOrderer() if err != nil { return err } _, err = chMgmtClient.SaveChannel(req, resmgmt.WithOrderer(orderer)) if err != nil { return errors.Errorf("Error from save channel: %s", err.Error()) } fmt.Printf("Channel created/updated: %s\n", cliconfig.Config().ChannelID()) return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/channel/channeljoincmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package channel import ( "fmt" "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var chainJoinCmd = &cobra.Command{ Use: "join", Short: "Join Channel", Long: "Join a channel", Run: func(cmd *cobra.Command, args []string) { action, err := newChannelJoinAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing channelJoinAction: %v", err) return } defer action.Terminate() err = action.invoke() if err != nil { cliconfig.Config().Logger().Errorf("Error while running channelJoinAction: %v", err) } }, } func getChannelJoinCmd() *cobra.Command { flags := chainJoinCmd.Flags() cliconfig.InitChannelID(flags) cliconfig.InitOrdererURL(flags) cliconfig.InitPeerURL(flags) return chainJoinCmd } type channelJoinAction struct { action.Action } func newChannelJoinAction(flags *pflag.FlagSet) (*channelJoinAction, error) { action := &channelJoinAction{} err := action.Initialize(flags) if err != nil { return nil, err } if len(action.Peers()) == 0 { return nil, errors.Errorf("at least one peer is required for join") } return action, nil } func (a *channelJoinAction) invoke() error { fmt.Printf("Attempting to join channel: %s\n", cliconfig.Config().ChannelID()) var lastErr error for orgID, peers := range a.PeersByOrg() { fmt.Printf("Joining channel %s on org[%s] peers:\n", cliconfig.Config().ChannelID(), orgID) for _, peer := range peers { fmt.Printf("-- %s\n", peer.URL()) } err := a.joinChannel(orgID, peers) if err != nil { lastErr = err } } return lastErr } func (a *channelJoinAction) joinChannel(orgID string, peers []fab.Peer) error { cliconfig.Config().Logger().Debugf("Joining channel [%s]...\n", cliconfig.Config().ChannelID()) fmt.Printf("==========> JOIN ORG: %s\n", orgID) resMgmtClient, err := a.ResourceMgmtClientForOrg(orgID) if err != nil { return err } orderer, err := a.RandomOrderer() if err != nil { return err } err = resMgmtClient.JoinChannel(cliconfig.Config().ChannelID(), resmgmt.WithTargets(peers...), resmgmt.WithOrderer(orderer)) if err != nil { return errors.WithMessage(err, "Could not join channel: %v") } fmt.Printf("Channel %s joined!\n", cliconfig.Config().ChannelID()) return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/cmd/fabric-cli.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package cmd import ( "os" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/channel" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/event" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/query" "github.com/spf13/cobra" ) func newFabricCLICmd() *cobra.Command { mainCmd := &cobra.Command{ Use: "fabric-cli", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return nil }, Run: func(cmd *cobra.Command, args []string) { cmd.HelpFunc()(cmd, args) }, } flags := mainCmd.PersistentFlags() cliconfig.InitConfigFile(flags) cliconfig.InitLoggingLevel(flags) cliconfig.InitUserName(flags) cliconfig.InitUserPassword(flags) cliconfig.InitOrdererTLSCertificate(flags) cliconfig.InitPrintFormat(flags) cliconfig.InitWriter(flags) cliconfig.InitBase64(flags) cliconfig.InitOrgIDs(flags) mainCmd.AddCommand(chaincode.Cmd()) mainCmd.AddCommand(query.Cmd()) mainCmd.AddCommand(channel.Cmd()) mainCmd.AddCommand(event.Cmd()) return mainCmd } func Execute() { if newFabricCLICmd().Execute() != nil { os.Exit(1) } } ================================================ FILE: fabric-cli/cmd/fabric-cli/config/config.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package config import ( "fmt" "strconv" "time" "github.com/hyperledger/fabric-sdk-go/pkg/fab/events/deliverclient/seek" "strings" "github.com/spf13/pflag" "os" "github.com/hyperledger/fabric-sdk-go/pkg/common/logging" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/core" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" "github.com/hyperledger/fabric-sdk-go/pkg/core/config" ) const ( loggerName = "fabriccli" userStatePath = "/tmp/enroll_user" // AutoDetectSelectionProvider indicates that a selection provider is to be automatically determined using channel capabilities AutoDetectSelectionProvider = "auto" // StaticSelectionProvider indicates that a static selection provider is to be used for selecting peers for invoke/query commands StaticSelectionProvider = "static" // DynamicSelectionProvider indicates that a dynamic selection provider is to be used for selecting peers for invoke/query commands DynamicSelectionProvider = "dynamic" // FabricSelectionProvider indicates that the Fabric selection provider is to be used for selecting peers for invoke/query commands FabricSelectionProvider = "fabric" ) // Flags const ( UserFlag = "user" userDescription = "The user" defaultUser = "" PasswordFlag = "pw" passwordDescription = "The password of the user" defaultPassword = "" ChaincodeVersionFlag = "v" chaincodeVersionDescription = "The chaincode version" defaultChaincodeVersion = "v0" LoggingLevelFlag = "logging-level" loggingLevelDescription = "Logging level - ERROR, WARN, INFO, DEBUG" defaultLoggingLevel = "ERROR" OrgIDsFlag = "orgid" orgIDsDescription = "A comma-separated list of organization IDs" defaultOrgIDs = "" ChannelIDFlag = "cid" channelIDDescription = "The channel ID" defaultChannelID = "" ChaincodeIDFlag = "ccid" chaincodeIDDescription = "The Chaincode ID" defaultChaincodeID = "" ChaincodePathFlag = "ccp" chaincodePathDescription = "The chaincode path" defaultChaincodePath = "" ConfigFileFlag = "config" configFileDescription = "The path of the config.yaml file" defaultConfigFile = "" PeerURLFlag = "peer" peerURLDescription = "A comma-separated list of peer targets, e.g. 'grpcs://localhost:7051,grpcs://localhost:8051'" defaultPeerURL = "" OrdererFlag = "orderer" ordererURLDescription = "The URL of the orderer, e.g. grpcs://localhost:7050" defaultOrdererURL = "" PrintFormatFlag = "format" printFormatDescription = "The output format - display, json, raw" WriterFlag = "writer" writerDescription = "The writer - stdout, stderr, log" Base64Flag = "base64" base64Description = "If true then binary values are encoded in base64 (only applies to 'display' format)" CertificateFileFlag = "cacert" certificateDescription = "The path of the ca-cert.pem file" defaultCertificate = "" ArgsFlag = "args" argsDescription = `The args in JSON format. Example: {"Func":"function","Args":["arg1","arg2"]}. Note that $rand(N) may be used anywhere within the value of the arg in order to generate a random value between 0 and N. For example {"Func":"function","Args":["arg_$rand(100)","$rand(10)"]}.` IterationsFlag = "iterations" iterationsDescription = "The number of times to invoke the chaincode" defaultIterations = "1" SleepFlag = "sleep" sleepTimeDescription = "The number of milliseconds to sleep between invocations of the chaincode." defaultSleepTime = "0" TxFileFlag = "txfile" txFileDescription = "The path of the channel.tx file" defaultTxFile = "" ChaincodeEventFlag = "event" chaincodeEventDescription = "The name of the chaincode event to listen for" defaultChaincodeEvent = "" SeekTypeFlag = "seek" seekTypeDescription = "The seek type. Possible values: oldest - delivers all blocks from the oldest block; newest - delivers the newest block; from - delivers from the block number as specified by the '--num' flag" defaultSeekType = string(seek.Newest) TxIDFlag = "txid" txIDDescription = "The transaction ID" defaultTxID = "" BlockNumFlag = "num" blockNumDescription = "The block number" defaultBlockNum = "0" BlockHashFlag = "hash" blockHashDescription = "The block hash" defaultBlockHash = "" TraverseFlag = "traverse" traverseDescription = "Blocks will be traversed starting with the given block in reverse order up to the given number of blocks" defaultTraverse = "0" ChaincodePolicyFlag = "policy" chaincodePolicyDescription = "The chaincode policy, e.g. OutOf(1,'Org1MSP.admin','Org2MSP.admin',AND('Org3MSP.member','Org4MSP.member'))" defaultChaincodePolicy = "" CollectionConfigFileFlag = "collconfig" collectionConfigFileDescription = "The path of the JSON file that contains the private data collection configuration for the chaincode" defaultCollectionConfigFile = "" TimeoutFlag = "timeout" timeoutDescription = "The timeout (in milliseconds) for the operation" defaultTimeout = "5000" PrintPayloadOnlyFlag = "payload" printPayloadOnlyDescription = "If specified then only the payload from the transaction proposal response(s) will be output" defaultPrintPayloadOnly = "false" ValidateFlag = "validate" validateDescription = "If specified then endorsement responses from queries will be validated" defaultValidate = "false" ConcurrencyFlag = "concurrency" concurrencyDescription = "Specifies the number of concurrent requests sent on an invoke or a query chaincode request" defaultConcurrency = "1" MaxAttemptsFlag = "attempts" maxAttemptsDescription = "Specifies the maximum number of attempts to be made for a single chaincode invocation request. If >1 then retries will be attempted should transient errors occur." defaultMaxAttempts = "3" InitialBackoffFlag = "backoff" initialBackoffDescription = "The initial backoff is the time (in milliseconds) to wait before resubmitting an invocation after a transient error" defaultInitialBackoff = "1000" MaxBackoffFlag = "maxbackoff" maxBackoffDescription = "The maximum backoff time (in milliseconds)" defaultMaxBackoff = "5000" BackoffFactorFlag = "backofffactor" backoffFactorDescription = "The factor by which the backoff time is multiplied each time a retry fails. For example, if the initial backoff is 1s and factor is 2 then the next retry will have a backoff of 2s and a subsequent backoff will be 4s up to the maximum backoff" defaultBackoffFactor = "2" VerboseFlag = "verbose" verboseDescription = "If specified then the transaction proposal responses will be output when iterations > 1, otherwise transaction proposal responses are only output when iterations = 1" defaultVerbosity = "false" SelectionProviderFlag = "selectprovider" selectionProviderDescription = "The peer selection provider for invoke/query commands. The possible values are: (1) static - Selects all peers; (2) dynamic - Uses the built-in selection service from the SDK to select a minimal set of peers according to the endorsement policy of the chaincode; (3) fabric - Uses Fabric's Discovery Service to select a minimal set of peers according to the endorsement/collection policy of the chaincode; (4) auto (default) - Automatically determines which selection service to use based on channel capabilities." defaultSelectionProvider = AutoDetectSelectionProvider GoPathFlag = "gopath" goPathDescription = "GOPATH for chaincode install command. If not set, GOPATH is taken from the environment" defaultGoPath = "" ) var opts *options var instance *CLIConfig type options struct { certificate string user string password string loggingLevel string orgIDsStr string channelID string chaincodeID string chaincodePath string chaincodeVersion string peerURL string ordererURL string iterations int sleepTime int64 configFile string txFile string txID string printFormat string writer string base64 bool args string chaincodeEvent string seekType string blockHash string blockNum uint64 traverse int chaincodePolicy string collectionConfigFile string timeout int64 printPayloadOnly bool validate bool concurrency int maxAttempts int initialBackoff int64 maxBackoff int64 backoffFactor float64 verbose bool selectionProvider string goPath string } func init() { opts = &options{ user: defaultUser, password: defaultPassword, loggingLevel: defaultLoggingLevel, channelID: defaultChannelID, orgIDsStr: defaultOrgIDs, chaincodeVersion: defaultChaincodeVersion, iterations: 1, concurrency: 1, args: getEmptyArgs(), } } // CLIConfig overrides certain configuration values with those supplied on the command-line type CLIConfig struct { core.ConfigProvider logger *logging.Logger setFlags map[string]string } // InitConfig initializes the configuration func InitConfig(flags *pflag.FlagSet) error { instance = &CLIConfig{ logger: logging.NewLogger(loggerName), setFlags: make(map[string]string), } flags.Visit(func(flag *pflag.Flag) { instance.setFlags[flag.Name] = flag.Value.String() }) cnfg := config.FromFile(opts.configFile) instance.ConfigProvider = cnfg return nil } // IsFlagSet indicates whether or not the given flag is set func IsFlagSet(name string) bool { _, ok := instance.setFlags[name] return ok } // Provider returns the config provider func Provider() core.ConfigProvider { return instance.ConfigProvider } // Config returns the CLI configuration func Config() *CLIConfig { return instance } // Logger returns the Logger for the CLI tool func (c *CLIConfig) Logger() *logging.Logger { return c.logger } // LoggingLevel specifies the logging level (DEBUG, INFO, WARNING, ERROR, or CRITICAL) func (c *CLIConfig) LoggingLevel() string { return opts.loggingLevel } // InitLoggingLevel initializes the logging level from the provided arguments func InitLoggingLevel(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultLoggingLevel, loggingLevelDescription, defaultValueAndDescription...) flags.StringVar(&opts.loggingLevel, LoggingLevelFlag, defaultValue, description) } // InitConfigFile initializes the config file path from the provided arguments func InitConfigFile(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultConfigFile, configFileDescription, defaultValueAndDescription...) flags.StringVar(&opts.configFile, ConfigFileFlag, defaultValue, description) } // OrgID specifies the ID of the current organization. If multiple org IDs are specified then the first one is returned. func (c *CLIConfig) OrgID() string { if len(c.OrgIDs()) == 0 { return "" } return c.OrgIDs()[0] } // OrgIDs returns a comma-separated list of organization IDs func (c *CLIConfig) OrgIDs() []string { var orgIDs []string if len(strings.TrimSpace(opts.orgIDsStr)) > 0 { s := strings.Split(opts.orgIDsStr, ",") for _, orgID := range s { orgIDs = append(orgIDs, orgID) } } return orgIDs } // InitOrgIDs initializes the org IDs from the provided arguments func InitOrgIDs(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultOrgIDs, orgIDsDescription, defaultValueAndDescription...) flags.StringVar(&opts.orgIDsStr, OrgIDsFlag, defaultValue, description) } // ChannelID returns the channel ID func (c *CLIConfig) ChannelID() string { return opts.channelID } // InitChannelID initializes the channel ID from the provided arguments func InitChannelID(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultChannelID, channelIDDescription, defaultValueAndDescription...) flags.StringVar(&opts.channelID, ChannelIDFlag, defaultValue, description) } // UserName returns the name of the enrolled user func (c *CLIConfig) UserName() string { return opts.user } // InitUserName initializes the user name from the provided arguments func InitUserName(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultUser, userDescription, defaultValueAndDescription...) flags.StringVar(&opts.user, UserFlag, defaultValue, description) } // UserPassword is the password to use when enrolling a user func (c *CLIConfig) UserPassword() string { return opts.password } // InitUserPassword initializes the user password from the provided arguments func InitUserPassword(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultPassword, passwordDescription, defaultValueAndDescription...) flags.StringVar(&opts.password, PasswordFlag, defaultValue, description) } // ChaincodeID returns the chaicode ID func (c *CLIConfig) ChaincodeID() string { return opts.chaincodeID } // InitChaincodeID initializes the chaincode ID from the provided arguments func InitChaincodeID(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultChaincodeID, chaincodeIDDescription, defaultValueAndDescription...) flags.StringVar(&opts.chaincodeID, ChaincodeIDFlag, defaultValue, description) } // ChaincodeEvent the name of the chaincode event to listen for func (c *CLIConfig) ChaincodeEvent() string { return opts.chaincodeEvent } // InitChaincodeEvent initializes the chaincode event name from the provided arguments func InitChaincodeEvent(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultChaincodeEvent, chaincodeEventDescription, defaultValueAndDescription...) flags.StringVar(&opts.chaincodeEvent, ChaincodeEventFlag, defaultValue, description) } // SeekType the seek type for Deliver Events. Possible values: // - Oldest - will deliver all blocks from the oldest block and will continue listening for new blocks // - Newest - will deliver the newest block and will continue listening for new blocks // - FromBlock - Delivers from the specific block, as specified by the "--num" flag func (c *CLIConfig) SeekType() seek.Type { return seek.Type(opts.seekType) } // InitSeekType initializes the seek type from the provided arguments func InitSeekType(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultSeekType, seekTypeDescription, defaultValueAndDescription...) flags.StringVar(&opts.seekType, SeekTypeFlag, defaultValue, description) } // ChaincodePath returns the source path of the chaincode to install/instantiate func (c *CLIConfig) ChaincodePath() string { return opts.chaincodePath } // InitChaincodePath initializes the chaincode install source path from the provided arguments func InitChaincodePath(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultChaincodePath, chaincodePathDescription, defaultValueAndDescription...) flags.StringVar(&opts.chaincodePath, ChaincodePathFlag, defaultValue, description) } // ChaincodeVersion returns the version of the chaincode func (c *CLIConfig) ChaincodeVersion() string { return opts.chaincodeVersion } // InitChaincodeVersion initializes the chaincode version from the provided arguments func InitChaincodeVersion(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultChaincodeVersion, chaincodeVersionDescription, defaultValueAndDescription...) flags.StringVar(&opts.chaincodeVersion, ChaincodeVersionFlag, defaultValue, description) } // PeerURL returns a comma-separated list of peers in the format host1:port1,host2:port2,... func (c *CLIConfig) PeerURL() string { return opts.peerURL } // PeerURLs returns a list of peer URLs func (c *CLIConfig) PeerURLs() []string { var urls []string if len(strings.TrimSpace(opts.peerURL)) > 0 { s := strings.Split(opts.peerURL, ",") for _, orgID := range s { urls = append(urls, orgID) } } return urls } // InitPeerURL initializes the peer URL from the provided arguments func InitPeerURL(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultPeerURL, peerURLDescription, defaultValueAndDescription...) flags.StringVar(&opts.peerURL, PeerURLFlag, defaultValue, description) } // OrdererURL returns the URL of the orderer func (c *CLIConfig) OrdererURL() string { return opts.ordererURL } // InitOrdererURL initializes the orderer URL from the provided arguments func InitOrdererURL(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultOrdererURL, ordererURLDescription, defaultValueAndDescription...) flags.StringVar(&opts.ordererURL, OrdererFlag, defaultValue, description) } // Iterations returns the number of times that a chaincode should be invoked func (c *CLIConfig) Iterations() int { return opts.iterations } // InitIterations initializes the number of query/invoke iterations from the provided arguments func InitIterations(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultIterations, iterationsDescription, defaultValueAndDescription...) i, err := strconv.Atoi(defaultValue) if err != nil { fmt.Printf("Invalid number for %s: %s\n", IterationsFlag, defaultValue) os.Exit(-1) } flags.IntVar(&opts.iterations, IterationsFlag, i, description) } // SleepTime returns the number of milliseconds to sleep between invocations of a chaincode func (c *CLIConfig) SleepTime() int64 { return opts.sleepTime } // InitSleepTime initializes the sleep time from the provided arguments func InitSleepTime(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultSleepTime, sleepTimeDescription, defaultValueAndDescription...) i, err := strconv.Atoi(defaultValue) if err != nil { fmt.Printf("Invalid number for %s: %s\n", SleepFlag, defaultValue) os.Exit(-1) } flags.Int64Var(&opts.sleepTime, SleepFlag, int64(i), description) } // BlockNum returns the block number (where 0 is the first block) func (c *CLIConfig) BlockNum() uint64 { return opts.blockNum } // InitBlockNum initializes the bluck number from the provided arguments func InitBlockNum(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultBlockNum, blockNumDescription, defaultValueAndDescription...) i, err := strconv.ParseUint(defaultValue, 10, 64) if err != nil { fmt.Printf("Invalid number for %s: %s\n", BlockNumFlag, defaultValue) os.Exit(-1) } flags.Uint64Var(&opts.blockNum, BlockNumFlag, i, description) } // BlockHash specifies the hash of the block func (c *CLIConfig) BlockHash() string { return opts.blockHash } // InitBlockHash initializes the block hash from the provided arguments func InitBlockHash(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultBlockHash, blockHashDescription, defaultValueAndDescription...) flags.StringVar(&opts.blockHash, BlockHashFlag, defaultValue, description) } // Traverse returns the number of blocks to traverse backwards in the query block command func (c *CLIConfig) Traverse() int { return opts.traverse } // InitTraverse initializes the 'traverse' flag from the provided arguments func InitTraverse(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultTraverse, traverseDescription, defaultValueAndDescription...) i, err := strconv.Atoi(defaultValue) if err != nil { fmt.Printf("Invalid number for %s: %s\n", TimeoutFlag, defaultValue) i = 1 } flags.IntVar(&opts.traverse, TraverseFlag, i, description) } // PrintFormat returns the print (output) format for a block func (c *CLIConfig) PrintFormat() string { return opts.printFormat } // InitPrintFormat initializes the print format from the provided arguments func InitPrintFormat(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription("display", printFormatDescription, defaultValueAndDescription...) flags.StringVar(&opts.printFormat, PrintFormatFlag, defaultValue, description) } // Writer returns the writer for output func (c *CLIConfig) Writer() string { return opts.writer } // InitWriter initializes the print writer from the provided arguments func InitWriter(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription("stdout", writerDescription, defaultValueAndDescription...) flags.StringVar(&opts.writer, WriterFlag, defaultValue, description) } // Base64 indicates whether binary values are to be encoded in base64. (Only applies to 'display' format.) func (c *CLIConfig) Base64() bool { return opts.base64 } // InitBase64 initializes the base64 flag from the provided arguments func InitBase64(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription("false", writerDescription, defaultValueAndDescription...) flags.BoolVar(&opts.base64, Base64Flag, defaultValue == "true", description) } // OrdererTLSCertificate is the path of the orderer TLS certificate func (c *CLIConfig) OrdererTLSCertificate() string { return opts.certificate } // InitOrdererTLSCertificate initializes the orderer TLS certificate from the provided arguments func InitOrdererTLSCertificate(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultCertificate, certificateDescription, defaultValueAndDescription...) flags.StringVar(&opts.certificate, CertificateFileFlag, defaultValue, description) } // Args returns the chaincode invocation arguments as a JSON string in the format, {"Func":"function","Args":["arg1","arg2",...]} func (c *CLIConfig) Args() string { return opts.args } // InitArgs initializes the invoke/query args from the provided arguments func InitArgs(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(getEmptyArgs(), argsDescription, defaultValueAndDescription...) flags.StringVar(&opts.args, ArgsFlag, defaultValue, description) } // TxFile is the path of the .tx file used to create a channel func (c *CLIConfig) TxFile() string { return opts.txFile } // InitTxFile initializes the path of the .tx file used to create/update a channel from the provided arguments func InitTxFile(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultTxFile, txFileDescription, defaultValueAndDescription...) flags.StringVar(&opts.txFile, TxFileFlag, defaultValue, description) } // TxID returns the transaction ID func (c *CLIConfig) TxID() string { return opts.txID } // InitTxID initializes the transaction D from the provided arguments func InitTxID(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultTxID, txIDDescription, defaultValueAndDescription...) flags.StringVar(&opts.txID, TxIDFlag, defaultValue, description) } // ChaincodePolicy returns the chaincode policy string, e.g Nof(1,(SignedBy(Org1Msp),SignedBy(Org2MSP))) func (c *CLIConfig) ChaincodePolicy() string { return opts.chaincodePolicy } // InitChaincodePolicy initializes the chaincode policy from the provided arguments func InitChaincodePolicy(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultChaincodePolicy, chaincodePolicyDescription, defaultValueAndDescription...) flags.StringVar(&opts.chaincodePolicy, ChaincodePolicyFlag, defaultValue, description) } // CollectionConfigFile returns the path of the JSON file that contains the private data collection configuration for the chaincode to be instantiated/upgraded func (c *CLIConfig) CollectionConfigFile() string { return opts.collectionConfigFile } // InitCollectionConfigFile initializes the collection config file from the provided arguments func InitCollectionConfigFile(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultCollectionConfigFile, collectionConfigFileDescription, defaultValueAndDescription...) flags.StringVar(&opts.collectionConfigFile, CollectionConfigFileFlag, defaultValue, description) } // Timeout returns the timeout (in milliseconds) for various operations func (c *CLIConfig) Timeout(timeoutType fab.TimeoutType) time.Duration { // TODO use provided timoutType return time.Duration(opts.timeout) * time.Millisecond } // InitTimeout initializes the timeout from the provided arguments func InitTimeout(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultTimeout, timeoutDescription, defaultValueAndDescription...) i, err := strconv.Atoi(defaultValue) if err != nil { fmt.Printf("Invalid number for %s: %s\n", TimeoutFlag, defaultValue) i = 1000 } flags.Int64Var(&opts.timeout, TimeoutFlag, int64(i), description) } // PrintPayloadOnly indicates whether only the payload or the entire // transaction proposal response should be printed func (c *CLIConfig) PrintPayloadOnly() bool { return opts.printPayloadOnly } // InitPrintPayloadOnly initializes the PrintPayloadOnly flag from the provided arguments func InitPrintPayloadOnly(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultPrintPayloadOnly, printPayloadOnlyDescription, defaultValueAndDescription...) flags.BoolVar(&opts.printPayloadOnly, PrintPayloadOnlyFlag, defaultValue == "true", description) } // Validate indicates whether the endorsement responses from a query should be validated func (c *CLIConfig) Validate() bool { return opts.validate } // InitValidate initializes the Validate flag from the provided arguments func InitValidate(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultValidate, validateDescription, defaultValueAndDescription...) flags.BoolVar(&opts.validate, ValidateFlag, defaultValue == "true", description) } // Concurrency returns the number of concurrent invocations/queries func (c *CLIConfig) Concurrency() uint16 { return uint16(opts.concurrency) } // InitConcurrency initializes the 'concurrency' flag from the provided arguments func InitConcurrency(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultConcurrency, concurrencyDescription, defaultValueAndDescription...) i, err := strconv.Atoi(defaultValue) if err != nil { fmt.Printf("Invalid number for %s: %s\n", TimeoutFlag, defaultValue) i = 1 } flags.IntVar(&opts.concurrency, ConcurrencyFlag, i, description) } // MaxAttempts returns the maximum number of invocations attempts to be made // for a single chaincode invocation request. If >1 then a retry will be attempted // if a transient failure occurs. func (c *CLIConfig) MaxAttempts() int { return opts.maxAttempts } // InitMaxAttempts initializes the 'maxAttempts' flag from the provided arguments func InitMaxAttempts(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultMaxAttempts, maxAttemptsDescription, defaultValueAndDescription...) i, err := strconv.Atoi(defaultValue) if err != nil { fmt.Printf("Invalid number for %s: %s\n", TimeoutFlag, defaultValue) i = 1 } flags.IntVar(&opts.maxAttempts, MaxAttemptsFlag, i, description) } // InitialBackoff returns the time (in milliseconds) to wait // before resubmitting an invocation after a transient error func (c *CLIConfig) InitialBackoff() time.Duration { return time.Duration(opts.initialBackoff) * time.Millisecond } // InitInitialBackoff initializes the initial backoff from the provided arguments func InitInitialBackoff(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultInitialBackoff, initialBackoffDescription, defaultValueAndDescription...) i, err := strconv.Atoi(defaultValue) if err != nil { fmt.Printf("Invalid number for %s: %s\n", TimeoutFlag, defaultValue) i = 1000 } flags.Int64Var(&opts.initialBackoff, InitialBackoffFlag, int64(i), description) } // MaxBackoff returns the number func (c *CLIConfig) MaxBackoff() time.Duration { return time.Duration(opts.maxBackoff) * time.Millisecond } // InitMaxBackoff initializes the maximum backoff from the provided arguments func InitMaxBackoff(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultMaxBackoff, maxBackoffDescription, defaultValueAndDescription...) i, err := strconv.Atoi(defaultValue) if err != nil { fmt.Printf("Invalid number for %s: %s\n", TimeoutFlag, defaultValue) i = 1000 } flags.Int64Var(&opts.maxBackoff, MaxBackoffFlag, int64(i), description) } // BackoffFactor returns the factor by which the backoff time is multiplied each time a retry fails. For example, if the initial // backoff is 1s and factor is 2 then the next retry will have a backoff of 2s and a subsequent backoff will be 4s up to the maximum backoff func (c *CLIConfig) BackoffFactor() float64 { return opts.backoffFactor } // InitBackoffFactor initializes the backoff factor from the provided arguments func InitBackoffFactor(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultBackoffFactor, backoffFactorDescription, defaultValueAndDescription...) i, err := strconv.Atoi(defaultValue) if err != nil { fmt.Printf("Invalid number for %s: %s\n", TimeoutFlag, defaultValue) i = 1000 } flags.Float64Var(&opts.backoffFactor, BackoffFactorFlag, float64(i), description) } // Verbose indicates whether or not to print the transaction proposal responses // when Iterations > 1 func (c *CLIConfig) Verbose() bool { return opts.verbose } // InitVerbosity initializes the Verbose flag from the provided arguments func InitVerbosity(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultVerbosity, verboseDescription, defaultValueAndDescription...) flags.BoolVar(&opts.verbose, VerboseFlag, defaultValue == "true", description) } // SelectionProvider returns the peer selection provider - either static or dynamic func (c *CLIConfig) SelectionProvider() string { return opts.selectionProvider } // InitSelectionProvider initializes the peer selection provider from the provided arguments func InitSelectionProvider(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultSelectionProvider, selectionProviderDescription, defaultValueAndDescription...) flags.StringVar(&opts.selectionProvider, SelectionProviderFlag, defaultValue, description) } // InitGoPath initializes the gopath from the provided arguments func InitGoPath(flags *pflag.FlagSet, defaultValueAndDescription ...string) { defaultValue, description := getDefaultValueAndDescription(defaultGoPath, goPathDescription, defaultValueAndDescription...) flags.StringVar(&opts.goPath, GoPathFlag, defaultValue, description) } // GoPath returns the gopath func (c *CLIConfig) GoPath() string { gopath := opts.goPath if !IsFlagSet(GoPathFlag) { gopath = os.Getenv("GOPATH") } return gopath } // IsLoggingEnabledFor indicates whether the logger is enabled for the given logging level func (c *CLIConfig) IsLoggingEnabledFor(level logging.Level) bool { return logging.IsEnabledFor(loggerName, level) } // Utility functions... func getEmptyArgs() string { return "{}" } func getDefaultValueAndDescription(defaultValue string, defaultDescription string, overrides ...string) (value, description string) { if len(overrides) > 0 { value = overrides[0] } else { value = defaultValue } if len(overrides) > 1 { description = overrides[1] } else { description = defaultDescription } return value, description } ================================================ FILE: fabric-cli/cmd/fabric-cli/event/eventcmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package event import ( "github.com/spf13/cobra" ) var eventCmd = &cobra.Command{ Use: "event", Short: "Event commands", Long: "Event commands", Run: func(cmd *cobra.Command, args []string) { cmd.HelpFunc()(cmd, args) }, } // Cmd returns the events command func Cmd() *cobra.Command { eventCmd.AddCommand(getListenCCCmd()) eventCmd.AddCommand(getListenTXCmd()) eventCmd.AddCommand(getListenBlockCmd()) eventCmd.AddCommand(getListenFilteredBlockCmd()) return eventCmd } ================================================ FILE: fabric-cli/cmd/fabric-cli/event/inputevent.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package event import ( "bufio" "os" ) type inputEvent struct { done chan bool } // WaitForEnter waits until the user presses Enter func (c *inputEvent) WaitForEnter() chan bool { go c.readFromCLI() return c.done } func (c *inputEvent) readFromCLI() { reader := bufio.NewReader(os.Stdin) reader.ReadString('\n') c.done <- true } ================================================ FILE: fabric-cli/cmd/fabric-cli/event/listenblockcmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package event import ( "fmt" "github.com/hyperledger/fabric-sdk-go/pkg/client/event" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var listenBlockCmd = &cobra.Command{ Use: "listenblock", Short: "Listen to block events.", Long: "Listen to block events", Run: func(cmd *cobra.Command, args []string) { action, err := newlistenBlockAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing listenBlockAction: %v", err) return } defer action.Terminate() err = action.invoke() if err != nil { cliconfig.Config().Logger().Errorf("Error while running listenBlockAction: %v", err) } }, } func getListenBlockCmd() *cobra.Command { flags := listenBlockCmd.Flags() cliconfig.InitChannelID(flags) cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to listen for events, e.g. localhost:7051") cliconfig.InitSeekType(flags) cliconfig.InitBlockNum(flags) return listenBlockCmd } type listenBlockAction struct { action.Action inputEvent } func newlistenBlockAction(flags *pflag.FlagSet) (*listenBlockAction, error) { action := &listenBlockAction{inputEvent: inputEvent{done: make(chan bool)}} err := action.Initialize(flags) return action, err } func (a *listenBlockAction) invoke() error { eventClient, err := a.EventClient(event.WithBlockEvents(), event.WithSeekType(cliconfig.Config().SeekType()), event.WithBlockNum(cliconfig.Config().BlockNum())) if err != nil { return err } fmt.Printf("Registering block event\n") breg, beventch, err := eventClient.RegisterBlockEvent() if err != nil { return errors.WithMessage(err, "Error registering for block events") } defer eventClient.Unregister(breg) enterch := a.WaitForEnter() for { select { case _, _ = <-enterch: return nil case event, ok := <-beventch: if !ok { return errors.WithMessage(err, "unexpected closed channel while waiting for block event") } a.Printer().PrintBlock(event.Block) fmt.Println("Press to terminate") } } } ================================================ FILE: fabric-cli/cmd/fabric-cli/event/listencccmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package event import ( "fmt" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var listenccCmd = &cobra.Command{ Use: "listencc", Short: "Listen to chaincode events.", Long: "Listen to chaincode events", Run: func(cmd *cobra.Command, args []string) { if cliconfig.Config().ChaincodeID() == "" { fmt.Printf("\nMust specify the chaincode ID\n\n") cmd.HelpFunc()(cmd, args) return } if cliconfig.Config().ChaincodeEvent() == "" { fmt.Printf("\nMust specify the event name\n\n") cmd.HelpFunc()(cmd, args) return } action, err := newListenCCAction(cmd.Flags()) if err != nil { fmt.Printf("\nError while initializing listenCCAction: %v\n", err) return } defer action.Terminate() err = action.invoke() if err != nil { fmt.Printf("\nError while running listenCCAction: %v\n", err) } }, } func getListenCCCmd() *cobra.Command { flags := listenccCmd.Flags() cliconfig.InitChannelID(flags) cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to listen for events, e.g. grpcs://localhost:7051") cliconfig.InitChaincodeID(flags) cliconfig.InitChaincodeEvent(flags) return listenccCmd } type listenccAction struct { action.Action inputEvent } func newListenCCAction(flags *pflag.FlagSet) (*listenccAction, error) { action := &listenccAction{inputEvent: inputEvent{done: make(chan bool)}} err := action.Initialize(flags) return action, err } func (a *listenccAction) invoke() error { fmt.Printf("Registering CC event on chaincode [%s] and event [%s]\n", cliconfig.Config().ChaincodeID(), cliconfig.Config().ChaincodeEvent()) eventHub, err := a.EventClient() if err != nil { return err } breg, beventch, err := eventHub.RegisterChaincodeEvent(cliconfig.Config().ChaincodeID(), cliconfig.Config().ChaincodeEvent()) if err != nil { return errors.WithMessage(err, "Error registering for block events") } defer eventHub.Unregister(breg) enterch := a.WaitForEnter() for { select { case _, _ = <-enterch: return nil case event, ok := <-beventch: if !ok { return errors.WithMessage(err, "unexpected closed channel while waiting for block event") } a.Printer().PrintChaincodeEvent(event) fmt.Println("Press to terminate") } } } ================================================ FILE: fabric-cli/cmd/fabric-cli/event/listenfilteredblockcmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package event import ( "fmt" "github.com/hyperledger/fabric-sdk-go/pkg/client/event" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var listenFilteredBlockCmd = &cobra.Command{ Use: "listenfilteredblock", Short: "Listen to filtered block events.", Long: "Listen to filtered block events", Run: func(cmd *cobra.Command, args []string) { action, err := newlistenFilteredBlockAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing listenFilteredBlockAction: %v", err) return } defer action.Terminate() err = action.invoke() if err != nil { cliconfig.Config().Logger().Errorf("Error while running listenFilteredBlockAction: %v", err) } }, } func getListenFilteredBlockCmd() *cobra.Command { flags := listenFilteredBlockCmd.Flags() cliconfig.InitChannelID(flags) cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to listen for events, e.g. localhost:7051") cliconfig.InitSeekType(flags) cliconfig.InitBlockNum(flags) return listenFilteredBlockCmd } type listenFilteredBlockAction struct { action.Action inputEvent } func newlistenFilteredBlockAction(flags *pflag.FlagSet) (*listenFilteredBlockAction, error) { action := &listenFilteredBlockAction{inputEvent: inputEvent{done: make(chan bool)}} err := action.Initialize(flags) return action, err } func (a *listenFilteredBlockAction) invoke() error { eventClient, err := a.EventClient(event.WithSeekType(cliconfig.Config().SeekType()), event.WithBlockNum(cliconfig.Config().BlockNum())) if err != nil { return err } fmt.Printf("Registering filtered block event\n") breg, beventch, err := eventClient.RegisterFilteredBlockEvent() if err != nil { return errors.WithMessage(err, "Error registering for filtered block events") } defer eventClient.Unregister(breg) enterch := a.WaitForEnter() for { select { case _, _ = <-enterch: return nil case event, ok := <-beventch: if !ok { return errors.WithMessage(err, "unexpected closed channel while waiting for filtered block event") } a.Printer().PrintFilteredBlock(event.FilteredBlock) fmt.Println("Press to terminate") } } } ================================================ FILE: fabric-cli/cmd/fabric-cli/event/listentxcmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package event import ( "fmt" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var listenTxCmd = &cobra.Command{ Use: "listentx", Short: "Listen to transaction events.", Long: "Listen to transaction events", Run: func(cmd *cobra.Command, args []string) { if cliconfig.Config().TxID() == "" { fmt.Printf("\nMust specify the transaction ID\n\n") cmd.HelpFunc()(cmd, args) return } action, err := newListenTXAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing listenTxAction: %v", err) return } defer action.Terminate() err = action.invoke() if err != nil { cliconfig.Config().Logger().Errorf("Error while running listenTxAction: %v", err) } }, } func getListenTXCmd() *cobra.Command { flags := listenTxCmd.Flags() cliconfig.InitChannelID(flags) cliconfig.InitTxID(flags) cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to listen for events, e.g. grpcs://localhost:7051") return listenTxCmd } type listentxAction struct { action.Action inputEvent } func newListenTXAction(flags *pflag.FlagSet) (*listentxAction, error) { action := &listentxAction{inputEvent: inputEvent{done: make(chan bool)}} err := action.Initialize(flags) return action, err } func (a *listentxAction) invoke() error { eventHub, err := a.EventClient() if err != nil { return err } fmt.Printf("Registering TX event for TxID [%s]\n", cliconfig.Config().TxID()) reg, eventch, err := eventHub.RegisterTxStatusEvent(cliconfig.Config().TxID()) if err != nil { return errors.WithMessage(err, "Error registering for block events") } defer eventHub.Unregister(reg) enterch := a.WaitForEnter() fmt.Println("Press to terminate") select { case _, _ = <-enterch: return nil case event, ok := <-eventch: if !ok { return errors.WithMessage(err, "unexpected closed channel while waiting for tx status event") } fmt.Printf("Received TX event. TxID: %s, Code: %s, Error: %s\n", event.TxID, event.TxValidationCode, err) } return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/executor/executor.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package executor import ( "fmt" "math" "sync" "time" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/executor/worker" ) // State is the state of the executor type State uint8 const ( // NEW indicates that the executor is new and has not been started yet NEW State = iota // STARTED indicates that the executor is up and running STARTED // TERMINATED indicates that the executor has been shut down TERMINATED ) // Executor maintains a pool of workers that execute Tasks in separate Go routines. The caller submits // a Task to the Executor, which is submitted to an available worker. If a worker is not available then // the task is queue until one becomes available. The Executor is useful for throttling requests in order // not to overload the application. type Executor struct { name string state State tasks chan worker.Task terminating chan bool pool *worker.Pool wg sync.WaitGroup } // NewConcurrent creates a new, concurrent executor with the given concurrency. // As tasks are submitted they are queued while waiting for a worker for execution. // // - name: The name of the executor (useful for debugging) // - concurrency: The concurrency, i.e. the number of workers executing concurrently func NewConcurrent(name string, concurrency uint16) *Executor { return New(name, math.MaxInt16, worker.NewPool(name, concurrency)) } // NewBoundedConcurrent creates a new, concurrent executor with the given concurrency // and queue length. As tasks are submitted they are queued while waiting for a worker for execution. Once the // number of queued tasks reaches the given queue length, the Submit operation will block until a worker becomes // available. // // - name: The name of the executor (useful for debugging) // - concurrency: The concurrency, i.e. the number of workers executing concurrently // - queueLength: The maximum number of tasks allowed to be queued while waiting for a worker func NewBoundedConcurrent(name string, concurrency uint16, queueLength uint16) *Executor { return New(name, queueLength, worker.NewPool(name, concurrency)) } // New creates a new, multi-threaded executor with the given options: // - name: The name of the executor (useful for debugging) // - queueLength: The maximum number of tasks allowed to be queued while waiting for a worker // If queueSize == concurrency then the Submit() function will block until a worker becomes free, // otherwise the task will be added to the queue and Submit() will not block. // pool - The worker pool func New(name string, queueLength uint16, pool *worker.Pool) *Executor { return &Executor{ name: name, state: NEW, terminating: make(chan bool), tasks: make(chan worker.Task, queueLength), pool: pool, } } // Start starts the Executor func (e *Executor) Start() bool { if e.state != NEW { return false } // Start the worker pool e.pool.Start() // Start the task dispatcher go e.dispatch() e.state = STARTED return true } // Submit submits a new task func (e *Executor) Submit(task worker.Task) error { if e.state != STARTED { return fmt.Errorf("executor [%s] is not started", e.name) } // Submit the task to the dispatcher cliconfig.Config().Logger().Debugf("Submit[%s] - submitting task...\n", e.name) e.wg.Add(1) e.tasks <- task cliconfig.Config().Logger().Debugf("...Submit[%s] - submitted task\n", e.name) return nil } // SubmitDelayed submits a new task in the future func (e *Executor) SubmitDelayed(task worker.Task, delay time.Duration) error { if e.state != STARTED { return fmt.Errorf("executor [%s] is not started", e.name) } cliconfig.Config().Logger().Debugf("Submit[%s] - submitting task to execute in %s ...\n", e.name, delay) e.wg.Add(1) go func() { <-time.After(delay) e.Submit(task) e.wg.Done() }() return nil } // Wait waits for all outstanding tasks to complete func (e *Executor) Wait() { e.wg.Wait() } // Stop stops the executor. // - wait: If true then the call will block until all outstanding // tasks have completed; otherwise the executor will shut down immediately func (e *Executor) Stop(wait bool) bool { if e.state != STARTED { return false } e.state = TERMINATED cliconfig.Config().Logger().Debugf("[%s] Stopping executor ...\n", e.name) // Wait for the dispatcher to purge its queue e.wg.Wait() cliconfig.Config().Logger().Debugf("[%s] Stopping the dispatcher ...\n", e.name) // Stop the dispatcher e.terminating <- true cliconfig.Config().Logger().Debugf("[%s] Stopping the worker pool ...\n", e.name) // Stop the worker pool e.pool.Stop(wait) cliconfig.Config().Logger().Debugf("[%s] ... executor stopped.\n", e.name) return true } func (e *Executor) dispatch() { for { select { // Wait for a task case task := <-e.tasks: e.pool.Submit(task) e.wg.Done() case <-e.terminating: cliconfig.Config().Logger().Debugf("[%s] ... executor dispatcher ended\n", e.name) return } } } ================================================ FILE: fabric-cli/cmd/fabric-cli/executor/worker/worker.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package worker import ( cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" ) // State is the state of a Worker type State uint8 const ( // READY indicates that a worker is ready to accept a new task READY State = iota // STOPPED indicates that the worker has terminated STOPPED ) // Task is the task that the Worker invokes type Task interface { Invoke() } // Events receives event notifications from the worker type Events interface { // StateChange indicates the new state of the worker StateChange(w *Worker, state State) // TaskStarted indicates that the given worker has started executing the given task TaskStarted(w *Worker, task Task) // TaskCompleted indicates that the given worker has completed the given task TaskCompleted(w *Worker, task Task) } // Worker invokes a Task type Worker struct { name string events Events task chan Task done chan bool } func newWorker(name string, events Events) *Worker { return &Worker{ name: name, events: events, task: make(chan Task), done: make(chan bool), } } // Name returns the name of the worker (useful for debugging) func (w *Worker) Name() string { return w.name } // Submit submits a task func (w *Worker) Submit(task Task) { w.task <- task } func (w *Worker) invoke(task Task) { cliconfig.Config().Logger().Debugf("Worker[%s].invoke ...\n", w.name) defer w.events.TaskCompleted(w, task) w.events.TaskStarted(w, task) task.Invoke() cliconfig.Config().Logger().Debugf("Worker[%s].invoke done.\n", w.name) } // Start starts the worker func (w *Worker) Start() { cliconfig.Config().Logger().Debugf("Worker[%s] starting...\n", w.name) go func() { for { cliconfig.Config().Logger().Debugf("Worker[%s] waiting for task...\n", w.name) // Inform the events that I'm available w.events.StateChange(w, READY) select { case task := <-w.task: w.invoke(task) case <-w.done: w.events.StateChange(w, STOPPED) cliconfig.Config().Logger().Debugf("Worker[%s] stopped\n", w.name) return } } }() } // Stop stops the worker func (w *Worker) Stop() { cliconfig.Config().Logger().Debugf("Worker[%s] stopping...\n", w.name) w.done <- true } ================================================ FILE: fabric-cli/cmd/fabric-cli/executor/worker/workerpool.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package worker import ( "fmt" "sync" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" ) // Pool contains a pool of workers that can each execute a Task type Pool struct { name string workers []*Worker availableWorker chan *Worker taskWg sync.WaitGroup wg sync.WaitGroup } // NewPool creates a worker Pool with the given Factory func NewPool(name string, concurrency uint16) *Pool { pool := &Pool{ name: name, availableWorker: make(chan *Worker, concurrency), workers: make([]*Worker, concurrency), } // Create the workers for i := 0; i < int(concurrency); i++ { pool.workers[i] = newWorker(fmt.Sprintf("%s-%d", name, i), pool) } return pool } // Name returns the name of the pool func (p *Pool) Name() string { return p.name } // Start starts the pool func (p *Pool) Start() { p.wg.Add(len(p.workers)) // Start the workers for _, w := range p.workers { w.Start() } } // Stop stops the pool and optionally waits until all tasks have completed func (p *Pool) Stop(wait bool) { cliconfig.Config().Logger().Debugf("[%s] Stopping worker pool ...\n", p.name) if wait { // Wait for all the tasks to complete cliconfig.Config().Logger().Debugf("[%s] ... waiting for tasks to complete ...\n", p.name) p.taskWg.Wait() } else { cliconfig.Config().Logger().Debugf("[%s] ... forcing all tasks to stop ...\n", p.name) } // Shut down the workers cliconfig.Config().Logger().Debugf("[%s] ... stopping workers ...\n", p.name) for i := 0; i < len(p.workers); i++ { w := <-p.availableWorker w.Stop() } // Wait for all of the workers to stop p.wg.Wait() } // Submit submits a Task for execution func (p *Pool) Submit(task Task) { cliconfig.Config().Logger().Debugf("worker pool.Submit[%s] - waiting for available worker\n", p.name) p.taskWg.Add(1) // Wait for an available worker w := <-p.availableWorker cliconfig.Config().Logger().Debugf("worker pool.Submit[%s] - got worker [%s]. Submitting task...\n", p.name, w.Name()) // Submit the task to the worker w.Submit(task) cliconfig.Config().Logger().Debugf("worker pool.Submit[%s] - submitted task to worker[%s]\n", p.name, w.Name()) } // StateChange is invoked when the state of the Worker changes func (p *Pool) StateChange(w *Worker, state State) { switch state { case READY: p.availableWorker <- w break case STOPPED: cliconfig.Config().Logger().Debugf("...Worker[%s] stopped\n", w.Name()) p.wg.Done() break default: cliconfig.Config().Logger().Warnf("Unsupported worker state: %d\n", state) break } } // TaskStarted is invoked when the given Worker begins executing the given Task func (p *Pool) TaskStarted(w *Worker, task Task) { // Nothing to do } // TaskCompleted is invoked when the given Worker completed executing the given Task func (p *Pool) TaskCompleted(w *Worker, task Task) { p.taskWg.Done() } ================================================ FILE: fabric-cli/cmd/fabric-cli/fabric-cli.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package main import ( "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/cmd" ) func main() { cmd.Execute() } ================================================ FILE: fabric-cli/cmd/fabric-cli/go.mod ================================================ // Copyright SecureKey Technologies Inc. All Rights Reserved. // // SPDX-License-Identifier: Apache-2.0 module github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli require ( github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5 // indirect github.com/golang/protobuf v1.3.2 github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85 github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200106161850-8f3d32c9d1a6 github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/magiconair/properties v1.8.0 // indirect github.com/mitchellh/mapstructure v0.0.0-20180511142126-bb74f1db0675 // indirect github.com/pelletier/go-toml v1.2.0 // indirect github.com/pkg/errors v0.8.1 github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e // indirect github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7 // indirect github.com/spf13/afero v1.1.1 // indirect github.com/spf13/cobra v0.0.3 github.com/spf13/pflag v1.0.1 github.com/stretchr/testify v1.3.0 ) go 1.13 ================================================ FILE: fabric-cli/cmd/fabric-cli/go.sum ================================================ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5 h1:PqZ3bA4yzwywivzk7PBQWngJp2/PAS0bWRZerKteicY= github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93 h1:qdfmdGwtm13OVx+AxguOWUTbgmXGn2TbdUHipo3chMg= github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce h1:xdsDDbiBDQTKASoGEZ+pEmF1OnWuu8AQ9I8iNbHNeno= github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hyperledger/fabric-lib-go v1.0.0 h1:UL1w7c9LvHZUSkIvHTDGklxFv2kTeva1QI2emOVc324= github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85 h1:bNgEcCg5NVRWs/T+VUEfhgh5Olx/N4VB+0+ybW+oSuA= github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200106161850-8f3d32c9d1a6 h1:oEdHFGkrXcfoJdXmxem5fCyXS23SdfHc2UPt5g8o6HM= github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200106161850-8f3d32c9d1a6/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27 h1:XA/VH+SzpYyukhgh7v2mTp8rZoKKITXR/x3FIizVEXs= github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27/go.mod h1:WCBAbTOdfhHhz7YXujeZMF7owC4tPb1naKFsgfUISjo= github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20180511142126-bb74f1db0675 h1:/rdJjIiKG5rRdwG5yxHmSE/7ZREjpyC0kL7GxGT/qJw= github.com/mitchellh/mapstructure v0.0.0-20180511142126-bb74f1db0675/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/procfs v0.0.0-20180705121852-ae68e2d4c00f/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7 h1:NgR6WN8nQ4SmFC1sSUHY8SriLuWCZ6cCIQtH4vDZN3c= github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.1 h1:Lt3ihYMlE+lreX1GS4Qw4ZsNpYQLxIXKBTEOXm3nt6I= github.com/spf13/afero v1.1.1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg= github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec h1:2ZXvIUGghLpdTVHR1UfvfrzoVlZaE/yOWC5LueIHZig= github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.0.2 h1:Ncr3ZIuJn322w2k1qmzXDnkLAdQMlJqBa9kfAH+irso= github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d h1:XB2jc5XQ9uhizGTS2vWcN01bc4dI6z3C4KY5MQm8SS8= google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= ================================================ FILE: fabric-cli/cmd/fabric-cli/printer/blockprinter.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package printer import ( "encoding/base64" "fmt" "net/http" "reflect" "strings" "github.com/golang/protobuf/proto" fabriccmn "github.com/hyperledger/fabric-protos-go/common" "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" "github.com/hyperledger/fabric-protos-go/msp" ab "github.com/hyperledger/fabric-protos-go/orderer" pb "github.com/hyperledger/fabric-protos-go/peer" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/core/common/ccprovider" "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil" ledgerUtil "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/core/ledger/util" "github.com/pkg/errors" ) const ( // AnchorPeersKey is the key name for the AnchorPeers ConfigValue AnchorPeersKey = "AnchorPeers" // ReadersPolicyKey is the key used for the read policy ReadersPolicyKey = "Readers" // WritersPolicyKey is the key used for the read policy WritersPolicyKey = "Writers" // AdminsPolicyKey is the key used for the read policy AdminsPolicyKey = "Admins" // MSPKey is the org key used for MSP configuration MSPKey = "MSP" // ConsensusTypeKey is the cb.ConfigItem type key name for the ConsensusType message ConsensusTypeKey = "ConsensusType" // BatchSizeKey is the cb.ConfigItem type key name for the BatchSize message BatchSizeKey = "BatchSize" // BatchTimeoutKey is the cb.ConfigItem type key name for the BatchTimeout message BatchTimeoutKey = "BatchTimeout" // ChannelRestrictionsKey is the key name for the ChannelRestrictions message ChannelRestrictionsKey = "ChannelRestrictions" // KafkaBrokersKey is the cb.ConfigItem type key name for the KafkaBrokers message KafkaBrokersKey = "KafkaBrokers" // ChannelCreationPolicyKey is the key for the ChannelCreationPolicy value ChannelCreationPolicyKey = "ChannelCreationPolicy" // ConsortiumKey is the key for the cb.ConfigValue for the Consortium message ConsortiumKey = "Consortium" // HashingAlgorithmKey is the cb.ConfigItem type key name for the HashingAlgorithm message HashingAlgorithmKey = "HashingAlgorithm" // BlockDataHashingStructureKey is the cb.ConfigItem type key name for the BlockDataHashingStructure message BlockDataHashingStructureKey = "BlockDataHashingStructure" // OrdererAddressesKey is the cb.ConfigItem type key name for the OrdererAddresses message OrdererAddressesKey = "OrdererAddresses" // ChannelGroupKey is the name of the channel group ChannelGroupKey = "Channel" // CapabilitiesKey is the key for capabilities CapabilitiesKey = "Capabilities" collectionSeparator = "~" ) // Printer is used for printing various data structures type Printer interface { // PrintBlockchainInfo outputs BlockchainInfo PrintBlockchainInfo(info *fabriccmn.BlockchainInfo) // PrintBlock outputs a Block PrintBlock(block *fabriccmn.Block) // PrintFilteredBlock outputs a Block PrintFilteredBlock(block *pb.FilteredBlock) // PrintChannels outputs the array of ChannelInfo PrintChannels(channels []*pb.ChannelInfo) // PrintChaincodes outputs the given array of ChaincodeInfo PrintChaincodes(chaincodes []*pb.ChaincodeInfo) // PrintProcessedTransaction outputs a ProcessedTransaction PrintProcessedTransaction(tx *pb.ProcessedTransaction) // PrintChaincodeData outputs ChaincodeData PrintChaincodeData(ccdata *ccprovider.ChaincodeData, collConfig *pb.CollectionConfigPackage) // PrintTxProposalResponses outputs the proposal responses PrintTxProposalResponses(responses []*fab.TransactionProposalResponse, payloadOnly bool) // PrintResponses outputs responses PrintResponses(response []*pb.Response) // PrintChaincodeEvent outputs a chaincode event PrintChaincodeEvent(event *fab.CCEvent) // PrintPeers outputs the array of Peers PrintPeers(peers []fab.Peer) // Print outputs a formatted string Print(frmt string, vars ...interface{}) } // BlockPrinter is an implementation of BlockPrinter type BlockPrinter struct { printer } // NewBlockPrinter returns a new Printer of the given OutputFormat and WriterType func NewBlockPrinter(format OutputFormat, writerType WriterType) *BlockPrinter { return &BlockPrinter{ printer: *newPrinter(format, writerType), } } // NewBlockPrinterWithOpts returns a new Printer of the given OutputFormat and WriterType func NewBlockPrinterWithOpts(format OutputFormat, writerType WriterType, opts *FormatterOpts) *BlockPrinter { return &BlockPrinter{ printer: *newPrinterWithOpts(format, writerType, opts), } } // PrintBlockchainInfo prints BlockchainInfo func (p *BlockPrinter) PrintBlockchainInfo(info *fabriccmn.BlockchainInfo) { if p.Formatter == nil { fmt.Printf("%s\n", info) return } p.PrintHeader() p.Field("Height", info.Height) p.Field("CurrentBlockHash", Base64URLEncode(info.CurrentBlockHash)) p.Field("PreviousBlockHash", Base64URLEncode(info.PreviousBlockHash)) p.PrintFooter() } // PrintBlock prints a Block func (p *BlockPrinter) PrintBlock(block *fabriccmn.Block) { if p.Formatter == nil { fmt.Printf("%s\n", block) return } p.PrintHeader() p.Element("Header") p.Field("Number", block.Header.Number) p.Field("PreviousHash", Base64URLEncode(block.Header.PreviousHash)) p.Field("DataHash", Base64URLEncode(block.Header.DataHash)) p.ElementEnd() p.Element("Metadata") p.PrintBlockMetadata(block.Metadata) p.ElementEnd() p.Element("Data") p.Array("Data") for i := range block.Data.Data { p.Item("Envelope", i) p.PrintEnvelope(ExtractEnvelopeOrPanic(block, i)) p.ItemEnd() } p.ArrayEnd() p.ElementEnd() p.PrintFooter() } // PrintFilteredBlock prints a FilteredBlock func (p *BlockPrinter) PrintFilteredBlock(block *pb.FilteredBlock) { if p.Formatter == nil { fmt.Printf("%s\n", block) return } p.PrintHeader() p.Field("ChannelID", block.ChannelId) p.Field("Number", block.Number) p.Element("FilteredTransactions") p.Array("FilteredTransactions") for _, tx := range block.FilteredTransactions { p.PrintFilteredTransaction(tx) } p.ArrayEnd() p.ElementEnd() p.PrintFooter() } // PrintChannels prints the array of ChannelInfo func (p *BlockPrinter) PrintChannels(channels []*pb.ChannelInfo) { if p.Formatter == nil { fmt.Printf("%s\n", channels) return } p.PrintHeader() p.Array("Channels") for _, channel := range channels { p.Field("ChannelId", channel.ChannelId) } p.ArrayEnd() p.PrintFooter() } func (p *BlockPrinter) PrintPeers(peers []fab.Peer) { if p.Formatter == nil { fmt.Printf("%s\n", peers) return } p.PrintHeader() p.Array("Peers") for _, peer := range peers { p.Item("Peer", peer.URL()) p.PrintPeer(peer) p.ItemEnd() } p.ArrayEnd() p.PrintFooter() } // PrintChaincodes prints the array of ChaincodeInfo func (p *BlockPrinter) PrintChaincodes(chaincodes []*pb.ChaincodeInfo) { if p.Formatter == nil { fmt.Printf("%s\n", chaincodes) return } p.PrintHeader() p.Array("") for _, ccInfo := range chaincodes { p.Item("ChaincodeInfo", ccInfo.Name) p.PrintChaincodeInfo(ccInfo) p.ItemEnd() } p.ArrayEnd() p.PrintFooter() } // PrintProcessedTransaction prints a ProcessedTransaction func (p *BlockPrinter) PrintProcessedTransaction(tx *pb.ProcessedTransaction) { if p.Formatter == nil { fmt.Printf("%s\n", tx) return } p.PrintHeader() p.Print("ValidationCode: %s", pb.TxValidationCode(tx.ValidationCode)) p.PrintEnvelope(tx.TransactionEnvelope) p.PrintFooter() } // PrintChaincodeData prints the given ChaincodeData func (p *BlockPrinter) PrintChaincodeData(ccData *ccprovider.ChaincodeData, collConfig *pb.CollectionConfigPackage) { if p.Formatter == nil { fmt.Printf("%s\n", ccData) return } p.PrintHeader() p.doPrintChaincodeData(ccData) if collConfig != nil { p.doPrintCollConfig(collConfig) } p.PrintFooter() } func (p *BlockPrinter) doPrintChaincodeData(ccData *ccprovider.ChaincodeData) { p.Field("Id", ccData.Id) p.Field("Name", ccData.Name) p.Field("Version", ccData.Version) p.Field("Escc", ccData.Escc) p.Field("Vscc", ccData.Vscc) cdsData := &ccprovider.CDSData{} unmarshalOrPanic(ccData.Data, cdsData) p.Element("Data") p.PrintCDSData(cdsData) p.ElementEnd() policy := &fabriccmn.SignaturePolicyEnvelope{} unmarshalOrPanic(ccData.Policy, policy) p.Element("Policy") p.PrintSignaturePolicyEnvelope(policy) p.ElementEnd() instPolicy := &fabriccmn.SignaturePolicyEnvelope{} unmarshalOrPanic(ccData.InstantiationPolicy, instPolicy) p.Element("InstantiationPolicy") p.PrintSignaturePolicyEnvelope(instPolicy) p.ElementEnd() } func (p *BlockPrinter) doPrintCollConfig(collConfig *pb.CollectionConfigPackage) { p.Array("CollectionConfig") for i, c := range collConfig.Config { p.Item("Config", i) sc := c.GetStaticCollectionConfig() if sc == nil { p.Value("unknown config type") continue } p.printStaticCollectionConfig(sc) p.ItemEnd() } p.ArrayEnd() } func (p *BlockPrinter) printStaticCollectionConfig(config *pb.StaticCollectionConfig) { p.Field("Name", config.Name) p.Field("BlockToLive", config.BlockToLive) p.Field("MaximumPeerCount", config.MaximumPeerCount) p.Field("RequiredPeerCount", config.RequiredPeerCount) p.Field("MemberOnlyRead", config.MemberOnlyRead) p.Field("MemberOnlyWrite", config.MemberOnlyWrite) p.Element("MemberOrgsPolicy") p.PrintSignaturePolicyEnvelope(config.MemberOrgsPolicy.GetSignaturePolicy()) p.ElementEnd() } // PrintTxProposalResponses prints the given transaction proposal responses func (p *BlockPrinter) PrintTxProposalResponses(responses []*fab.TransactionProposalResponse, payloadOnly bool) { if p.Formatter == nil { for i, response := range responses { fmt.Printf("Response[%d]: %v\n", i, response) } return } p.PrintHeader() p.Array("") for i, response := range responses { p.Item("Response", i) p.PrintTxProposalResponse(response, payloadOnly) p.ItemEnd() } p.ArrayEnd() p.PrintFooter() } // PrintChaincodeEvent prints the given ChaincodeEvent func (p *BlockPrinter) PrintChaincodeEvent(event *fab.CCEvent) { if p.Formatter == nil { fmt.Printf("%v\n", event) return } p.PrintHeader() p.Field("ChaincodeID", event.ChaincodeID) p.Field("EventName", event.EventName) //p.Field("ChannelID", event.ChannelID) p.Field("TxID", event.TxID) p.Field("Payload", event.Payload) p.PrintFooter() } // PrintTxProposalResponse prints the TransactionProposalResponse func (p *BlockPrinter) PrintTxProposalResponse(response *fab.TransactionProposalResponse, payloadOnly bool) { if payloadOnly { if response.Status != http.StatusOK { p.Field("Err", response.Status) } else if response.ProposalResponse == nil || response.ProposalResponse.Response == nil { p.Field("Response", nil) } else { p.Field("Payload", response.ProposalResponse.Response.Payload) } } else { p.Field("Endorser", response.Endorser) p.Field("Status", response.Status) p.Element("ProposalResponse") p.PrintProposalResponse(response.ProposalResponse) p.ElementEnd() } } // PrintProposalResponse prints a ProposalResponse func (p *BlockPrinter) PrintProposalResponse(response *pb.ProposalResponse) { if response == nil { return } p.Element("Response") p.PrintResponse(response.Response) p.ElementEnd() prp := &pb.ProposalResponsePayload{} unmarshalOrPanic(response.Payload, prp) p.Element("ProposalResponsePayload") p.PrintProposalResponsePayload(prp) p.ElementEnd() p.Element("Endorsement") p.PrintEndorsement(response.Endorsement) p.ElementEnd() } // PrintResponses prints an array of Response func (p *BlockPrinter) PrintResponses(responses []*pb.Response) { if p.Formatter == nil { for i, response := range responses { fmt.Printf("Response[%d]: %v\n", i, response) } return } p.PrintHeader() p.Array("") for i, response := range responses { p.Item("Response", i) p.PrintResponse(response) p.ItemEnd() } p.ArrayEnd() p.PrintFooter() } // PrintResponse prints the Response func (p *BlockPrinter) PrintResponse(response *pb.Response) { p.Field("Message", response.Message) p.Field("Status", response.Status) p.Field("Payload", response.Payload) } // PrintCDSData prints the chaincode deployment spec data (CDSData) func (p *BlockPrinter) PrintCDSData(cdsData *ccprovider.CDSData) { p.Field("CodeHash", Base64URLEncode(cdsData.CodeHash)) p.Field("MetaDataHash", Base64URLEncode(cdsData.MetaDataHash)) } // PrintEnvelope prints the given Envelope func (p *BlockPrinter) PrintEnvelope(envelope *fabriccmn.Envelope) { p.Field("Signature", envelope.Signature) payload := ExtractPayloadOrPanic(envelope) p.Element("Payload") p.PrintPayload(payload) p.ElementEnd() } // PrintPayload prints a Payload func (p *BlockPrinter) PrintPayload(payload *fabriccmn.Payload) { p.Element("Header") chdr, err := UnmarshalChannelHeader(payload.Header.ChannelHeader) if err != nil { panic(err) } p.Element("ChannelHeader") p.PrintChannelHeader(chdr) p.ElementEnd() sigHeader, err := GetSignatureHeader(payload.Header.SignatureHeader) if err != nil { panic(err) } p.Element("SignatureHeader") p.PrintSignatureHeader(sigHeader) p.ElementEnd() p.ElementEnd() // Header p.Element("Data") p.Field("Type", fabriccmn.HeaderType(chdr.Type)) p.PrintData(fabriccmn.HeaderType(chdr.Type), payload.Data) p.ElementEnd() } // PrintChannelHeader prints the ChannelHeader func (p *BlockPrinter) PrintChannelHeader(chdr *fabriccmn.ChannelHeader) { p.Field("Type", fabriccmn.HeaderType(chdr.Type)) p.Field("ChannelId", chdr.ChannelId) p.Field("Epoch", chdr.Epoch) ccHdrExt := &pb.ChaincodeHeaderExtension{} unmarshalOrPanic(chdr.Extension, ccHdrExt) p.Element("Extension") p.PrintChaincodeHeaderExtension(ccHdrExt) p.ElementEnd() p.Field("Timestamp", chdr.Timestamp) p.Field("TxId", chdr.TxId) p.Field("Version", chdr.Version) } // PrintChaincodeHeaderExtension prints the ChaincodeHeaderExtension func (p *BlockPrinter) PrintChaincodeHeaderExtension(ccHdrExt *pb.ChaincodeHeaderExtension) { p.Element("ChaincodeId") p.PrintChaincodeID(ccHdrExt.ChaincodeId) p.ElementEnd() } // PrintChaincodeID prints the ChaincodeID func (p *BlockPrinter) PrintChaincodeID(ccID *pb.ChaincodeID) { if ccID == nil { return } p.Field("Name", ccID.Name) p.Field("Version", ccID.Version) p.Field("Path", ccID.Path) } // PrintChaincodeInfo prints ChaincodeInfo func (p *BlockPrinter) PrintChaincodeInfo(ccInfo *pb.ChaincodeInfo) { p.Field("Name", ccInfo.Name) p.Field("Path", ccInfo.Path) p.Field("Version", ccInfo.Version) p.Field("Escc", ccInfo.Escc) p.Field("Vscc", ccInfo.Vscc) p.Field("Input", ccInfo.Input) } // PrintSignatureHeader prints a SignatureHeader func (p *BlockPrinter) PrintSignatureHeader(sigHdr *fabriccmn.SignatureHeader) { p.Field("Nonce", sigHdr.Nonce) p.Field("Creator", sigHdr.Creator) } // PrintData prints the block of data formatted according to the given HeaderType func (p *BlockPrinter) PrintData(headerType fabriccmn.HeaderType, data []byte) { if headerType == fabriccmn.HeaderType_CONFIG { envelope := &fabriccmn.ConfigEnvelope{} if err := proto.Unmarshal(data, envelope); err != nil { panic(errors.Errorf("Bad envelope: %v", err)) } p.Print("Config Envelope:") p.PrintConfigEnvelope(envelope) } else if headerType == fabriccmn.HeaderType_CONFIG_UPDATE { envelope := &fabriccmn.ConfigUpdateEnvelope{} if err := proto.Unmarshal(data, envelope); err != nil { panic(errors.Errorf("Bad envelope: %v", err)) } p.Print("Config Update Envelope:") p.PrintConfigUpdateEnvelope(envelope) } else if headerType == fabriccmn.HeaderType_ENDORSER_TRANSACTION { tx, err := GetTransaction(data) if err != nil { panic(errors.Errorf("Bad envelope: %v", err)) } p.Print("Transaction:") p.PrintTransaction(tx) } else { p.Field("Unsupported Envelope", Base64URLEncode(data)) } } // PrintConfigEnvelope prints the ConfigEnvelope func (p *BlockPrinter) PrintConfigEnvelope(envelope *fabriccmn.ConfigEnvelope) { p.Element("Config") p.PrintConfig(envelope.Config) p.ElementEnd() p.Element("LastUpdate") p.PrintEnvelope(envelope.LastUpdate) p.ElementEnd() } // PrintConfigUpdateEnvelope prints a ConfigUpdateEnvelope func (p *BlockPrinter) PrintConfigUpdateEnvelope(envelope *fabriccmn.ConfigUpdateEnvelope) { p.Array("Signatures") for i, sig := range envelope.Signatures { p.Item("Config Signature", i) p.PrintConfigSignature(sig) p.ItemEnd() } p.ArrayEnd() configUpdate := &fabriccmn.ConfigUpdate{} if err := proto.Unmarshal(envelope.ConfigUpdate, configUpdate); err != nil { panic(err) } p.Element("ConfigUpdate") p.PrintConfigUpdate(configUpdate) p.ElementEnd() } // PrintTransaction prints a Transaction func (p *BlockPrinter) PrintTransaction(tx *pb.Transaction) { p.Array("Actions") for i, action := range tx.Actions { p.Item("Action", i) p.PrintTXAction(action) p.ItemEnd() } p.ArrayEnd() } // PrintFilteredTransaction prints a FilteredTransaction func (p *BlockPrinter) PrintFilteredTransaction(tx *pb.FilteredTransaction) { p.Field("Txid", tx.GetTxid()) p.Field("Type", tx.GetType()) p.Field("TxValidationCode", tx.GetTxValidationCode()) p.Element("ChaincodeEvents") p.Array("ChaincodeEvents") txActions := tx.GetTransactionActions() if txActions != nil { for _, ccAction := range txActions.ChaincodeActions { p.PrintFilteredCCAction(ccAction) } } p.ArrayEnd() p.ElementEnd() } // PrintTXAction prinbts a transaction action func (p *BlockPrinter) PrintTXAction(action *pb.TransactionAction) { p.Element("Header") sigHeader, err := GetSignatureHeader(action.Header) if err != nil { panic(err) } p.PrintSignatureHeader(sigHeader) p.ElementEnd() p.Element("Payload") chaPayload, err := GetChaincodeActionPayload(action.Payload) if err != nil { panic(err) } p.PrintChaincodeActionPayload(chaPayload) p.ElementEnd() } // PrintFilteredCCAction prinbts a chaincode action func (p *BlockPrinter) PrintFilteredCCAction(action *pb.FilteredChaincodeAction) { ccEvent := action.GetChaincodeEvent() p.Field("Txid", ccEvent.GetTxId()) p.Field("ChaincodeId", ccEvent.GetChaincodeId()) p.Field("EventName", ccEvent.GetEventName()) p.Field("Payload", ccEvent.GetPayload()) } // PrintChaincodeActionPayload prints a ChaincodeActionPayload func (p *BlockPrinter) PrintChaincodeActionPayload(chaPayload *pb.ChaincodeActionPayload) { cpp := &pb.ChaincodeProposalPayload{} err := proto.Unmarshal(chaPayload.ChaincodeProposalPayload, cpp) if err != nil { panic(err) } p.Element("ChaincodeProposalPayload") p.PrintChaincodeProposalPayload(cpp) p.ElementEnd() p.Element("Action") p.PrintAction(chaPayload.Action) p.ElementEnd() } // PrintChaincodeProposalPayload prints a ChaincodeProposalPayload func (p *BlockPrinter) PrintChaincodeProposalPayload(cpp *pb.ChaincodeProposalPayload) { cis := &pb.ChaincodeInvocationSpec{} err := proto.Unmarshal(cpp.Input, cis) if err != nil { panic(err) } p.Element("Input") p.PrintChaincodeInvocationSpec(cis) p.ElementEnd() p.Array("TransientMap") for key, value := range cpp.TransientMap { p.Item("Key", key) p.Field("Value", value) p.ItemEnd() } p.ArrayEnd() } // PrintChaincodeInvocationSpec prints a ChaincodeProposalPayload func (p *BlockPrinter) PrintChaincodeInvocationSpec(cis *pb.ChaincodeInvocationSpec) { p.Element("ChaincodeSpec") p.PrintChaincodeSpec(cis.ChaincodeSpec) p.ElementEnd() } // PrintAction prints a ChaincodeEndorsedAction func (p *BlockPrinter) PrintAction(action *pb.ChaincodeEndorsedAction) { p.Array("Endorsements") for i, endorsement := range action.Endorsements { p.Item("Endorsement", i) p.PrintEndorsement(endorsement) p.ItemEnd() } p.ArrayEnd() prp := &pb.ProposalResponsePayload{} unmarshalOrPanic(action.ProposalResponsePayload, prp) p.Element("ProposalResponsePayload") p.PrintProposalResponsePayload(prp) p.ElementEnd() } // PrintProposalResponsePayload prints a ProposalResponsePayload func (p *BlockPrinter) PrintProposalResponsePayload(prp *pb.ProposalResponsePayload) { p.Field("ProposalHash", Base64URLEncode(prp.ProposalHash)) chaincodeAction := &pb.ChaincodeAction{} unmarshalOrPanic(prp.Extension, chaincodeAction) p.Element("Extension") p.PrintChaincodeAction(chaincodeAction) p.ElementEnd() } // PrintChaincodeAction prints a ChaincodeAction func (p *BlockPrinter) PrintChaincodeAction(chaincodeAction *pb.ChaincodeAction) { p.Element("Response") p.PrintChaincodeResponse(chaincodeAction.Response) p.ElementEnd() p.Element("Results") if len(chaincodeAction.Results) > 0 { txRWSet := &rwsetutil.TxRwSet{} if err := txRWSet.FromProtoBytes(chaincodeAction.Results); err != nil { panic(err) } p.PrintTxReadWriteSet(txRWSet) } p.ElementEnd() p.Element("Events") if len(chaincodeAction.Events) > 0 { chaincodeEvent := &pb.ChaincodeEvent{} unmarshalOrPanic(chaincodeAction.Events, chaincodeEvent) p.PrintChaincodeEventFromBlock(chaincodeEvent) } p.ElementEnd() } // PrintTxReadWriteSet prints a transaction read-write set (TxRwSet) func (p *BlockPrinter) PrintTxReadWriteSet(txRWSet *rwsetutil.TxRwSet) { p.Array("NsRWs") for i, nsRWSet := range txRWSet.NsRwSets { p.Item("TxRwSet", i) p.PrintNsReadWriteSet(nsRWSet) p.ItemEnd() } p.ArrayEnd() } // PrintNsReadWriteSet prints a namespaced read-write set (NsRwSet) func (p *BlockPrinter) PrintNsReadWriteSet(nsRWSet *rwsetutil.NsRwSet) { p.Field("NameSpace", nsRWSet.NameSpace) p.Element("KvRwSet") p.PrintKvRwSet(nsRWSet.KvRwSet, nsRWSet.NameSpace) p.ElementEnd() p.Element("CollHashedRwSets") p.PrintCollHashedRwSets(nsRWSet.CollHashedRwSets) p.ElementEnd() } // PrintKvRwSet prints a key-value read-write set func (p *BlockPrinter) PrintKvRwSet(kvRWSet *kvrwset.KVRWSet, namespace string) { p.Array("Reads") for i, r := range kvRWSet.Reads { p.Item("Read", i) p.PrintRead(r) p.ItemEnd() } p.ArrayEnd() p.Array("Writes") for i, w := range kvRWSet.Writes { p.Item("Write", i) if namespace == "lscc" { p.PrintLSCCWrite(w) } else { p.PrintWrite(w) } p.ItemEnd() } p.ArrayEnd() p.Array("RangeQueriesInfo") for i, rqi := range kvRWSet.RangeQueriesInfo { p.Item("RangeQueryInfo", i) p.PrintRangeQueryInfo(rqi) p.ItemEnd() } p.ArrayEnd() } // PrintCollHashedRwSets prints an array of collection hashed read-write set func (p *BlockPrinter) PrintCollHashedRwSets(collHashedRwSets []*rwsetutil.CollHashedRwSet) { p.Array("CollHashedRwSets") for i, w := range collHashedRwSets { p.Item("CollHashedRwSet", i) p.PrintCollHashedRwSet(w) p.ItemEnd() } p.ArrayEnd() } // PrintCollHashedRwSet prints a collection hashed read-write set func (p *BlockPrinter) PrintCollHashedRwSet(collHashedRwSet *rwsetutil.CollHashedRwSet) { p.Field("CollectionName", collHashedRwSet.CollectionName) p.Field("PvtRwSetHash", Base64URLEncode(collHashedRwSet.PvtRwSetHash)) p.Element("HashedRwSet") p.PrintHashedRwSet(collHashedRwSet.HashedRwSet) p.ElementEnd() } // PrintHashedRwSet prints a HashedRWSet func (p *BlockPrinter) PrintHashedRwSet(hashedRwSet *kvrwset.HashedRWSet) { p.PrintHashedReads(hashedRwSet.HashedReads) p.PrintHashedWrites(hashedRwSet.HashedWrites) } // PrintHashedReads prints an array of key-value read hashes (KVReadHash) func (p *BlockPrinter) PrintHashedReads(hashedReads []*kvrwset.KVReadHash) { p.Array("HashedReads") for i, r := range hashedReads { p.Item("HashedRead", i) p.PrintHashedRead(r) p.ItemEnd() } p.ArrayEnd() } // PrintHashedWrites prints an array of key-value write hashes (KVWriteHash) func (p *BlockPrinter) PrintHashedWrites(hashedWrites []*kvrwset.KVWriteHash) { p.Array("HashedWrites") for i, r := range hashedWrites { p.Item("HashedWrite", i) p.PrintHashedWrite(r) p.ItemEnd() } p.ArrayEnd() } // PrintHashedRead prints a key-value read hash (KVReadHash) func (p *BlockPrinter) PrintHashedRead(hashedRead *kvrwset.KVReadHash) { p.Field("KeyHash", Base64URLEncode(hashedRead.KeyHash)) p.PrintVersion(hashedRead.Version) } // PrintHashedWrite prints a key-value write hash (KVWriteHash) func (p *BlockPrinter) PrintHashedWrite(hashedWrite *kvrwset.KVWriteHash) { p.Field("KeyHash", Base64URLEncode(hashedWrite.KeyHash)) p.Field("ValueHash", Base64URLEncode(hashedWrite.ValueHash)) p.Field("IsDelete", hashedWrite.IsDelete) } // PrintRangeQueryInfo prints a RangeQueryInfo func (p *BlockPrinter) PrintRangeQueryInfo(rqi *kvrwset.RangeQueryInfo) { p.Field("StartKey", rqi.StartKey) p.Field("EndKey", rqi.EndKey) p.Field("ItrExhausted", rqi.ItrExhausted) p.Element("ReadsInfo") p.PrintReadsInfo(rqi.ReadsInfo) p.ElementEnd() } // PrintReadsInfo prints a RangeQuery reads info func (p *BlockPrinter) PrintReadsInfo(ri interface{}) { switch x := ri.(type) { case *kvrwset.RangeQueryInfo_RawReads: p.PrintRawReads(x.RawReads) case *kvrwset.RangeQueryInfo_ReadsMerkleHashes: p.PrintReadsMerkleHashes(x.ReadsMerkleHashes) case nil: default: p.Print("unknown type: %v", reflect.TypeOf(ri)) } } // PrintRawReads prints QueryReads func (p *BlockPrinter) PrintRawReads(qr *kvrwset.QueryReads) { p.Array("QueryReads") for i, r := range qr.KvReads { p.Item("Read", i) p.PrintRead(r) p.ItemEnd() } p.ArrayEnd() } // PrintReadsMerkleHashes prints QueryReadsMerkleSummary func (p *BlockPrinter) PrintReadsMerkleHashes(qr *kvrwset.QueryReadsMerkleSummary) { p.Field("MaxDegree", qr.MaxDegree) p.Field("MaxLevel", qr.MaxLevel) p.Array("MaxLevelHashes") for i, r := range qr.MaxLevelHashes { p.ItemValue("Hash", i, Base64URLEncode(r)) } p.ArrayEnd() } // PrintRead prints a func (p *BlockPrinter) PrintRead(r *kvrwset.KVRead) { p.Field("Key", r.Key) p.Element("Version") p.PrintVersion(r.Version) p.ElementEnd() } // PrintVersion print a Version func (p *BlockPrinter) PrintVersion(version *kvrwset.Version) { if version == nil { return } p.Field("BlockNum", version.BlockNum) p.Field("TxNum", version.TxNum) } // PrintWrite prints a key-value write (KVWrite) func (p *BlockPrinter) PrintWrite(w *kvrwset.KVWrite) { p.Field("Key", w.Key) p.Field("IsDelete", w.IsDelete) p.Field("Value", w.Value) } // PrintLSCCWrite prints a key-value write (KVWrite) func (p *BlockPrinter) PrintLSCCWrite(w *kvrwset.KVWrite) { p.Field("Key", w.Key) p.Field("IsDelete", w.IsDelete) if w.IsDelete { return } if isCollectionConfigKey(w.Key) { p.printCollectionConfig(w.Value) } else { p.printChaincodeData(w.Value) } } func (p *BlockPrinter) printChaincodeData(value []byte) { chaincodeData := &ccprovider.ChaincodeData{} if err := proto.Unmarshal(value, chaincodeData); err != nil { fmt.Printf("Error unmarshalling chaincode data from lscc KV WriteSet: %s", err) } else { p.Element("Value_ChaincodeData") p.doPrintChaincodeData(chaincodeData) p.ElementEnd() } } func (p *BlockPrinter) printCollectionConfig(value []byte) { cp := &pb.CollectionConfigPackage{} err := proto.Unmarshal(value, cp) if err != nil { fmt.Printf("Error unmarshalling collection config from lscc KV WriteSet: %s", err) return } p.doPrintCollConfig(cp) } // PrintChaincodeResponse prints a response func (p *BlockPrinter) PrintChaincodeResponse(response *pb.Response) { p.Field("Message", response.Message) p.Field("Status", response.Status) p.Field("Payload", response.Payload) } // PrintChaincodeEventFromBlock prints a ChaincodeEvent func (p *BlockPrinter) PrintChaincodeEventFromBlock(chaincodeEvent *pb.ChaincodeEvent) { p.Field("ChaincodeId", chaincodeEvent.ChaincodeId) p.Field("EventName", chaincodeEvent.EventName) p.Field("TxID", chaincodeEvent.TxId) p.Field("Payload", chaincodeEvent.Payload) } // PrintEndorsement prints an Endorsement func (p *BlockPrinter) PrintEndorsement(endorsement *pb.Endorsement) { p.Field("Endorser", endorsement.Endorser) p.Field("Signature", endorsement.Signature) } // PrintConfig prints a Config func (p *BlockPrinter) PrintConfig(config *fabriccmn.Config) { p.Field("Sequence", config.Sequence) p.Element("ChannelGroup") p.PrintConfigGroup(config.ChannelGroup) p.ElementEnd() } // PrintConfigGroup prints a ConfigGroup func (p *BlockPrinter) PrintConfigGroup(configGroup *fabriccmn.ConfigGroup) { if configGroup == nil { return } p.Field("Version", configGroup.Version) p.Field("ModPolicy", configGroup.ModPolicy) p.Array("Groups") for key, grp := range configGroup.Groups { p.Item("Group", key) p.PrintConfigGroup(grp) p.ItemEnd() } p.ArrayEnd() p.Array("Values") for key, val := range configGroup.Values { p.Item("Value", key) p.PrintConfigValue(key, val) p.ItemEnd() } p.ArrayEnd() p.Array("Policies") for key, policy := range configGroup.Policies { p.Item("Policy", key) p.PrintConfigPolicy(policy) p.ItemEnd() } p.ArrayEnd() } // PrintConfigPolicy prints a ConfigPolicy func (p *BlockPrinter) PrintConfigPolicy(policy *fabriccmn.ConfigPolicy) { p.Field("ModPolicy", policy.ModPolicy) p.Field("Version", policy.Version) if policy.Policy == nil { return } policyType := fabriccmn.Policy_PolicyType(policy.Policy.Type) switch policyType { case fabriccmn.Policy_SIGNATURE: sigPolicyEnv := &fabriccmn.SignaturePolicyEnvelope{} unmarshalOrPanic(policy.Policy.Value, sigPolicyEnv) p.Field("Type", "SIGNATURE") p.PrintSignaturePolicyEnvelope(sigPolicyEnv) break case fabriccmn.Policy_MSP: p.Field("Type", "MSP") p.Print("!!!!!!! Don't know how to Print MSP policy") break case fabriccmn.Policy_IMPLICIT_META: impMetaPolicy := &fabriccmn.ImplicitMetaPolicy{} unmarshalOrPanic(policy.Policy.Value, impMetaPolicy) p.Field("Type", "IMPLICIT_META") p.PrintImplicitMetaPolicy(impMetaPolicy) break default: break } } // PrintCapabilities prints capabilities func (p *BlockPrinter) PrintCapabilities(capabilities *fabriccmn.Capabilities) { for capability := range capabilities.Capabilities { p.Field("Capability", capability) } } // PrintImplicitMetaPolicy prints an ImplicitMetaPolicy func (p *BlockPrinter) PrintImplicitMetaPolicy(impMetaPolicy *fabriccmn.ImplicitMetaPolicy) { p.Field("Rule", impMetaPolicy.Rule) p.Field("Sub-policy", impMetaPolicy.SubPolicy) } // PrintSignaturePolicyEnvelope prints a SignaturePolicyEnvelope func (p *BlockPrinter) PrintSignaturePolicyEnvelope(sigPolicyEnv *fabriccmn.SignaturePolicyEnvelope) { p.Element("Rule") p.PrintSignaturePolicy(sigPolicyEnv.Rule) p.ElementEnd() p.Array("Identities") for i, identity := range sigPolicyEnv.Identities { p.Item("Identity", i) p.PrintMSPPrincipal(identity) p.ItemEnd() } p.ArrayEnd() } // PrintMSPPrincipal prints a MSPPrincipal func (p *BlockPrinter) PrintMSPPrincipal(principal *msp.MSPPrincipal) { p.Field("PrincipalClassification", principal.PrincipalClassification) p.Element("Principal") switch principal.PrincipalClassification { case msp.MSPPrincipal_ROLE: // Principal contains the msp role mspRole := &msp.MSPRole{} unmarshalOrPanic(principal.Principal, mspRole) p.Field("Role", mspRole.Role) p.Field("MspIdentifier", mspRole.MspIdentifier) case msp.MSPPrincipal_IDENTITY: p.Value(principal.Principal) case msp.MSPPrincipal_ORGANIZATION_UNIT: // Principal contains the OrganizationUnit unit := &msp.OrganizationUnit{} unmarshalOrPanic(principal.Principal, unit) p.Field("MspIdentifier", unit.MspIdentifier) p.Field("OrganizationalUnitIdentifier", unit.OrganizationalUnitIdentifier) p.Field("CertifiersIdentifier", unit.CertifiersIdentifier) default: p.Value("unknown PrincipalClassification") } p.ElementEnd() } // PrintSignaturePolicy prints a SignaturePolicy func (p *BlockPrinter) PrintSignaturePolicy(sigPolicy *fabriccmn.SignaturePolicy) { switch t := sigPolicy.Type.(type) { case *fabriccmn.SignaturePolicy_SignedBy: p.Field("Type", "SignedBy") p.PrintSignaturePolicySignedBy(t) case *fabriccmn.SignaturePolicy_NOutOf_: p.Field("Type", "NOutOf") p.PrintSignaturePolicyNOutOf(t.NOutOf) default: p.Print("!!!!!!! Don't know how to print signature policy: %s", t) } } // PrintSignaturePolicySignedBy prints a SignaturePolicy_SignedBy policy func (p *BlockPrinter) PrintSignaturePolicySignedBy(sigPolicy *fabriccmn.SignaturePolicy_SignedBy) { p.Field("SignedBy", sigPolicy.SignedBy) } // PrintSignaturePolicyNOutOf prints a SignaturePolicy_NOutOf policy func (p *BlockPrinter) PrintSignaturePolicyNOutOf(sigPolicy *fabriccmn.SignaturePolicy_NOutOf) { p.Field("N", sigPolicy.N) p.Array("Rules") for i, policy := range sigPolicy.Rules { p.Item("Rule", i) p.PrintSignaturePolicy(policy) p.ItemEnd() } p.ArrayEnd() } // PrintConfigValue prints a ConfigValue func (p *BlockPrinter) PrintConfigValue(name string, value *fabriccmn.ConfigValue) { p.Field("Version", value.Version) p.Field("ModPolicy", value.ModPolicy) switch name { case AnchorPeersKey: anchorPeers := &pb.AnchorPeers{} unmarshalOrPanic(value.Value, anchorPeers) p.Element("AnchorPeers") p.PrintAnchorPeers(anchorPeers) p.ElementEnd() break case MSPKey: mspConfig := &msp.MSPConfig{} unmarshalOrPanic(value.Value, mspConfig) p.Element("MSPConfig") p.PrintMSPConfig(mspConfig) p.ElementEnd() break case ConsensusTypeKey: consensusType := &ab.ConsensusType{} unmarshalOrPanic(value.Value, consensusType) p.Field("ConsensusType", consensusType.Type) break case BatchSizeKey: batchSize := &ab.BatchSize{} unmarshalOrPanic(value.Value, batchSize) p.Element("BatchSize") p.PrintBatchSize(batchSize) p.ElementEnd() break case BatchTimeoutKey: batchTimeout := &ab.BatchTimeout{} unmarshalOrPanic(value.Value, batchTimeout) p.Field("Timeout", batchTimeout.Timeout) break case ChannelRestrictionsKey: chRestrictions := &ab.ChannelRestrictions{} unmarshalOrPanic(value.Value, chRestrictions) p.Element("ChannelRestrictions") p.Field("MaxCount", chRestrictions.MaxCount) p.ElementEnd() break case ChannelCreationPolicyKey: creationPolicy := &fabriccmn.ConfigPolicy{} unmarshalOrPanic(value.Value, creationPolicy) p.Element("ChannelCreationPolicy") p.PrintConfigPolicy(creationPolicy) p.ElementEnd() break // case ChainCreationPolicyNamesKey: // chainCreationPolicyNames := &ab.ChainCreationPolicyNames{} // unmarshalOrPanic(value.Value, chainCreationPolicyNames) // p.Print("ChainCreationPolicyNames") // p.Field("Names", chainCreationPolicyNames.Names) // break case HashingAlgorithmKey: hashingAlgorithm := &fabriccmn.HashingAlgorithm{} unmarshalOrPanic(value.Value, hashingAlgorithm) p.Element("HashingAlgorithm") p.Field("Name", hashingAlgorithm.Name) p.ElementEnd() break case BlockDataHashingStructureKey: hashingStructure := &fabriccmn.BlockDataHashingStructure{} unmarshalOrPanic(value.Value, hashingStructure) p.Element("BlockDataHashingStructure") p.Field("Width", hashingStructure.Width) p.ElementEnd() break case OrdererAddressesKey: addresses := &fabriccmn.OrdererAddresses{} unmarshalOrPanic(value.Value, addresses) p.Element("OrdererAddresses") p.Field("Addresses", addresses.Addresses) p.ElementEnd() break case ConsortiumKey: consortium := &fabriccmn.Consortium{} unmarshalOrPanic(value.Value, consortium) p.Element("Consortium") p.Field("Name", consortium.Name) p.ElementEnd() break case CapabilitiesKey: capabilities := &fabriccmn.Capabilities{} unmarshalOrPanic(value.Value, capabilities) p.Element("Capabilities") p.PrintCapabilities(capabilities) p.ElementEnd() break default: p.Print("!!!!!!! Don't know how to Print config value: %s", name) break } } // PrintBatchSize prints a BatchSize func (p *BlockPrinter) PrintBatchSize(batchSize *ab.BatchSize) { p.Field("MaxMessageCount", batchSize.MaxMessageCount) p.Field("AbsoluteMaxBytes", batchSize.AbsoluteMaxBytes) p.Field("PreferredMaxBytes", batchSize.PreferredMaxBytes) } // ProviderType indicates the type of an identity provider type ProviderType int // The ProviderType of a member relative to the member API const ( FABRIC ProviderType = iota // MSP is of FABRIC type IDEMIX // MSP is of IDEMIX type OTHER // MSP is of OTHER TYPE ) // PrintMSPConfig prints a MSPConfig func (p *BlockPrinter) PrintMSPConfig(mspConfig *msp.MSPConfig) { switch ProviderType(mspConfig.Type) { case FABRIC: p.Print("Type: FABRIC") config := &msp.FabricMSPConfig{} unmarshalOrPanic(mspConfig.Config, config) p.Print("Config:") p.PrintFabricMSPConfig(config) break default: p.Print("Type: OTHER") break } } // PrintFabricMSPConfig prints a FabricMSPConfig func (p *BlockPrinter) PrintFabricMSPConfig(mspConfig *msp.FabricMSPConfig) { p.Field("Name", mspConfig.Name) p.Array("Admins") for i, admCert := range mspConfig.Admins { p.ItemValue("Admin Cert", i, admCert) } p.ArrayEnd() } // PrintAnchorPeers prints AnchorPeers func (p *BlockPrinter) PrintAnchorPeers(anchorPeers *pb.AnchorPeers) { p.Array("AnchorPeers") for i, anchorPeer := range anchorPeers.AnchorPeers { p.Item("Anchor Peer", i) p.PrintAnchorPeer(anchorPeer) p.ItemEnd() } p.ArrayEnd() } // PrintAnchorPeer prints an AnchorPeer func (p *BlockPrinter) PrintAnchorPeer(anchorPeer *pb.AnchorPeer) { p.Field("Host", anchorPeer.Host) p.Field("Port", anchorPeer.Port) } // PrintConfigSignature prints ConfigSignature func (p *BlockPrinter) PrintConfigSignature(sig *fabriccmn.ConfigSignature) { p.Field("Signature", sig.Signature) sigHeader, err := GetSignatureHeader(sig.SignatureHeader) if err != nil { panic(err) } p.Element("SignatureHeader") p.PrintSignatureHeader(sigHeader) p.ElementEnd() } // PrintConfigUpdate prints ConfigUpdate func (p *BlockPrinter) PrintConfigUpdate(configUpdate *fabriccmn.ConfigUpdate) { p.Field("ChannelId", configUpdate.ChannelId) p.Element("ReadSet") p.PrintConfigGroup(configUpdate.ReadSet) p.ElementEnd() p.Element("WriteSet") p.PrintConfigGroup(configUpdate.WriteSet) p.ElementEnd() } // PrintBlockMetadata prints BlockMetadata func (p *BlockPrinter) PrintBlockMetadata(blockMetaData *fabriccmn.BlockMetadata) { p.PrintSignaturesMetadata(getMetadataOrPanic(blockMetaData, fabriccmn.BlockMetadataIndex_SIGNATURES)) p.PrintLastConfigMetadata(getMetadataOrPanic(blockMetaData, fabriccmn.BlockMetadataIndex_LAST_CONFIG)) p.PrintTransactionsFilterMetadata(ledgerUtil.TxValidationFlags(blockMetaData.Metadata[fabriccmn.BlockMetadataIndex_TRANSACTIONS_FILTER])) p.PrintOrdererMetadata(getMetadataOrPanic(blockMetaData, fabriccmn.BlockMetadataIndex_ORDERER)) } // PrintSignaturesMetadata prints signature Metadata func (p *BlockPrinter) PrintSignaturesMetadata(metadata *fabriccmn.Metadata) { p.Array("Signatures") for i, metadataSignature := range metadata.Signatures { shdr, err := GetSignatureHeader(metadataSignature.SignatureHeader) if err != nil { panic(errors.Errorf("Failed unmarshalling meta data signature header. Error: %v", err)) } p.Item("Metadata Signature", i) p.PrintSignatureHeader(shdr) p.ItemEnd() } p.ArrayEnd() } // PrintLastConfigMetadata prints last-config MetaData func (p *BlockPrinter) PrintLastConfigMetadata(metadata *fabriccmn.Metadata) { lastConfig := &fabriccmn.LastConfig{} err := proto.Unmarshal(metadata.Value, lastConfig) if err != nil { panic(errors.Errorf("Failed unmarshalling meta data last config. Error: %v", err)) } p.Field("Last Config Index", lastConfig.Index) } // PrintTransactionsFilterMetadata prints TxValidationFlags func (p *BlockPrinter) PrintTransactionsFilterMetadata(txFilter ledgerUtil.TxValidationFlags) { p.Array("TransactionFilters") for i := 0; i < len(txFilter); i++ { p.ItemValue("TxValidationFlag", i, txFilter.Flag(i)) } p.ArrayEnd() } // PrintOrdererMetadata prints orderer Metadata func (p *BlockPrinter) PrintOrdererMetadata(metadata *fabriccmn.Metadata) { p.Field("Orderer Metadata", metadata.Value) } // PrintChaincodeDeploymentSpec prints ChaincodeDeploymentSpec func (p *BlockPrinter) PrintChaincodeDeploymentSpec(depSpec *pb.ChaincodeDeploymentSpec) { p.Element("ChaincodeSpec") p.PrintChaincodeSpec(depSpec.ChaincodeSpec) p.ElementEnd() } // PrintChaincodeSpec prints ChaincodeSpec func (p *BlockPrinter) PrintChaincodeSpec(ccSpec *pb.ChaincodeSpec) { p.Element("ChaincodeId") p.PrintChaincodeID(ccSpec.ChaincodeId) p.ElementEnd() p.Field("Timeout", ccSpec.Timeout) p.Field("Type", ccSpec.Type) p.Element("Input") p.PrintChaincodeInput(ccSpec.Input) p.ElementEnd() } // PrintChaincodeInput prints ChaincodeInput func (p *BlockPrinter) PrintChaincodeInput(ccInput *pb.ChaincodeInput) { p.Array("Args") for i, value := range ccInput.Args { p.ItemValue("Arg", i, value) } p.ArrayEnd() p.Array("Decorations") for key, value := range ccInput.Decorations { p.ItemValue("Decoration", key, value) } p.ArrayEnd() } // PrintPeer prints the peer func (p *BlockPrinter) PrintPeer(peer fab.Peer) { p.Field("URL", peer.URL()) p.Field("MSP", peer.MSPID()) peerState, ok := peer.(fab.PeerState) if ok { p.Field("BlockHeight", peerState.BlockHeight()) } } func getMetadataOrPanic(blockMetaData *fabriccmn.BlockMetadata, index fabriccmn.BlockMetadataIndex) *fabriccmn.Metadata { metaData := &fabriccmn.Metadata{} err := proto.Unmarshal(blockMetaData.Metadata[index], metaData) if err != nil { panic(errors.Errorf("Unable to unmarshal meta data at index %d", index)) } return metaData } func unmarshalOrPanic(buf []byte, pb proto.Message) { err := proto.Unmarshal(buf, pb) if err != nil { panic(err) } } // Base64URLEncode encodes the byte array into a base64 string func Base64URLEncode(data []byte) string { return base64.RawURLEncoding.EncodeToString(data) } // Base64URLDecode decodes the base64 string into a byte array func Base64URLDecode(data string) ([]byte, error) { //check if it has padding or not if strings.HasSuffix(data, "=") { return base64.URLEncoding.DecodeString(data) } return base64.RawURLEncoding.DecodeString(data) } // isCollectionConfigKey detects if a key is a collection key func isCollectionConfigKey(key string) bool { return strings.Contains(key, collectionSeparator) } ================================================ FILE: fabric-cli/cmd/fabric-cli/printer/formatter.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package printer import ( "fmt" "strings" ) // OutputFormat specifies the format for printing data type OutputFormat uint8 const ( // RAW displays the raw data RAW OutputFormat = iota // JSON formats the data into Java Script Object Notation format JSON // DISPLAY formats the data into a human readable format DISPLAY ) func (f OutputFormat) String() string { switch f { case DISPLAY: return "display" case JSON: return "json" case RAW: return "raw" default: return "unknown" } } // AsOutputFormat returns the OutputFormat given an Output Format string func AsOutputFormat(f string) OutputFormat { switch strings.ToLower(f) { case "json": return JSON case "raw": return RAW default: return DISPLAY } } // Formatter outputs the data in a specific format type Formatter interface { // PrintHeader outputs a header PrintHeader() // PrintFooter outputs a footer PrintFooter() // Element starts an element Element(element string) // ElementEnd ends an element ElementEnd() // Field outputs the value of a field Field(field string, value interface{}) // Array starts an array Array(element string) // ArrayEnd ends the array ArrayEnd() // Item starts a complex array item Item(element string, index interface{}) // ItemEnd ends an array item ItemEnd() // ItemValue outputs a single array item ItemValue(element string, index interface{}, value interface{}) // Value outputs a value Value(value interface{}) // Print outputs additional info Print(frmt string, vars ...interface{}) } // FormatterOpts contains options for the formatter type FormatterOpts struct { // Base64Encode indicates whether binary values are to be encoded in base 64 Base64Encode bool } // NewFormatter returns a new Formatter given the format and writer type. nil is returned // if no formatter exists for the given type func NewFormatter(format OutputFormat, writerType WriterType) Formatter { return NewFormatterWithOpts(format, writerType, &FormatterOpts{}) } // NewFormatterWithOpts returns a new Formatter given the format and writer type. nil is returned // if no formatter exists for the given type func NewFormatterWithOpts(format OutputFormat, writerType WriterType, opts *FormatterOpts) Formatter { switch format { case JSON: return &jsonFormatter{formatter: formatter{writer: NewWriter(writerType)}} case DISPLAY: return &displayFormatter{formatter: formatter{writer: NewWriter(writerType)}, base64Encode: opts.Base64Encode} default: return nil } } type formatter struct { writer Writer } func (f *formatter) write(format string, a ...interface{}) error { return f.writer.Write(format, a...) } type displayFormatter struct { formatter indent int base64Encode bool } func (p *displayFormatter) Print(frmt string, vars ...interface{}) { format := fmt.Sprintf("%s%s\n", p.prefix(), frmt) p.write(format, vars...) } func (p *displayFormatter) Field(field string, value interface{}) { if value != nil { p.write("%s%s: %v\n", p.prefix(), field, p.encodeValue(value)) } else { p.write("%s%s:\n", p.prefix(), field) } } func (p *displayFormatter) Element(element string) { if element != "" { p.write("%s%s:\n", p.prefix(), element) } p.indent++ } func (p *displayFormatter) ElementEnd() { p.indent-- } func (p *displayFormatter) Array(element string) { if element != "" { p.write("%s%s:\n", p.prefix(), element) } p.indent++ } func (p *displayFormatter) ArrayEnd() { p.indent-- } func (p *displayFormatter) Item(element string, index interface{}) { if element != "" { p.write("%s%s[%v]:\n", p.prefix(), element, index) } p.indent++ } func (p *displayFormatter) ItemEnd() { p.ElementEnd() } func (p *displayFormatter) ItemValue(element string, index interface{}, value interface{}) { if element != "" { p.write("%s%s[%v]: %v\n", p.prefix(), element, index, p.encodeValue(value)) } } func (p *displayFormatter) Value(value interface{}) { p.write("%s%v", p.prefix(), p.encodeValue(value)) } func (p *displayFormatter) PrintHeader() { p.write("%s\n", strings.Repeat("*", 100)) } func (p *displayFormatter) PrintFooter() { p.write("%s\n", strings.Repeat("*", 100)) } func (p *displayFormatter) prefix() string { s := "***** " for i := 0; i < p.indent; i++ { s = s + fmt.Sprintf("|%s", strings.Repeat(" ", indentSize-1)) } return s } func (p *displayFormatter) encodeValue(value interface{}) interface{} { switch value.(type) { case []byte: if p.base64Encode { return Base64URLEncode(value.([]byte)) } return string(value.([]byte)) default: return value } } type jsonFormatter struct { formatter commaRequired bool } func (p *jsonFormatter) Print(frmt string, vars ...interface{}) { // Ignore additional output in JSON format } func (p *jsonFormatter) Field(field string, value interface{}) { if p.commaRequired { p.write(",") } if value != nil { p.write("\"%s\":\"%v\"", field, p.encodeValue(value)) } else { p.write("\"%s\":\"null\"", field) } p.commaRequired = true } func (p *jsonFormatter) Element(element string) { if p.commaRequired { p.write(",") p.commaRequired = false } if element != "" { p.write("\"%s\":{", element) } else { p.write("{") } } func (p *jsonFormatter) ElementEnd() { p.write("}") p.commaRequired = true } func (p *jsonFormatter) Array(element string) { if p.commaRequired { p.write(",") p.commaRequired = false } if element != "" { p.write("\"%s\":[", element) } else { p.write("[") } } func (p *jsonFormatter) ArrayEnd() { p.write("]") p.commaRequired = true } func (p *jsonFormatter) Item(element string, index interface{}) { if p.commaRequired { p.write(",") p.commaRequired = false } p.write("{") } func (p *jsonFormatter) ItemEnd() { p.ElementEnd() } func (p *jsonFormatter) ItemValue(element string, index interface{}, value interface{}) { if i, ok := index.(int); ok && i > 0 { p.commaRequired = true p.write(",") } p.write("\"%v\"", p.encodeValue(value)) } func (p *jsonFormatter) Value(value interface{}) { if p.commaRequired { p.write(",") } p.write("\"%v\"", p.encodeValue(value)) } func (p *jsonFormatter) PrintHeader() { p.Element("") p.commaRequired = false } func (p *jsonFormatter) PrintFooter() { p.ElementEnd() p.write("\n") p.commaRequired = false } func (p *jsonFormatter) encodeValue(value interface{}) interface{} { switch value.(type) { case []byte: return Base64URLEncode(value.([]byte)) default: return value } } ================================================ FILE: fabric-cli/cmd/fabric-cli/printer/printer.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package printer import "fmt" const ( indentSize = 3 ) type printer struct { Formatter Formatter } // newPrinter returns a new Printer of the given OutputFormat and WriterType func newPrinter(format OutputFormat, writerType WriterType) *printer { return &printer{Formatter: NewFormatter(format, writerType)} } // newPrinterWithOpts returns a new Printer of the given OutputFormat and WriterType func newPrinterWithOpts(format OutputFormat, writerType WriterType, opts *FormatterOpts) *printer { return &printer{Formatter: NewFormatterWithOpts(format, writerType, opts)} } // Print prints a formatted string func (p *printer) Print(frmt string, vars ...interface{}) { if p.Formatter == nil { fmt.Printf(frmt, vars) return } p.Formatter.Print(frmt, vars...) } // Field prints a field/value func (p *printer) Field(Field string, value interface{}) { p.Formatter.Field(Field, value) } // Element starts a new named element. (Should be followed by ElementEnd.) func (p *printer) Element(element string) { p.Formatter.Element(element) } // ElementEnd ends an element that was started with ElementStart. func (p *printer) ElementEnd() { p.Formatter.ElementEnd() } // Array starts an array. (Should be followed by ArrayEnd.) func (p *printer) Array(element string) { p.Formatter.Array(element) } // ArrayEnd ends an array that was started with Array. func (p *printer) ArrayEnd() { p.Formatter.ArrayEnd() } // Item starts an array item at the given index. (A previous call to Array must have been made.) func (p *printer) Item(element string, index interface{}) { p.Formatter.Item(element, index) } // ItemEnd ends an array item that was started with Item. func (p *printer) ItemEnd() { p.Formatter.ItemEnd() } // ItemValue prints an array value at the given index. (A previous call to Array must have been made.) func (p *printer) ItemValue(element string, index interface{}, value interface{}) { p.Formatter.ItemValue(element, index, value) } // Value prints a value. func (p *printer) Value(value interface{}) { p.Formatter.Value(value) } // PrintHeader prints a header. func (p *printer) PrintHeader() { p.Formatter.PrintHeader() } // PrintFooter prints a footer. func (p *printer) PrintFooter() { p.Formatter.PrintFooter() } ================================================ FILE: fabric-cli/cmd/fabric-cli/printer/protoutils.go ================================================ /* Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package printer import ( "fmt" "github.com/golang/protobuf/proto" cb "github.com/hyperledger/fabric-protos-go/common" "github.com/hyperledger/fabric-protos-go/peer" "github.com/pkg/errors" ) // ExtractEnvelopeOrPanic retrieves the requested envelope from a given block // and unmarshals it -- it panics if either of these operations fail func ExtractEnvelopeOrPanic(block *cb.Block, index int) *cb.Envelope { envelope, err := ExtractEnvelope(block, index) if err != nil { panic(err) } return envelope } // ExtractEnvelope retrieves the requested envelope from a given block and // unmarshals it func ExtractEnvelope(block *cb.Block, index int) (*cb.Envelope, error) { if block.Data == nil { return nil, errors.New("block data is nil") } envelopeCount := len(block.Data.Data) if index < 0 || index >= envelopeCount { return nil, errors.New("envelope index out of bounds") } marshaledEnvelope := block.Data.Data[index] envelope, err := GetEnvelopeFromBlock(marshaledEnvelope) err = errors.WithMessage(err, fmt.Sprintf("block data does not carry an envelope at index %d", index)) return envelope, err } // GetEnvelopeFromBlock gets an envelope from a block's Data field. func GetEnvelopeFromBlock(data []byte) (*cb.Envelope, error) { // Block always begins with an envelope var err error env := &cb.Envelope{} if err = proto.Unmarshal(data, env); err != nil { return nil, errors.Wrap(err, "error unmarshaling Envelope") } return env, nil } // ExtractPayloadOrPanic retrieves the payload of a given envelope and // unmarshals it -- it panics if either of these operations fail func ExtractPayloadOrPanic(envelope *cb.Envelope) *cb.Payload { payload, err := ExtractPayload(envelope) if err != nil { panic(err) } return payload } // ExtractPayload retrieves the payload of a given envelope and unmarshals it. func ExtractPayload(envelope *cb.Envelope) (*cb.Payload, error) { payload := &cb.Payload{} err := proto.Unmarshal(envelope.Payload, payload) err = errors.Wrap(err, "no payload in envelope") return payload, err } // UnmarshalChannelHeader returns a ChannelHeader from bytes func UnmarshalChannelHeader(bytes []byte) (*cb.ChannelHeader, error) { chdr := &cb.ChannelHeader{} err := proto.Unmarshal(bytes, chdr) return chdr, errors.Wrap(err, "error unmarshaling ChannelHeader") } // GetSignatureHeader Get SignatureHeader from bytes func GetSignatureHeader(bytes []byte) (*cb.SignatureHeader, error) { sh := &cb.SignatureHeader{} err := proto.Unmarshal(bytes, sh) return sh, errors.Wrap(err, "error unmarshaling SignatureHeader") } // GetTransaction Get Transaction from bytes func GetTransaction(txBytes []byte) (*peer.Transaction, error) { tx := &peer.Transaction{} err := proto.Unmarshal(txBytes, tx) return tx, errors.Wrap(err, "error unmarshaling Transaction") } // GetChaincodeActionPayload Get ChaincodeActionPayload from bytes func GetChaincodeActionPayload(capBytes []byte) (*peer.ChaincodeActionPayload, error) { cap := &peer.ChaincodeActionPayload{} err := proto.Unmarshal(capBytes, cap) return cap, errors.Wrap(err, "error unmarshaling ChaincodeActionPayload") } ================================================ FILE: fabric-cli/cmd/fabric-cli/printer/writer.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package printer import ( "fmt" "os" "strings" config "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" ) // WriterType specifies the format for printing data type WriterType uint8 const ( // STDOUT writes to standard out STDOUT WriterType = iota // STDERR writes to standard error STDERR // LOG writes to the logger LOG ) const ( stdout = "stdout" stderr = "stderr" log = "log" ) func (f WriterType) String() string { switch f { case STDOUT: return stdout case STDERR: return stderr case LOG: return log default: return "unknown" } } // AsWriterType returns the WriterType given a Writer Type string func AsWriterType(t string) WriterType { switch strings.ToLower(t) { case log: return LOG case stderr: return STDERR default: return STDOUT } } // Writer writes the output type Writer interface { Write(format string, a ...interface{}) error } // NewWriter returns a new writer given the writer type func NewWriter(writerType WriterType) Writer { switch writerType { case STDERR: return &stdErrWriter{} case LOG: return &logWriter{} default: return &stdOutWriter{} } } type stdOutWriter struct { } func (w *stdOutWriter) Write(format string, a ...interface{}) error { _, err := fmt.Fprintf(os.Stdout, format, a...) return err } type stdErrWriter struct { } func (w *stdErrWriter) Write(format string, a ...interface{}) error { _, err := fmt.Fprintf(os.Stderr, format, a...) return err } type logWriter struct { } func (w *logWriter) Write(format string, a ...interface{}) error { config.Config().Logger().Infof(format, a...) return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/query/queryblockcmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package query import ( "encoding/base64" "strings" fabricCommon "github.com/hyperledger/fabric-protos-go/common" "github.com/hyperledger/fabric-sdk-go/pkg/client/ledger" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var queryBlockCmd = &cobra.Command{ Use: "block", Short: "Query block", Long: "Queries a block", Run: func(cmd *cobra.Command, args []string) { action, err := newQueryBlockAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing queryBlockAction: %v", err) return } defer action.Terminate() err = action.invoke() if err != nil { cliconfig.Config().Logger().Errorf("Error while running queryBlockAction: %v", err) } }, } func getQueryBlockCmd() *cobra.Command { flags := queryBlockCmd.Flags() cliconfig.InitChannelID(flags) cliconfig.InitBlockNum(flags) cliconfig.InitBlockHash(flags) cliconfig.InitTraverse(flags) cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to install the chaincode, e.g. grpcs://localhost:7051") return queryBlockCmd } type queryBlockAction struct { action.Action } func newQueryBlockAction(flags *pflag.FlagSet) (*queryBlockAction, error) { action := &queryBlockAction{} err := action.Initialize(flags) return action, err } func (a *queryBlockAction) invoke() error { ledgerClient, err := a.LedgerClient() if err != nil { return errors.Errorf("Error getting admin channel client: %v", err) } var block *fabricCommon.Block if cliconfig.IsFlagSet(cliconfig.BlockNumFlag) { var err error block, err = ledgerClient.QueryBlock(cliconfig.Config().BlockNum()) if err != nil { return err } } else if cliconfig.IsFlagSet(cliconfig.BlockHashFlag) { var err error hashBytes, err := Base64URLDecode(cliconfig.Config().BlockHash()) if err != nil { return err } block, err = ledgerClient.QueryBlockByHash(hashBytes) if err != nil { return err } } else { return errors.Errorf("must specify either a block number of a block hash") } a.Printer().PrintBlock(block) a.traverse(ledgerClient, block, cliconfig.Config().Traverse()-1) return nil } func (a *queryBlockAction) traverse(ledgerClient *ledger.Client, currentBlock *fabricCommon.Block, num int) error { if num <= 0 { return nil } block, err := ledgerClient.QueryBlockByHash(currentBlock.Header.PreviousHash) if err != nil { return err } a.Printer().PrintBlock(block) if block.Header.PreviousHash != nil { return a.traverse(ledgerClient, block, num-1) } return nil } // Base64URLDecode decodes the base64 string into a byte array func Base64URLDecode(data string) ([]byte, error) { //check if it has padding or not if strings.HasSuffix(data, "=") { return base64.URLEncoding.DecodeString(data) } return base64.RawURLEncoding.DecodeString(data) } ================================================ FILE: fabric-cli/cmd/fabric-cli/query/querychannelscmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package query import ( "fmt" "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var queryChannelsCmd = &cobra.Command{ Use: "channels", Short: "Query channels", Long: "Queries the channels of the specified peer", Run: func(cmd *cobra.Command, args []string) { action, err := newQueryChannelsAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing queryChannelsAction: %v", err) return } defer action.Terminate() if len(cliconfig.Config().PeerURLs()) != 1 { fmt.Printf("\nMust specify exactly one peer URL\n\n") cmd.HelpFunc()(cmd, args) return } err = action.run() if err != nil { cliconfig.Config().Logger().Errorf("Error while running queryChannelsAction: %v", err) } }, } func getQueryChannelsCmd() *cobra.Command { cliconfig.InitPeerURL(queryChannelsCmd.Flags()) return queryChannelsCmd } type queryChannelsAction struct { action.Action } func newQueryChannelsAction(flags *pflag.FlagSet) (*queryChannelsAction, error) { action := &queryChannelsAction{} err := action.Initialize(flags) return action, err } func (a *queryChannelsAction) run() error { url := cliconfig.Config().PeerURLs() if len(url) != 1 { return errors.New("must specify exactly one peer URL") } peer, ok := a.PeerFromURL(url[0]) if !ok { return fmt.Errorf("invalid peer URL: %s", url) } user, err := a.OrgAdminUser(a.OrgID()) if err != nil { return err } client, err := a.ResourceMgmtClientForUser(user) if err != nil { return errors.WithMessage(err, "error getting fabric client") } response, err := client.QueryChannels(resmgmt.WithTargets(peer)) if err != nil { return err } fmt.Printf("Channels for peer [%s]\n", a.Peer().URL()) a.Printer().PrintChannels(response.Channels) return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/query/querycmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package query import ( cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" ) var queryCmd = &cobra.Command{ Use: "query", Short: "Query commands", Long: "Query commands", Run: func(cmd *cobra.Command, args []string) { cmd.HelpFunc()(cmd, args) }, } // Cmd returns the query command func Cmd() *cobra.Command { cliconfig.InitChannelID(queryCmd.Flags()) queryCmd.AddCommand(getQueryBlockCmd()) queryCmd.AddCommand(getQueryInfoCmd()) queryCmd.AddCommand(getQueryTXCmd()) queryCmd.AddCommand(getQueryChannelsCmd()) queryCmd.AddCommand(getQueryInstalledCmd()) queryCmd.AddCommand(getQueryPeersCmd()) queryCmd.AddCommand(getQueryLocalPeersCmd()) return queryCmd } ================================================ FILE: fabric-cli/cmd/fabric-cli/query/queryinfocmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package query import ( "fmt" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var queryInfoCmd = &cobra.Command{ Use: "info", Short: "Query info", Long: "Queries general info", Run: func(cmd *cobra.Command, args []string) { action, err := newQueryInfoAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing queryInfoAction: %v", err) return } defer action.Terminate() if cliconfig.Config().ChannelID() == "" { fmt.Printf("\nMust specify channel ID\n\n") cmd.HelpFunc()(cmd, args) return } err = action.run() if err != nil { cliconfig.Config().Logger().Errorf("Error while running queryInfoAction: %v", err) } }, } func getQueryInfoCmd() *cobra.Command { flags := queryInfoCmd.Flags() cliconfig.InitTxID(flags) cliconfig.InitChannelID(flags) cliconfig.InitPeerURL(flags) return queryInfoCmd } type queryInfoAction struct { action.Action } func newQueryInfoAction(flags *pflag.FlagSet) (*queryInfoAction, error) { action := &queryInfoAction{} err := action.Initialize(flags) return action, err } func (a *queryInfoAction) run() error { channelClient, err := a.LedgerClient() if err != nil { return errors.Errorf("Error getting admin ledger client: %v", err) } info, err := channelClient.QueryInfo() if err != nil { return err } a.Printer().PrintBlockchainInfo(info.BCI) return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/query/queryinstalledcmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package query import ( "fmt" "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var queryInstalledCmd = &cobra.Command{ Use: "installed", Short: "Query installed chaincodes", Long: "Queries the chaincodes installed to the specified peer", Run: func(cmd *cobra.Command, args []string) { action, err := newqueryInstalledAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing queryInstalledAction: %v", err) return } if len(cliconfig.Config().PeerURLs()) != 1 { fmt.Printf("\nMust specify exactly one peer URL\n\n") cmd.HelpFunc()(cmd, args) return } defer action.Terminate() err = action.run() if err != nil { cliconfig.Config().Logger().Errorf("Error while running queryInstalledAction: %v", err) } }, } func getQueryInstalledCmd() *cobra.Command { cliconfig.InitPeerURL(queryInstalledCmd.Flags()) return queryInstalledCmd } type queryInstalledAction struct { action.Action } func newqueryInstalledAction(flags *pflag.FlagSet) (*queryInstalledAction, error) { action := &queryInstalledAction{} err := action.Initialize(flags) return action, err } func (a *queryInstalledAction) run() error { url := cliconfig.Config().PeerURLs() if len(url) != 1 { return errors.New("must specify exactly one peer URL") } peer, ok := a.PeerFromURL(url[0]) if !ok { return fmt.Errorf("invalid peer URL: %s", url) } user, err := a.OrgAdminUser(a.OrgID()) if err != nil { return err } client, err := a.ResourceMgmtClientForUser(user) if err != nil { return err } response, err := client.QueryInstalledChaincodes(resmgmt.WithTargets(peer)) if err != nil { return err } fmt.Printf("Chaincodes for peer [%s]\n", a.Peer().URL()) a.Printer().PrintChaincodes(response.Chaincodes) return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/query/querylocalpeerscmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package query import ( "fmt" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var queryLocalPeersCmd = &cobra.Command{ Use: "localpeers", Short: "Query local peers", Long: "Queries the peers for the specified org", Run: func(cmd *cobra.Command, args []string) { action, err := newQueryLocalPeersAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing queryLocalPeersAction: %v", err) return } defer action.Terminate() if cliconfig.Config().OrgID() == "" { fmt.Printf("\nMust specify org ID\n\n") cmd.HelpFunc()(cmd, args) return } err = action.run() if err != nil { cliconfig.Config().Logger().Errorf("Error while running queryLocalPeersAction: %v", err) } }, } func getQueryLocalPeersCmd() *cobra.Command { flags := queryLocalPeersCmd.Flags() cliconfig.InitOrgIDs(flags) cliconfig.InitPeerURL(flags) return queryLocalPeersCmd } type queryLocalPeersAction struct { action.Action } func newQueryLocalPeersAction(flags *pflag.FlagSet) (*queryLocalPeersAction, error) { action := &queryLocalPeersAction{} err := action.Initialize(flags) return action, err } func (a *queryLocalPeersAction) run() error { localContext, err := a.LocalContext() if err != nil { return err } peers, err := localContext.LocalDiscoveryService().GetPeers() if err != nil { return err } a.Printer().PrintPeers(peers) return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/query/querypeerscmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package query import ( "fmt" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var queryPeersCmd = &cobra.Command{ Use: "peers", Short: "Query peers", Long: "Queries the peers for the specified channel", Run: func(cmd *cobra.Command, args []string) { action, err := newQueryPeersAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing queryPeersAction: %v", err) return } defer action.Terminate() if cliconfig.Config().ChannelID() == "" { fmt.Printf("\nMust specify channel ID\n\n") cmd.HelpFunc()(cmd, args) return } err = action.run() if err != nil { cliconfig.Config().Logger().Errorf("Error while running queryPeersAction: %v", err) } }, } func getQueryPeersCmd() *cobra.Command { flags := queryPeersCmd.Flags() cliconfig.InitChannelID(flags) cliconfig.InitPeerURL(flags) return queryPeersCmd } type queryPeersAction struct { action.Action } func newQueryPeersAction(flags *pflag.FlagSet) (*queryPeersAction, error) { action := &queryPeersAction{} err := action.Initialize(flags) return action, err } func (a *queryPeersAction) run() error { chProvider, err := a.ChannelProvider() if err != nil { return err } chContext, err := chProvider() if err != nil { return err } discovery, err := chContext.ChannelService().Discovery() if err != nil { return err } peers, err := discovery.GetPeers() if err != nil { return err } a.Printer().PrintPeers(peers) return nil } ================================================ FILE: fabric-cli/cmd/fabric-cli/query/querytxcmd.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package query import ( "fmt" "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" "github.com/pkg/errors" "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" "github.com/spf13/cobra" "github.com/spf13/pflag" ) var queryTXCmd = &cobra.Command{ Use: "tx", Short: "Query transaction", Long: "Queries a transaction", Run: func(cmd *cobra.Command, args []string) { if cliconfig.Config().TxID() == "" { fmt.Printf("\nMust specify the transaction ID\n\n") cmd.HelpFunc()(cmd, args) return } action, err := newQueryTXAction(cmd.Flags()) if err != nil { cliconfig.Config().Logger().Errorf("Error while initializing queryTXAction: %v", err) return } defer action.Terminate() err = action.run() if err != nil { cliconfig.Config().Logger().Errorf("Error while running queryTXAction: %v", err) } }, } func getQueryTXCmd() *cobra.Command { flags := queryTXCmd.Flags() cliconfig.InitChannelID(flags) cliconfig.InitTxID(flags) cliconfig.InitPeerURL(flags) return queryTXCmd } type queryTXAction struct { action.Action } func newQueryTXAction(flags *pflag.FlagSet) (*queryTXAction, error) { action := &queryTXAction{} err := action.Initialize(flags) return action, err } func (a *queryTXAction) run() error { ledgerClient, err := a.LedgerClient() if err != nil { return errors.Errorf("Error getting ledger client: %v", err) } tx, err := ledgerClient.QueryTransaction(fab.TransactionID(cliconfig.Config().TxID())) if err != nil { return err } fmt.Printf("Transaction %s in channel %s\n", cliconfig.Config().TxID(), cliconfig.Config().ChannelID()) a.Printer().PrintProcessedTransaction(tx) return nil } ================================================ FILE: fabric-cli/test/fixtures/config/config_test_local.yaml ================================================ # # Copyright SecureKey Technologies Inc. All Rights Reserved. # # SPDX-License-Identifier: Apache-2.0 # # # The network connection profile provides client applications the information about the target # blockchain network that are necessary for the applications to interact with it. These are all # knowledge that must be acquired from out-of-band sources. This file provides such a source. # # # Schema version of the content. Used by the SDK to apply the corresponding parsing rules. # version: 1.0.0 # # The client section used by GO SDK. # client: # Which organization does this application instance belong to? The value must be the name of an org # defined under "organizations" organization: org1 logging: level: info # Root of the MSP directories with keys and certs. cryptoconfig: path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH} # Some SDKs support pluggable KV stores, the properties under "credentialStore" # are implementation specific credentialStore: # [Optional]. Used by user store. Not needed if all credentials are embedded in configuration # and enrollments are performed elswhere. path: "/tmp/state-store" # [Optional]. Specific to the CryptoSuite implementation used by GO SDK. Software-based implementations # requiring a key store. PKCS#11 based implementations does not. cryptoStore: # Specific to the underlying KeyValueStore that backs the crypto key store. path: /tmp/msp # BCCSP config for the client. Used by GO SDK. BCCSP: security: enabled: true default: provider: "SW" hashAlgorithm: "SHA2" softVerify: true ephemeral: false level: 256 tlsCerts: # [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false systemCertPool: false # [Optional]. Client key and cert for TLS handshake with peers and orderers client: key: path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.key cert: path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.crt # # [Optional]. But most apps would have this section so that channel objects can be constructed # based on the content below. If an app is creating channels, then it likely will not need this # section. # channels: # name of the channel mychannel: # Required. list of peers from participating orgs peers: local.peer0.org1.example.com: # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must # have the chaincode installed. The app can also use this property to decide which peers # to send the chaincode install request. Default: true endorsingPeer: true # [Optional]. will this peer be sent query proposals? The peer must have the chaincode # installed. The app can also use this property to decide which peers to send the # chaincode install request. Default: true chaincodeQuery: true # [Optional]. will this peer be sent query proposals that do not require chaincodes, like # queryBlock(), queryTransaction(), etc. Default: true ledgerQuery: true # [Optional]. will this peer be the target of the SDK's listener registration? All peers can # produce events but the app typically only needs to connect to one to listen to events. # Default: true eventSource: true local.peer0.org2.example.com: endorsingPeer: true chaincodeQuery: true ledgerQuery: true eventSource: true # [Optional]. The application can use these options to perform channel operations like retrieving channel # config etc. policies: #[Optional] options for retrieving channel configuration blocks queryChannelConfig: #[Optional] min number of success responses (from targets/peers) minResponses: 1 #[Optional] channel config will be retrieved for these number of random targets maxTargets: 1 #[Optional] retry options for query config block retryOpts: #[Optional] number of retry attempts attempts: 5 #[Optional] the back off interval for the first retry attempt initialBackoff: 500ms #[Optional] the maximum back off interval for any retry attempt maxBackoff: 5s #[Optional] he factor by which the initial back off period is exponentially incremented backoffFactor: 2.0 # multi-org test channel orgchannel: peers: local.peer0.org1.example.com: endorsingPeer: true chaincodeQuery: true ledgerQuery: true eventSource: true local.peer0.org2.example.com: endorsingPeer: true chaincodeQuery: true ledgerQuery: true eventSource: true # [Optional]. The application can use these options to perform channel operations like retrieving channel # config etc. policies: #[Optional] options for retrieving channel configuration blocks queryChannelConfig: #[Optional] min number of success responses (from targets/peers) minResponses: 1 #[Optional] channel config will be retrieved for these number of random targets maxTargets: 1 #[Optional] retry options for query config block retryOpts: #[Optional] number of retry attempts attempts: 5 #[Optional] the back off interval for the first retry attempt initialBackoff: 500ms #[Optional] the maximum back off interval for any retry attempt maxBackoff: 5s #[Optional] he factor by which the initial back off period is exponentially incremented backoffFactor: 2.0 # # list of participating organizations in this network # organizations: org1: mspid: Org1MSP # This org's MSP store (absolute path or relative to client.cryptoconfig) cryptoPath: peerOrganizations/org1.example.com/users/{username}@org1.example.com/msp peers: - local.peer0.org1.example.com - local.peer1.org1.example.com # [Optional]. Certificate Authorities issue certificates for identification purposes in a Fabric based # network. Typically certificates provisioning is done in a separate process outside of the # runtime network. Fabric-CA is a special certificate authority that provides a REST APIs for # dynamic certificate management (enroll, revoke, re-enroll). The following section is only for # Fabric-CA servers. # certificateAuthorities: # - local.ca.org1.example.com # the profile will contain public information about organizations other than the one it belongs to. # These are necessary information to make transaction lifecycles work, including MSP IDs and # peers with a public URL to send transaction proposals. The file will not contain private # information reserved for members of the organization, such as admin key and certificate, # fabric-ca registrar enroll ID and secret, etc. org2: mspid: Org2MSP # This org's MSP store (absolute path or relative to client.cryptoconfig) cryptoPath: peerOrganizations/org2.example.com/users/{username}@org2.example.com/msp peers: - local.peer0.org2.example.com - local.peer1.org2.example.com # certificateAuthorities: # - local.ca.org2.example.com # Orderer Org name ordererorg: # Membership Service Provider ID for this organization mspID: "OrdererOrg" # Needed to load users crypto keys and certs for this org (absolute path or relative to global crypto path, DEV mode) cryptoPath: ordererOrganizations/example.com/users/{username}@example.com/msp # # List of orderers to send transaction and channel create/update requests to. For the time # being only one orderer is needed. If more than one is defined, which one get used by the # SDK is implementation specific. Consult each SDK's documentation for its handling of orderers. # orderers: local.orderer.example.com: url: localhost:7050 # these are standard properties defined by the gRPC library # they will be passed in as-is to gRPC client constructor grpcOptions: ssl-target-name-override: orderer.example.com # These parameters should be set in coordination with the keepalive policy on the server, # as incompatible settings can result in closing of connection. # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled keep-alive-time: 0s keep-alive-timeout: 20s keep-alive-permit: false fail-fast: false # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs allow-insecure: false tlsCACerts: # Certificate location absolute path path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem # # List of peers to send various requests to, including endorsement, query # and event listener registration. # peers: local.peer0.org1.example.com: # this URL is used to send endorsement and query requests url: localhost:7051 # eventUrl is only needed when using eventhub (default is delivery service) eventUrl: localhost:7053 grpcOptions: ssl-target-name-override: peer0.org1.example.com # These parameters should be set in coordination with the keepalive policy on the server, # as incompatible settings can result in closing of connection. # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled keep-alive-time: 0s keep-alive-timeout: 20s keep-alive-permit: false fail-fast: false # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs allow-insecure: false tlsCACerts: # Certificate location absolute path path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem local.peer1.org1.example.com: # this URL is used to send endorsement and query requests url: localhost:7151 # eventUrl is only needed when using eventhub (default is delivery service) eventUrl: localhost:7153 grpcOptions: ssl-target-name-override: peer1.org1.example.com # These parameters should be set in coordination with the keepalive policy on the server, # as incompatible settings can result in closing of connection. # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled keep-alive-time: 0s keep-alive-timeout: 20s keep-alive-permit: false fail-fast: false # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs allow-insecure: false tlsCACerts: # Certificate location absolute path path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem local.peer0.org2.example.com: url: localhost:8051 # eventUrl is only needed when using eventhub (default is delivery service) eventUrl: localhost:8053 grpcOptions: ssl-target-name-override: peer0.org2.example.com # These parameters should be set in coordination with the keepalive policy on the server, # as incompatible settings can result in closing of connection. # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled keep-alive-time: 0s keep-alive-timeout: 20s keep-alive-permit: false fail-fast: false # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs allow-insecure: false tlsCACerts: path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem local.peer1.org2.example.com: url: localhost:9051 # eventUrl is only needed when using eventhub (default is delivery service) eventUrl: localhost:9053 grpcOptions: ssl-target-name-override: peer1.org2.example.com # These parameters should be set in coordination with the keepalive policy on the server, # as incompatible settings can result in closing of connection. # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled keep-alive-time: 0s keep-alive-timeout: 20s keep-alive-permit: false fail-fast: false # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs allow-insecure: false tlsCACerts: path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem # # Fabric-CA is a special kind of Certificate Authority provided by Hyperledger Fabric which allows # certificate management to be done via REST APIs. Application may choose to use a standard # Certificate Authority instead of Fabric-CA, in which case this section would not be specified. # certificateAuthorities: ca.org1.example.com: url: https://ca.org1.example.com:7054 tlsCACerts: # Comma-Separated list of paths path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem # Client key and cert for SSL handshake with Fabric CA client: key: path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.key cert: path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.crt # Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is # needed to enroll and invoke new users. registrar: enrollId: admin enrollSecret: adminpw # [Optional] The optional name of the CA. caName: ca.org1.example.com ca.org2.example.com: url: https://ca.org2.example.com:8054 tlsCACerts: # Comma-Separated list of paths path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem # Client key and cert for SSL handshake with Fabric CA client: key: path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.key cert: path: ${GOPATH}/src/github.com/securekey/fabric-examples/fabric-cli/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/tls.example.com/users/User1@tls.example.com/tls/client.crt # Fabric-CA supports dynamic user enrollment via REST APIs. A "root" user, a.k.a registrar, is # needed to enroll and invoke new users. registrar: enrollId: admin enrollSecret: adminpw # [Optional] The optional name of the CA. caName: ca.org2.example.com entityMatchers: peer: - pattern: peer0.org1.example.com:7051 urlSubstitutionExp: localhost:7051 eventUrlSubstitutionExp: localhost:7053 sslTargetOverrideUrlSubstitutionExp: peer0.org1.example.com mappedHost: local.peer0.org1.example.com - pattern: peer1.org1.example.com:7151 urlSubstitutionExp: localhost:7151 eventUrlSubstitutionExp: localhost:7153 sslTargetOverrideUrlSubstitutionExp: peer1.org1.example.com mappedHost: local.peer1.org1.example.com - pattern: peer0.org2.example.com:8051 urlSubstitutionExp: localhost:8051 eventUrlSubstitutionExp: localhost:8053 sslTargetOverrideUrlSubstitutionExp: peer0.org2.example.com mappedHost: local.peer0.org2.example.com - pattern: peer1.org2.example.com:9051 urlSubstitutionExp: localhost:9051 eventUrlSubstitutionExp: localhost:9053 sslTargetOverrideUrlSubstitutionExp: peer1.org2.example.com mappedHost: local.peer1.org2.example.com orderer: - pattern: orderer.example.com urlSubstitutionExp: localhost:7050 sslTargetOverrideUrlSubstitutionExp: orderer.example.com mappedHost: local.orderer.example.com # certificateAuthority: # - pattern: (\w+).org1.example.(\w+) # urlSubstitutionExp: https://localhost:7054 # mappedHost: local.ca.org1.example.com # # - pattern: (\w+).org2.example.(\w+) # urlSubstitutionExp: https://localhost:8054 # mappedHost: local.ca.org2.example.com ================================================ FILE: fabric-cli/test/fixtures/config/pvtdatacollection.json ================================================ [ { "name": "coll1", "policy": "OR('Org1MSP.member', 'Org2MSP.member')", "requiredPeerCount": 1, "maxPeerCount": 2 }, { "name": "coll2", "policy": "OR('Org2MSP.member')", "requiredPeerCount": 0, "maxPeerCount": 2 } ] ================================================ FILE: fabric-cli/test/fixtures/testdata/src/github.com/securekey/example2_cc/example2_cc.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package main import ( "encoding/json" "fmt" "strings" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" ) type invokeFunc func(stub shim.ChaincodeStubInterface, args []string) pb.Response type funcMap map[string]invokeFunc const ( getFunc = "get" putFunc = "put" delFunc = "del" putPrivateFunc = "putprivate" getPrivateFunc = "getprivate" delPrivateFunc = "delprivate" putBothFunc = "putboth" getAndPutBothFunc = "getandputboth" invokeCCFunc = "invokecc" ) // ExampleCC example simple Chaincode implementation type ExampleCC struct { funcRegistry funcMap } // Init ... func (cc *ExampleCC) Init(stub shim.ChaincodeStubInterface) pb.Response { return shim.Success(nil) } // Invoke invoke the chaincode with a given function func (cc *ExampleCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response { fmt.Println("########### example2_cc Invoke ###########") function, args := stub.GetFunctionAndParameters() if function == "" { return shim.Error("Expecting function") } f, ok := cc.funcRegistry[function] if !ok { return shim.Error(fmt.Sprintf("Unknown function [%s]. Expecting one of: %v", function, cc.functions())) } return f(stub, args) } func (cc *ExampleCC) put(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 2 { return shim.Error("Invalid args. Expecting key and value") } key := args[0] value := args[1] existingValue, err := stub.GetState(key) if err != nil { return shim.Error(fmt.Sprintf("Error getting data for key [%s]: %s", key, err)) } if existingValue != nil { value = string(existingValue) + "-" + value } if err := stub.PutState(key, []byte(value)); err != nil { return shim.Error(fmt.Sprintf("Error putting data for key [%s]: %s", key, err)) } return shim.Success([]byte(value)) } func (cc *ExampleCC) get(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 1 { return shim.Error("Invalid args. Expecting key") } key := args[0] value, err := stub.GetState(key) if err != nil { return shim.Error(fmt.Sprintf("Error getting data for key [%s]: %s", key, err)) } return shim.Success([]byte(value)) } func (cc *ExampleCC) del(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 1 { return shim.Error("Invalid args. Expecting key") } key := args[1] err := stub.DelState(key) if err != nil { return shim.Error(fmt.Sprintf("Failed to delete state for [%s]: %s", key, err)) } return shim.Success(nil) } func (cc *ExampleCC) putPrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 3 { return shim.Error("Invalid args. Expecting collection, key and value") } coll := args[0] key := args[1] value := args[2] if err := stub.PutPrivateData(coll, key, []byte(value)); err != nil { return shim.Error(fmt.Sprintf("Error putting private data for collection [%s] and key [%s]: %s", coll, key, err)) } return shim.Success(nil) } func (cc *ExampleCC) getPrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 2 { return shim.Error("Invalid args. Expecting collection and key") } coll := args[0] key := args[1] value, err := stub.GetPrivateData(coll, key) if err != nil { return shim.Error(fmt.Sprintf("Error getting private data for collection [%s] and key [%s]: %s", coll, key, err)) } return shim.Success([]byte(value)) } func (cc *ExampleCC) delPrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 2 { return shim.Error("Invalid args. Expecting collection and key") } coll := args[0] key := args[1] err := stub.DelPrivateData(coll, key) if err != nil { return shim.Error(fmt.Sprintf("Error getting private data for collection [%s] and key [%s]: %s", coll, key, err)) } return shim.Success(nil) } func (cc *ExampleCC) putBoth(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 5 { return shim.Error("Invalid args. Expecting key, value, collection, privkey and privvalue") } key := args[0] value := args[1] coll := args[2] privKey := args[3] privValue := args[4] if err := stub.PutState(key, []byte(value)); err != nil { return shim.Error(fmt.Sprintf("Error putting state for key [%s]: %s", key, err)) } if err := stub.PutPrivateData(coll, privKey, []byte(privValue)); err != nil { return shim.Error(fmt.Sprintf("Error putting private data for collection [%s] and key [%s]: %s", coll, key, err)) } return shim.Success(nil) } func (cc *ExampleCC) getAndPutBoth(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 5 { return shim.Error("Invalid args. Expecting key, value, collection, privkey and privvalue") } key := args[0] value := args[1] coll := args[2] privKey := args[3] privValue := args[4] oldValue, err := stub.GetState(key) if err != nil { return shim.Error(fmt.Sprintf("Error getting state for key [%s]: %s", key, err)) } if oldValue != nil { value = value + "_" + string(oldValue) } oldPrivValue, err := stub.GetPrivateData(coll, privKey) if err != nil { return shim.Error(fmt.Sprintf("Error getting private data for collection [%s] and key [%s]: %s", coll, privKey, err)) } if oldPrivValue != nil { privValue = privValue + "_" + string(oldPrivValue) } if err := stub.PutState(key, []byte(value)); err != nil { return shim.Error(fmt.Sprintf("Error putting state for key [%s]: %s", key, err)) } if err := stub.PutPrivateData(coll, privKey, []byte(privValue)); err != nil { return shim.Error(fmt.Sprintf("Error putting private data for collection [%s] and key [%s]: %s", coll, key, err)) } return shim.Success(nil) } type argStruct struct { Args []string `json:"Args"` } func asBytes(args []string) [][]byte { bytes := make([][]byte, len(args)) for i, arg := range args { bytes[i] = []byte(arg) } return bytes } func (cc *ExampleCC) invokeCC(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) < 2 { return shim.Error(`Invalid args. Expecting name of chaincode to invoke and chaincode args in the format {"Args":["arg1","arg2",...]}`) } ccName := args[0] invokeArgsJSON := strings.Replace(args[1], "`", `"`, -1) argStruct := argStruct{} if err := json.Unmarshal([]byte(invokeArgsJSON), &argStruct); err != nil { return shim.Error(fmt.Sprintf("Invalid invoke args: %s", err)) } if err := stub.PutState(stub.GetTxID()+"_invokedcc", []byte(ccName)); err != nil { return shim.Error(fmt.Sprintf("Error putting state: %s", err)) } return stub.InvokeChaincode(ccName, asBytes(argStruct.Args), "") } func (cc *ExampleCC) initRegistry() { cc.funcRegistry = make(map[string]invokeFunc) cc.funcRegistry[getFunc] = cc.get cc.funcRegistry[putFunc] = cc.put cc.funcRegistry[delFunc] = cc.del cc.funcRegistry[getPrivateFunc] = cc.getPrivate cc.funcRegistry[putPrivateFunc] = cc.putPrivate cc.funcRegistry[delPrivateFunc] = cc.delPrivate cc.funcRegistry[putBothFunc] = cc.putBoth cc.funcRegistry[getAndPutBothFunc] = cc.getAndPutBoth cc.funcRegistry[invokeCCFunc] = cc.invokeCC } func (cc *ExampleCC) functions() []string { var funcs []string for key := range cc.funcRegistry { funcs = append(funcs, key) } return funcs } func main() { cc := new(ExampleCC) cc.initRegistry() err := shim.Start(cc) if err != nil { fmt.Printf("Error starting example chaincode: %s", err) } } ================================================ FILE: fabric-cli/test/fixtures/testdata/src/github.com/securekey/example_cc/example_cc.go ================================================ /* Copyright IBM Corp. 2016 All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package main import ( "fmt" "strconv" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" ) // SimpleChaincode example simple Chaincode implementation type SimpleChaincode struct { } // Init ... func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { fmt.Println("########### example_cc Init ###########") args := stub.GetStringArgs() var A, B string // Entities var Aval, Bval int // Asset holdings var err error if len(args) != 4 { return shim.Error(fmt.Sprintf("Incorrect number of arguments. Expecting 4, got %d", len(args))) } // Initialize the chaincode A = args[0] Aval, err = strconv.Atoi(args[1]) if err != nil { return shim.Error("Expecting integer value for asset holding") } B = args[2] Bval, err = strconv.Atoi(args[3]) if err != nil { return shim.Error("Expecting integer value for asset holding") } fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) // Write the state to the ledger err = stub.PutState(A, []byte(strconv.Itoa(Aval))) if err != nil { return shim.Error(err.Error()) } err = stub.PutState(B, []byte(strconv.Itoa(Bval))) if err != nil { return shim.Error(err.Error()) } if transientMap, err := stub.GetTransient(); err == nil { if transientData, ok := transientMap["result"]; ok { fmt.Printf("Transient data in 'init' : %s\n", transientData) return shim.Success(transientData) } } return shim.Success(nil) } // Query ... func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface) pb.Response { return shim.Error("Unknown supported call") } // Invoke ... // Transaction makes payment of X units from A to B func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { fmt.Println("########### example_cc Invoke ###########") args := stub.GetStringArgs() if len(args) == 0 { return shim.Error("Function not provided") } function := args[0] if len(args) < 2 { return shim.Error("Incorrect number of arguments. Expecting at least 2") } if function == "delete" { // Deletes an entity from its state return t.delete(stub, args) } if function == "query" { // queries an entity state return t.query(stub, args) } if function == "move" { eventID := "testEvent" if len(args) >= 5 { eventID = args[4] } if err := stub.SetEvent(eventID, []byte("Test Payload")); err != nil { return shim.Error("Unable to set CC event: testEvent. Aborting transaction ...") } return t.move(stub, args) } if function == "put" { return t.put(stub, args[1:]) } if function == "get" { return t.get(stub, args[1:]) } return shim.Error(fmt.Sprintf("Unknown function call: %s", function)) } func (t *SimpleChaincode) move(stub shim.ChaincodeStubInterface, args []string) pb.Response { // must be an invoke var A, B string // Entities var Aval, Bval int // Asset holdings var X int // Transaction value var err error if len(args) < 4 { return shim.Error("Incorrect number of arguments. Expecting 4, function followed by 2 names and 1 value") } A = args[1] B = args[2] // Get the state from the ledger // TODO: will be nice to have a GetAllState call to ledger Avalbytes, err := stub.GetState(A) if err != nil { return shim.Error("Failed to get state") } if Avalbytes == nil { return shim.Error("Entity not found") } Aval, _ = strconv.Atoi(string(Avalbytes)) Bvalbytes, err := stub.GetState(B) if err != nil { return shim.Error("Failed to get state") } if Bvalbytes == nil { return shim.Error("Entity not found") } Bval, _ = strconv.Atoi(string(Bvalbytes)) // Perform the execution X, err = strconv.Atoi(args[3]) if err != nil { return shim.Error("Invalid transaction amount, expecting a integer value") } Aval = Aval - X Bval = Bval + X fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) // Write the state back to the ledger err = stub.PutState(A, []byte(strconv.Itoa(Aval))) if err != nil { return shim.Error(err.Error()) } err = stub.PutState(B, []byte(strconv.Itoa(Bval))) if err != nil { return shim.Error(err.Error()) } if transientMap, err := stub.GetTransient(); err == nil { if transientData, ok := transientMap["result"]; ok { fmt.Printf("Transient data in 'move' : %s\n", transientData) return shim.Success(transientData) } } return shim.Success(nil) } // Deletes an entity from state func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 1 { return shim.Error("Incorrect number of arguments. Expecting 1") } A := args[1] // Delete the key from the state in ledger err := stub.DelState(A) if err != nil { return shim.Error("Failed to delete state") } return shim.Success(nil) } // Query callback representing the query of a chaincode func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response { var A string // Entities var err error if len(args) != 2 { return shim.Error(fmt.Sprintf("Incorrect number of arguments: %v", args)) } A = args[1] // Get the state from the ledger Avalbytes, err := stub.GetState(A) if err != nil { jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}" return shim.Error(jsonResp) } if Avalbytes == nil { jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}" return shim.Error(jsonResp) } jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}" fmt.Printf("Query Response:%s\n", jsonResp) return shim.Success(Avalbytes) } func (t *SimpleChaincode) put(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 2 { return shim.Error("Invalid args. Expecting key and value") } key := args[0] value := args[1] existingValue, err := stub.GetState(key) if err != nil { return shim.Error(fmt.Sprintf("Error getting data for key [%s]: %s", key, err)) } if existingValue != nil { value = string(existingValue) + "-" + value } if err := stub.PutState(key, []byte(value)); err != nil { return shim.Error(fmt.Sprintf("Error putting data for key [%s]: %s", key, err)) } return shim.Success([]byte(value)) } func (t *SimpleChaincode) get(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 1 { return shim.Error("Invalid args. Expecting key") } key := args[0] value, err := stub.GetState(key) if err != nil { return shim.Error(fmt.Sprintf("Error getting data for key [%s]: %s", key, err)) } return shim.Success([]byte(value)) } func main() { err := shim.Start(new(SimpleChaincode)) if err != nil { fmt.Printf("Error starting Simple chaincode: %s", err) } } ================================================ FILE: fabric-cli/test/fixtures/testdata/src/go.mod ================================================ // Copyright SecureKey Technologies Inc. All Rights Reserved. // // SPDX-License-Identifier: Apache-2.0 module github.com/securekey/fabric-examples/test/cc require github.com/hyperledger/fabric v1.4.0 go 1.13 ================================================ FILE: fabric-cli/test/fixtures/testdata/src/go.sum ================================================ github.com/hyperledger/fabric v1.4.0/go.mod h1:tGFAOCT696D3rG0Vofd2dyWYLySHlh0aQjf7Q1HAju0= ================================================ FILE: fabric-cli/test/integration/fabric-cli_test.go ================================================ /* Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package integration import ( "fmt" "os" "strings" "testing" clicmd "github.com/securekey/fabric-examples/fabric-cli/cmd" ) // // Test cases that can run (and debugged) from an IDE // func run(cmd string) { os.Args = strings.Split(cmd, " ") os.Setenv("GRPC_TRACE", "all") os.Setenv("GRPC_VERBOSITY", "DEBUG") os.Setenv("GRPC_GO_LOG_SEVERITY_LEVEL", "INFO") clicmd.Execute() } func header(h string) { fmt.Println("****************************************") fmt.Println("*") fmt.Printf("* %s\n", h) fmt.Println("*") fmt.Println("****************************************") } //// ********** Create a channel ************ //// func TestCreate_a_channel(t *testing.T) { header("Create a channel") run("fabric-cli channel create --cid mychannel --txfile ../fixtures/fabric/v1.1/channel/mychannel.tx --config ../fixtures/config/config_test_local.yaml") } //// ********** Join a channel ************ //// func TestJoin_org1_peer_to_a_channel(t *testing.T) { header("Join a peer to a channel") run("fabric-cli.go channel join --cid mychannel --peer localhost:7051 --config ../fixtures/config/config_test_local.yaml") } func TestJoin_org2_peer_to_a_channel(t *testing.T) { header("Join a peer to a channel") run("fabric-cli.go channel join --cid mychannel --peer localhost:8051 --config ../fixtures/config/config_test_local.yaml") } func TestJoin_all_peers_in_org1_to_a_channel(t *testing.T) { header("Join all peers in org1 to a channel") run("fabric-cli.go channel join --cid mychannel --orgid org1 --config ../fixtures/config/config_test_local.yaml") } func TestJoin_all_peers_in_org2_to_a_channel(t *testing.T) { header("Join all peers in org1 to a channel") run("fabric-cli.go channel join --cid mychannel --orgid org2 --config ../fixtures/config/config_test_local.yaml") } func TestJoin_all_peers_to_a_channel(t *testing.T) { header("Join all peers to a channel") run("fabric-cli.go channel join --cid mychannel --config ../fixtures/config/config_test_local.yaml") } //// ********** Install chaincode ************ //// func TestInstall_chaincode_on_all_peers_of_org1(t *testing.T) { header("Install chaincode on all peers of org1") run("fabric-cli.go chaincode install --cid mychannel --orgid org1 --ccp github.com/example_cc --ccid ExampleCC --v v0 --gopath ../fixtures/testdata --config ../fixtures/config/config_test_local.yaml") } func TestInstall_chaincode_on_all_peers_of_org2(t *testing.T) { header("Install chaincode on all peers of org2") run("fabric-cli.go chaincode install --cid=mychannel --orgid org2 --ccp=github.com/example_cc --ccid=ExampleCC --v v0 --gopath ../fixtures/testdata --config ../fixtures/config/config_test_local.yaml") } func TestInstall_chaincode_on_all_peers(t *testing.T) { header("Install chaincode on all peers") run("fabric-cli.go chaincode install --cid=mychannel --ccp=github.com/example_cc --ccid=ExampleCC --v v0 --gopath ../fixtures/testdata --config ../fixtures/config/config_test_local.yaml") } func TestInstall_chaincode_on_all_peers_v1(t *testing.T) { header("Install chaincode on all peers") run("fabric-cli.go chaincode install --cid=mychannel --ccp=github.com/example_cc --ccid=ExampleCC --v v1 --gopath ../fixtures/testdata --config ../fixtures/config/config_test_local.yaml") } //// ********** Instantiate ************ //// func TestInstantiate_chaincode_with_default_endorsement_policy(t *testing.T) { header("Instantiate chaincode with default endorsement policy") run("fabric-cli.go chaincode instantiate --cid mychannel --ccp=github.com/example_cc --ccid ExampleCC --v v0 --args {\"Args\":[\"A\",\"1\",\"B\",\"2\"]} --config ../fixtures/config/config_test_local.yaml") } func TestInstantiate_chaincode_with_specified_endorsement_policy(t *testing.T) { header("Instantiate chaincode with specified endorsement policy") run("fabric-cli.go chaincode instantiate --cid mychannel --ccp=github.com/example_cc --ccid ExampleCC --v v0 --args {\"Args\":[\"A\",\"1\",\"B\",\"2\"]} --policy AND('Org1MSP.member','Org2MSP.member') --config ../fixtures/config/config_test_local.yaml") } func TestInstantiate_chaincode_with_specified_private_data_collection_configuration(t *testing.T) { header("Instantiate chaincode with specified private data collection configuration") run("fabric-cli.go chaincode instantiate --cid mychannel --ccp=github.com/example_cc --ccid ExampleCC --v v0 --args {\"Args\":[\"A\",\"1\",\"B\",\"2\"]} --policy AND('Org1MSP.member','Org2MSP.member') --collconfig ../fixtures/config/pvtdatacollection.json --config ../fixtures/config/config_test_local.yaml") } //// ********** Upgrade chaincode to v1 ************ //// func TestUpgrade_chaincode_to_v1(t *testing.T) { header("Upgrade chaincode") //run("fabric-cli.go chaincode upgrade --cid mychannel --ccp=github.com/example_cc --ccid ExampleCC --v v1 --args {\"Args\":[\"A\",\"1\",\"B\",\"2\"]} --policy AND('Org1MSP.member','Org2MSP.member') --config ../fixtures/config/config_test_local.yaml") run("fabric-cli.go chaincode upgrade --cid mychannel --ccp=github.com/example_cc --ccid ExampleCC --v v1 --args {\"Args\":[\"A\",\"1\",\"B\",\"2\"]} --config ../fixtures/config/config_test_local.yaml") } //// ********** Query channel ************ //// func TestQuery_info(t *testing.T) { header("Query info") run("fabric-cli.go query info --cid mychannel --config ../fixtures/config/config_test_local.yaml") } func TestQuery_block_by_block_number(t *testing.T) { header("Query block by block number") run("fabric-cli.go query block --cid mychannel --num 0 --config ../fixtures/config/config_test_local.yaml") } func TestQuery_block_by_hash(t *testing.T) { header("Query block by hash") // hash is the output of "query info" run("fabric-cli.go query block --cid mychannel --hash HnjHWaHuTr813ettkpL7LXRx20QxY3X9MVbJesGqs6o --config ../fixtures/config/config_test_local.yaml") } func TestQuery_block_output_in_JSON_format(t *testing.T) { header("Query block output in JSON format") run("fabric-cli.go query block --cid mychannel --num 0 --format json --config ../fixtures/config/config_test_local.yaml") } func TestQuery_transaction(t *testing.T) { header("Query transaction") run("fabric-cli.go query tx --cid mychannel --txid 711451464d26a5564fa7066f0d2acb513b79800d4e4b11e144492bb620155210 --config ../fixtures/config/config_test_local.yaml") } func TestQuery_channels_joined_by_a_peer(t *testing.T) { header("Query channels joined by a peer") run("fabric-cli.go query channels --peer localhost:7051 --config ../fixtures/config/config_test_local.yaml") } func TestQuery_installed_chaincodes_on_a_peer(t *testing.T) { header("Query installed chaincodes on a peer") run("fabric-cli.go query installed --peer localhost:7051 --config ../fixtures/config/config_test_local.yaml") } //// ********** Retrieve chaincode deployment info ************ //// func TestRetrieve_chaincode_deployment_info(t *testing.T) { header("Retrieve chaincode deployment info") run("fabric-cli.go chaincode info --cid mychannel --ccid ExampleCC --config ../fixtures/config/config_test_local.yaml") } //// ********** Query Chaincode ************ //// func TestQuery_chaincode_on_a_set_of_peers(t *testing.T) { header("Query chaincode on a set of peers") run("fabric-cli.go chaincode query --ccid ExampleCC --args {\"Func\":\"query\",\"Args\":[\"A\"]} --peer localhost:7051,localhost:8051 --config ../fixtures/config/config_test_local.yaml") } func TestQuery_chaincode_and_view_payloads_only(t *testing.T) { header("Query chaincode and view payloads only") run("fabric-cli.go chaincode query --ccid=ExampleCC --args {\"Func\":\"query\",\"Args\":[\"A\"]} --peer localhost:7051,localhost:8051 --payload --config ../fixtures/config/config_test_local.yaml") } //// ********** Invoke Chaincode ************ //// func TestInvoke_chaincode(t *testing.T) { header("Invoke chaincode") run("fabric-cli.go chaincode invoke --ccid=ExampleCC --args {\"Func\":\"move\",\"Args\":[\"A\",\"B\",\"1\"]} --config ../fixtures/config/config_test_local.yaml") } func TestInvoke_chaincode_5_times(t *testing.T) { header("Invoke chaincode 5 times") run("fabric-cli.go chaincode invoke --ccid=ExampleCC --args {\"Func\":\"move\",\"Args\":[\"A\",\"B\",\"1\"]} --iterations 5 --config ../fixtures/config/config_test_local.yaml") } func TestInvoke_chaincode_100_times_in_8_Go_routines(t *testing.T) { header("Invoke chaincode 100 times in 8 Go routines with 3 attempts for each invocation (in case the invocation fails)") run("fabric-cli.go chaincode invoke --ccid=ExampleCC --args {\"Func\":\"move\",\"Args\":[\"A\",\"B\",\"1\"]} --iterations 100 --concurrency 8 --attempts 3 --config ../fixtures/config/config_test_local.yaml") } func TestInvoke_chaincode_with_two_sets_of_args(t *testing.T) { header("Invoke chaincode with two sets of args, 100 times each in 8 Go routines with 3 attempts for each invocation (in case the invocation fails)") run("fabric-cli.go chaincode invoke --ccid=ExampleCC --args [{\"Func\":\"move\",\"Args\":[\"A\",\"B\",\"1\"]},{\"Func\":\"move\",\"Args\":[\"B\",\"A\",\"2\"]}] --iterations 100 --concurrency 8 --attempts 3 --config ../fixtures/config/config_test_local.yaml") } func TestInvoke_chaincode_using_dynamic_selection_provider(t *testing.T) { header("Invoke chaincode using a 'dynamic' selection provider that chooses a minimal set of peers required to satisfy the endorsement policy of the chaincode:") run("fabric-cli.go chaincode invoke --ccid=ExampleCC --args {\"Func\":\"move\",\"Args\":[\"A\",\"B\",\"1\"]} --orgid org1,org2 --selectprovider=dynamic --config ../fixtures/config/config_test_local.yaml") } //// ********** Events ************ //// func TestListen_for_block_events(t *testing.T) { header("Listen for block events (output in JSON)") run("fabric-cli.go event listenblock --format json --config ../fixtures/config/config_test_local.yaml") } func TestListen_for_filtered_block_events(t *testing.T) { header("Listen for filtered block events (output in JSON)") run("fabric-cli.go event listenfilteredblock --format json --config ../fixtures/config/config_test_local.yaml") } func TestListen_for_chaincode_events(t *testing.T) { header("Listen for chaincode events") run("fabric-cli.go event listencc --ccid=ExampleCC --event=testEvent --config ../fixtures/config/config_test_local.yaml") } ================================================ FILE: fabric-cli/test/integration/go.mod ================================================ // Copyright SecureKey Technologies Inc. All Rights Reserved. // // SPDX-License-Identifier: Apache-2.0 module github.com/securekey/fabric-examples/integration require github.com/securekey/fabric-examples/fabric-cli v0.0.0 replace github.com/securekey/fabric-examples/fabric-cli v0.0.0 => ../../../fabric-cli/cmd/fabric-cli go 1.13 ================================================ FILE: fabric-cli/test/integration/go.sum ================================================ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5 h1:PqZ3bA4yzwywivzk7PBQWngJp2/PAS0bWRZerKteicY= github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93 h1:qdfmdGwtm13OVx+AxguOWUTbgmXGn2TbdUHipo3chMg= github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce h1:xdsDDbiBDQTKASoGEZ+pEmF1OnWuu8AQ9I8iNbHNeno= github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hyperledger/fabric-lib-go v1.0.0 h1:UL1w7c9LvHZUSkIvHTDGklxFv2kTeva1QI2emOVc324= github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= github.com/hyperledger/fabric-protos-go v0.0.0-20190821180310-6b6ac9042dfd h1:z0IbaMd4Ry2Cmmxujzy4UDgCUsT/0dOqqoGtOcvDw9Q= github.com/hyperledger/fabric-protos-go v0.0.0-20190821180310-6b6ac9042dfd/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/hyperledger/fabric-protos-go v0.0.0-20191204195335-3ddf3f16d6cf/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/hyperledger/fabric-sdk-go v1.0.0-alpha5.0.20190827185549-6c3f788a32f8 h1:VUal7sIRsOAO8KBIcStUTEmda41y5eTbZhQfHRDq4Uk= github.com/hyperledger/fabric-sdk-go v1.0.0-alpha5.0.20190827185549-6c3f788a32f8/go.mod h1:H5Atl/PpXhEKYYShSLFElohDoB11o4/R0OwBxOs7hcM= github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20190930220855-cea2ffaf627c/go.mod h1:i8yJ9t8i1fGe7opUcq6uESxhruMJNXlc+Rx9ooBZsYg= github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20191219180315-e1055f391525/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE= github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200106161850-8f3d32c9d1a6/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27 h1:XA/VH+SzpYyukhgh7v2mTp8rZoKKITXR/x3FIizVEXs= github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27/go.mod h1:WCBAbTOdfhHhz7YXujeZMF7owC4tPb1naKFsgfUISjo= github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20180511142126-bb74f1db0675 h1:/rdJjIiKG5rRdwG5yxHmSE/7ZREjpyC0kL7GxGT/qJw= github.com/mitchellh/mapstructure v0.0.0-20180511142126-bb74f1db0675/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/procfs v0.0.0-20180705121852-ae68e2d4c00f/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7 h1:NgR6WN8nQ4SmFC1sSUHY8SriLuWCZ6cCIQtH4vDZN3c= github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/securekey/fabric-examples v0.0.0-20190226225026-644fda76ee3b h1:hUFS/EkSw2bclWJ5nNpYYijbQhZIOxqGb74AR3RkfF4= github.com/securekey/fabric-examples v0.0.0-20190226225026-644fda76ee3b/go.mod h1:TFB0Em4NQmx/PNpsdoJxqRwdS9j70aGbdTL/pqgc8DE= github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.1 h1:Lt3ihYMlE+lreX1GS4Qw4ZsNpYQLxIXKBTEOXm3nt6I= github.com/spf13/afero v1.1.1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg= github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec h1:2ZXvIUGghLpdTVHR1UfvfrzoVlZaE/yOWC5LueIHZig= github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.0.2 h1:Ncr3ZIuJn322w2k1qmzXDnkLAdQMlJqBa9kfAH+irso= github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d h1:XB2jc5XQ9uhizGTS2vWcN01bc4dI6z3C4KY5MQm8SS8= google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=