├── .gitignore ├── .gitreview ├── .vscode └── settings.json ├── 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 ├── scripts └── fabric-sdk-go │ ├── apply_upstream.sh │ ├── example-network-clean.sh │ ├── populate.sh │ └── readme-example-network-clean.txt └── 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 /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | # 6 | *.db 7 | *report.xml 8 | .DS_Store 9 | .vscode 10 | debug.test 11 | vendor/ 12 | .idea/ 13 | /fabric-cli/cmd/fabric-cli/fabric-cli 14 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=gerrit.securekey.com 3 | port=29418 4 | project=fabric-examples 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | fabric-examples 2 | -------------------------------------------------------------------------------- /fabric-cli/.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | # 6 | vendor/ 7 | fabric-sdk-go/ 8 | -------------------------------------------------------------------------------- /fabric-cli/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /fabric-cli/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | # 6 | 7 | # Supported Targets: 8 | # 9 | # populate-sdk: retrieves all fabric-sdk-files required for tests 10 | # fabric-sdk-go-pin: populates only upstream files (not included in git) 11 | # example-network: start the example fabric network 12 | # example-network-clean: stops any running network and cleans up the artifacts 13 | # clean: removes all generated artifacts 14 | # 15 | 16 | # Tool commands (overridable) 17 | GO_CMD ?= go 18 | GO_DEP_CMD ?= dep 19 | DOCKER_CMD ?= docker 20 | DOCKER_COMPOSE_CMD ?= docker-compose 21 | 22 | # fabric-sdk-go version (overridable) 23 | FABRIC_SDK_GO_BRANCH ?= master 24 | FABRIC_SDK_GO_COMMIT ?= 8f3d32c9d1a66f88d405c9f5335870c5277f773a 25 | 26 | # Test fixture paths 27 | FIXTURE_DOCKERENV_PATH := fabric-sdk-go/test/fixtures/dockerenv 28 | 29 | .PHONY: polulate-sdk 30 | populate-sdk: fabric-sdk-go-pin fabric-sdk-go-populate 31 | 32 | .PHONY: fabric-sdk-go-pin 33 | fabric-sdk-go-pin: 34 | @echo "Pinning fabric-sdk-go ..." 35 | @UPSTREAM_COMMIT=$(FABRIC_SDK_GO_COMMIT) UPSTREAM_BRANCH=$(FABRIC_SDK_GO_BRANCH) scripts/fabric-sdk-go/apply_upstream.sh 36 | 37 | .PHONY: fabric-sdk-go-populate 38 | fabric-sdk-go-populate: 39 | @scripts/fabric-sdk-go/populate.sh 40 | 41 | .PHONY: clean 42 | clean: example-network-clean 43 | rm -Rf vendor 44 | rm -Rf fabric-sdk-go 45 | 46 | .PHONY: example-network 47 | example-network: 48 | @cd ./fabric-sdk-go && \ 49 | make dockerenv-stable-up 50 | 51 | .PHONY: example-network-clean 52 | example-network-clean: 53 | @DOCKER_CMD=$(DOCKER_CMD) scripts/fabric-sdk-go/example-network-clean.sh 54 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/action/svcproviderfactory.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package action 8 | 9 | import ( 10 | "github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/dynamicselection" 11 | "github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/fabricselection" 12 | "github.com/hyperledger/fabric-sdk-go/pkg/client/common/selection/staticselection" 13 | "github.com/hyperledger/fabric-sdk-go/pkg/common/options" 14 | contextApi "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context" 15 | "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" 16 | "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk/factory/defsvc" 17 | "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk/provider/chpvdr" 18 | "github.com/pkg/errors" 19 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 20 | ) 21 | 22 | // serviceProviderFactory is configured with either static or dynamic selection provider 23 | type serviceProviderFactory struct { 24 | defsvc.ProviderFactory 25 | } 26 | 27 | func newServiceProviderFactory() (*serviceProviderFactory, error) { 28 | return &serviceProviderFactory{}, nil 29 | } 30 | 31 | type fabricSelectionChannelProvider struct { 32 | fab.ChannelProvider 33 | service fab.ChannelService 34 | selection fab.SelectionService 35 | } 36 | 37 | type fabricSelectionChannelService struct { 38 | fab.ChannelService 39 | selection fab.SelectionService 40 | } 41 | 42 | // CreateChannelProvider returns a new default implementation of channel provider 43 | func (f *serviceProviderFactory) CreateChannelProvider(config fab.EndpointConfig, opts ...options.Opt) (fab.ChannelProvider, error) { 44 | chProvider, err := chpvdr.New(config, opts...) 45 | if err != nil { 46 | return nil, err 47 | } 48 | return &fabricSelectionChannelProvider{ 49 | ChannelProvider: chProvider, 50 | }, nil 51 | } 52 | 53 | type closable interface { 54 | Close() 55 | } 56 | 57 | // Close frees resources and caches. 58 | func (cp *fabricSelectionChannelProvider) Close() { 59 | if c, ok := cp.ChannelProvider.(closable); ok { 60 | c.Close() 61 | } 62 | if cp.selection != nil { 63 | if c, ok := cp.selection.(closable); ok { 64 | c.Close() 65 | } 66 | } 67 | } 68 | 69 | type providerInit interface { 70 | Initialize(providers contextApi.Providers) error 71 | } 72 | 73 | func (cp *fabricSelectionChannelProvider) Initialize(providers contextApi.Providers) error { 74 | if init, ok := cp.ChannelProvider.(providerInit); ok { 75 | return init.Initialize(providers) 76 | } 77 | return nil 78 | } 79 | 80 | // ChannelService creates a ChannelService for an identity 81 | func (cp *fabricSelectionChannelProvider) ChannelService(ctx fab.ClientContext, channelID string) (fab.ChannelService, error) { 82 | chService, err := cp.ChannelProvider.ChannelService(ctx, channelID) 83 | if err != nil { 84 | return nil, err 85 | } 86 | 87 | discovery, err := chService.Discovery() 88 | if err != nil { 89 | return nil, err 90 | } 91 | 92 | if cp.selection == nil { 93 | switch cliconfig.Config().SelectionProvider() { 94 | case cliconfig.StaticSelectionProvider: 95 | cliconfig.Config().Logger().Debugf("Using static selection provider.") 96 | cp.selection, err = staticselection.NewService(discovery) 97 | case cliconfig.DynamicSelectionProvider: 98 | cliconfig.Config().Logger().Debugf("Using dynamic selection provider.") 99 | cp.selection, err = dynamicselection.NewService(ctx, channelID, discovery) 100 | case cliconfig.FabricSelectionProvider: 101 | cliconfig.Config().Logger().Debugf("Using Fabric selection provider.") 102 | cp.selection, err = fabricselection.New(ctx, channelID, discovery) 103 | default: 104 | return nil, errors.Errorf("invalid selection provider: %s", cliconfig.Config().SelectionProvider()) 105 | } 106 | 107 | if err != nil { 108 | return nil, err 109 | } 110 | } 111 | 112 | return &fabricSelectionChannelService{ 113 | ChannelService: chService, 114 | selection: cp.selection, 115 | }, nil 116 | } 117 | 118 | func (cs *fabricSelectionChannelService) Selection() (fab.SelectionService, error) { 119 | return cs.selection, nil 120 | } 121 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/chaincodecmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var chaincodeCmd = &cobra.Command{ 15 | Use: "chaincode", 16 | Short: "Chaincode commands", 17 | Long: "Chaincode commands", 18 | Run: func(cmd *cobra.Command, args []string) { 19 | cmd.HelpFunc()(cmd, args) 20 | }, 21 | } 22 | 23 | // Cmd returns the chaincode command 24 | func Cmd() *cobra.Command { 25 | cliconfig.InitChannelID(chaincodeCmd.Flags()) 26 | 27 | chaincodeCmd.AddCommand(getInstallCmd()) 28 | chaincodeCmd.AddCommand(getInstantiateCmd()) 29 | chaincodeCmd.AddCommand(getInvokeCmd()) 30 | chaincodeCmd.AddCommand(getQueryCmd()) 31 | chaincodeCmd.AddCommand(getGetInfoCmd()) 32 | chaincodeCmd.AddCommand(getUpgradeCmd()) 33 | 34 | return chaincodeCmd 35 | } 36 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/getinfocmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "fmt" 11 | "strings" 12 | 13 | "github.com/golang/protobuf/proto" 14 | pb "github.com/hyperledger/fabric-protos-go/peer" 15 | "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" 16 | "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/core/common/ccprovider" 17 | "github.com/pkg/errors" 18 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 19 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 20 | "github.com/spf13/cobra" 21 | "github.com/spf13/pflag" 22 | ) 23 | 24 | const ( 25 | lifecycleSCC = "lscc" 26 | 27 | getCCDataFunc = "getccdata" 28 | getCollConfigFunc = "getcollectionsconfig" 29 | ) 30 | 31 | var getInfoCmd = &cobra.Command{ 32 | Use: "info", 33 | Short: "Get chaincode info", 34 | Long: "Retrieves details about the chaincode", 35 | Run: func(cmd *cobra.Command, args []string) { 36 | if cliconfig.Config().ChaincodeID() == "" { 37 | fmt.Printf("\nMust specify the chaincode ID\n\n") 38 | cmd.HelpFunc()(cmd, args) 39 | return 40 | } 41 | action, err := newGetInfoAction(cmd.Flags()) 42 | if err != nil { 43 | cliconfig.Config().Logger().Errorf("Error while initializing getAction: %v", err) 44 | return 45 | } 46 | 47 | defer action.Terminate() 48 | 49 | err = action.invoke() 50 | if err != nil { 51 | cliconfig.Config().Logger().Errorf("Error while running getAction: %v", err) 52 | } 53 | }, 54 | } 55 | 56 | func getGetInfoCmd() *cobra.Command { 57 | flags := getInfoCmd.Flags() 58 | cliconfig.InitPeerURL(flags) 59 | cliconfig.InitChannelID(flags) 60 | cliconfig.InitChaincodeID(flags) 61 | return getInfoCmd 62 | } 63 | 64 | type getInfoAction struct { 65 | action.Action 66 | } 67 | 68 | func newGetInfoAction(flags *pflag.FlagSet) (*getInfoAction, error) { 69 | action := &getInfoAction{} 70 | err := action.Initialize(flags) 71 | if len(action.Peers()) == 0 { 72 | return nil, errors.New("a peer must be specified") 73 | } 74 | return action, err 75 | } 76 | 77 | func (action *getInfoAction) invoke() error { 78 | channelClient, err := action.ChannelClient() 79 | if err != nil { 80 | return errors.Errorf("error retrieving channel client: %v", err) 81 | } 82 | 83 | ccData, err := action.getCCData(channelClient) 84 | if err != nil { 85 | return errors.WithMessagef(err, "error querying for chaincode data") 86 | } 87 | 88 | collConfig, err := action.getCollConfig(channelClient) 89 | if err != nil { 90 | if !strings.Contains(errors.Cause(err).Error(), "collections config not defined for chaincode") { 91 | return errors.WithMessagef(err, "error querying for collection config") 92 | } 93 | } 94 | 95 | action.Printer().PrintChaincodeData(ccData, collConfig) 96 | 97 | return nil 98 | } 99 | 100 | func (action *getInfoAction) getCCData(channelClient *channel.Client) (*ccprovider.ChaincodeData, error) { 101 | var args [][]byte 102 | args = append(args, []byte(cliconfig.Config().ChannelID())) 103 | args = append(args, []byte(cliconfig.Config().ChaincodeID())) 104 | 105 | peer := action.Peer() 106 | fmt.Printf("querying chaincode info for %s on peer: %s...\n", cliconfig.Config().ChaincodeID(), peer.URL()) 107 | 108 | response, err := channelClient.Query( 109 | channel.Request{ChaincodeID: lifecycleSCC, Fcn: getCCDataFunc, Args: args}, 110 | channel.WithTargetEndpoints(peer.URL())) 111 | if err != nil { 112 | return nil, errors.Errorf("error querying for chaincode info: %v", err) 113 | } 114 | 115 | ccData := &ccprovider.ChaincodeData{} 116 | err = proto.Unmarshal(response.Payload, ccData) 117 | if err != nil { 118 | return nil, errors.Errorf("error unmarshalling chaincode data: %v", err) 119 | } 120 | return ccData, nil 121 | } 122 | 123 | func (action *getInfoAction) getCollConfig(channelClient *channel.Client) (*pb.CollectionConfigPackage, error) { 124 | var args [][]byte 125 | args = append(args, []byte(cliconfig.Config().ChaincodeID())) 126 | 127 | peer := action.Peer() 128 | fmt.Printf("querying collections config for %s on peer: %s...\n", cliconfig.Config().ChaincodeID(), peer.URL()) 129 | 130 | response, err := channelClient.Query( 131 | channel.Request{ChaincodeID: lifecycleSCC, Fcn: getCollConfigFunc, Args: args}, 132 | channel.WithTargetEndpoints(peer.URL())) 133 | if err != nil { 134 | return nil, errors.Errorf("error querying for collections config: %v", err) 135 | } 136 | 137 | collConfig := &pb.CollectionConfigPackage{} 138 | err = proto.Unmarshal(response.Payload, collConfig) 139 | if err != nil { 140 | return nil, errors.Errorf("error unmarshalling collections config: %v", err) 141 | } 142 | return collConfig, nil 143 | } 144 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/installcmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "fmt" 11 | "net/http" 12 | 13 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 14 | "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" 15 | "github.com/hyperledger/fabric-sdk-go/pkg/fab/ccpackager/gopackager" 16 | "github.com/pkg/errors" 17 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 18 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 19 | "github.com/spf13/cobra" 20 | "github.com/spf13/pflag" 21 | ) 22 | 23 | var installCmd = &cobra.Command{ 24 | Use: "install", 25 | Short: "Install chaincode.", 26 | Long: "Install chaincode", 27 | Run: func(cmd *cobra.Command, args []string) { 28 | if cliconfig.Config().ChaincodeID() == "" { 29 | fmt.Printf("\nMust specify the chaincode ID\n\n") 30 | cmd.HelpFunc()(cmd, args) 31 | return 32 | } 33 | if cliconfig.Config().ChaincodePath() == "" { 34 | fmt.Printf("\nMust specify the path of the chaincode\n\n") 35 | cmd.HelpFunc()(cmd, args) 36 | return 37 | } 38 | action, err := newInstallAction(cmd.Flags()) 39 | if err != nil { 40 | cliconfig.Config().Logger().Errorf("Error while initializing installAction: %v", err) 41 | return 42 | } 43 | 44 | defer action.Terminate() 45 | 46 | err = action.invoke() 47 | if err != nil { 48 | cliconfig.Config().Logger().Errorf("Error while running installAction: %v", err) 49 | } 50 | }, 51 | } 52 | 53 | func getInstallCmd() *cobra.Command { 54 | flags := installCmd.Flags() 55 | cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to install the chaincode, e.g. localhost:7051") 56 | cliconfig.InitChannelID(flags) 57 | cliconfig.InitChaincodeID(flags) 58 | cliconfig.InitChaincodePath(flags) 59 | cliconfig.InitChaincodeVersion(flags) 60 | cliconfig.InitGoPath(flags) 61 | return installCmd 62 | } 63 | 64 | type installAction struct { 65 | action.Action 66 | } 67 | 68 | func newInstallAction(flags *pflag.FlagSet) (*installAction, error) { 69 | action := &installAction{} 70 | err := action.Initialize(flags) 71 | return action, err 72 | } 73 | 74 | func (action *installAction) invoke() error { 75 | var lastErr error 76 | for orgID, peers := range action.PeersByOrg() { 77 | fmt.Printf("Installing chaincode %s on org[%s] peers:\n", cliconfig.Config().ChaincodeID(), orgID) 78 | for _, peer := range peers { 79 | fmt.Printf("-- %s\n", peer.URL()) 80 | } 81 | err := action.installChaincode(orgID, peers) 82 | if err != nil { 83 | lastErr = err 84 | } 85 | } 86 | 87 | return lastErr 88 | } 89 | 90 | func (action *installAction) installChaincode(orgID string, targets []fab.Peer) error { 91 | 92 | resMgmtClient, err := action.ResourceMgmtClientForOrg(orgID) 93 | if err != nil { 94 | return err 95 | } 96 | 97 | ccPkg, err := gopackager.NewCCPackage(cliconfig.Config().ChaincodePath(), cliconfig.Config().GoPath()) 98 | if err != nil { 99 | return err 100 | } 101 | req := resmgmt.InstallCCRequest{ 102 | Name: cliconfig.Config().ChaincodeID(), 103 | Path: cliconfig.Config().ChaincodePath(), 104 | Version: cliconfig.Config().ChaincodeVersion(), 105 | Package: ccPkg, 106 | } 107 | responses, err := resMgmtClient.InstallCC(req, resmgmt.WithTargets(targets...)) 108 | if err != nil { 109 | return errors.Errorf("InstallChaincode returned error: %v", err) 110 | } 111 | 112 | ccIDVersion := cliconfig.Config().ChaincodeID() + "." + cliconfig.Config().ChaincodeVersion() 113 | 114 | var errs []error 115 | for _, resp := range responses { 116 | if resp.Info == "already installed" { 117 | fmt.Printf("Chaincode %s already installed on peer: %s.\n", ccIDVersion, resp.Target) 118 | } else if resp.Status != http.StatusOK { 119 | errs = append(errs, errors.Errorf("installCC returned error from peer %s: %s", resp.Target, resp.Info)) 120 | } else { 121 | fmt.Printf("...successfuly installed chaincode %s on peer %s.\n", ccIDVersion, resp.Target) 122 | } 123 | } 124 | 125 | if len(errs) > 0 { 126 | cliconfig.Config().Logger().Warnf("Errors returned from InstallCC: %v\n", errs) 127 | return errs[0] 128 | } 129 | 130 | return nil 131 | } 132 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/instantiatecmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "encoding/json" 11 | "fmt" 12 | "io/ioutil" 13 | "strings" 14 | 15 | "github.com/hyperledger/fabric-protos-go/common" 16 | pb "github.com/hyperledger/fabric-protos-go/peer" 17 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 18 | "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/cauthdsl" 19 | "github.com/pkg/errors" 20 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 21 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" 22 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 23 | "github.com/spf13/cobra" 24 | "github.com/spf13/pflag" 25 | ) 26 | 27 | var instantiateCmd = &cobra.Command{ 28 | Use: "instantiate", 29 | Short: "Instantiate chaincode.", 30 | Long: "Instantiates the chaincode", 31 | Run: func(cmd *cobra.Command, args []string) { 32 | if cliconfig.Config().ChaincodeID() == "" { 33 | fmt.Printf("\nMust specify the chaincode ID\n\n") 34 | cmd.HelpFunc()(cmd, args) 35 | return 36 | } 37 | if cliconfig.Config().ChaincodePath() == "" { 38 | fmt.Printf("\nMust specify the path of the chaincode\n\n") 39 | cmd.HelpFunc()(cmd, args) 40 | return 41 | } 42 | action, err := newInstantiateAction(cmd.Flags()) 43 | if err != nil { 44 | cliconfig.Config().Logger().Errorf("Error while initializing instantiateAction: %v", err) 45 | return 46 | } 47 | 48 | defer action.Terminate() 49 | 50 | err = action.invoke() 51 | if err != nil { 52 | cliconfig.Config().Logger().Errorf("Error while running instantiateAction: %v", err) 53 | } 54 | }, 55 | } 56 | 57 | func getInstantiateCmd() *cobra.Command { 58 | flags := instantiateCmd.Flags() 59 | cliconfig.InitPeerURL(flags) 60 | cliconfig.InitChannelID(flags) 61 | cliconfig.InitChaincodeID(flags) 62 | cliconfig.InitChaincodePath(flags) 63 | cliconfig.InitChaincodeVersion(flags) 64 | cliconfig.InitArgs(flags) 65 | cliconfig.InitChaincodePolicy(flags) 66 | cliconfig.InitCollectionConfigFile(flags) 67 | cliconfig.InitTimeout(flags) 68 | return instantiateCmd 69 | } 70 | 71 | type instantiateAction struct { 72 | action.Action 73 | } 74 | 75 | func newInstantiateAction(flags *pflag.FlagSet) (*instantiateAction, error) { 76 | action := &instantiateAction{} 77 | err := action.Initialize(flags) 78 | if len(action.Peers()) == 0 { 79 | return nil, errors.Errorf("a peer must be specified") 80 | } 81 | return action, err 82 | } 83 | 84 | func (a *instantiateAction) invoke() error { 85 | s := cliconfig.Config().Args() 86 | argBytes := []byte(s) 87 | args := &action.ArgStruct{} 88 | 89 | if err := json.Unmarshal(argBytes, args); err != nil { 90 | return errors.Errorf("Error unmarshalling JSON arg string: %v", err) 91 | } 92 | 93 | resMgmtClient, err := a.ResourceMgmtClient() 94 | if err != nil { 95 | return err 96 | } 97 | 98 | cliconfig.Config().Logger().Infof("Sending instantiate %s ...\n", cliconfig.Config().ChaincodeID()) 99 | 100 | chaincodePolicy, err := a.newChaincodePolicy() 101 | if err != nil { 102 | return err 103 | } 104 | 105 | // Private Data Collection Configuration 106 | // - see fixtures/config/pvtdatacollection.json for sample config file 107 | var collConfig []*pb.CollectionConfig 108 | collConfigFile := cliconfig.Config().CollectionConfigFile() 109 | if collConfigFile != "" { 110 | collConfig, err = getCollectionConfigFromFile(cliconfig.Config().CollectionConfigFile()) 111 | if err != nil { 112 | return errors.Wrapf(err, "error getting private data collection configuration from file [%s]", cliconfig.Config().CollectionConfigFile()) 113 | } 114 | } 115 | 116 | req := resmgmt.InstantiateCCRequest{ 117 | Name: cliconfig.Config().ChaincodeID(), 118 | Path: cliconfig.Config().ChaincodePath(), 119 | Version: cliconfig.Config().ChaincodeVersion(), 120 | Args: utils.AsBytes(utils.NewContext(), args.Args), 121 | Policy: chaincodePolicy, 122 | CollConfig: collConfig, 123 | } 124 | 125 | _, err = resMgmtClient.InstantiateCC(cliconfig.Config().ChannelID(), req, resmgmt.WithTargets(a.Peer())) 126 | if err != nil { 127 | if strings.Contains(err.Error(), "chaincode exists "+cliconfig.Config().ChaincodeID()) { 128 | // Ignore 129 | cliconfig.Config().Logger().Infof("Chaincode %s already instantiated.", cliconfig.Config().ChaincodeID()) 130 | fmt.Printf("...chaincode %s already instantiated.\n", cliconfig.Config().ChaincodeID()) 131 | return nil 132 | } 133 | return errors.Errorf("error instantiating chaincode: %v", err) 134 | } 135 | 136 | fmt.Printf("...successfuly instantiated chaincode %s on channel %s.\n", cliconfig.Config().ChaincodeID(), cliconfig.Config().ChannelID()) 137 | 138 | return nil 139 | } 140 | 141 | func (a *instantiateAction) newChaincodePolicy() (*common.SignaturePolicyEnvelope, error) { 142 | if cliconfig.Config().ChaincodePolicy() != "" { 143 | // Create a signature policy from the policy expression passed in 144 | return newChaincodePolicy(cliconfig.Config().ChaincodePolicy()) 145 | } 146 | 147 | // Default policy is 'signed by any member' for all known orgs 148 | return cauthdsl.AcceptAllPolicy, nil 149 | } 150 | 151 | func newChaincodePolicy(policyString string) (*common.SignaturePolicyEnvelope, error) { 152 | ccPolicy, err := cauthdsl.FromString(policyString) 153 | if err != nil { 154 | return nil, errors.Errorf("invalid chaincode policy [%s]: %s", policyString, err) 155 | } 156 | return ccPolicy, nil 157 | } 158 | 159 | type collectionConfigJSON struct { 160 | Name string `json:"name"` 161 | Policy string `json:"policy"` 162 | RequiredPeerCount int32 `json:"requiredPeerCount"` 163 | MaxPeerCount int32 `json:"maxPeerCount"` 164 | } 165 | 166 | func getCollectionConfigFromFile(ccFile string) ([]*pb.CollectionConfig, error) { 167 | fileBytes, err := ioutil.ReadFile(ccFile) 168 | if err != nil { 169 | return nil, errors.Wrapf(err, "could not read file [%s]", ccFile) 170 | } 171 | cconf := &[]collectionConfigJSON{} 172 | if err = json.Unmarshal(fileBytes, cconf); err != nil { 173 | return nil, errors.Wrapf(err, "error parsing collection configuration in file [%s]", ccFile) 174 | } 175 | return getCollectionConfig(*cconf) 176 | } 177 | 178 | func getCollectionConfig(cconf []collectionConfigJSON) ([]*pb.CollectionConfig, error) { 179 | ccarray := make([]*pb.CollectionConfig, 0, len(cconf)) 180 | for _, cconfitem := range cconf { 181 | p, err := cauthdsl.FromString(cconfitem.Policy) 182 | if err != nil { 183 | return nil, errors.WithMessage(err, fmt.Sprintf("invalid policy %s", cconfitem.Policy)) 184 | } 185 | cpc := &pb.CollectionPolicyConfig{ 186 | Payload: &pb.CollectionPolicyConfig_SignaturePolicy{ 187 | SignaturePolicy: p, 188 | }, 189 | } 190 | cc := &pb.CollectionConfig{ 191 | Payload: &pb.CollectionConfig_StaticCollectionConfig{ 192 | StaticCollectionConfig: &pb.StaticCollectionConfig{ 193 | Name: cconfitem.Name, 194 | MemberOrgsPolicy: cpc, 195 | RequiredPeerCount: cconfitem.RequiredPeerCount, 196 | MaximumPeerCount: cconfitem.MaxPeerCount, 197 | }, 198 | }, 199 | } 200 | ccarray = append(ccarray, cc) 201 | } 202 | return ccarray, nil 203 | } 204 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/invokecmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "fmt" 11 | "strconv" 12 | "sync" 13 | "time" 14 | 15 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 16 | "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" 17 | "github.com/pkg/errors" 18 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 19 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/invoketask" 20 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/multitask" 21 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/task" 22 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" 23 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 24 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/executor" 25 | "github.com/spf13/cobra" 26 | "github.com/spf13/pflag" 27 | ) 28 | 29 | var invokeCmd = &cobra.Command{ 30 | Use: "invoke", 31 | Short: "invoke chaincode.", 32 | Long: "invoke chaincode", 33 | Run: func(cmd *cobra.Command, args []string) { 34 | if cliconfig.Config().ChaincodeID() == "" { 35 | fmt.Printf("\nMust specify the chaincode ID\n\n") 36 | cmd.HelpFunc()(cmd, args) 37 | return 38 | } 39 | action, err := newInvokeAction(cmd.Flags()) 40 | if err != nil { 41 | cliconfig.Config().Logger().Errorf("Error while initializing invokeAction: %v", err) 42 | return 43 | } 44 | 45 | defer action.Terminate() 46 | 47 | err = action.invoke() 48 | if err != nil { 49 | cliconfig.Config().Logger().Errorf("Error while running invokeAction: %v", err) 50 | } 51 | }, 52 | } 53 | 54 | func getInvokeCmd() *cobra.Command { 55 | flags := invokeCmd.Flags() 56 | cliconfig.InitPeerURL(flags) 57 | cliconfig.InitChannelID(flags) 58 | cliconfig.InitChaincodeID(flags) 59 | cliconfig.InitArgs(flags) 60 | cliconfig.InitIterations(flags) 61 | cliconfig.InitSleepTime(flags) 62 | cliconfig.InitTimeout(flags) 63 | cliconfig.InitPrintPayloadOnly(flags) 64 | cliconfig.InitConcurrency(flags) 65 | cliconfig.InitMaxAttempts(flags) 66 | cliconfig.InitInitialBackoff(flags) 67 | cliconfig.InitMaxBackoff(flags) 68 | cliconfig.InitBackoffFactor(flags) 69 | cliconfig.InitVerbosity(flags) 70 | cliconfig.InitSelectionProvider(flags) 71 | return invokeCmd 72 | } 73 | 74 | type invokeAction struct { 75 | action.Action 76 | numInvoked uint32 77 | done chan bool 78 | } 79 | 80 | func newInvokeAction(flags *pflag.FlagSet) (*invokeAction, error) { 81 | action := &invokeAction{done: make(chan bool)} 82 | err := action.Initialize(flags) 83 | return action, err 84 | } 85 | 86 | func (a *invokeAction) invoke() error { 87 | channelClient, err := a.ChannelClient() 88 | if err != nil { 89 | return errors.Errorf("Error getting channel client: %v", err) 90 | } 91 | 92 | argsArray, err := action.ArgsArray() 93 | if err != nil { 94 | return err 95 | } 96 | 97 | executor := executor.NewConcurrent("Invoke Chaincode", cliconfig.Config().Concurrency()) 98 | executor.Start() 99 | defer executor.Stop(true) 100 | 101 | success := 0 102 | var errs []error 103 | var successDurations []time.Duration 104 | var failDurations []time.Duration 105 | 106 | var targets []fab.Peer 107 | if len(cliconfig.Config().PeerURL()) > 0 || len(cliconfig.Config().OrgIDs()) > 0 { 108 | targets = a.Peers() 109 | } 110 | 111 | var wg sync.WaitGroup 112 | var mutex sync.RWMutex 113 | var tasks []task.Task 114 | var taskID int 115 | for i := 0; i < cliconfig.Config().Iterations(); i++ { 116 | ctxt := utils.NewContext() 117 | multiTask := multitask.New(wg.Done) 118 | for _, args := range argsArray { 119 | taskID++ 120 | var startTime time.Time 121 | cargs := args 122 | task := invoketask.New( 123 | ctxt, 124 | strconv.Itoa(taskID), channelClient, targets, 125 | cliconfig.Config().ChaincodeID(), 126 | &cargs, executor, 127 | retry.Opts{ 128 | Attempts: cliconfig.Config().MaxAttempts(), 129 | InitialBackoff: cliconfig.Config().InitialBackoff(), 130 | MaxBackoff: cliconfig.Config().MaxBackoff(), 131 | BackoffFactor: cliconfig.Config().BackoffFactor(), 132 | RetryableCodes: retry.ChannelClientRetryableCodes, 133 | }, 134 | cliconfig.Config().Verbose() || cliconfig.Config().Iterations() == 1, 135 | cliconfig.Config().PrintPayloadOnly(), a.Printer(), 136 | 137 | func() { 138 | startTime = time.Now() 139 | }, 140 | func(err error) { 141 | duration := time.Since(startTime) 142 | mutex.Lock() 143 | defer mutex.Unlock() 144 | if err != nil { 145 | errs = append(errs, err) 146 | failDurations = append(failDurations, duration) 147 | } else { 148 | success++ 149 | successDurations = append(successDurations, duration) 150 | } 151 | }) 152 | multiTask.Add(task) 153 | } 154 | tasks = append(tasks, multiTask) 155 | } 156 | 157 | wg.Add(len(tasks)) 158 | 159 | numInvocations := len(tasks) * len(argsArray) 160 | 161 | done := make(chan bool) 162 | go func() { 163 | ticker := time.NewTicker(10 * time.Second) 164 | for { 165 | select { 166 | case <-ticker.C: 167 | mutex.RLock() 168 | if len(errs) > 0 { 169 | fmt.Printf("*** %d failed invocation(s) out of %d\n", len(errs), numInvocations) 170 | } 171 | fmt.Printf("*** %d successfull invocation(s) out of %d\n", success, numInvocations) 172 | mutex.RUnlock() 173 | case <-done: 174 | return 175 | } 176 | } 177 | }() 178 | 179 | startTime := time.Now() 180 | sleepTime := time.Duration(cliconfig.Config().SleepTime()) * time.Millisecond 181 | 182 | for _, task := range tasks { 183 | if err := executor.Submit(task); err != nil { 184 | return errors.Errorf("error submitting task: %s", err) 185 | } 186 | if sleepTime > 0 { 187 | time.Sleep(sleepTime) 188 | } 189 | } 190 | 191 | // Wait for all tasks to complete 192 | wg.Wait() 193 | done <- true 194 | 195 | duration := time.Now().Sub(startTime) 196 | 197 | var allErrs []error 198 | var attempts int 199 | for _, task := range tasks { 200 | attempts = attempts + task.Attempts() 201 | if task.LastError() != nil { 202 | allErrs = append(allErrs, task.LastError()) 203 | } 204 | } 205 | 206 | if len(errs) > 0 { 207 | fmt.Printf("\n*** %d errors invoking chaincode:\n", len(errs)) 208 | for _, err := range errs { 209 | fmt.Printf("%s\n", err) 210 | } 211 | } else if len(allErrs) > 0 { 212 | fmt.Printf("\n*** %d transient errors invoking chaincode:\n", len(allErrs)) 213 | for _, err := range allErrs { 214 | fmt.Printf("%s\n", err) 215 | } 216 | } 217 | 218 | if numInvocations/len(argsArray) > 1 { 219 | fmt.Printf("\n") 220 | fmt.Printf("*** ---------- Summary: ----------\n") 221 | fmt.Printf("*** - Invocations: %d\n", numInvocations) 222 | fmt.Printf("*** - Concurrency: %d\n", cliconfig.Config().Concurrency()) 223 | fmt.Printf("*** - Successfull: %d\n", success) 224 | fmt.Printf("*** - Total attempts: %d\n", attempts) 225 | fmt.Printf("*** - Duration: %2.2fs\n", duration.Seconds()) 226 | fmt.Printf("*** - Rate: %2.2f/s\n", float64(numInvocations)/duration.Seconds()) 227 | fmt.Printf("*** - Average: %2.2fs\n", average(append(successDurations, failDurations...))) 228 | fmt.Printf("*** - Average Success: %2.2fs\n", average(successDurations)) 229 | fmt.Printf("*** - Average Fail: %2.2fs\n", average(failDurations)) 230 | fmt.Printf("*** - Min Success: %2.2fs\n", min(successDurations)) 231 | fmt.Printf("*** - Max Success: %2.2fs\n", max(successDurations)) 232 | fmt.Printf("*** ------------------------------\n") 233 | } 234 | 235 | return nil 236 | } 237 | 238 | func average(durations []time.Duration) float64 { 239 | if len(durations) == 0 { 240 | return 0 241 | } 242 | 243 | var total float64 244 | for _, duration := range durations { 245 | total += duration.Seconds() 246 | } 247 | return total / float64(len(durations)) 248 | } 249 | 250 | func min(durations []time.Duration) float64 { 251 | min, _ := minMax(durations) 252 | return min 253 | } 254 | 255 | func max(durations []time.Duration) float64 { 256 | _, max := minMax(durations) 257 | return max 258 | } 259 | 260 | func minMax(durations []time.Duration) (min float64, max float64) { 261 | for _, duration := range durations { 262 | if min == 0 || min > duration.Seconds() { 263 | min = duration.Seconds() 264 | } 265 | if max == 0 || max < duration.Seconds() { 266 | max = duration.Seconds() 267 | } 268 | } 269 | return 270 | } 271 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/invokeerror/invokeerror.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package invokeerror 8 | 9 | import "github.com/pkg/errors" 10 | 11 | type ErrorCode int 12 | 13 | const ( 14 | // PersistentError indicates that an unknown error occurred 15 | // and a retry of the request would NOT be successful 16 | PersistentError ErrorCode = iota 17 | 18 | // TransientError indicates that a transient error occurred 19 | // and a retry of the request could be successful 20 | TransientError 21 | 22 | // TimeoutOnCommit indicates that a timeout occurred while waiting 23 | // for a TxStatus event 24 | TimeoutOnCommit 25 | ) 26 | 27 | // Error extends error with 28 | // additional context 29 | type Error interface { 30 | error 31 | 32 | // Status returns the error code 33 | ErrorCode() ErrorCode 34 | } 35 | 36 | type invokeError struct { 37 | error 38 | code ErrorCode 39 | } 40 | 41 | // New returns a new Error 42 | func New(code ErrorCode, msg string) Error { 43 | return &invokeError{ 44 | error: errors.New(msg), 45 | code: code, 46 | } 47 | } 48 | 49 | // Wrap returns a new Error 50 | func Wrap(code ErrorCode, cause error, msg string) Error { 51 | return &invokeError{ 52 | error: errors.Wrap(cause, msg), 53 | code: code, 54 | } 55 | } 56 | 57 | // Wrapf returns a new Error 58 | func Wrapf(code ErrorCode, cause error, fmt string, args ...interface{}) Error { 59 | return &invokeError{ 60 | error: errors.Wrapf(cause, fmt, args...), 61 | code: code, 62 | } 63 | } 64 | 65 | // Errorf returns a new Error 66 | func Errorf(code ErrorCode, fmt string, args ...interface{}) Error { 67 | return &invokeError{ 68 | error: errors.Errorf(fmt, args...), 69 | code: code, 70 | } 71 | } 72 | 73 | // ErrorCode returns the error code 74 | func (e *invokeError) ErrorCode() ErrorCode { 75 | return e.code 76 | } 77 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/invoketask/invoketask.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package invoketask 8 | 9 | import ( 10 | pb "github.com/hyperledger/fabric-protos-go/peer" 11 | "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" 12 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 13 | "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" 14 | "github.com/pkg/errors" 15 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 16 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/invokeerror" 17 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" 18 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 19 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/executor" 20 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/printer" 21 | ) 22 | 23 | // Task is a Task that invokes a chaincode 24 | type Task struct { 25 | ctxt utils.Context 26 | executor *executor.Executor 27 | channelClient *channel.Client 28 | targets []fab.Peer 29 | id string 30 | ccID string 31 | args *action.ArgStruct 32 | retryOpts retry.Opts 33 | attempt int 34 | lastErr error 35 | startedCB func() 36 | completedCB func(err error) 37 | verbose bool 38 | printer printer.Printer 39 | txID string 40 | payloadOnly bool 41 | } 42 | 43 | // New returns a new Task 44 | func New(ctxt utils.Context, id string, channelClient *channel.Client, targets []fab.Peer, ccID string, args *action.ArgStruct, 45 | executor *executor.Executor, retryOpts retry.Opts, verbose bool, 46 | payloadOnly bool, p printer.Printer, startedCB func(), completedCB func(err error)) *Task { 47 | return &Task{ 48 | ctxt: ctxt, 49 | id: id, 50 | channelClient: channelClient, 51 | targets: targets, 52 | printer: p, 53 | ccID: ccID, 54 | args: args, 55 | executor: executor, 56 | retryOpts: retryOpts, 57 | startedCB: startedCB, 58 | completedCB: completedCB, 59 | attempt: 1, 60 | verbose: verbose, 61 | payloadOnly: payloadOnly, 62 | } 63 | } 64 | 65 | // Attempts returns the number of invocation attempts that were made 66 | // in order to achieve a successful response 67 | func (t *Task) Attempts() int { 68 | return t.attempt 69 | } 70 | 71 | // LastError returns the last error that was recorder 72 | func (t *Task) LastError() error { 73 | return t.lastErr 74 | } 75 | 76 | // Invoke invokes the task 77 | func (t *Task) Invoke() { 78 | t.startedCB() 79 | if err := t.doInvoke(); err != nil { 80 | t.lastErr = err 81 | t.completedCB(err) 82 | } else { 83 | cliconfig.Config().Logger().Debugf("(%s) - Successfully invoked chaincode\n", t.id) 84 | t.completedCB(nil) 85 | } 86 | } 87 | 88 | func (t *Task) doInvoke() error { 89 | cliconfig.Config().Logger().Debugf("(%s) - Invoking chaincode: %s, function: %s, args: %+v. Attempt #%d...\n", 90 | t.id, t.ccID, t.args.Func, t.args.Args, t.attempt) 91 | 92 | var opts []channel.RequestOption 93 | opts = append(opts, channel.WithRetry(t.retryOpts)) 94 | opts = append(opts, channel.WithBeforeRetry(func(err error) { 95 | t.attempt++ 96 | })) 97 | if len(t.targets) > 0 { 98 | opts = append(opts, channel.WithTargets(t.targets...)) 99 | } 100 | 101 | response, err := t.channelClient.Execute( 102 | channel.Request{ 103 | ChaincodeID: t.ccID, 104 | Fcn: t.args.Func, 105 | Args: utils.AsBytes(t.ctxt, t.args.Args), 106 | }, 107 | opts..., 108 | ) 109 | if err != nil { 110 | return invokeerror.Errorf(invokeerror.TransientError, "SendTransactionProposal return error: %v", err) 111 | } 112 | 113 | if t.verbose { 114 | t.printer.PrintTxProposalResponses(response.Responses, t.payloadOnly) 115 | } 116 | 117 | t.txID = string(response.TransactionID) 118 | 119 | switch pb.TxValidationCode(response.TxValidationCode) { 120 | case pb.TxValidationCode_VALID: 121 | cliconfig.Config().Logger().Debugf("(%s) - Successfully committed transaction [%s] ...\n", t.id, response.TransactionID) 122 | return nil 123 | case pb.TxValidationCode_DUPLICATE_TXID, pb.TxValidationCode_MVCC_READ_CONFLICT, pb.TxValidationCode_PHANTOM_READ_CONFLICT: 124 | 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) 125 | return invokeerror.Wrapf(invokeerror.TransientError, errors.New("Duplicate TxID"), "invoke Error received from eventhub for TxID [%s]. Code: %s", response.TransactionID, response.TxValidationCode) 126 | default: 127 | cliconfig.Config().Logger().Debugf("(%s) - Transaction commit failed for [%s] with code [%s].\n", t.id, response.TransactionID, response.TxValidationCode) 128 | return invokeerror.Wrapf(invokeerror.PersistentError, errors.New("error"), "invoke Error received from eventhub for TxID [%s]. Code: %s", response.TransactionID, response.TxValidationCode) 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/multitask/multitask.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package multitask 8 | 9 | import "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/task" 10 | 11 | // MultiTask contains a set of Tasks to be invoked synchronously 12 | type MultiTask struct { 13 | tasks []task.Task 14 | completedCB func() 15 | } 16 | 17 | // New creates a new multi task 18 | func New(completedCB func()) *MultiTask { 19 | return &MultiTask{ 20 | completedCB: completedCB, 21 | } 22 | } 23 | 24 | // Add adds a task 25 | func (m *MultiTask) Add(task task.Task) { 26 | m.tasks = append(m.tasks, task) 27 | } 28 | 29 | // Invoke invokes the task 30 | func (m *MultiTask) Invoke() { 31 | defer m.completedCB() 32 | 33 | for _, task := range m.tasks { 34 | task.Invoke() 35 | } 36 | } 37 | 38 | // Attempts returns the number of invocation attempts that were made 39 | // in order to achieve a successful response 40 | func (m *MultiTask) Attempts() int { 41 | var attempts int 42 | for _, t := range m.tasks { 43 | attempts += t.Attempts() 44 | } 45 | return attempts 46 | } 47 | 48 | // LastError returns the last error that was recorder 49 | func (m *MultiTask) LastError() error { 50 | for _, t := range m.tasks { 51 | if t.LastError() != nil { 52 | return t.LastError() 53 | } 54 | } 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/querycmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "fmt" 11 | "strconv" 12 | "sync" 13 | "time" 14 | 15 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 16 | "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" 17 | "github.com/pkg/errors" 18 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 19 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/multitask" 20 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/querytask" 21 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/task" 22 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" 23 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 24 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/executor" 25 | "github.com/spf13/cobra" 26 | "github.com/spf13/pflag" 27 | ) 28 | 29 | var queryCmd = &cobra.Command{ 30 | Use: "query", 31 | Short: "Query chaincode.", 32 | Long: "Query chaincode", 33 | Run: func(cmd *cobra.Command, args []string) { 34 | if cliconfig.Config().ChaincodeID() == "" { 35 | fmt.Printf("\nMust specify the chaincode ID\n\n") 36 | cmd.HelpFunc()(cmd, args) 37 | return 38 | } 39 | action, err := newQueryAction(cmd.Flags()) 40 | if err != nil { 41 | cliconfig.Config().Logger().Errorf("Error while initializing queryAction: %v", err) 42 | return 43 | } 44 | 45 | defer action.Terminate() 46 | 47 | err = action.query() 48 | if err != nil { 49 | cliconfig.Config().Logger().Errorf("Error while running queryAction: %v", err) 50 | } 51 | }, 52 | } 53 | 54 | func getQueryCmd() *cobra.Command { 55 | flags := queryCmd.Flags() 56 | cliconfig.InitPeerURL(flags) 57 | cliconfig.InitChannelID(flags) 58 | cliconfig.InitChaincodeID(flags) 59 | cliconfig.InitArgs(flags) 60 | cliconfig.InitIterations(flags) 61 | cliconfig.InitSleepTime(flags) 62 | cliconfig.InitTimeout(flags) 63 | cliconfig.InitPrintPayloadOnly(flags) 64 | cliconfig.InitConcurrency(flags) 65 | cliconfig.InitVerbosity(flags) 66 | cliconfig.InitSelectionProvider(flags) 67 | cliconfig.InitValidate(flags) 68 | return queryCmd 69 | } 70 | 71 | type queryAction struct { 72 | action.Action 73 | numInvoked uint32 74 | done chan bool 75 | } 76 | 77 | func newQueryAction(flags *pflag.FlagSet) (*queryAction, error) { 78 | action := &queryAction{done: make(chan bool)} 79 | err := action.Initialize(flags) 80 | return action, err 81 | } 82 | 83 | func (a *queryAction) query() error { 84 | channelClient, err := a.ChannelClient() 85 | if err != nil { 86 | return errors.Errorf("Error getting channel client: %v", err) 87 | } 88 | 89 | argsArray, err := action.ArgsArray() 90 | if err != nil { 91 | return err 92 | } 93 | 94 | var targets []fab.Peer 95 | if len(cliconfig.Config().PeerURL()) > 0 || len(cliconfig.Config().OrgIDs()) > 0 { 96 | targets = a.Peers() 97 | } 98 | 99 | executor := executor.NewConcurrent("Query Chaincode", cliconfig.Config().Concurrency()) 100 | executor.Start() 101 | defer executor.Stop(true) 102 | 103 | verbose := cliconfig.Config().Verbose() || cliconfig.Config().Iterations() == 1 104 | 105 | var mutex sync.RWMutex 106 | var tasks []task.Task 107 | var errs []error 108 | var wg sync.WaitGroup 109 | var taskID int 110 | var success int 111 | var successDurations []time.Duration 112 | var failDurations []time.Duration 113 | 114 | for i := 0; i < cliconfig.Config().Iterations(); i++ { 115 | ctxt := utils.NewContext() 116 | multiTask := multitask.New(wg.Done) 117 | for _, args := range argsArray { 118 | taskID++ 119 | var startTime time.Time 120 | cargs := args 121 | task := querytask.New( 122 | ctxt, 123 | strconv.Itoa(taskID), channelClient, targets, &cargs, a.Printer(), 124 | retry.Opts{ 125 | Attempts: cliconfig.Config().MaxAttempts(), 126 | InitialBackoff: cliconfig.Config().InitialBackoff(), 127 | MaxBackoff: cliconfig.Config().MaxBackoff(), 128 | BackoffFactor: cliconfig.Config().BackoffFactor(), 129 | RetryableCodes: retry.ChannelClientRetryableCodes, 130 | }, 131 | verbose, 132 | cliconfig.Config().PrintPayloadOnly(), 133 | cliconfig.Config().Validate(), 134 | func() { 135 | startTime = time.Now() 136 | }, 137 | func(err error) { 138 | duration := time.Since(startTime) 139 | mutex.Lock() 140 | if err != nil { 141 | errs = append(errs, err) 142 | } else { 143 | success++ 144 | successDurations = append(successDurations, duration) 145 | } 146 | mutex.Unlock() 147 | }) 148 | multiTask.Add(task) 149 | } 150 | tasks = append(tasks, multiTask) 151 | } 152 | 153 | wg.Add(len(tasks)) 154 | 155 | numInvocations := len(tasks) * len(argsArray) 156 | 157 | done := make(chan bool) 158 | go func() { 159 | ticker := time.NewTicker(3 * time.Second) 160 | for { 161 | select { 162 | case <-ticker.C: 163 | mutex.RLock() 164 | if len(errs) > 0 { 165 | fmt.Printf("*** %d failed query(s) out of %d\n", len(errs), numInvocations) 166 | } 167 | fmt.Printf("*** %d successfull query(s) out of %d\n", success, numInvocations) 168 | mutex.RUnlock() 169 | case <-done: 170 | return 171 | } 172 | } 173 | }() 174 | 175 | startTime := time.Now() 176 | sleepTime := time.Duration(cliconfig.Config().SleepTime()) * time.Millisecond 177 | 178 | for _, task := range tasks { 179 | if err := executor.Submit(task); err != nil { 180 | return errors.Errorf("error submitting task: %s", err) 181 | } 182 | if sleepTime > 0 { 183 | time.Sleep(sleepTime) 184 | } 185 | } 186 | 187 | // Wait for all tasks to complete 188 | wg.Wait() 189 | done <- true 190 | 191 | duration := time.Now().Sub(startTime) 192 | 193 | var allErrs []error 194 | var attempts int 195 | for _, task := range tasks { 196 | attempts = attempts + task.Attempts() 197 | if task.LastError() != nil { 198 | allErrs = append(allErrs, task.LastError()) 199 | } 200 | } 201 | 202 | if len(errs) > 0 { 203 | fmt.Printf("\n*** %d errors querying chaincode:\n", len(errs)) 204 | for _, err := range errs { 205 | fmt.Printf("%s\n", err) 206 | } 207 | } else if len(allErrs) > 0 { 208 | fmt.Printf("\n*** %d transient errors querying chaincode:\n", len(allErrs)) 209 | for _, err := range allErrs { 210 | fmt.Printf("%s\n", err) 211 | } 212 | } 213 | 214 | if numInvocations/len(argsArray) > 1 { 215 | fmt.Printf("\n") 216 | fmt.Printf("*** ---------- Summary: ----------\n") 217 | fmt.Printf("*** - Queries: %d\n", numInvocations) 218 | fmt.Printf("*** - Concurrency: %d\n", cliconfig.Config().Concurrency()) 219 | fmt.Printf("*** - Successfull: %d\n", success) 220 | fmt.Printf("*** - Total attempts: %d\n", attempts) 221 | fmt.Printf("*** - Duration: %2.2fs\n", duration.Seconds()) 222 | fmt.Printf("*** - Rate: %2.2f/s\n", float64(numInvocations)/duration.Seconds()) 223 | fmt.Printf("*** - Average: %2.2fs\n", average(append(successDurations, failDurations...))) 224 | fmt.Printf("*** - Average Success: %2.2fs\n", average(successDurations)) 225 | fmt.Printf("*** - Average Fail: %2.2fs\n", average(failDurations)) 226 | fmt.Printf("*** - Min Success: %2.2fs\n", min(successDurations)) 227 | fmt.Printf("*** - Max Success: %2.2fs\n", max(successDurations)) 228 | fmt.Printf("*** ------------------------------\n") 229 | } 230 | 231 | return nil 232 | } 233 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/querytask/querytask.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package querytask 8 | 9 | import ( 10 | "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" 11 | "github.com/hyperledger/fabric-sdk-go/pkg/client/channel/invoke" 12 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 13 | "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" 14 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 15 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" 16 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 17 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/printer" 18 | ) 19 | 20 | // Task is the query task 21 | type Task struct { 22 | ctxt utils.Context 23 | channelClient *channel.Client 24 | targets []fab.Peer 25 | retryOpts retry.Opts 26 | id string 27 | args *action.ArgStruct 28 | startedCB func() 29 | completedCB func(err error) 30 | printer printer.Printer 31 | verbose bool 32 | payloadOnly bool 33 | validate bool 34 | attempt int 35 | lastErr error 36 | } 37 | 38 | // New creates a new query Task 39 | func New(ctxt utils.Context, id string, channelClient *channel.Client, targets []fab.Peer, args *action.ArgStruct, printer printer.Printer, 40 | retryOpts retry.Opts, verbose bool, payloadOnly bool, validate bool, startedCB func(), completedCB func(err error)) *Task { 41 | return &Task{ 42 | ctxt: ctxt, 43 | id: id, 44 | channelClient: channelClient, 45 | targets: targets, 46 | retryOpts: retryOpts, 47 | args: args, 48 | startedCB: startedCB, 49 | completedCB: completedCB, 50 | attempt: 1, 51 | printer: printer, 52 | verbose: verbose, 53 | payloadOnly: payloadOnly, 54 | validate: validate, 55 | } 56 | } 57 | 58 | // Invoke invokes the query task 59 | func (t *Task) Invoke() { 60 | t.startedCB() 61 | 62 | var opts []channel.RequestOption 63 | opts = append(opts, channel.WithRetry(t.retryOpts)) 64 | opts = append(opts, channel.WithBeforeRetry(func(err error) { 65 | t.attempt++ 66 | })) 67 | if len(t.targets) > 0 { 68 | opts = append(opts, channel.WithTargets(t.targets...)) 69 | } 70 | 71 | request := channel.Request{ 72 | ChaincodeID: cliconfig.Config().ChaincodeID(), 73 | Fcn: t.args.Func, 74 | Args: utils.AsBytes(t.ctxt, t.args.Args), 75 | } 76 | 77 | var additionalHandlers []invoke.Handler 78 | if t.validate { 79 | // Add the validation handlers 80 | additionalHandlers = append(additionalHandlers, 81 | invoke.NewEndorsementValidationHandler( 82 | invoke.NewSignatureValidationHandler(), 83 | ), 84 | ) 85 | } 86 | 87 | response, err := t.channelClient.InvokeHandler( 88 | invoke.NewProposalProcessorHandler( 89 | invoke.NewEndorsementHandler(additionalHandlers...), 90 | ), 91 | request, opts...) 92 | if err != nil { 93 | cliconfig.Config().Logger().Debugf("(%s) - Error querying chaincode: %s\n", t.id, err) 94 | t.lastErr = err 95 | t.completedCB(err) 96 | } else { 97 | cliconfig.Config().Logger().Debugf("(%s) - Chaincode query was successful\n", t.id) 98 | 99 | if t.verbose { 100 | t.printer.PrintTxProposalResponses(response.Responses, t.payloadOnly) 101 | } 102 | 103 | t.completedCB(nil) 104 | } 105 | } 106 | 107 | // Attempts returns the number of invocation attempts that were made 108 | // in order to achieve a successful response 109 | func (t *Task) Attempts() int { 110 | return t.attempt 111 | } 112 | 113 | // LastError returns the last error that was recorder 114 | func (t *Task) LastError() error { 115 | return t.lastErr 116 | } 117 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/task/task.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package task 8 | 9 | // Task is an invocable unit of work 10 | type Task interface { 11 | // Invoke invokes the task 12 | Invoke() 13 | 14 | // Attempts returns the number of invocation attempts that were made 15 | // in order to achieve a successful response 16 | Attempts() int 17 | 18 | // LastError returns the last error that occurred 19 | LastError() error 20 | } 21 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/upgradecmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "encoding/json" 11 | "fmt" 12 | "strings" 13 | 14 | fabricCommon "github.com/hyperledger/fabric-protos-go/common" 15 | pb "github.com/hyperledger/fabric-protos-go/peer" 16 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 17 | "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/cauthdsl" 18 | "github.com/pkg/errors" 19 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 20 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode/utils" 21 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 22 | "github.com/spf13/cobra" 23 | "github.com/spf13/pflag" 24 | ) 25 | 26 | var upgradeCmd = &cobra.Command{ 27 | Use: "upgrade", 28 | Short: "Upgrade chaincode.", 29 | Long: "Upgrades the chaincode", 30 | Run: func(cmd *cobra.Command, args []string) { 31 | if cliconfig.Config().ChaincodeID() == "" { 32 | fmt.Printf("\nMust specify the chaincode ID\n\n") 33 | cmd.HelpFunc()(cmd, args) 34 | return 35 | } 36 | if cliconfig.Config().ChaincodePath() == "" { 37 | fmt.Printf("\nMust specify the path of the chaincode\n\n") 38 | cmd.HelpFunc()(cmd, args) 39 | return 40 | } 41 | action, err := newUpgradeAction(cmd.Flags()) 42 | if err != nil { 43 | cliconfig.Config().Logger().Errorf("Error while initializing upgradeAction: %v", err) 44 | return 45 | } 46 | 47 | defer action.Terminate() 48 | 49 | err = action.invoke() 50 | if err != nil { 51 | cliconfig.Config().Logger().Errorf("Error while running upgradeAction: %v", err) 52 | } 53 | }, 54 | } 55 | 56 | func getUpgradeCmd() *cobra.Command { 57 | flags := upgradeCmd.Flags() 58 | cliconfig.InitPeerURL(flags) 59 | cliconfig.InitChannelID(flags) 60 | cliconfig.InitChaincodeID(flags) 61 | cliconfig.InitChaincodePath(flags) 62 | cliconfig.InitChaincodeVersion(flags) 63 | cliconfig.InitArgs(flags) 64 | cliconfig.InitChaincodePolicy(flags) 65 | cliconfig.InitCollectionConfigFile(flags) 66 | cliconfig.InitTimeout(flags) 67 | return upgradeCmd 68 | } 69 | 70 | type upgradeAction struct { 71 | action.Action 72 | } 73 | 74 | func newUpgradeAction(flags *pflag.FlagSet) (*upgradeAction, error) { 75 | action := &upgradeAction{} 76 | err := action.Initialize(flags) 77 | if len(action.Peers()) == 0 { 78 | return nil, errors.Errorf("a peer must be specified") 79 | } 80 | return action, err 81 | } 82 | 83 | func (a *upgradeAction) invoke() error { 84 | argBytes := []byte(cliconfig.Config().Args()) 85 | args := &action.ArgStruct{} 86 | 87 | if err := json.Unmarshal(argBytes, args); err != nil { 88 | return errors.Errorf("Error unmarshalling JSON arg string: %v", err) 89 | } 90 | 91 | resMgmtClient, err := a.ResourceMgmtClient() 92 | if err != nil { 93 | return err 94 | } 95 | 96 | cliconfig.Config().Logger().Infof("Sending upgrade %s ...\n", cliconfig.Config().ChaincodeID()) 97 | 98 | chaincodePolicy, err := a.newChaincodePolicy() 99 | if err != nil { 100 | return err 101 | } 102 | 103 | // Private Data Collection Configuration 104 | // - see fixtures/config/pvtdatacollection.json for sample config file 105 | var collConfig []*pb.CollectionConfig 106 | collConfigFile := cliconfig.Config().CollectionConfigFile() 107 | if collConfigFile != "" { 108 | collConfig, err = getCollectionConfigFromFile(cliconfig.Config().CollectionConfigFile()) 109 | if err != nil { 110 | return errors.Wrapf(err, "error getting private data collection configuration from file [%s]", cliconfig.Config().CollectionConfigFile()) 111 | } 112 | } 113 | 114 | req := resmgmt.UpgradeCCRequest{ 115 | Name: cliconfig.Config().ChaincodeID(), 116 | Path: cliconfig.Config().ChaincodePath(), 117 | Version: cliconfig.Config().ChaincodeVersion(), 118 | Args: utils.AsBytes(utils.NewContext(), args.Args), 119 | Policy: chaincodePolicy, 120 | CollConfig: collConfig, 121 | } 122 | 123 | _, err = resMgmtClient.UpgradeCC(cliconfig.Config().ChannelID(), req, resmgmt.WithTargets(a.Peers()...)) 124 | if err != nil { 125 | if strings.Contains(err.Error(), "chaincode exists "+cliconfig.Config().ChaincodeID()) { 126 | // Ignore 127 | cliconfig.Config().Logger().Infof("Chaincode %s already instantiated.", cliconfig.Config().ChaincodeID()) 128 | fmt.Printf("...chaincode %s already instantiated.\n", cliconfig.Config().ChaincodeID()) 129 | return nil 130 | } 131 | return errors.Errorf("error instantiating chaincode: %v", err) 132 | } 133 | 134 | fmt.Printf("...successfuly upgraded chaincode %s on channel %s.\n", cliconfig.Config().ChaincodeID(), cliconfig.Config().ChannelID()) 135 | 136 | return nil 137 | } 138 | 139 | func (a *upgradeAction) newChaincodePolicy() (*fabricCommon.SignaturePolicyEnvelope, error) { 140 | if cliconfig.Config().ChaincodePolicy() != "" { 141 | // Create a signature policy from the policy expression passed in 142 | return newChaincodePolicy(cliconfig.Config().ChaincodePolicy()) 143 | } 144 | 145 | // Default policy is 'signed my any member' for all known orgs 146 | var mspIDs []string 147 | for _, orgID := range cliconfig.Config().OrgIDs() { 148 | orgConfig, ok := a.EndpointConfig().NetworkConfig().Organizations[orgID] 149 | if !ok { 150 | return nil, errors.Errorf("Unable to get the MSP ID from org ID %s", orgID) 151 | } 152 | mspIDs = append(mspIDs, orgConfig.MSPID) 153 | } 154 | return cauthdsl.SignedByAnyMember(mspIDs), nil 155 | } 156 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/utils/test.json: -------------------------------------------------------------------------------- 1 | {"Field1": "Value1"} -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/utils/util.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package utils 8 | 9 | import ( 10 | "fmt" 11 | "github.com/pkg/errors" 12 | "io/ioutil" 13 | "math/rand" 14 | "os" 15 | "path/filepath" 16 | "strconv" 17 | "strings" 18 | "sync/atomic" 19 | "time" 20 | 21 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 22 | ) 23 | 24 | const ( 25 | randFunc = "$rand(" 26 | padFunc = "$pad(" 27 | seqFunc = "$seq(" 28 | setFunc = "$set(" 29 | fileFunc = "$file(" 30 | varExp = "${" 31 | ) 32 | 33 | var ( 34 | sequence uint64 35 | ) 36 | 37 | type Context interface { 38 | SetVar(name, value string) 39 | GetVar(name string) (string, bool) 40 | } 41 | 42 | // AsBytes converts the string array to an array of byte arrays. 43 | // The args may contain functions $rand(n) or $pad(n,chars). 44 | // The functions are evaluated before returning. 45 | // 46 | // Examples: 47 | // - "key$rand(3)" -> "key0" or "key1" or "key2" 48 | // - "val$pad(3,XYZ) -> "valXYZXYZXYZ" 49 | // - "val$pad($rand(3),XYZ) -> "val" or "valXYZ" or "valXYZXYZ" 50 | // - "key$seq()" -> "key1", "key2", "key2", ... 51 | // - "val$pad($seq(),X)" -> "valX", "valXX", "valXX", "valXXX", ... 52 | // - "Key_$set(x,$seq())=Val_${x}" -> Key_1=Val_1, Key_2=Val_2, ... 53 | func AsBytes(ctxt Context, args []string) [][]byte { 54 | rand := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) 55 | bytes := make([][]byte, len(args)) 56 | 57 | if cliconfig.Config().Verbose() { 58 | fmt.Printf("Args:\n") 59 | } 60 | for i, a := range args { 61 | arg := getArg(ctxt, rand, a) 62 | if cliconfig.Config().Verbose() { 63 | fmt.Printf("- [%d]=%s\n", i, arg) 64 | } 65 | bytes[i] = []byte(arg) 66 | } 67 | return bytes 68 | } 69 | 70 | func getArg(ctxt Context, r *rand.Rand, arg string) string { 71 | arg = evaluateSeqExpression(arg) 72 | arg = evaluateRandExpression(r, arg) 73 | arg = evaluatePadExpression(arg) 74 | arg = evaluateFileExpression(arg) 75 | arg = evaluateSetExpression(ctxt, arg) 76 | arg = evaluateVarExpression(ctxt, arg) 77 | return arg 78 | } 79 | 80 | // evaluateSeqExpression replaces occurrences of $seq() with a sequential 81 | // number starting at 1 and incrementing for each task 82 | func evaluateSeqExpression(arg string) string { 83 | return evaluateExpression(arg, seqFunc, ")", 84 | func(expression string) (string, error) { 85 | return strconv.FormatUint(atomic.AddUint64(&sequence, 1), 10), nil 86 | }) 87 | } 88 | 89 | // evaluateRandExpression replaces occurrences of $rand(n) with a random 90 | // number between 0 and n (exclusive) 91 | func evaluateRandExpression(r *rand.Rand, arg string) string { 92 | return evaluateExpression(arg, randFunc, ")", 93 | func(expression string) (string, error) { 94 | n, err := strconv.ParseInt(expression, 10, 64) 95 | if err != nil { 96 | return "", errors.Errorf("invalid number %s in $rand expression\n", expression) 97 | } 98 | return strconv.FormatInt(r.Int63n(n), 10), nil 99 | }) 100 | } 101 | 102 | // evaluatePadExpression replaces occurrences of $pad(n,chars) with n of the given pad characters 103 | func evaluatePadExpression(arg string) string { 104 | return evaluateExpression(arg, padFunc, ")", 105 | func(expression string) (string, error) { 106 | s := strings.Split(expression, ",") 107 | if len(s) != 2 { 108 | return "", errors.Errorf("invalid $pad expression: '%s'. Expecting $pad(n,chars)", expression) 109 | } 110 | 111 | n, err := strconv.Atoi(s[0]) 112 | if err != nil { 113 | return "", errors.Errorf("invalid number %s in $pad expression\n", s[0]) 114 | } 115 | 116 | result := "" 117 | for i := 0; i < n; i++ { 118 | result += s[1] 119 | } 120 | 121 | return result, nil 122 | }) 123 | } 124 | 125 | // evaluateFileExpression replaces occurrences of $file(path) with the contents of the file 126 | func evaluateFileExpression(arg string) string { 127 | return evaluateExpression(arg, fileFunc, ")", 128 | func(expression string) (string, error) { 129 | return readFile(expression) 130 | }) 131 | } 132 | 133 | // evaluateSetExpression sets a variable to the given value using the syntax $set(var,expression). 134 | // The variable may be used in a subsequent expression, ${var}. 135 | // Example: $set(v,$rand(10)) sets variable "v" to a random value that may be accessed as ${v} 136 | func evaluateSetExpression(ctxt Context, arg string) string { 137 | return evaluateExpression(arg, setFunc, ")", 138 | func(expression string) (string, error) { 139 | s := strings.Split(expression, ",") 140 | if len(s) != 2 { 141 | return "", errors.Errorf("invalid $set expression: '%s'. Expecting $set(var,value)", expression) 142 | } 143 | 144 | variable := s[0] 145 | value := s[1] 146 | 147 | ctxt.SetVar(variable, value) 148 | return value, nil 149 | }) 150 | } 151 | 152 | // evaluateVarExpression references a variable previously set with the $set(var,expression) expression. 153 | // Example: ${someVar} 154 | func evaluateVarExpression(ctxt Context, arg string) string { 155 | return evaluateExpression(arg, varExp, "}", 156 | func(varName string) (string, error) { 157 | value, ok := ctxt.GetVar(varName) 158 | if !ok { 159 | return "", errors.Errorf("variable [%s] not set", varName) 160 | } 161 | return value, nil 162 | }) 163 | } 164 | 165 | func evaluateExpression(expression, funcType, endDelim string, evaluate func(string) (string, error)) string { 166 | result := "" 167 | for { 168 | i := strings.Index(expression, funcType) 169 | if i == -1 { 170 | result += expression 171 | break 172 | } 173 | 174 | j := strings.Index(expression[i:], endDelim) 175 | if j == -1 { 176 | fmt.Printf("expecting '%s' in expression '%s'", endDelim, expression) 177 | result = expression 178 | break 179 | } 180 | 181 | j = i + j 182 | 183 | replacement, err := evaluate(expression[i+len(funcType) : j]) 184 | if err != nil { 185 | fmt.Printf("%s\n", err) 186 | result += expression[0 : j+1] 187 | } else { 188 | result += expression[0:i] + replacement 189 | } 190 | 191 | expression = expression[j+1:] 192 | } 193 | 194 | return result 195 | } 196 | 197 | func NewContext() Context { 198 | return &defaultContext{ 199 | vars: make(map[string]string), 200 | } 201 | } 202 | 203 | type defaultContext struct { 204 | vars map[string]string 205 | } 206 | 207 | func (c *defaultContext) SetVar(k, v string) { 208 | c.vars[k] = v 209 | } 210 | 211 | func (c *defaultContext) GetVar(k string) (string, bool) { 212 | value, ok := c.vars[k] 213 | return value, ok 214 | } 215 | 216 | func readFile(filePath string) (string, error) { 217 | fmt.Printf("Reading file: [%s]", filePath) 218 | file, err := os.Open(filepath.Clean(filePath)) 219 | if err != nil { 220 | return "", errors.Wrapf(err, "error opening file [%s]", filePath) 221 | } 222 | defer func() { 223 | fileErr := file.Close() 224 | if fileErr != nil { 225 | cliconfig.Config().Logger().Errorf("Failed to close file : %s", fileErr) 226 | } 227 | }() 228 | 229 | configBytes, err := ioutil.ReadAll(file) 230 | if err != nil { 231 | return "", errors.Wrapf(err, "error reading config file [%s]", filePath) 232 | } 233 | return string(configBytes), nil 234 | } 235 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/chaincode/utils/util_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package utils 8 | 9 | import ( 10 | "fmt" 11 | "github.com/stretchr/testify/assert" 12 | "math/rand" 13 | "testing" 14 | "time" 15 | ) 16 | 17 | func TestEvaluatePadExpression(t *testing.T) { 18 | result := evaluatePadExpression("Value_$pad(3,XYZ)!") 19 | assert.Equal(t, "Value_XYZXYZXYZ!", result) 20 | 21 | result = evaluatePadExpression("Value_$pad(3,XYZ)_$pad(2,123)!") 22 | assert.Equal(t, "Value_XYZXYZXYZ_123123!", result) 23 | } 24 | 25 | func TestFailEvaluatePadExpression(t *testing.T) { 26 | result := evaluatePadExpression("Value_$pad(3,XYZ!") 27 | assert.Equal(t, "Value_$pad(3,XYZ!", result) 28 | 29 | result = evaluatePadExpression("Value_$pad3,XYZ)!") 30 | assert.Equal(t, "Value_$pad3,XYZ)!", result) 31 | 32 | result = evaluatePadExpression("Value_$pad(3)!") 33 | assert.Equal(t, "Value_$pad(3)!", result) 34 | 35 | result = evaluatePadExpression("Value_$pad(3)_$pad(3,X)!") 36 | assert.Equal(t, "Value_$pad(3)_XXX!", result) 37 | } 38 | 39 | func TestEvaluateRandExpression(t *testing.T) { 40 | rand := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) 41 | for i := 0; i < 5; i++ { 42 | result := evaluateRandExpression(rand, "Value_$rand(2)!") 43 | assert.True(t, result == "Value_0!" || result == "Value_1!") 44 | 45 | result = evaluateRandExpression(rand, "Value_$rand(2)_$rand(1)!") 46 | assert.True(t, result == "Value_0_0!" || result == "Value_1_0!") 47 | } 48 | } 49 | 50 | func TestFailEvaluateRandExpression(t *testing.T) { 51 | rand := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) 52 | result := evaluateRandExpression(rand, "Value_$rand(3,!") 53 | assert.Equal(t, "Value_$rand(3,!", result) 54 | 55 | result = evaluateRandExpression(rand, "Value_$rand3)!") 56 | assert.Equal(t, "Value_$rand3)!", result) 57 | 58 | result = evaluateRandExpression(rand, "Value_$rand(X)!") 59 | assert.Equal(t, "Value_$rand(X)!", result) 60 | 61 | result = evaluateRandExpression(rand, "Value_$rand(X)_$rand(1)!") 62 | assert.Equal(t, "Value_$rand(X)_0!", result) 63 | } 64 | 65 | func TestEvaluateSeqExpression(t *testing.T) { 66 | assert.Equal(t, "Value_1!", evaluateSeqExpression("Value_$seq()!")) 67 | assert.Equal(t, "Value_2!", evaluateSeqExpression("Value_$seq()!")) 68 | assert.Equal(t, "Value_3!", evaluateSeqExpression("Value_$seq()!")) 69 | } 70 | 71 | func TestFailEvaluateSeqExpression(t *testing.T) { 72 | assert.Equal(t, "Value_$seq(!", evaluateSeqExpression("Value_$seq(!")) 73 | } 74 | 75 | func TestEvaluateFileExpression(t *testing.T) { 76 | assert.Equal(t, `{"Field1": "Value1"}`, evaluateFileExpression("$file(./test.json)")) 77 | } 78 | 79 | func TestFailEvaluateFileExpression(t *testing.T) { 80 | assert.Equal(t, "$file(./invalid.json)", evaluateSeqExpression("$file(./invalid.json)")) 81 | } 82 | 83 | func TestEvaluateSetExpression(t *testing.T) { 84 | ctxt := NewContext() 85 | assert.Equal(t, "Value_1000!", evaluateSetExpression(ctxt, "Value_$set(x,1000)!")) 86 | assert.Equal(t, "Value_1000!", evaluateVarExpression(ctxt, "Value_${x}!")) 87 | } 88 | 89 | func TestFailEvaluateSetExpression(t *testing.T) { 90 | ctxt := NewContext() 91 | assert.Equal(t, "Value_$set(x,1000", evaluateSetExpression(ctxt, "Value_$set(x,1000")) 92 | assert.Equal(t, "Value_${x", evaluateVarExpression(ctxt, "Value_${x")) 93 | 94 | // Var not set 95 | assert.Equal(t, "Value_${x}", evaluateVarExpression(NewContext(), "Value_${x}")) 96 | } 97 | 98 | func TestGetArg(t *testing.T) { 99 | rand := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) 100 | result := getArg(NewContext(), rand, "Value_$pad(3,X)!") 101 | assert.Equal(t, "Value_XXX!", result) 102 | 103 | for i := 0; i < 5; i++ { 104 | result := getArg(NewContext(), rand, "Value_$rand(2)!") 105 | assert.True(t, result == "Value_0!" || result == "Value_1!") 106 | } 107 | 108 | for i := 0; i < 5; i++ { 109 | result := getArg(NewContext(), rand, "Value_$pad(3,X)_$rand(2)!") 110 | assert.True(t, result == "Value_XXX_0!" || result == "Value_XXX_1!") 111 | } 112 | 113 | for i := 0; i < 5; i++ { 114 | result := getArg(NewContext(), rand, "Value_$pad($rand(3),X)!") 115 | assert.True(t, result == "Value_!" || result == "Value_X!" || result == "Value_XX!") 116 | } 117 | 118 | n := sequence + 1 119 | for i := n; i <= n+5; i++ { 120 | result := getArg(NewContext(), rand, "Value_$seq()!") 121 | assert.True(t, result == fmt.Sprintf("Value_%d!", i)) 122 | } 123 | 124 | n = sequence + 1 125 | for i := n; i <= n+5; i++ { 126 | ctxt := NewContext() 127 | assert.Equal(t, fmt.Sprintf("Key_%d=Val_%d", i, i), getArg(ctxt, rand, "Key_$set(x,$seq())=Val_${x}")) 128 | assert.Equal(t, fmt.Sprintf("Value_%d!", i), getArg(ctxt, rand, "Value_${x}!")) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/channel/channelcmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package channel 8 | 9 | import ( 10 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var channelCmd = &cobra.Command{ 15 | Use: "channel", 16 | Short: "Channel commands", 17 | Long: "Channel commands", 18 | Run: func(cmd *cobra.Command, args []string) { 19 | cmd.HelpFunc()(cmd, args) 20 | }, 21 | } 22 | 23 | // Cmd returns the channel command 24 | func Cmd() *cobra.Command { 25 | cliconfig.InitChannelID(channelCmd.Flags()) 26 | 27 | channelCmd.AddCommand(getChannelCreateCmd()) 28 | channelCmd.AddCommand(getChannelJoinCmd()) 29 | 30 | return channelCmd 31 | } 32 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/channel/channelcreatecmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package channel 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 13 | "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/msp" 14 | "github.com/pkg/errors" 15 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 16 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 17 | "github.com/spf13/cobra" 18 | "github.com/spf13/pflag" 19 | ) 20 | 21 | var channelCreateCmd = &cobra.Command{ 22 | Use: "create", 23 | Short: "Create Channel", 24 | Long: "Create a new channel", 25 | Run: func(cmd *cobra.Command, args []string) { 26 | action, err := newChannelCreateAction(cmd.Flags()) 27 | if err != nil { 28 | cliconfig.Config().Logger().Errorf("Error while initializing channelCreateAction: %v", err) 29 | return 30 | } 31 | 32 | defer action.Terminate() 33 | 34 | err = action.invoke() 35 | if err != nil { 36 | cliconfig.Config().Logger().Errorf("Error while running channelCreateAction: %v", err) 37 | } 38 | }, 39 | } 40 | 41 | func getChannelCreateCmd() *cobra.Command { 42 | flags := channelCreateCmd.Flags() 43 | cliconfig.InitChannelID(flags) 44 | cliconfig.InitOrdererURL(flags) 45 | cliconfig.InitTxFile(flags) 46 | return channelCreateCmd 47 | } 48 | 49 | type channelCreateAction struct { 50 | action.Action 51 | } 52 | 53 | func newChannelCreateAction(flags *pflag.FlagSet) (*channelCreateAction, error) { 54 | a := &channelCreateAction{} 55 | err := a.Initialize(flags) 56 | return a, err 57 | } 58 | 59 | func (a *channelCreateAction) invoke() error { 60 | user, err := a.OrgAdminUser(a.OrgID()) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | chMgmtClient, err := a.ResourceMgmtClient() 66 | if err != nil { 67 | return err 68 | } 69 | 70 | fmt.Printf("Attempting to create/update channel: %s\n", cliconfig.Config().ChannelID()) 71 | 72 | req := resmgmt.SaveChannelRequest{ 73 | ChannelID: cliconfig.Config().ChannelID(), 74 | ChannelConfigPath: cliconfig.Config().TxFile(), 75 | SigningIdentities: []msp.SigningIdentity{user}, 76 | } 77 | 78 | orderer, err := a.RandomOrderer() 79 | if err != nil { 80 | return err 81 | } 82 | 83 | _, err = chMgmtClient.SaveChannel(req, resmgmt.WithOrderer(orderer)) 84 | if err != nil { 85 | return errors.Errorf("Error from save channel: %s", err.Error()) 86 | } 87 | 88 | fmt.Printf("Channel created/updated: %s\n", cliconfig.Config().ChannelID()) 89 | 90 | return nil 91 | } 92 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/channel/channeljoincmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package channel 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 13 | "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" 14 | "github.com/pkg/errors" 15 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 16 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 17 | "github.com/spf13/cobra" 18 | "github.com/spf13/pflag" 19 | ) 20 | 21 | var chainJoinCmd = &cobra.Command{ 22 | Use: "join", 23 | Short: "Join Channel", 24 | Long: "Join a channel", 25 | Run: func(cmd *cobra.Command, args []string) { 26 | action, err := newChannelJoinAction(cmd.Flags()) 27 | if err != nil { 28 | cliconfig.Config().Logger().Errorf("Error while initializing channelJoinAction: %v", err) 29 | return 30 | } 31 | 32 | defer action.Terminate() 33 | 34 | err = action.invoke() 35 | if err != nil { 36 | cliconfig.Config().Logger().Errorf("Error while running channelJoinAction: %v", err) 37 | } 38 | }, 39 | } 40 | 41 | func getChannelJoinCmd() *cobra.Command { 42 | flags := chainJoinCmd.Flags() 43 | cliconfig.InitChannelID(flags) 44 | cliconfig.InitOrdererURL(flags) 45 | cliconfig.InitPeerURL(flags) 46 | return chainJoinCmd 47 | } 48 | 49 | type channelJoinAction struct { 50 | action.Action 51 | } 52 | 53 | func newChannelJoinAction(flags *pflag.FlagSet) (*channelJoinAction, error) { 54 | action := &channelJoinAction{} 55 | err := action.Initialize(flags) 56 | if err != nil { 57 | return nil, err 58 | } 59 | if len(action.Peers()) == 0 { 60 | return nil, errors.Errorf("at least one peer is required for join") 61 | } 62 | return action, nil 63 | } 64 | 65 | func (a *channelJoinAction) invoke() error { 66 | fmt.Printf("Attempting to join channel: %s\n", cliconfig.Config().ChannelID()) 67 | 68 | var lastErr error 69 | for orgID, peers := range a.PeersByOrg() { 70 | fmt.Printf("Joining channel %s on org[%s] peers:\n", cliconfig.Config().ChannelID(), orgID) 71 | for _, peer := range peers { 72 | fmt.Printf("-- %s\n", peer.URL()) 73 | } 74 | err := a.joinChannel(orgID, peers) 75 | if err != nil { 76 | lastErr = err 77 | } 78 | } 79 | return lastErr 80 | } 81 | 82 | func (a *channelJoinAction) joinChannel(orgID string, peers []fab.Peer) error { 83 | cliconfig.Config().Logger().Debugf("Joining channel [%s]...\n", cliconfig.Config().ChannelID()) 84 | 85 | fmt.Printf("==========> JOIN ORG: %s\n", orgID) 86 | 87 | resMgmtClient, err := a.ResourceMgmtClientForOrg(orgID) 88 | if err != nil { 89 | return err 90 | } 91 | 92 | orderer, err := a.RandomOrderer() 93 | if err != nil { 94 | return err 95 | } 96 | 97 | err = resMgmtClient.JoinChannel(cliconfig.Config().ChannelID(), resmgmt.WithTargets(peers...), resmgmt.WithOrderer(orderer)) 98 | if err != nil { 99 | return errors.WithMessage(err, "Could not join channel: %v") 100 | } 101 | 102 | fmt.Printf("Channel %s joined!\n", cliconfig.Config().ChannelID()) 103 | 104 | return nil 105 | } 106 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/cmd/fabric-cli.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package cmd 8 | 9 | import ( 10 | "os" 11 | 12 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/chaincode" 13 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/channel" 14 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 15 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/event" 16 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/query" 17 | "github.com/spf13/cobra" 18 | ) 19 | 20 | func newFabricCLICmd() *cobra.Command { 21 | 22 | mainCmd := &cobra.Command{ 23 | Use: "fabric-cli", 24 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 25 | return nil 26 | }, 27 | Run: func(cmd *cobra.Command, args []string) { 28 | cmd.HelpFunc()(cmd, args) 29 | }, 30 | } 31 | 32 | flags := mainCmd.PersistentFlags() 33 | cliconfig.InitConfigFile(flags) 34 | cliconfig.InitLoggingLevel(flags) 35 | cliconfig.InitUserName(flags) 36 | cliconfig.InitUserPassword(flags) 37 | cliconfig.InitOrdererTLSCertificate(flags) 38 | cliconfig.InitPrintFormat(flags) 39 | cliconfig.InitWriter(flags) 40 | cliconfig.InitBase64(flags) 41 | cliconfig.InitOrgIDs(flags) 42 | 43 | mainCmd.AddCommand(chaincode.Cmd()) 44 | mainCmd.AddCommand(query.Cmd()) 45 | mainCmd.AddCommand(channel.Cmd()) 46 | mainCmd.AddCommand(event.Cmd()) 47 | 48 | return mainCmd 49 | } 50 | 51 | func Execute() { 52 | if newFabricCLICmd().Execute() != nil { 53 | os.Exit(1) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/event/eventcmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package event 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | ) 12 | 13 | var eventCmd = &cobra.Command{ 14 | Use: "event", 15 | Short: "Event commands", 16 | Long: "Event commands", 17 | Run: func(cmd *cobra.Command, args []string) { 18 | cmd.HelpFunc()(cmd, args) 19 | }, 20 | } 21 | 22 | // Cmd returns the events command 23 | func Cmd() *cobra.Command { 24 | eventCmd.AddCommand(getListenCCCmd()) 25 | eventCmd.AddCommand(getListenTXCmd()) 26 | eventCmd.AddCommand(getListenBlockCmd()) 27 | eventCmd.AddCommand(getListenFilteredBlockCmd()) 28 | 29 | return eventCmd 30 | } 31 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/event/inputevent.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package event 8 | 9 | import ( 10 | "bufio" 11 | "os" 12 | ) 13 | 14 | type inputEvent struct { 15 | done chan bool 16 | } 17 | 18 | // WaitForEnter waits until the user presses Enter 19 | func (c *inputEvent) WaitForEnter() chan bool { 20 | go c.readFromCLI() 21 | return c.done 22 | } 23 | 24 | func (c *inputEvent) readFromCLI() { 25 | reader := bufio.NewReader(os.Stdin) 26 | reader.ReadString('\n') 27 | c.done <- true 28 | } 29 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/event/listenblockcmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package event 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-sdk-go/pkg/client/event" 13 | "github.com/pkg/errors" 14 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 15 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 16 | "github.com/spf13/cobra" 17 | "github.com/spf13/pflag" 18 | ) 19 | 20 | var listenBlockCmd = &cobra.Command{ 21 | Use: "listenblock", 22 | Short: "Listen to block events.", 23 | Long: "Listen to block events", 24 | Run: func(cmd *cobra.Command, args []string) { 25 | action, err := newlistenBlockAction(cmd.Flags()) 26 | if err != nil { 27 | cliconfig.Config().Logger().Errorf("Error while initializing listenBlockAction: %v", err) 28 | return 29 | } 30 | 31 | defer action.Terminate() 32 | 33 | err = action.invoke() 34 | if err != nil { 35 | cliconfig.Config().Logger().Errorf("Error while running listenBlockAction: %v", err) 36 | } 37 | }, 38 | } 39 | 40 | func getListenBlockCmd() *cobra.Command { 41 | flags := listenBlockCmd.Flags() 42 | cliconfig.InitChannelID(flags) 43 | cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to listen for events, e.g. localhost:7051") 44 | cliconfig.InitSeekType(flags) 45 | cliconfig.InitBlockNum(flags) 46 | return listenBlockCmd 47 | } 48 | 49 | type listenBlockAction struct { 50 | action.Action 51 | inputEvent 52 | } 53 | 54 | func newlistenBlockAction(flags *pflag.FlagSet) (*listenBlockAction, error) { 55 | action := &listenBlockAction{inputEvent: inputEvent{done: make(chan bool)}} 56 | err := action.Initialize(flags) 57 | return action, err 58 | } 59 | 60 | func (a *listenBlockAction) invoke() error { 61 | eventClient, err := a.EventClient(event.WithBlockEvents(), event.WithSeekType(cliconfig.Config().SeekType()), event.WithBlockNum(cliconfig.Config().BlockNum())) 62 | if err != nil { 63 | return err 64 | } 65 | 66 | fmt.Printf("Registering block event\n") 67 | 68 | breg, beventch, err := eventClient.RegisterBlockEvent() 69 | if err != nil { 70 | return errors.WithMessage(err, "Error registering for block events") 71 | } 72 | defer eventClient.Unregister(breg) 73 | 74 | enterch := a.WaitForEnter() 75 | for { 76 | select { 77 | case _, _ = <-enterch: 78 | return nil 79 | case event, ok := <-beventch: 80 | if !ok { 81 | return errors.WithMessage(err, "unexpected closed channel while waiting for block event") 82 | } 83 | a.Printer().PrintBlock(event.Block) 84 | fmt.Println("Press to terminate") 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/event/listencccmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package event 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/pkg/errors" 13 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 14 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 15 | "github.com/spf13/cobra" 16 | "github.com/spf13/pflag" 17 | ) 18 | 19 | var listenccCmd = &cobra.Command{ 20 | Use: "listencc", 21 | Short: "Listen to chaincode events.", 22 | Long: "Listen to chaincode events", 23 | Run: func(cmd *cobra.Command, args []string) { 24 | if cliconfig.Config().ChaincodeID() == "" { 25 | fmt.Printf("\nMust specify the chaincode ID\n\n") 26 | cmd.HelpFunc()(cmd, args) 27 | return 28 | } 29 | if cliconfig.Config().ChaincodeEvent() == "" { 30 | fmt.Printf("\nMust specify the event name\n\n") 31 | cmd.HelpFunc()(cmd, args) 32 | return 33 | } 34 | 35 | action, err := newListenCCAction(cmd.Flags()) 36 | if err != nil { 37 | fmt.Printf("\nError while initializing listenCCAction: %v\n", err) 38 | return 39 | } 40 | 41 | defer action.Terminate() 42 | 43 | err = action.invoke() 44 | if err != nil { 45 | fmt.Printf("\nError while running listenCCAction: %v\n", err) 46 | } 47 | }, 48 | } 49 | 50 | func getListenCCCmd() *cobra.Command { 51 | flags := listenccCmd.Flags() 52 | cliconfig.InitChannelID(flags) 53 | cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to listen for events, e.g. grpcs://localhost:7051") 54 | cliconfig.InitChaincodeID(flags) 55 | cliconfig.InitChaincodeEvent(flags) 56 | return listenccCmd 57 | } 58 | 59 | type listenccAction struct { 60 | action.Action 61 | inputEvent 62 | } 63 | 64 | func newListenCCAction(flags *pflag.FlagSet) (*listenccAction, error) { 65 | action := &listenccAction{inputEvent: inputEvent{done: make(chan bool)}} 66 | err := action.Initialize(flags) 67 | return action, err 68 | } 69 | 70 | func (a *listenccAction) invoke() error { 71 | 72 | fmt.Printf("Registering CC event on chaincode [%s] and event [%s]\n", cliconfig.Config().ChaincodeID(), cliconfig.Config().ChaincodeEvent()) 73 | 74 | eventHub, err := a.EventClient() 75 | if err != nil { 76 | return err 77 | } 78 | 79 | breg, beventch, err := eventHub.RegisterChaincodeEvent(cliconfig.Config().ChaincodeID(), cliconfig.Config().ChaincodeEvent()) 80 | if err != nil { 81 | return errors.WithMessage(err, "Error registering for block events") 82 | } 83 | defer eventHub.Unregister(breg) 84 | 85 | enterch := a.WaitForEnter() 86 | for { 87 | select { 88 | case _, _ = <-enterch: 89 | return nil 90 | case event, ok := <-beventch: 91 | if !ok { 92 | return errors.WithMessage(err, "unexpected closed channel while waiting for block event") 93 | } 94 | a.Printer().PrintChaincodeEvent(event) 95 | fmt.Println("Press to terminate") 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/event/listenfilteredblockcmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package event 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-sdk-go/pkg/client/event" 13 | "github.com/pkg/errors" 14 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 15 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 16 | "github.com/spf13/cobra" 17 | "github.com/spf13/pflag" 18 | ) 19 | 20 | var listenFilteredBlockCmd = &cobra.Command{ 21 | Use: "listenfilteredblock", 22 | Short: "Listen to filtered block events.", 23 | Long: "Listen to filtered block events", 24 | Run: func(cmd *cobra.Command, args []string) { 25 | action, err := newlistenFilteredBlockAction(cmd.Flags()) 26 | if err != nil { 27 | cliconfig.Config().Logger().Errorf("Error while initializing listenFilteredBlockAction: %v", err) 28 | return 29 | } 30 | 31 | defer action.Terminate() 32 | 33 | err = action.invoke() 34 | if err != nil { 35 | cliconfig.Config().Logger().Errorf("Error while running listenFilteredBlockAction: %v", err) 36 | } 37 | }, 38 | } 39 | 40 | func getListenFilteredBlockCmd() *cobra.Command { 41 | flags := listenFilteredBlockCmd.Flags() 42 | cliconfig.InitChannelID(flags) 43 | cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to listen for events, e.g. localhost:7051") 44 | cliconfig.InitSeekType(flags) 45 | cliconfig.InitBlockNum(flags) 46 | return listenFilteredBlockCmd 47 | } 48 | 49 | type listenFilteredBlockAction struct { 50 | action.Action 51 | inputEvent 52 | } 53 | 54 | func newlistenFilteredBlockAction(flags *pflag.FlagSet) (*listenFilteredBlockAction, error) { 55 | action := &listenFilteredBlockAction{inputEvent: inputEvent{done: make(chan bool)}} 56 | err := action.Initialize(flags) 57 | return action, err 58 | } 59 | 60 | func (a *listenFilteredBlockAction) invoke() error { 61 | eventClient, err := a.EventClient(event.WithSeekType(cliconfig.Config().SeekType()), event.WithBlockNum(cliconfig.Config().BlockNum())) 62 | if err != nil { 63 | return err 64 | } 65 | 66 | fmt.Printf("Registering filtered block event\n") 67 | 68 | breg, beventch, err := eventClient.RegisterFilteredBlockEvent() 69 | if err != nil { 70 | return errors.WithMessage(err, "Error registering for filtered block events") 71 | } 72 | defer eventClient.Unregister(breg) 73 | 74 | enterch := a.WaitForEnter() 75 | for { 76 | select { 77 | case _, _ = <-enterch: 78 | return nil 79 | case event, ok := <-beventch: 80 | if !ok { 81 | return errors.WithMessage(err, "unexpected closed channel while waiting for filtered block event") 82 | } 83 | a.Printer().PrintFilteredBlock(event.FilteredBlock) 84 | fmt.Println("Press to terminate") 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/event/listentxcmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package event 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/pkg/errors" 13 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 14 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 15 | "github.com/spf13/cobra" 16 | "github.com/spf13/pflag" 17 | ) 18 | 19 | var listenTxCmd = &cobra.Command{ 20 | Use: "listentx", 21 | Short: "Listen to transaction events.", 22 | Long: "Listen to transaction events", 23 | Run: func(cmd *cobra.Command, args []string) { 24 | if cliconfig.Config().TxID() == "" { 25 | fmt.Printf("\nMust specify the transaction ID\n\n") 26 | cmd.HelpFunc()(cmd, args) 27 | return 28 | } 29 | action, err := newListenTXAction(cmd.Flags()) 30 | if err != nil { 31 | cliconfig.Config().Logger().Errorf("Error while initializing listenTxAction: %v", err) 32 | return 33 | } 34 | 35 | defer action.Terminate() 36 | 37 | err = action.invoke() 38 | if err != nil { 39 | cliconfig.Config().Logger().Errorf("Error while running listenTxAction: %v", err) 40 | } 41 | }, 42 | } 43 | 44 | func getListenTXCmd() *cobra.Command { 45 | flags := listenTxCmd.Flags() 46 | cliconfig.InitChannelID(flags) 47 | cliconfig.InitTxID(flags) 48 | cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to listen for events, e.g. grpcs://localhost:7051") 49 | return listenTxCmd 50 | } 51 | 52 | type listentxAction struct { 53 | action.Action 54 | inputEvent 55 | } 56 | 57 | func newListenTXAction(flags *pflag.FlagSet) (*listentxAction, error) { 58 | action := &listentxAction{inputEvent: inputEvent{done: make(chan bool)}} 59 | err := action.Initialize(flags) 60 | return action, err 61 | } 62 | 63 | func (a *listentxAction) invoke() error { 64 | 65 | eventHub, err := a.EventClient() 66 | if err != nil { 67 | return err 68 | } 69 | 70 | fmt.Printf("Registering TX event for TxID [%s]\n", cliconfig.Config().TxID()) 71 | 72 | reg, eventch, err := eventHub.RegisterTxStatusEvent(cliconfig.Config().TxID()) 73 | if err != nil { 74 | return errors.WithMessage(err, "Error registering for block events") 75 | } 76 | defer eventHub.Unregister(reg) 77 | 78 | enterch := a.WaitForEnter() 79 | fmt.Println("Press to terminate") 80 | 81 | select { 82 | case _, _ = <-enterch: 83 | return nil 84 | case event, ok := <-eventch: 85 | if !ok { 86 | return errors.WithMessage(err, "unexpected closed channel while waiting for tx status event") 87 | } 88 | fmt.Printf("Received TX event. TxID: %s, Code: %s, Error: %s\n", event.TxID, event.TxValidationCode, err) 89 | } 90 | 91 | return nil 92 | } 93 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/executor/executor.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package executor 8 | 9 | import ( 10 | "fmt" 11 | "math" 12 | "sync" 13 | "time" 14 | 15 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 16 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/executor/worker" 17 | ) 18 | 19 | // State is the state of the executor 20 | type State uint8 21 | 22 | const ( 23 | // NEW indicates that the executor is new and has not been started yet 24 | NEW State = iota 25 | 26 | // STARTED indicates that the executor is up and running 27 | STARTED 28 | 29 | // TERMINATED indicates that the executor has been shut down 30 | TERMINATED 31 | ) 32 | 33 | // Executor maintains a pool of workers that execute Tasks in separate Go routines. The caller submits 34 | // a Task to the Executor, which is submitted to an available worker. If a worker is not available then 35 | // the task is queue until one becomes available. The Executor is useful for throttling requests in order 36 | // not to overload the application. 37 | type Executor struct { 38 | name string 39 | state State 40 | tasks chan worker.Task 41 | terminating chan bool 42 | pool *worker.Pool 43 | wg sync.WaitGroup 44 | } 45 | 46 | // NewConcurrent creates a new, concurrent executor with the given concurrency. 47 | // As tasks are submitted they are queued while waiting for a worker for execution. 48 | // 49 | // - name: The name of the executor (useful for debugging) 50 | // - concurrency: The concurrency, i.e. the number of workers executing concurrently 51 | func NewConcurrent(name string, concurrency uint16) *Executor { 52 | return New(name, math.MaxInt16, worker.NewPool(name, concurrency)) 53 | } 54 | 55 | // NewBoundedConcurrent creates a new, concurrent executor with the given concurrency 56 | // and queue length. As tasks are submitted they are queued while waiting for a worker for execution. Once the 57 | // number of queued tasks reaches the given queue length, the Submit operation will block until a worker becomes 58 | // available. 59 | // 60 | // - name: The name of the executor (useful for debugging) 61 | // - concurrency: The concurrency, i.e. the number of workers executing concurrently 62 | // - queueLength: The maximum number of tasks allowed to be queued while waiting for a worker 63 | func NewBoundedConcurrent(name string, concurrency uint16, queueLength uint16) *Executor { 64 | return New(name, queueLength, worker.NewPool(name, concurrency)) 65 | } 66 | 67 | // New creates a new, multi-threaded executor with the given options: 68 | // - name: The name of the executor (useful for debugging) 69 | // - queueLength: The maximum number of tasks allowed to be queued while waiting for a worker 70 | // If queueSize == concurrency then the Submit() function will block until a worker becomes free, 71 | // otherwise the task will be added to the queue and Submit() will not block. 72 | // pool - The worker pool 73 | func New(name string, queueLength uint16, pool *worker.Pool) *Executor { 74 | return &Executor{ 75 | name: name, 76 | state: NEW, 77 | terminating: make(chan bool), 78 | tasks: make(chan worker.Task, queueLength), 79 | pool: pool, 80 | } 81 | } 82 | 83 | // Start starts the Executor 84 | func (e *Executor) Start() bool { 85 | if e.state != NEW { 86 | return false 87 | } 88 | 89 | // Start the worker pool 90 | e.pool.Start() 91 | 92 | // Start the task dispatcher 93 | go e.dispatch() 94 | 95 | e.state = STARTED 96 | 97 | return true 98 | } 99 | 100 | // Submit submits a new task 101 | func (e *Executor) Submit(task worker.Task) error { 102 | if e.state != STARTED { 103 | return fmt.Errorf("executor [%s] is not started", e.name) 104 | } 105 | 106 | // Submit the task to the dispatcher 107 | cliconfig.Config().Logger().Debugf("Submit[%s] - submitting task...\n", e.name) 108 | e.wg.Add(1) 109 | e.tasks <- task 110 | cliconfig.Config().Logger().Debugf("...Submit[%s] - submitted task\n", e.name) 111 | 112 | return nil 113 | } 114 | 115 | // SubmitDelayed submits a new task in the future 116 | func (e *Executor) SubmitDelayed(task worker.Task, delay time.Duration) error { 117 | if e.state != STARTED { 118 | return fmt.Errorf("executor [%s] is not started", e.name) 119 | } 120 | 121 | cliconfig.Config().Logger().Debugf("Submit[%s] - submitting task to execute in %s ...\n", e.name, delay) 122 | 123 | e.wg.Add(1) 124 | 125 | go func() { 126 | <-time.After(delay) 127 | e.Submit(task) 128 | e.wg.Done() 129 | }() 130 | 131 | return nil 132 | } 133 | 134 | // Wait waits for all outstanding tasks to complete 135 | func (e *Executor) Wait() { 136 | e.wg.Wait() 137 | } 138 | 139 | // Stop stops the executor. 140 | // - wait: If true then the call will block until all outstanding 141 | // tasks have completed; otherwise the executor will shut down immediately 142 | func (e *Executor) Stop(wait bool) bool { 143 | if e.state != STARTED { 144 | return false 145 | } 146 | 147 | e.state = TERMINATED 148 | 149 | cliconfig.Config().Logger().Debugf("[%s] Stopping executor ...\n", e.name) 150 | 151 | // Wait for the dispatcher to purge its queue 152 | e.wg.Wait() 153 | 154 | cliconfig.Config().Logger().Debugf("[%s] Stopping the dispatcher ...\n", e.name) 155 | 156 | // Stop the dispatcher 157 | e.terminating <- true 158 | 159 | cliconfig.Config().Logger().Debugf("[%s] Stopping the worker pool ...\n", e.name) 160 | 161 | // Stop the worker pool 162 | e.pool.Stop(wait) 163 | 164 | cliconfig.Config().Logger().Debugf("[%s] ... executor stopped.\n", e.name) 165 | 166 | return true 167 | } 168 | 169 | func (e *Executor) dispatch() { 170 | for { 171 | select { 172 | // Wait for a task 173 | case task := <-e.tasks: 174 | e.pool.Submit(task) 175 | e.wg.Done() 176 | 177 | case <-e.terminating: 178 | cliconfig.Config().Logger().Debugf("[%s] ... executor dispatcher ended\n", e.name) 179 | return 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/executor/worker/worker.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package worker 8 | 9 | import ( 10 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 11 | ) 12 | 13 | // State is the state of a Worker 14 | type State uint8 15 | 16 | const ( 17 | // READY indicates that a worker is ready to accept a new task 18 | READY State = iota 19 | 20 | // STOPPED indicates that the worker has terminated 21 | STOPPED 22 | ) 23 | 24 | // Task is the task that the Worker invokes 25 | type Task interface { 26 | Invoke() 27 | } 28 | 29 | // Events receives event notifications from the worker 30 | type Events interface { 31 | // StateChange indicates the new state of the worker 32 | StateChange(w *Worker, state State) 33 | 34 | // TaskStarted indicates that the given worker has started executing the given task 35 | TaskStarted(w *Worker, task Task) 36 | 37 | // TaskCompleted indicates that the given worker has completed the given task 38 | TaskCompleted(w *Worker, task Task) 39 | } 40 | 41 | // Worker invokes a Task 42 | type Worker struct { 43 | name string 44 | events Events 45 | task chan Task 46 | done chan bool 47 | } 48 | 49 | func newWorker(name string, events Events) *Worker { 50 | return &Worker{ 51 | name: name, 52 | events: events, 53 | task: make(chan Task), 54 | done: make(chan bool), 55 | } 56 | } 57 | 58 | // Name returns the name of the worker (useful for debugging) 59 | func (w *Worker) Name() string { 60 | return w.name 61 | } 62 | 63 | // Submit submits a task 64 | func (w *Worker) Submit(task Task) { 65 | w.task <- task 66 | } 67 | 68 | func (w *Worker) invoke(task Task) { 69 | cliconfig.Config().Logger().Debugf("Worker[%s].invoke ...\n", w.name) 70 | defer w.events.TaskCompleted(w, task) 71 | 72 | w.events.TaskStarted(w, task) 73 | task.Invoke() 74 | cliconfig.Config().Logger().Debugf("Worker[%s].invoke done.\n", w.name) 75 | } 76 | 77 | // Start starts the worker 78 | func (w *Worker) Start() { 79 | cliconfig.Config().Logger().Debugf("Worker[%s] starting...\n", w.name) 80 | go func() { 81 | for { 82 | cliconfig.Config().Logger().Debugf("Worker[%s] waiting for task...\n", w.name) 83 | 84 | // Inform the events that I'm available 85 | w.events.StateChange(w, READY) 86 | 87 | select { 88 | case task := <-w.task: 89 | w.invoke(task) 90 | 91 | case <-w.done: 92 | w.events.StateChange(w, STOPPED) 93 | cliconfig.Config().Logger().Debugf("Worker[%s] stopped\n", w.name) 94 | return 95 | } 96 | } 97 | }() 98 | } 99 | 100 | // Stop stops the worker 101 | func (w *Worker) Stop() { 102 | cliconfig.Config().Logger().Debugf("Worker[%s] stopping...\n", w.name) 103 | w.done <- true 104 | } 105 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/executor/worker/workerpool.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package worker 8 | 9 | import ( 10 | "fmt" 11 | "sync" 12 | 13 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 14 | ) 15 | 16 | // Pool contains a pool of workers that can each execute a Task 17 | type Pool struct { 18 | name string 19 | workers []*Worker 20 | availableWorker chan *Worker 21 | taskWg sync.WaitGroup 22 | wg sync.WaitGroup 23 | } 24 | 25 | // NewPool creates a worker Pool with the given Factory 26 | func NewPool(name string, concurrency uint16) *Pool { 27 | pool := &Pool{ 28 | name: name, 29 | availableWorker: make(chan *Worker, concurrency), 30 | workers: make([]*Worker, concurrency), 31 | } 32 | 33 | // Create the workers 34 | for i := 0; i < int(concurrency); i++ { 35 | pool.workers[i] = newWorker(fmt.Sprintf("%s-%d", name, i), pool) 36 | } 37 | 38 | return pool 39 | } 40 | 41 | // Name returns the name of the pool 42 | func (p *Pool) Name() string { 43 | return p.name 44 | } 45 | 46 | // Start starts the pool 47 | func (p *Pool) Start() { 48 | p.wg.Add(len(p.workers)) 49 | 50 | // Start the workers 51 | for _, w := range p.workers { 52 | w.Start() 53 | } 54 | } 55 | 56 | // Stop stops the pool and optionally waits until all tasks have completed 57 | func (p *Pool) Stop(wait bool) { 58 | cliconfig.Config().Logger().Debugf("[%s] Stopping worker pool ...\n", p.name) 59 | 60 | if wait { 61 | // Wait for all the tasks to complete 62 | cliconfig.Config().Logger().Debugf("[%s] ... waiting for tasks to complete ...\n", p.name) 63 | p.taskWg.Wait() 64 | } else { 65 | cliconfig.Config().Logger().Debugf("[%s] ... forcing all tasks to stop ...\n", p.name) 66 | } 67 | 68 | // Shut down the workers 69 | cliconfig.Config().Logger().Debugf("[%s] ... stopping workers ...\n", p.name) 70 | for i := 0; i < len(p.workers); i++ { 71 | w := <-p.availableWorker 72 | w.Stop() 73 | } 74 | 75 | // Wait for all of the workers to stop 76 | p.wg.Wait() 77 | } 78 | 79 | // Submit submits a Task for execution 80 | func (p *Pool) Submit(task Task) { 81 | cliconfig.Config().Logger().Debugf("worker pool.Submit[%s] - waiting for available worker\n", p.name) 82 | 83 | p.taskWg.Add(1) 84 | 85 | // Wait for an available worker 86 | w := <-p.availableWorker 87 | 88 | cliconfig.Config().Logger().Debugf("worker pool.Submit[%s] - got worker [%s]. Submitting task...\n", p.name, w.Name()) 89 | 90 | // Submit the task to the worker 91 | w.Submit(task) 92 | 93 | cliconfig.Config().Logger().Debugf("worker pool.Submit[%s] - submitted task to worker[%s]\n", p.name, w.Name()) 94 | } 95 | 96 | // StateChange is invoked when the state of the Worker changes 97 | func (p *Pool) StateChange(w *Worker, state State) { 98 | switch state { 99 | case READY: 100 | p.availableWorker <- w 101 | break 102 | 103 | case STOPPED: 104 | cliconfig.Config().Logger().Debugf("...Worker[%s] stopped\n", w.Name()) 105 | p.wg.Done() 106 | break 107 | 108 | default: 109 | cliconfig.Config().Logger().Warnf("Unsupported worker state: %d\n", state) 110 | break 111 | } 112 | } 113 | 114 | // TaskStarted is invoked when the given Worker begins executing the given Task 115 | func (p *Pool) TaskStarted(w *Worker, task Task) { 116 | // Nothing to do 117 | } 118 | 119 | // TaskCompleted is invoked when the given Worker completed executing the given Task 120 | func (p *Pool) TaskCompleted(w *Worker, task Task) { 121 | p.taskWg.Done() 122 | } 123 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/fabric-cli.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package main 8 | 9 | import ( 10 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/cmd" 11 | ) 12 | 13 | func main() { 14 | cmd.Execute() 15 | } 16 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/go.mod: -------------------------------------------------------------------------------- 1 | // Copyright SecureKey Technologies Inc. All Rights Reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | module github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli 6 | 7 | require ( 8 | github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5 // indirect 9 | github.com/golang/protobuf v1.3.2 10 | github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85 11 | github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200106161850-8f3d32c9d1a6 12 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 13 | github.com/magiconair/properties v1.8.0 // indirect 14 | github.com/mitchellh/mapstructure v0.0.0-20180511142126-bb74f1db0675 // indirect 15 | github.com/pelletier/go-toml v1.2.0 // indirect 16 | github.com/pkg/errors v0.8.1 17 | github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e // indirect 18 | github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7 // indirect 19 | github.com/spf13/afero v1.1.1 // indirect 20 | github.com/spf13/cobra v0.0.3 21 | github.com/spf13/pflag v1.0.1 22 | github.com/stretchr/testify v1.3.0 23 | ) 24 | 25 | go 1.13 26 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 3 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 4 | github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= 5 | github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= 6 | github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= 7 | github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= 8 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= 9 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 10 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 11 | github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= 12 | github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5 h1:PqZ3bA4yzwywivzk7PBQWngJp2/PAS0bWRZerKteicY= 13 | github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= 14 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 16 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 17 | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= 18 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 19 | github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= 20 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 21 | github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= 22 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 23 | github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= 24 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 25 | github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= 26 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 27 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 28 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 29 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 30 | github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= 31 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 32 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= 33 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 34 | github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= 35 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 36 | github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93 h1:qdfmdGwtm13OVx+AxguOWUTbgmXGn2TbdUHipo3chMg= 37 | github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= 38 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 39 | github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce h1:xdsDDbiBDQTKASoGEZ+pEmF1OnWuu8AQ9I8iNbHNeno= 40 | github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= 41 | github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= 42 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 43 | github.com/hyperledger/fabric-lib-go v1.0.0 h1:UL1w7c9LvHZUSkIvHTDGklxFv2kTeva1QI2emOVc324= 44 | github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= 45 | github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85 h1:bNgEcCg5NVRWs/T+VUEfhgh5Olx/N4VB+0+ybW+oSuA= 46 | github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= 47 | github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200106161850-8f3d32c9d1a6 h1:oEdHFGkrXcfoJdXmxem5fCyXS23SdfHc2UPt5g8o6HM= 48 | github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200106161850-8f3d32c9d1a6/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE= 49 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 50 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 51 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= 52 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 53 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 54 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 55 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 56 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 57 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 58 | github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 59 | github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= 60 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 61 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 62 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 63 | github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27 h1:XA/VH+SzpYyukhgh7v2mTp8rZoKKITXR/x3FIizVEXs= 64 | github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27/go.mod h1:WCBAbTOdfhHhz7YXujeZMF7owC4tPb1naKFsgfUISjo= 65 | github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 66 | github.com/mitchellh/mapstructure v0.0.0-20180511142126-bb74f1db0675 h1:/rdJjIiKG5rRdwG5yxHmSE/7ZREjpyC0kL7GxGT/qJw= 67 | github.com/mitchellh/mapstructure v0.0.0-20180511142126-bb74f1db0675/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 68 | github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= 69 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 70 | github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I= 71 | github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 72 | github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 73 | github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= 74 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 75 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 76 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 77 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 78 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 79 | github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8= 80 | github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 81 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= 82 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 83 | github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 84 | github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54= 85 | github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 86 | github.com/prometheus/procfs v0.0.0-20180705121852-ae68e2d4c00f/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 87 | github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7 h1:NgR6WN8nQ4SmFC1sSUHY8SriLuWCZ6cCIQtH4vDZN3c= 88 | github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 89 | github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 90 | github.com/spf13/afero v1.1.1 h1:Lt3ihYMlE+lreX1GS4Qw4ZsNpYQLxIXKBTEOXm3nt6I= 91 | github.com/spf13/afero v1.1.1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 92 | github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg= 93 | github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= 94 | github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= 95 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 96 | github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec h1:2ZXvIUGghLpdTVHR1UfvfrzoVlZaE/yOWC5LueIHZig= 97 | github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 98 | github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= 99 | github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 100 | github.com/spf13/viper v1.0.2 h1:Ncr3ZIuJn322w2k1qmzXDnkLAdQMlJqBa9kfAH+irso= 101 | github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= 102 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 103 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= 104 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 105 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= 106 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 107 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 108 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 109 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 110 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 111 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 112 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 113 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 114 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= 115 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 116 | golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= 117 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 118 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 119 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 120 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 121 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 122 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 123 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 124 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= 125 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 126 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= 127 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 128 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 129 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 130 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 131 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 132 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 133 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 134 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 135 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 136 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 137 | google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d h1:XB2jc5XQ9uhizGTS2vWcN01bc4dI6z3C4KY5MQm8SS8= 138 | google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 139 | google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= 140 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 141 | google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= 142 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 143 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 144 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 145 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 146 | gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= 147 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 148 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 149 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 150 | gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= 151 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 152 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 153 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 154 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/printer/formatter.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package printer 8 | 9 | import ( 10 | "fmt" 11 | "strings" 12 | ) 13 | 14 | // OutputFormat specifies the format for printing data 15 | type OutputFormat uint8 16 | 17 | const ( 18 | // RAW displays the raw data 19 | RAW OutputFormat = iota 20 | 21 | // JSON formats the data into Java Script Object Notation format 22 | JSON 23 | 24 | // DISPLAY formats the data into a human readable format 25 | DISPLAY 26 | ) 27 | 28 | func (f OutputFormat) String() string { 29 | switch f { 30 | case DISPLAY: 31 | return "display" 32 | case JSON: 33 | return "json" 34 | case RAW: 35 | return "raw" 36 | default: 37 | return "unknown" 38 | } 39 | } 40 | 41 | // AsOutputFormat returns the OutputFormat given an Output Format string 42 | func AsOutputFormat(f string) OutputFormat { 43 | switch strings.ToLower(f) { 44 | case "json": 45 | return JSON 46 | case "raw": 47 | return RAW 48 | default: 49 | return DISPLAY 50 | } 51 | } 52 | 53 | // Formatter outputs the data in a specific format 54 | type Formatter interface { 55 | // PrintHeader outputs a header 56 | PrintHeader() 57 | 58 | // PrintFooter outputs a footer 59 | PrintFooter() 60 | 61 | // Element starts an element 62 | Element(element string) 63 | 64 | // ElementEnd ends an element 65 | ElementEnd() 66 | 67 | // Field outputs the value of a field 68 | Field(field string, value interface{}) 69 | 70 | // Array starts an array 71 | Array(element string) 72 | 73 | // ArrayEnd ends the array 74 | ArrayEnd() 75 | 76 | // Item starts a complex array item 77 | Item(element string, index interface{}) 78 | 79 | // ItemEnd ends an array item 80 | ItemEnd() 81 | 82 | // ItemValue outputs a single array item 83 | ItemValue(element string, index interface{}, value interface{}) 84 | 85 | // Value outputs a value 86 | Value(value interface{}) 87 | 88 | // Print outputs additional info 89 | Print(frmt string, vars ...interface{}) 90 | } 91 | 92 | // FormatterOpts contains options for the formatter 93 | type FormatterOpts struct { 94 | // Base64Encode indicates whether binary values are to be encoded in base 64 95 | Base64Encode bool 96 | } 97 | 98 | // NewFormatter returns a new Formatter given the format and writer type. nil is returned 99 | // if no formatter exists for the given type 100 | func NewFormatter(format OutputFormat, writerType WriterType) Formatter { 101 | return NewFormatterWithOpts(format, writerType, &FormatterOpts{}) 102 | } 103 | 104 | // NewFormatterWithOpts returns a new Formatter given the format and writer type. nil is returned 105 | // if no formatter exists for the given type 106 | func NewFormatterWithOpts(format OutputFormat, writerType WriterType, opts *FormatterOpts) Formatter { 107 | switch format { 108 | case JSON: 109 | return &jsonFormatter{formatter: formatter{writer: NewWriter(writerType)}} 110 | case DISPLAY: 111 | return &displayFormatter{formatter: formatter{writer: NewWriter(writerType)}, base64Encode: opts.Base64Encode} 112 | default: 113 | return nil 114 | } 115 | } 116 | 117 | type formatter struct { 118 | writer Writer 119 | } 120 | 121 | func (f *formatter) write(format string, a ...interface{}) error { 122 | return f.writer.Write(format, a...) 123 | } 124 | 125 | type displayFormatter struct { 126 | formatter 127 | indent int 128 | base64Encode bool 129 | } 130 | 131 | func (p *displayFormatter) Print(frmt string, vars ...interface{}) { 132 | format := fmt.Sprintf("%s%s\n", p.prefix(), frmt) 133 | p.write(format, vars...) 134 | } 135 | 136 | func (p *displayFormatter) Field(field string, value interface{}) { 137 | if value != nil { 138 | p.write("%s%s: %v\n", p.prefix(), field, p.encodeValue(value)) 139 | } else { 140 | p.write("%s%s:\n", p.prefix(), field) 141 | } 142 | } 143 | 144 | func (p *displayFormatter) Element(element string) { 145 | if element != "" { 146 | p.write("%s%s:\n", p.prefix(), element) 147 | } 148 | p.indent++ 149 | } 150 | 151 | func (p *displayFormatter) ElementEnd() { 152 | p.indent-- 153 | } 154 | 155 | func (p *displayFormatter) Array(element string) { 156 | if element != "" { 157 | p.write("%s%s:\n", p.prefix(), element) 158 | } 159 | p.indent++ 160 | } 161 | 162 | func (p *displayFormatter) ArrayEnd() { 163 | p.indent-- 164 | 165 | } 166 | 167 | func (p *displayFormatter) Item(element string, index interface{}) { 168 | if element != "" { 169 | p.write("%s%s[%v]:\n", p.prefix(), element, index) 170 | } 171 | p.indent++ 172 | } 173 | 174 | func (p *displayFormatter) ItemEnd() { 175 | p.ElementEnd() 176 | } 177 | 178 | func (p *displayFormatter) ItemValue(element string, index interface{}, value interface{}) { 179 | if element != "" { 180 | p.write("%s%s[%v]: %v\n", p.prefix(), element, index, p.encodeValue(value)) 181 | } 182 | } 183 | 184 | func (p *displayFormatter) Value(value interface{}) { 185 | p.write("%s%v", p.prefix(), p.encodeValue(value)) 186 | } 187 | 188 | func (p *displayFormatter) PrintHeader() { 189 | p.write("%s\n", strings.Repeat("*", 100)) 190 | } 191 | 192 | func (p *displayFormatter) PrintFooter() { 193 | p.write("%s\n", strings.Repeat("*", 100)) 194 | } 195 | 196 | func (p *displayFormatter) prefix() string { 197 | s := "***** " 198 | for i := 0; i < p.indent; i++ { 199 | s = s + fmt.Sprintf("|%s", strings.Repeat(" ", indentSize-1)) 200 | } 201 | return s 202 | } 203 | 204 | func (p *displayFormatter) encodeValue(value interface{}) interface{} { 205 | switch value.(type) { 206 | case []byte: 207 | if p.base64Encode { 208 | return Base64URLEncode(value.([]byte)) 209 | } 210 | return string(value.([]byte)) 211 | default: 212 | return value 213 | } 214 | } 215 | 216 | type jsonFormatter struct { 217 | formatter 218 | commaRequired bool 219 | } 220 | 221 | func (p *jsonFormatter) Print(frmt string, vars ...interface{}) { 222 | // Ignore additional output in JSON format 223 | } 224 | 225 | func (p *jsonFormatter) Field(field string, value interface{}) { 226 | if p.commaRequired { 227 | p.write(",") 228 | } 229 | 230 | if value != nil { 231 | p.write("\"%s\":\"%v\"", field, p.encodeValue(value)) 232 | } else { 233 | p.write("\"%s\":\"null\"", field) 234 | } 235 | 236 | p.commaRequired = true 237 | } 238 | 239 | func (p *jsonFormatter) Element(element string) { 240 | if p.commaRequired { 241 | p.write(",") 242 | p.commaRequired = false 243 | } 244 | if element != "" { 245 | p.write("\"%s\":{", element) 246 | } else { 247 | p.write("{") 248 | } 249 | } 250 | 251 | func (p *jsonFormatter) ElementEnd() { 252 | p.write("}") 253 | p.commaRequired = true 254 | } 255 | 256 | func (p *jsonFormatter) Array(element string) { 257 | if p.commaRequired { 258 | p.write(",") 259 | p.commaRequired = false 260 | } 261 | if element != "" { 262 | p.write("\"%s\":[", element) 263 | } else { 264 | p.write("[") 265 | } 266 | } 267 | 268 | func (p *jsonFormatter) ArrayEnd() { 269 | p.write("]") 270 | p.commaRequired = true 271 | } 272 | 273 | func (p *jsonFormatter) Item(element string, index interface{}) { 274 | if p.commaRequired { 275 | p.write(",") 276 | p.commaRequired = false 277 | } 278 | p.write("{") 279 | } 280 | 281 | func (p *jsonFormatter) ItemEnd() { 282 | p.ElementEnd() 283 | } 284 | 285 | func (p *jsonFormatter) ItemValue(element string, index interface{}, value interface{}) { 286 | if i, ok := index.(int); ok && i > 0 { 287 | p.commaRequired = true 288 | p.write(",") 289 | } 290 | p.write("\"%v\"", p.encodeValue(value)) 291 | } 292 | 293 | func (p *jsonFormatter) Value(value interface{}) { 294 | if p.commaRequired { 295 | p.write(",") 296 | } 297 | p.write("\"%v\"", p.encodeValue(value)) 298 | } 299 | 300 | func (p *jsonFormatter) PrintHeader() { 301 | p.Element("") 302 | p.commaRequired = false 303 | } 304 | 305 | func (p *jsonFormatter) PrintFooter() { 306 | p.ElementEnd() 307 | p.write("\n") 308 | p.commaRequired = false 309 | } 310 | 311 | func (p *jsonFormatter) encodeValue(value interface{}) interface{} { 312 | switch value.(type) { 313 | case []byte: 314 | return Base64URLEncode(value.([]byte)) 315 | default: 316 | return value 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/printer/printer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package printer 8 | 9 | import "fmt" 10 | 11 | const ( 12 | indentSize = 3 13 | ) 14 | 15 | type printer struct { 16 | Formatter Formatter 17 | } 18 | 19 | // newPrinter returns a new Printer of the given OutputFormat and WriterType 20 | func newPrinter(format OutputFormat, writerType WriterType) *printer { 21 | return &printer{Formatter: NewFormatter(format, writerType)} 22 | } 23 | 24 | // newPrinterWithOpts returns a new Printer of the given OutputFormat and WriterType 25 | func newPrinterWithOpts(format OutputFormat, writerType WriterType, opts *FormatterOpts) *printer { 26 | return &printer{Formatter: NewFormatterWithOpts(format, writerType, opts)} 27 | } 28 | 29 | // Print prints a formatted string 30 | func (p *printer) Print(frmt string, vars ...interface{}) { 31 | if p.Formatter == nil { 32 | fmt.Printf(frmt, vars) 33 | return 34 | } 35 | p.Formatter.Print(frmt, vars...) 36 | } 37 | 38 | // Field prints a field/value 39 | func (p *printer) Field(Field string, value interface{}) { 40 | p.Formatter.Field(Field, value) 41 | } 42 | 43 | // Element starts a new named element. (Should be followed by ElementEnd.) 44 | func (p *printer) Element(element string) { 45 | p.Formatter.Element(element) 46 | } 47 | 48 | // ElementEnd ends an element that was started with ElementStart. 49 | func (p *printer) ElementEnd() { 50 | p.Formatter.ElementEnd() 51 | } 52 | 53 | // Array starts an array. (Should be followed by ArrayEnd.) 54 | func (p *printer) Array(element string) { 55 | p.Formatter.Array(element) 56 | } 57 | 58 | // ArrayEnd ends an array that was started with Array. 59 | func (p *printer) ArrayEnd() { 60 | p.Formatter.ArrayEnd() 61 | } 62 | 63 | // Item starts an array item at the given index. (A previous call to Array must have been made.) 64 | func (p *printer) Item(element string, index interface{}) { 65 | p.Formatter.Item(element, index) 66 | } 67 | 68 | // ItemEnd ends an array item that was started with Item. 69 | func (p *printer) ItemEnd() { 70 | p.Formatter.ItemEnd() 71 | } 72 | 73 | // ItemValue prints an array value at the given index. (A previous call to Array must have been made.) 74 | func (p *printer) ItemValue(element string, index interface{}, value interface{}) { 75 | p.Formatter.ItemValue(element, index, value) 76 | } 77 | 78 | // Value prints a value. 79 | func (p *printer) Value(value interface{}) { 80 | p.Formatter.Value(value) 81 | } 82 | 83 | // PrintHeader prints a header. 84 | func (p *printer) PrintHeader() { 85 | p.Formatter.PrintHeader() 86 | } 87 | 88 | // PrintFooter prints a footer. 89 | func (p *printer) PrintFooter() { 90 | p.Formatter.PrintFooter() 91 | } 92 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/printer/protoutils.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright IBM Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package printer 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/golang/protobuf/proto" 13 | cb "github.com/hyperledger/fabric-protos-go/common" 14 | "github.com/hyperledger/fabric-protos-go/peer" 15 | "github.com/pkg/errors" 16 | ) 17 | 18 | // ExtractEnvelopeOrPanic retrieves the requested envelope from a given block 19 | // and unmarshals it -- it panics if either of these operations fail 20 | func ExtractEnvelopeOrPanic(block *cb.Block, index int) *cb.Envelope { 21 | envelope, err := ExtractEnvelope(block, index) 22 | if err != nil { 23 | panic(err) 24 | } 25 | return envelope 26 | } 27 | 28 | // ExtractEnvelope retrieves the requested envelope from a given block and 29 | // unmarshals it 30 | func ExtractEnvelope(block *cb.Block, index int) (*cb.Envelope, error) { 31 | if block.Data == nil { 32 | return nil, errors.New("block data is nil") 33 | } 34 | 35 | envelopeCount := len(block.Data.Data) 36 | if index < 0 || index >= envelopeCount { 37 | return nil, errors.New("envelope index out of bounds") 38 | } 39 | marshaledEnvelope := block.Data.Data[index] 40 | envelope, err := GetEnvelopeFromBlock(marshaledEnvelope) 41 | err = errors.WithMessage(err, fmt.Sprintf("block data does not carry an envelope at index %d", index)) 42 | return envelope, err 43 | } 44 | 45 | // GetEnvelopeFromBlock gets an envelope from a block's Data field. 46 | func GetEnvelopeFromBlock(data []byte) (*cb.Envelope, error) { 47 | // Block always begins with an envelope 48 | var err error 49 | env := &cb.Envelope{} 50 | if err = proto.Unmarshal(data, env); err != nil { 51 | return nil, errors.Wrap(err, "error unmarshaling Envelope") 52 | } 53 | 54 | return env, nil 55 | } 56 | 57 | // ExtractPayloadOrPanic retrieves the payload of a given envelope and 58 | // unmarshals it -- it panics if either of these operations fail 59 | func ExtractPayloadOrPanic(envelope *cb.Envelope) *cb.Payload { 60 | payload, err := ExtractPayload(envelope) 61 | if err != nil { 62 | panic(err) 63 | } 64 | return payload 65 | } 66 | 67 | // ExtractPayload retrieves the payload of a given envelope and unmarshals it. 68 | func ExtractPayload(envelope *cb.Envelope) (*cb.Payload, error) { 69 | payload := &cb.Payload{} 70 | err := proto.Unmarshal(envelope.Payload, payload) 71 | err = errors.Wrap(err, "no payload in envelope") 72 | return payload, err 73 | } 74 | 75 | // UnmarshalChannelHeader returns a ChannelHeader from bytes 76 | func UnmarshalChannelHeader(bytes []byte) (*cb.ChannelHeader, error) { 77 | chdr := &cb.ChannelHeader{} 78 | err := proto.Unmarshal(bytes, chdr) 79 | return chdr, errors.Wrap(err, "error unmarshaling ChannelHeader") 80 | } 81 | 82 | // GetSignatureHeader Get SignatureHeader from bytes 83 | func GetSignatureHeader(bytes []byte) (*cb.SignatureHeader, error) { 84 | sh := &cb.SignatureHeader{} 85 | err := proto.Unmarshal(bytes, sh) 86 | return sh, errors.Wrap(err, "error unmarshaling SignatureHeader") 87 | } 88 | 89 | // GetTransaction Get Transaction from bytes 90 | func GetTransaction(txBytes []byte) (*peer.Transaction, error) { 91 | tx := &peer.Transaction{} 92 | err := proto.Unmarshal(txBytes, tx) 93 | return tx, errors.Wrap(err, "error unmarshaling Transaction") 94 | 95 | } 96 | 97 | // GetChaincodeActionPayload Get ChaincodeActionPayload from bytes 98 | func GetChaincodeActionPayload(capBytes []byte) (*peer.ChaincodeActionPayload, error) { 99 | cap := &peer.ChaincodeActionPayload{} 100 | err := proto.Unmarshal(capBytes, cap) 101 | return cap, errors.Wrap(err, "error unmarshaling ChaincodeActionPayload") 102 | } 103 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/printer/writer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package printer 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | "strings" 13 | 14 | config "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 15 | ) 16 | 17 | // WriterType specifies the format for printing data 18 | type WriterType uint8 19 | 20 | const ( 21 | // STDOUT writes to standard out 22 | STDOUT WriterType = iota 23 | 24 | // STDERR writes to standard error 25 | STDERR 26 | 27 | // LOG writes to the logger 28 | LOG 29 | ) 30 | 31 | const ( 32 | stdout = "stdout" 33 | stderr = "stderr" 34 | log = "log" 35 | ) 36 | 37 | func (f WriterType) String() string { 38 | switch f { 39 | case STDOUT: 40 | return stdout 41 | case STDERR: 42 | return stderr 43 | case LOG: 44 | return log 45 | default: 46 | return "unknown" 47 | } 48 | } 49 | 50 | // AsWriterType returns the WriterType given a Writer Type string 51 | func AsWriterType(t string) WriterType { 52 | switch strings.ToLower(t) { 53 | case log: 54 | return LOG 55 | case stderr: 56 | return STDERR 57 | default: 58 | return STDOUT 59 | } 60 | } 61 | 62 | // Writer writes the output 63 | type Writer interface { 64 | Write(format string, a ...interface{}) error 65 | } 66 | 67 | // NewWriter returns a new writer given the writer type 68 | func NewWriter(writerType WriterType) Writer { 69 | switch writerType { 70 | case STDERR: 71 | return &stdErrWriter{} 72 | case LOG: 73 | return &logWriter{} 74 | default: 75 | return &stdOutWriter{} 76 | } 77 | } 78 | 79 | type stdOutWriter struct { 80 | } 81 | 82 | func (w *stdOutWriter) Write(format string, a ...interface{}) error { 83 | _, err := fmt.Fprintf(os.Stdout, format, a...) 84 | return err 85 | } 86 | 87 | type stdErrWriter struct { 88 | } 89 | 90 | func (w *stdErrWriter) Write(format string, a ...interface{}) error { 91 | _, err := fmt.Fprintf(os.Stderr, format, a...) 92 | return err 93 | } 94 | 95 | type logWriter struct { 96 | } 97 | 98 | func (w *logWriter) Write(format string, a ...interface{}) error { 99 | config.Config().Logger().Infof(format, a...) 100 | return nil 101 | } 102 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/query/queryblockcmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package query 8 | 9 | import ( 10 | "encoding/base64" 11 | "strings" 12 | 13 | fabricCommon "github.com/hyperledger/fabric-protos-go/common" 14 | "github.com/hyperledger/fabric-sdk-go/pkg/client/ledger" 15 | "github.com/pkg/errors" 16 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 17 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 18 | "github.com/spf13/cobra" 19 | "github.com/spf13/pflag" 20 | ) 21 | 22 | var queryBlockCmd = &cobra.Command{ 23 | Use: "block", 24 | Short: "Query block", 25 | Long: "Queries a block", 26 | Run: func(cmd *cobra.Command, args []string) { 27 | action, err := newQueryBlockAction(cmd.Flags()) 28 | if err != nil { 29 | cliconfig.Config().Logger().Errorf("Error while initializing queryBlockAction: %v", err) 30 | return 31 | } 32 | 33 | defer action.Terminate() 34 | 35 | err = action.invoke() 36 | if err != nil { 37 | cliconfig.Config().Logger().Errorf("Error while running queryBlockAction: %v", err) 38 | } 39 | }, 40 | } 41 | 42 | func getQueryBlockCmd() *cobra.Command { 43 | flags := queryBlockCmd.Flags() 44 | cliconfig.InitChannelID(flags) 45 | cliconfig.InitBlockNum(flags) 46 | cliconfig.InitBlockHash(flags) 47 | cliconfig.InitTraverse(flags) 48 | cliconfig.InitPeerURL(flags, "", "The URL of the peer on which to install the chaincode, e.g. grpcs://localhost:7051") 49 | return queryBlockCmd 50 | } 51 | 52 | type queryBlockAction struct { 53 | action.Action 54 | } 55 | 56 | func newQueryBlockAction(flags *pflag.FlagSet) (*queryBlockAction, error) { 57 | action := &queryBlockAction{} 58 | err := action.Initialize(flags) 59 | return action, err 60 | } 61 | 62 | func (a *queryBlockAction) invoke() error { 63 | ledgerClient, err := a.LedgerClient() 64 | if err != nil { 65 | return errors.Errorf("Error getting admin channel client: %v", err) 66 | } 67 | 68 | var block *fabricCommon.Block 69 | if cliconfig.IsFlagSet(cliconfig.BlockNumFlag) { 70 | var err error 71 | block, err = ledgerClient.QueryBlock(cliconfig.Config().BlockNum()) 72 | if err != nil { 73 | return err 74 | } 75 | } else if cliconfig.IsFlagSet(cliconfig.BlockHashFlag) { 76 | var err error 77 | 78 | hashBytes, err := Base64URLDecode(cliconfig.Config().BlockHash()) 79 | if err != nil { 80 | return err 81 | } 82 | 83 | block, err = ledgerClient.QueryBlockByHash(hashBytes) 84 | if err != nil { 85 | return err 86 | } 87 | } else { 88 | return errors.Errorf("must specify either a block number of a block hash") 89 | } 90 | 91 | a.Printer().PrintBlock(block) 92 | 93 | a.traverse(ledgerClient, block, cliconfig.Config().Traverse()-1) 94 | 95 | return nil 96 | } 97 | 98 | func (a *queryBlockAction) traverse(ledgerClient *ledger.Client, currentBlock *fabricCommon.Block, num int) error { 99 | if num <= 0 { 100 | return nil 101 | } 102 | 103 | block, err := ledgerClient.QueryBlockByHash(currentBlock.Header.PreviousHash) 104 | if err != nil { 105 | return err 106 | } 107 | 108 | a.Printer().PrintBlock(block) 109 | 110 | if block.Header.PreviousHash != nil { 111 | return a.traverse(ledgerClient, block, num-1) 112 | } 113 | return nil 114 | } 115 | 116 | // Base64URLDecode decodes the base64 string into a byte array 117 | func Base64URLDecode(data string) ([]byte, error) { 118 | //check if it has padding or not 119 | if strings.HasSuffix(data, "=") { 120 | return base64.URLEncoding.DecodeString(data) 121 | } 122 | return base64.RawURLEncoding.DecodeString(data) 123 | } 124 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/query/querychannelscmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package query 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 13 | "github.com/pkg/errors" 14 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 15 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 16 | "github.com/spf13/cobra" 17 | "github.com/spf13/pflag" 18 | ) 19 | 20 | var queryChannelsCmd = &cobra.Command{ 21 | Use: "channels", 22 | Short: "Query channels", 23 | Long: "Queries the channels of the specified peer", 24 | Run: func(cmd *cobra.Command, args []string) { 25 | action, err := newQueryChannelsAction(cmd.Flags()) 26 | if err != nil { 27 | cliconfig.Config().Logger().Errorf("Error while initializing queryChannelsAction: %v", err) 28 | return 29 | } 30 | defer action.Terminate() 31 | 32 | if len(cliconfig.Config().PeerURLs()) != 1 { 33 | fmt.Printf("\nMust specify exactly one peer URL\n\n") 34 | cmd.HelpFunc()(cmd, args) 35 | return 36 | } 37 | 38 | err = action.run() 39 | if err != nil { 40 | cliconfig.Config().Logger().Errorf("Error while running queryChannelsAction: %v", err) 41 | } 42 | }, 43 | } 44 | 45 | func getQueryChannelsCmd() *cobra.Command { 46 | cliconfig.InitPeerURL(queryChannelsCmd.Flags()) 47 | return queryChannelsCmd 48 | } 49 | 50 | type queryChannelsAction struct { 51 | action.Action 52 | } 53 | 54 | func newQueryChannelsAction(flags *pflag.FlagSet) (*queryChannelsAction, error) { 55 | action := &queryChannelsAction{} 56 | err := action.Initialize(flags) 57 | return action, err 58 | } 59 | 60 | func (a *queryChannelsAction) run() error { 61 | 62 | url := cliconfig.Config().PeerURLs() 63 | if len(url) != 1 { 64 | return errors.New("must specify exactly one peer URL") 65 | } 66 | peer, ok := a.PeerFromURL(url[0]) 67 | if !ok { 68 | return fmt.Errorf("invalid peer URL: %s", url) 69 | } 70 | 71 | user, err := a.OrgAdminUser(a.OrgID()) 72 | if err != nil { 73 | return err 74 | } 75 | 76 | client, err := a.ResourceMgmtClientForUser(user) 77 | if err != nil { 78 | return errors.WithMessage(err, "error getting fabric client") 79 | } 80 | 81 | response, err := client.QueryChannels(resmgmt.WithTargets(peer)) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | fmt.Printf("Channels for peer [%s]\n", a.Peer().URL()) 87 | 88 | a.Printer().PrintChannels(response.Channels) 89 | 90 | return nil 91 | } 92 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/query/querycmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package query 8 | 9 | import ( 10 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | var queryCmd = &cobra.Command{ 15 | Use: "query", 16 | Short: "Query commands", 17 | Long: "Query commands", 18 | Run: func(cmd *cobra.Command, args []string) { 19 | cmd.HelpFunc()(cmd, args) 20 | }, 21 | } 22 | 23 | // Cmd returns the query command 24 | func Cmd() *cobra.Command { 25 | cliconfig.InitChannelID(queryCmd.Flags()) 26 | 27 | queryCmd.AddCommand(getQueryBlockCmd()) 28 | queryCmd.AddCommand(getQueryInfoCmd()) 29 | queryCmd.AddCommand(getQueryTXCmd()) 30 | queryCmd.AddCommand(getQueryChannelsCmd()) 31 | queryCmd.AddCommand(getQueryInstalledCmd()) 32 | queryCmd.AddCommand(getQueryPeersCmd()) 33 | queryCmd.AddCommand(getQueryLocalPeersCmd()) 34 | 35 | return queryCmd 36 | } 37 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/query/queryinfocmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package query 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/pkg/errors" 13 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 14 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 15 | "github.com/spf13/cobra" 16 | "github.com/spf13/pflag" 17 | ) 18 | 19 | var queryInfoCmd = &cobra.Command{ 20 | Use: "info", 21 | Short: "Query info", 22 | Long: "Queries general info", 23 | Run: func(cmd *cobra.Command, args []string) { 24 | action, err := newQueryInfoAction(cmd.Flags()) 25 | if err != nil { 26 | cliconfig.Config().Logger().Errorf("Error while initializing queryInfoAction: %v", err) 27 | return 28 | } 29 | defer action.Terminate() 30 | 31 | if cliconfig.Config().ChannelID() == "" { 32 | fmt.Printf("\nMust specify channel ID\n\n") 33 | cmd.HelpFunc()(cmd, args) 34 | return 35 | } 36 | 37 | err = action.run() 38 | if err != nil { 39 | cliconfig.Config().Logger().Errorf("Error while running queryInfoAction: %v", err) 40 | } 41 | }, 42 | } 43 | 44 | func getQueryInfoCmd() *cobra.Command { 45 | flags := queryInfoCmd.Flags() 46 | cliconfig.InitTxID(flags) 47 | cliconfig.InitChannelID(flags) 48 | cliconfig.InitPeerURL(flags) 49 | return queryInfoCmd 50 | } 51 | 52 | type queryInfoAction struct { 53 | action.Action 54 | } 55 | 56 | func newQueryInfoAction(flags *pflag.FlagSet) (*queryInfoAction, error) { 57 | action := &queryInfoAction{} 58 | err := action.Initialize(flags) 59 | return action, err 60 | } 61 | 62 | func (a *queryInfoAction) run() error { 63 | channelClient, err := a.LedgerClient() 64 | if err != nil { 65 | return errors.Errorf("Error getting admin ledger client: %v", err) 66 | } 67 | 68 | info, err := channelClient.QueryInfo() 69 | if err != nil { 70 | return err 71 | } 72 | 73 | a.Printer().PrintBlockchainInfo(info.BCI) 74 | 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/query/queryinstalledcmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package query 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 13 | "github.com/pkg/errors" 14 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 15 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 16 | "github.com/spf13/cobra" 17 | "github.com/spf13/pflag" 18 | ) 19 | 20 | var queryInstalledCmd = &cobra.Command{ 21 | Use: "installed", 22 | Short: "Query installed chaincodes", 23 | Long: "Queries the chaincodes installed to the specified peer", 24 | Run: func(cmd *cobra.Command, args []string) { 25 | action, err := newqueryInstalledAction(cmd.Flags()) 26 | if err != nil { 27 | cliconfig.Config().Logger().Errorf("Error while initializing queryInstalledAction: %v", err) 28 | return 29 | } 30 | 31 | if len(cliconfig.Config().PeerURLs()) != 1 { 32 | fmt.Printf("\nMust specify exactly one peer URL\n\n") 33 | cmd.HelpFunc()(cmd, args) 34 | return 35 | } 36 | 37 | defer action.Terminate() 38 | 39 | err = action.run() 40 | if err != nil { 41 | cliconfig.Config().Logger().Errorf("Error while running queryInstalledAction: %v", err) 42 | } 43 | }, 44 | } 45 | 46 | func getQueryInstalledCmd() *cobra.Command { 47 | cliconfig.InitPeerURL(queryInstalledCmd.Flags()) 48 | return queryInstalledCmd 49 | } 50 | 51 | type queryInstalledAction struct { 52 | action.Action 53 | } 54 | 55 | func newqueryInstalledAction(flags *pflag.FlagSet) (*queryInstalledAction, error) { 56 | action := &queryInstalledAction{} 57 | err := action.Initialize(flags) 58 | return action, err 59 | } 60 | 61 | func (a *queryInstalledAction) run() error { 62 | 63 | url := cliconfig.Config().PeerURLs() 64 | if len(url) != 1 { 65 | return errors.New("must specify exactly one peer URL") 66 | } 67 | peer, ok := a.PeerFromURL(url[0]) 68 | if !ok { 69 | return fmt.Errorf("invalid peer URL: %s", url) 70 | } 71 | 72 | user, err := a.OrgAdminUser(a.OrgID()) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | client, err := a.ResourceMgmtClientForUser(user) 78 | if err != nil { 79 | return err 80 | } 81 | 82 | response, err := client.QueryInstalledChaincodes(resmgmt.WithTargets(peer)) 83 | if err != nil { 84 | return err 85 | } 86 | 87 | fmt.Printf("Chaincodes for peer [%s]\n", a.Peer().URL()) 88 | a.Printer().PrintChaincodes(response.Chaincodes) 89 | return nil 90 | } 91 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/query/querylocalpeerscmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package query 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 13 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 14 | "github.com/spf13/cobra" 15 | "github.com/spf13/pflag" 16 | ) 17 | 18 | var queryLocalPeersCmd = &cobra.Command{ 19 | Use: "localpeers", 20 | Short: "Query local peers", 21 | Long: "Queries the peers for the specified org", 22 | Run: func(cmd *cobra.Command, args []string) { 23 | action, err := newQueryLocalPeersAction(cmd.Flags()) 24 | if err != nil { 25 | cliconfig.Config().Logger().Errorf("Error while initializing queryLocalPeersAction: %v", err) 26 | return 27 | } 28 | defer action.Terminate() 29 | 30 | if cliconfig.Config().OrgID() == "" { 31 | fmt.Printf("\nMust specify org ID\n\n") 32 | cmd.HelpFunc()(cmd, args) 33 | return 34 | } 35 | 36 | err = action.run() 37 | if err != nil { 38 | cliconfig.Config().Logger().Errorf("Error while running queryLocalPeersAction: %v", err) 39 | } 40 | }, 41 | } 42 | 43 | func getQueryLocalPeersCmd() *cobra.Command { 44 | flags := queryLocalPeersCmd.Flags() 45 | cliconfig.InitOrgIDs(flags) 46 | cliconfig.InitPeerURL(flags) 47 | return queryLocalPeersCmd 48 | } 49 | 50 | type queryLocalPeersAction struct { 51 | action.Action 52 | } 53 | 54 | func newQueryLocalPeersAction(flags *pflag.FlagSet) (*queryLocalPeersAction, error) { 55 | action := &queryLocalPeersAction{} 56 | err := action.Initialize(flags) 57 | return action, err 58 | } 59 | 60 | func (a *queryLocalPeersAction) run() error { 61 | localContext, err := a.LocalContext() 62 | if err != nil { 63 | return err 64 | } 65 | 66 | peers, err := localContext.LocalDiscoveryService().GetPeers() 67 | if err != nil { 68 | return err 69 | } 70 | 71 | a.Printer().PrintPeers(peers) 72 | 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/query/querypeerscmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package query 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 13 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 14 | "github.com/spf13/cobra" 15 | "github.com/spf13/pflag" 16 | ) 17 | 18 | var queryPeersCmd = &cobra.Command{ 19 | Use: "peers", 20 | Short: "Query peers", 21 | Long: "Queries the peers for the specified channel", 22 | Run: func(cmd *cobra.Command, args []string) { 23 | action, err := newQueryPeersAction(cmd.Flags()) 24 | if err != nil { 25 | cliconfig.Config().Logger().Errorf("Error while initializing queryPeersAction: %v", err) 26 | return 27 | } 28 | defer action.Terminate() 29 | 30 | if cliconfig.Config().ChannelID() == "" { 31 | fmt.Printf("\nMust specify channel ID\n\n") 32 | cmd.HelpFunc()(cmd, args) 33 | return 34 | } 35 | 36 | err = action.run() 37 | if err != nil { 38 | cliconfig.Config().Logger().Errorf("Error while running queryPeersAction: %v", err) 39 | } 40 | }, 41 | } 42 | 43 | func getQueryPeersCmd() *cobra.Command { 44 | flags := queryPeersCmd.Flags() 45 | cliconfig.InitChannelID(flags) 46 | cliconfig.InitPeerURL(flags) 47 | return queryPeersCmd 48 | } 49 | 50 | type queryPeersAction struct { 51 | action.Action 52 | } 53 | 54 | func newQueryPeersAction(flags *pflag.FlagSet) (*queryPeersAction, error) { 55 | action := &queryPeersAction{} 56 | err := action.Initialize(flags) 57 | return action, err 58 | } 59 | 60 | func (a *queryPeersAction) run() error { 61 | chProvider, err := a.ChannelProvider() 62 | if err != nil { 63 | return err 64 | } 65 | 66 | chContext, err := chProvider() 67 | if err != nil { 68 | return err 69 | } 70 | 71 | discovery, err := chContext.ChannelService().Discovery() 72 | if err != nil { 73 | return err 74 | } 75 | 76 | peers, err := discovery.GetPeers() 77 | if err != nil { 78 | return err 79 | } 80 | 81 | a.Printer().PrintPeers(peers) 82 | 83 | return nil 84 | } 85 | -------------------------------------------------------------------------------- /fabric-cli/cmd/fabric-cli/query/querytxcmd.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package query 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" 13 | "github.com/pkg/errors" 14 | "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/action" 15 | cliconfig "github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli/config" 16 | "github.com/spf13/cobra" 17 | "github.com/spf13/pflag" 18 | ) 19 | 20 | var queryTXCmd = &cobra.Command{ 21 | Use: "tx", 22 | Short: "Query transaction", 23 | Long: "Queries a transaction", 24 | Run: func(cmd *cobra.Command, args []string) { 25 | if cliconfig.Config().TxID() == "" { 26 | fmt.Printf("\nMust specify the transaction ID\n\n") 27 | cmd.HelpFunc()(cmd, args) 28 | return 29 | } 30 | action, err := newQueryTXAction(cmd.Flags()) 31 | if err != nil { 32 | cliconfig.Config().Logger().Errorf("Error while initializing queryTXAction: %v", err) 33 | return 34 | } 35 | 36 | defer action.Terminate() 37 | 38 | err = action.run() 39 | if err != nil { 40 | cliconfig.Config().Logger().Errorf("Error while running queryTXAction: %v", err) 41 | } 42 | }, 43 | } 44 | 45 | func getQueryTXCmd() *cobra.Command { 46 | flags := queryTXCmd.Flags() 47 | cliconfig.InitChannelID(flags) 48 | cliconfig.InitTxID(flags) 49 | cliconfig.InitPeerURL(flags) 50 | return queryTXCmd 51 | } 52 | 53 | type queryTXAction struct { 54 | action.Action 55 | } 56 | 57 | func newQueryTXAction(flags *pflag.FlagSet) (*queryTXAction, error) { 58 | action := &queryTXAction{} 59 | err := action.Initialize(flags) 60 | 61 | return action, err 62 | } 63 | 64 | func (a *queryTXAction) run() error { 65 | ledgerClient, err := a.LedgerClient() 66 | if err != nil { 67 | return errors.Errorf("Error getting ledger client: %v", err) 68 | } 69 | 70 | tx, err := ledgerClient.QueryTransaction(fab.TransactionID(cliconfig.Config().TxID())) 71 | if err != nil { 72 | return err 73 | } 74 | 75 | fmt.Printf("Transaction %s in channel %s\n", cliconfig.Config().TxID(), cliconfig.Config().ChannelID()) 76 | a.Printer().PrintProcessedTransaction(tx) 77 | 78 | return nil 79 | } 80 | -------------------------------------------------------------------------------- /fabric-cli/scripts/fabric-sdk-go/apply_upstream.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright SecureKey Technologies Inc. All Rights Reserved. 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | 8 | # This script fetches code used in the examples originating from the fabric-sdk-go project 9 | 10 | set -e 11 | 12 | UPSTREAM_PROJECT="github.com/hyperledger/fabric-sdk-go" 13 | UPSTREAM_BRANCH="${UPSTREAM_BRANCH}" 14 | SCRIPTS_PATH="scripts/fabric-sdk-go" 15 | 16 | FABRIC_SDK_GO_PATH='fabric-sdk-go' 17 | 18 | #### 19 | # Clone and patch packages into repo 20 | 21 | # Clone fabric-sdk-go project into temporary directory 22 | echo "Fetching upstream project ($UPSTREAM_PROJECT:$UPSTREAM_COMMIT) ..." 23 | CWD=`pwd` 24 | TMP=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir'` 25 | 26 | TMP_PROJECT_PATH=$TMP/src/$UPSTREAM_PROJECT 27 | mkdir -p $TMP_PROJECT_PATH 28 | cd ${TMP_PROJECT_PATH}/.. 29 | 30 | git clone https://${UPSTREAM_PROJECT}.git 31 | cd $TMP_PROJECT_PATH 32 | git checkout $UPSTREAM_BRANCH 33 | git reset --hard $UPSTREAM_COMMIT 34 | 35 | cd $CWD 36 | 37 | echo 'Removing current upstream project from working directory ...' 38 | rm -Rf "${FABRIC_SDK_GO_PATH}" 39 | mkdir -p "${FABRIC_SDK_GO_PATH}" 40 | 41 | declare -a PATHS=( 42 | "Makefile" 43 | "test/fixtures/*" 44 | "scripts/_go/*" 45 | "test/scripts/*" 46 | ) 47 | 48 | for i in "${PATHS[@]}" 49 | do 50 | DIR=$(dirname "${i}") 51 | DEST=$FABRIC_SDK_GO_PATH/$DIR 52 | mkdir -p $DEST 53 | cp -R $TMP_PROJECT_PATH/${i} $DEST 54 | done 55 | 56 | # Cleanup temporary files from patch application 57 | echo "Removing temporary files ..." 58 | rm -Rf $TMP 59 | -------------------------------------------------------------------------------- /fabric-cli/scripts/fabric-sdk-go/example-network-clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright SecureKey Technologies Inc. All Rights Reserved. 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | 8 | # This script deletes all docker containers, and example network docker images 9 | 10 | set -e 11 | 12 | cd fabric-sdk-go/test/fixtures/dockerenv/ 13 | docker-compose -f docker-compose.yaml -f docker-compose-chaincoded.yaml down 14 | cd ../../../.. 15 | -------------------------------------------------------------------------------- /fabric-cli/scripts/fabric-sdk-go/populate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright SecureKey Technologies Inc. All Rights Reserved. 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | # 7 | # This script populates the vendor folder. 8 | 9 | set -e 10 | 11 | cd fabric-sdk-go 12 | 13 | echo "Populating dockerd vendor ..." 14 | declare chaincodedPath="scripts/_go/src/chaincoded" 15 | rm -Rf ${chaincodedPath}/vendor/ 16 | mkdir -p ${chaincodedPath}/vendor/github.com/hyperledger/fabric 17 | git clone --branch release-1.3 --depth=1 https://github.com/hyperledger/fabric.git ${chaincodedPath}/vendor/github.com/hyperledger/fabric 18 | 19 | cd .. 20 | -------------------------------------------------------------------------------- /fabric-cli/scripts/fabric-sdk-go/readme-example-network-clean.txt: -------------------------------------------------------------------------------- 1 | # 2 | # The process of cleaning up example network artifacts is not yet automated. 3 | # 4 | # Step one: remove example network docker containers. 5 | # 6 | # Note that the lines below stops and removes ALL conatiners from your 7 | # system, which may not be what you really want if you are running 8 | # containers not related to the example network. 9 | # 10 | # $ docker stop $(docker ps -a -q) 11 | # $ docker rm $(docker ps -a -q) 12 | # 13 | # Step two: remove example network docker images. 14 | # 15 | # For repeated testing with bringing the example network up and down, 16 | # you typically don't remove HLF images as they need time to download 17 | # and recreate. 18 | # 19 | # If you are making changes to already deployed and instantiated 20 | # example_cc.go, you have two options: 21 | # 22 | # 1) deploy the new version of chaincode (specify the next version in 23 | # command line) and upgrade the chaincode to the new version 24 | # 25 | # 2) delete the chaincode images so you can start deploying/upgrading 26 | # from v0 again: 27 | # 28 | # $ docker images | grep examplecc 29 | # $ docker rmi 30 | 31 | -------------------------------------------------------------------------------- /fabric-cli/test/fixtures/config/pvtdatacollection.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "coll1", 4 | "policy": "OR('Org1MSP.member', 'Org2MSP.member')", 5 | "requiredPeerCount": 1, 6 | "maxPeerCount": 2 7 | }, 8 | { 9 | "name": "coll2", 10 | "policy": "OR('Org2MSP.member')", 11 | "requiredPeerCount": 0, 12 | "maxPeerCount": 2 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /fabric-cli/test/fixtures/testdata/src/github.com/securekey/example2_cc/example2_cc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package main 8 | 9 | import ( 10 | "encoding/json" 11 | "fmt" 12 | "strings" 13 | 14 | "github.com/hyperledger/fabric/core/chaincode/shim" 15 | pb "github.com/hyperledger/fabric/protos/peer" 16 | ) 17 | 18 | type invokeFunc func(stub shim.ChaincodeStubInterface, args []string) pb.Response 19 | type funcMap map[string]invokeFunc 20 | 21 | const ( 22 | getFunc = "get" 23 | putFunc = "put" 24 | delFunc = "del" 25 | putPrivateFunc = "putprivate" 26 | getPrivateFunc = "getprivate" 27 | delPrivateFunc = "delprivate" 28 | putBothFunc = "putboth" 29 | getAndPutBothFunc = "getandputboth" 30 | invokeCCFunc = "invokecc" 31 | ) 32 | 33 | // ExampleCC example simple Chaincode implementation 34 | type ExampleCC struct { 35 | funcRegistry funcMap 36 | } 37 | 38 | // Init ... 39 | func (cc *ExampleCC) Init(stub shim.ChaincodeStubInterface) pb.Response { 40 | return shim.Success(nil) 41 | } 42 | 43 | // Invoke invoke the chaincode with a given function 44 | func (cc *ExampleCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 45 | fmt.Println("########### example2_cc Invoke ###########") 46 | function, args := stub.GetFunctionAndParameters() 47 | if function == "" { 48 | return shim.Error("Expecting function") 49 | } 50 | 51 | f, ok := cc.funcRegistry[function] 52 | if !ok { 53 | return shim.Error(fmt.Sprintf("Unknown function [%s]. Expecting one of: %v", function, cc.functions())) 54 | } 55 | 56 | return f(stub, args) 57 | } 58 | 59 | func (cc *ExampleCC) put(stub shim.ChaincodeStubInterface, args []string) pb.Response { 60 | if len(args) != 2 { 61 | return shim.Error("Invalid args. Expecting key and value") 62 | } 63 | 64 | key := args[0] 65 | value := args[1] 66 | 67 | existingValue, err := stub.GetState(key) 68 | if err != nil { 69 | return shim.Error(fmt.Sprintf("Error getting data for key [%s]: %s", key, err)) 70 | } 71 | if existingValue != nil { 72 | value = string(existingValue) + "-" + value 73 | } 74 | 75 | if err := stub.PutState(key, []byte(value)); err != nil { 76 | return shim.Error(fmt.Sprintf("Error putting data for key [%s]: %s", key, err)) 77 | } 78 | 79 | return shim.Success([]byte(value)) 80 | } 81 | 82 | func (cc *ExampleCC) get(stub shim.ChaincodeStubInterface, args []string) pb.Response { 83 | if len(args) != 1 { 84 | return shim.Error("Invalid args. Expecting key") 85 | } 86 | 87 | key := args[0] 88 | 89 | value, err := stub.GetState(key) 90 | if err != nil { 91 | return shim.Error(fmt.Sprintf("Error getting data for key [%s]: %s", key, err)) 92 | } 93 | 94 | return shim.Success([]byte(value)) 95 | } 96 | 97 | func (cc *ExampleCC) del(stub shim.ChaincodeStubInterface, args []string) pb.Response { 98 | if len(args) != 1 { 99 | return shim.Error("Invalid args. Expecting key") 100 | } 101 | 102 | key := args[1] 103 | 104 | err := stub.DelState(key) 105 | if err != nil { 106 | return shim.Error(fmt.Sprintf("Failed to delete state for [%s]: %s", key, err)) 107 | } 108 | 109 | return shim.Success(nil) 110 | } 111 | 112 | func (cc *ExampleCC) putPrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response { 113 | if len(args) != 3 { 114 | return shim.Error("Invalid args. Expecting collection, key and value") 115 | } 116 | 117 | coll := args[0] 118 | key := args[1] 119 | value := args[2] 120 | 121 | if err := stub.PutPrivateData(coll, key, []byte(value)); err != nil { 122 | return shim.Error(fmt.Sprintf("Error putting private data for collection [%s] and key [%s]: %s", coll, key, err)) 123 | } 124 | 125 | return shim.Success(nil) 126 | } 127 | 128 | func (cc *ExampleCC) getPrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response { 129 | if len(args) != 2 { 130 | return shim.Error("Invalid args. Expecting collection and key") 131 | } 132 | 133 | coll := args[0] 134 | key := args[1] 135 | 136 | value, err := stub.GetPrivateData(coll, key) 137 | if err != nil { 138 | return shim.Error(fmt.Sprintf("Error getting private data for collection [%s] and key [%s]: %s", coll, key, err)) 139 | } 140 | 141 | return shim.Success([]byte(value)) 142 | } 143 | 144 | func (cc *ExampleCC) delPrivate(stub shim.ChaincodeStubInterface, args []string) pb.Response { 145 | if len(args) != 2 { 146 | return shim.Error("Invalid args. Expecting collection and key") 147 | } 148 | 149 | coll := args[0] 150 | key := args[1] 151 | 152 | err := stub.DelPrivateData(coll, key) 153 | if err != nil { 154 | return shim.Error(fmt.Sprintf("Error getting private data for collection [%s] and key [%s]: %s", coll, key, err)) 155 | } 156 | 157 | return shim.Success(nil) 158 | } 159 | 160 | func (cc *ExampleCC) putBoth(stub shim.ChaincodeStubInterface, args []string) pb.Response { 161 | if len(args) != 5 { 162 | return shim.Error("Invalid args. Expecting key, value, collection, privkey and privvalue") 163 | } 164 | 165 | key := args[0] 166 | value := args[1] 167 | coll := args[2] 168 | privKey := args[3] 169 | privValue := args[4] 170 | 171 | if err := stub.PutState(key, []byte(value)); err != nil { 172 | return shim.Error(fmt.Sprintf("Error putting state for key [%s]: %s", key, err)) 173 | } 174 | if err := stub.PutPrivateData(coll, privKey, []byte(privValue)); err != nil { 175 | return shim.Error(fmt.Sprintf("Error putting private data for collection [%s] and key [%s]: %s", coll, key, err)) 176 | } 177 | 178 | return shim.Success(nil) 179 | } 180 | 181 | func (cc *ExampleCC) getAndPutBoth(stub shim.ChaincodeStubInterface, args []string) pb.Response { 182 | if len(args) != 5 { 183 | return shim.Error("Invalid args. Expecting key, value, collection, privkey and privvalue") 184 | } 185 | 186 | key := args[0] 187 | value := args[1] 188 | coll := args[2] 189 | privKey := args[3] 190 | privValue := args[4] 191 | 192 | oldValue, err := stub.GetState(key) 193 | if err != nil { 194 | return shim.Error(fmt.Sprintf("Error getting state for key [%s]: %s", key, err)) 195 | } 196 | if oldValue != nil { 197 | value = value + "_" + string(oldValue) 198 | } 199 | oldPrivValue, err := stub.GetPrivateData(coll, privKey) 200 | if err != nil { 201 | return shim.Error(fmt.Sprintf("Error getting private data for collection [%s] and key [%s]: %s", coll, privKey, err)) 202 | } 203 | if oldPrivValue != nil { 204 | privValue = privValue + "_" + string(oldPrivValue) 205 | } 206 | 207 | if err := stub.PutState(key, []byte(value)); err != nil { 208 | return shim.Error(fmt.Sprintf("Error putting state for key [%s]: %s", key, err)) 209 | } 210 | if err := stub.PutPrivateData(coll, privKey, []byte(privValue)); err != nil { 211 | return shim.Error(fmt.Sprintf("Error putting private data for collection [%s] and key [%s]: %s", coll, key, err)) 212 | } 213 | 214 | return shim.Success(nil) 215 | } 216 | 217 | type argStruct struct { 218 | Args []string `json:"Args"` 219 | } 220 | 221 | func asBytes(args []string) [][]byte { 222 | bytes := make([][]byte, len(args)) 223 | for i, arg := range args { 224 | bytes[i] = []byte(arg) 225 | } 226 | return bytes 227 | } 228 | 229 | func (cc *ExampleCC) invokeCC(stub shim.ChaincodeStubInterface, args []string) pb.Response { 230 | if len(args) < 2 { 231 | return shim.Error(`Invalid args. Expecting name of chaincode to invoke and chaincode args in the format {"Args":["arg1","arg2",...]}`) 232 | } 233 | 234 | ccName := args[0] 235 | invokeArgsJSON := strings.Replace(args[1], "`", `"`, -1) 236 | 237 | argStruct := argStruct{} 238 | if err := json.Unmarshal([]byte(invokeArgsJSON), &argStruct); err != nil { 239 | return shim.Error(fmt.Sprintf("Invalid invoke args: %s", err)) 240 | } 241 | 242 | if err := stub.PutState(stub.GetTxID()+"_invokedcc", []byte(ccName)); err != nil { 243 | return shim.Error(fmt.Sprintf("Error putting state: %s", err)) 244 | } 245 | 246 | return stub.InvokeChaincode(ccName, asBytes(argStruct.Args), "") 247 | } 248 | 249 | func (cc *ExampleCC) initRegistry() { 250 | cc.funcRegistry = make(map[string]invokeFunc) 251 | cc.funcRegistry[getFunc] = cc.get 252 | cc.funcRegistry[putFunc] = cc.put 253 | cc.funcRegistry[delFunc] = cc.del 254 | cc.funcRegistry[getPrivateFunc] = cc.getPrivate 255 | cc.funcRegistry[putPrivateFunc] = cc.putPrivate 256 | cc.funcRegistry[delPrivateFunc] = cc.delPrivate 257 | cc.funcRegistry[putBothFunc] = cc.putBoth 258 | cc.funcRegistry[getAndPutBothFunc] = cc.getAndPutBoth 259 | cc.funcRegistry[invokeCCFunc] = cc.invokeCC 260 | } 261 | 262 | func (cc *ExampleCC) functions() []string { 263 | var funcs []string 264 | for key := range cc.funcRegistry { 265 | funcs = append(funcs, key) 266 | } 267 | return funcs 268 | } 269 | 270 | func main() { 271 | cc := new(ExampleCC) 272 | cc.initRegistry() 273 | err := shim.Start(cc) 274 | if err != nil { 275 | fmt.Printf("Error starting example chaincode: %s", err) 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /fabric-cli/test/fixtures/testdata/src/github.com/securekey/example_cc/example_cc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright IBM Corp. 2016 All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "fmt" 21 | "strconv" 22 | 23 | "github.com/hyperledger/fabric/core/chaincode/shim" 24 | pb "github.com/hyperledger/fabric/protos/peer" 25 | ) 26 | 27 | // SimpleChaincode example simple Chaincode implementation 28 | type SimpleChaincode struct { 29 | } 30 | 31 | // Init ... 32 | func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { 33 | fmt.Println("########### example_cc Init ###########") 34 | args := stub.GetStringArgs() 35 | var A, B string // Entities 36 | var Aval, Bval int // Asset holdings 37 | var err error 38 | 39 | if len(args) != 4 { 40 | return shim.Error(fmt.Sprintf("Incorrect number of arguments. Expecting 4, got %d", len(args))) 41 | } 42 | 43 | // Initialize the chaincode 44 | A = args[0] 45 | Aval, err = strconv.Atoi(args[1]) 46 | if err != nil { 47 | return shim.Error("Expecting integer value for asset holding") 48 | } 49 | B = args[2] 50 | Bval, err = strconv.Atoi(args[3]) 51 | if err != nil { 52 | return shim.Error("Expecting integer value for asset holding") 53 | } 54 | fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) 55 | 56 | // Write the state to the ledger 57 | err = stub.PutState(A, []byte(strconv.Itoa(Aval))) 58 | if err != nil { 59 | return shim.Error(err.Error()) 60 | } 61 | 62 | err = stub.PutState(B, []byte(strconv.Itoa(Bval))) 63 | if err != nil { 64 | return shim.Error(err.Error()) 65 | } 66 | 67 | if transientMap, err := stub.GetTransient(); err == nil { 68 | if transientData, ok := transientMap["result"]; ok { 69 | fmt.Printf("Transient data in 'init' : %s\n", transientData) 70 | return shim.Success(transientData) 71 | } 72 | } 73 | return shim.Success(nil) 74 | 75 | } 76 | 77 | // Query ... 78 | func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface) pb.Response { 79 | return shim.Error("Unknown supported call") 80 | } 81 | 82 | // Invoke ... 83 | // Transaction makes payment of X units from A to B 84 | func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 85 | fmt.Println("########### example_cc Invoke ###########") 86 | args := stub.GetStringArgs() 87 | if len(args) == 0 { 88 | return shim.Error("Function not provided") 89 | } 90 | 91 | function := args[0] 92 | 93 | if len(args) < 2 { 94 | return shim.Error("Incorrect number of arguments. Expecting at least 2") 95 | } 96 | 97 | if function == "delete" { 98 | // Deletes an entity from its state 99 | return t.delete(stub, args) 100 | } 101 | 102 | if function == "query" { 103 | // queries an entity state 104 | return t.query(stub, args) 105 | } 106 | 107 | if function == "move" { 108 | eventID := "testEvent" 109 | if len(args) >= 5 { 110 | eventID = args[4] 111 | } 112 | if err := stub.SetEvent(eventID, []byte("Test Payload")); err != nil { 113 | return shim.Error("Unable to set CC event: testEvent. Aborting transaction ...") 114 | } 115 | return t.move(stub, args) 116 | } 117 | 118 | if function == "put" { 119 | return t.put(stub, args[1:]) 120 | } 121 | 122 | if function == "get" { 123 | return t.get(stub, args[1:]) 124 | } 125 | 126 | return shim.Error(fmt.Sprintf("Unknown function call: %s", function)) 127 | } 128 | 129 | func (t *SimpleChaincode) move(stub shim.ChaincodeStubInterface, args []string) pb.Response { 130 | // must be an invoke 131 | var A, B string // Entities 132 | var Aval, Bval int // Asset holdings 133 | var X int // Transaction value 134 | var err error 135 | if len(args) < 4 { 136 | return shim.Error("Incorrect number of arguments. Expecting 4, function followed by 2 names and 1 value") 137 | } 138 | 139 | A = args[1] 140 | B = args[2] 141 | 142 | // Get the state from the ledger 143 | // TODO: will be nice to have a GetAllState call to ledger 144 | Avalbytes, err := stub.GetState(A) 145 | if err != nil { 146 | return shim.Error("Failed to get state") 147 | } 148 | if Avalbytes == nil { 149 | return shim.Error("Entity not found") 150 | } 151 | Aval, _ = strconv.Atoi(string(Avalbytes)) 152 | 153 | Bvalbytes, err := stub.GetState(B) 154 | if err != nil { 155 | return shim.Error("Failed to get state") 156 | } 157 | if Bvalbytes == nil { 158 | return shim.Error("Entity not found") 159 | } 160 | Bval, _ = strconv.Atoi(string(Bvalbytes)) 161 | 162 | // Perform the execution 163 | X, err = strconv.Atoi(args[3]) 164 | if err != nil { 165 | return shim.Error("Invalid transaction amount, expecting a integer value") 166 | } 167 | Aval = Aval - X 168 | Bval = Bval + X 169 | fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) 170 | 171 | // Write the state back to the ledger 172 | err = stub.PutState(A, []byte(strconv.Itoa(Aval))) 173 | if err != nil { 174 | return shim.Error(err.Error()) 175 | } 176 | 177 | err = stub.PutState(B, []byte(strconv.Itoa(Bval))) 178 | if err != nil { 179 | return shim.Error(err.Error()) 180 | } 181 | 182 | if transientMap, err := stub.GetTransient(); err == nil { 183 | if transientData, ok := transientMap["result"]; ok { 184 | fmt.Printf("Transient data in 'move' : %s\n", transientData) 185 | return shim.Success(transientData) 186 | } 187 | } 188 | return shim.Success(nil) 189 | } 190 | 191 | // Deletes an entity from state 192 | func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response { 193 | if len(args) != 1 { 194 | return shim.Error("Incorrect number of arguments. Expecting 1") 195 | } 196 | 197 | A := args[1] 198 | 199 | // Delete the key from the state in ledger 200 | err := stub.DelState(A) 201 | if err != nil { 202 | return shim.Error("Failed to delete state") 203 | } 204 | 205 | return shim.Success(nil) 206 | } 207 | 208 | // Query callback representing the query of a chaincode 209 | func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response { 210 | var A string // Entities 211 | var err error 212 | 213 | if len(args) != 2 { 214 | return shim.Error(fmt.Sprintf("Incorrect number of arguments: %v", args)) 215 | } 216 | 217 | A = args[1] 218 | 219 | // Get the state from the ledger 220 | Avalbytes, err := stub.GetState(A) 221 | if err != nil { 222 | jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}" 223 | return shim.Error(jsonResp) 224 | } 225 | 226 | if Avalbytes == nil { 227 | jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}" 228 | return shim.Error(jsonResp) 229 | } 230 | 231 | jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}" 232 | fmt.Printf("Query Response:%s\n", jsonResp) 233 | return shim.Success(Avalbytes) 234 | } 235 | 236 | func (t *SimpleChaincode) put(stub shim.ChaincodeStubInterface, args []string) pb.Response { 237 | if len(args) != 2 { 238 | return shim.Error("Invalid args. Expecting key and value") 239 | } 240 | 241 | key := args[0] 242 | value := args[1] 243 | 244 | existingValue, err := stub.GetState(key) 245 | if err != nil { 246 | return shim.Error(fmt.Sprintf("Error getting data for key [%s]: %s", key, err)) 247 | } 248 | if existingValue != nil { 249 | value = string(existingValue) + "-" + value 250 | } 251 | 252 | if err := stub.PutState(key, []byte(value)); err != nil { 253 | return shim.Error(fmt.Sprintf("Error putting data for key [%s]: %s", key, err)) 254 | } 255 | 256 | return shim.Success([]byte(value)) 257 | } 258 | 259 | func (t *SimpleChaincode) get(stub shim.ChaincodeStubInterface, args []string) pb.Response { 260 | if len(args) != 1 { 261 | return shim.Error("Invalid args. Expecting key") 262 | } 263 | 264 | key := args[0] 265 | 266 | value, err := stub.GetState(key) 267 | if err != nil { 268 | return shim.Error(fmt.Sprintf("Error getting data for key [%s]: %s", key, err)) 269 | } 270 | 271 | return shim.Success([]byte(value)) 272 | } 273 | 274 | func main() { 275 | err := shim.Start(new(SimpleChaincode)) 276 | if err != nil { 277 | fmt.Printf("Error starting Simple chaincode: %s", err) 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /fabric-cli/test/fixtures/testdata/src/go.mod: -------------------------------------------------------------------------------- 1 | // Copyright SecureKey Technologies Inc. All Rights Reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | module github.com/securekey/fabric-examples/test/cc 6 | 7 | require github.com/hyperledger/fabric v1.4.0 8 | 9 | go 1.13 10 | -------------------------------------------------------------------------------- /fabric-cli/test/fixtures/testdata/src/go.sum: -------------------------------------------------------------------------------- 1 | github.com/hyperledger/fabric v1.4.0/go.mod h1:tGFAOCT696D3rG0Vofd2dyWYLySHlh0aQjf7Q1HAju0= 2 | -------------------------------------------------------------------------------- /fabric-cli/test/integration/fabric-cli_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package integration 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | "strings" 13 | "testing" 14 | 15 | clicmd "github.com/securekey/fabric-examples/fabric-cli/cmd" 16 | ) 17 | 18 | // 19 | // Test cases that can run (and debugged) from an IDE 20 | // 21 | 22 | func run(cmd string) { 23 | os.Args = strings.Split(cmd, " ") 24 | os.Setenv("GRPC_TRACE", "all") 25 | os.Setenv("GRPC_VERBOSITY", "DEBUG") 26 | os.Setenv("GRPC_GO_LOG_SEVERITY_LEVEL", "INFO") 27 | clicmd.Execute() 28 | } 29 | 30 | func header(h string) { 31 | fmt.Println("****************************************") 32 | fmt.Println("*") 33 | fmt.Printf("* %s\n", h) 34 | fmt.Println("*") 35 | fmt.Println("****************************************") 36 | } 37 | 38 | //// ********** Create a channel ************ //// 39 | 40 | func TestCreate_a_channel(t *testing.T) { 41 | header("Create a channel") 42 | run("fabric-cli channel create --cid mychannel --txfile ../fixtures/fabric/v1.1/channel/mychannel.tx --config ../fixtures/config/config_test_local.yaml") 43 | } 44 | 45 | //// ********** Join a channel ************ //// 46 | 47 | func TestJoin_org1_peer_to_a_channel(t *testing.T) { 48 | header("Join a peer to a channel") 49 | run("fabric-cli.go channel join --cid mychannel --peer localhost:7051 --config ../fixtures/config/config_test_local.yaml") 50 | } 51 | 52 | func TestJoin_org2_peer_to_a_channel(t *testing.T) { 53 | header("Join a peer to a channel") 54 | run("fabric-cli.go channel join --cid mychannel --peer localhost:8051 --config ../fixtures/config/config_test_local.yaml") 55 | } 56 | 57 | func TestJoin_all_peers_in_org1_to_a_channel(t *testing.T) { 58 | header("Join all peers in org1 to a channel") 59 | run("fabric-cli.go channel join --cid mychannel --orgid org1 --config ../fixtures/config/config_test_local.yaml") 60 | } 61 | 62 | func TestJoin_all_peers_in_org2_to_a_channel(t *testing.T) { 63 | header("Join all peers in org1 to a channel") 64 | run("fabric-cli.go channel join --cid mychannel --orgid org2 --config ../fixtures/config/config_test_local.yaml") 65 | } 66 | 67 | func TestJoin_all_peers_to_a_channel(t *testing.T) { 68 | header("Join all peers to a channel") 69 | run("fabric-cli.go channel join --cid mychannel --config ../fixtures/config/config_test_local.yaml") 70 | } 71 | 72 | //// ********** Install chaincode ************ //// 73 | 74 | func TestInstall_chaincode_on_all_peers_of_org1(t *testing.T) { 75 | header("Install chaincode on all peers of org1") 76 | 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") 77 | } 78 | 79 | func TestInstall_chaincode_on_all_peers_of_org2(t *testing.T) { 80 | header("Install chaincode on all peers of org2") 81 | 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") 82 | } 83 | 84 | func TestInstall_chaincode_on_all_peers(t *testing.T) { 85 | header("Install chaincode on all peers") 86 | 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") 87 | } 88 | 89 | func TestInstall_chaincode_on_all_peers_v1(t *testing.T) { 90 | header("Install chaincode on all peers") 91 | 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") 92 | } 93 | 94 | //// ********** Instantiate ************ //// 95 | 96 | func TestInstantiate_chaincode_with_default_endorsement_policy(t *testing.T) { 97 | header("Instantiate chaincode with default endorsement policy") 98 | 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") 99 | } 100 | 101 | func TestInstantiate_chaincode_with_specified_endorsement_policy(t *testing.T) { 102 | header("Instantiate chaincode with specified endorsement policy") 103 | 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") 104 | } 105 | 106 | func TestInstantiate_chaincode_with_specified_private_data_collection_configuration(t *testing.T) { 107 | header("Instantiate chaincode with specified private data collection configuration") 108 | 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") 109 | } 110 | 111 | //// ********** Upgrade chaincode to v1 ************ //// 112 | 113 | func TestUpgrade_chaincode_to_v1(t *testing.T) { 114 | header("Upgrade chaincode") 115 | //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") 116 | 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") 117 | } 118 | 119 | //// ********** Query channel ************ //// 120 | 121 | func TestQuery_info(t *testing.T) { 122 | header("Query info") 123 | run("fabric-cli.go query info --cid mychannel --config ../fixtures/config/config_test_local.yaml") 124 | } 125 | 126 | func TestQuery_block_by_block_number(t *testing.T) { 127 | header("Query block by block number") 128 | run("fabric-cli.go query block --cid mychannel --num 0 --config ../fixtures/config/config_test_local.yaml") 129 | } 130 | 131 | func TestQuery_block_by_hash(t *testing.T) { 132 | header("Query block by hash") 133 | // hash is the output of "query info" 134 | run("fabric-cli.go query block --cid mychannel --hash HnjHWaHuTr813ettkpL7LXRx20QxY3X9MVbJesGqs6o --config ../fixtures/config/config_test_local.yaml") 135 | } 136 | 137 | func TestQuery_block_output_in_JSON_format(t *testing.T) { 138 | header("Query block output in JSON format") 139 | run("fabric-cli.go query block --cid mychannel --num 0 --format json --config ../fixtures/config/config_test_local.yaml") 140 | } 141 | 142 | func TestQuery_transaction(t *testing.T) { 143 | header("Query transaction") 144 | run("fabric-cli.go query tx --cid mychannel --txid 711451464d26a5564fa7066f0d2acb513b79800d4e4b11e144492bb620155210 --config ../fixtures/config/config_test_local.yaml") 145 | } 146 | 147 | func TestQuery_channels_joined_by_a_peer(t *testing.T) { 148 | header("Query channels joined by a peer") 149 | run("fabric-cli.go query channels --peer localhost:7051 --config ../fixtures/config/config_test_local.yaml") 150 | } 151 | 152 | func TestQuery_installed_chaincodes_on_a_peer(t *testing.T) { 153 | header("Query installed chaincodes on a peer") 154 | run("fabric-cli.go query installed --peer localhost:7051 --config ../fixtures/config/config_test_local.yaml") 155 | } 156 | 157 | //// ********** Retrieve chaincode deployment info ************ //// 158 | 159 | func TestRetrieve_chaincode_deployment_info(t *testing.T) { 160 | header("Retrieve chaincode deployment info") 161 | run("fabric-cli.go chaincode info --cid mychannel --ccid ExampleCC --config ../fixtures/config/config_test_local.yaml") 162 | } 163 | 164 | //// ********** Query Chaincode ************ //// 165 | 166 | func TestQuery_chaincode_on_a_set_of_peers(t *testing.T) { 167 | header("Query chaincode on a set of peers") 168 | 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") 169 | } 170 | 171 | func TestQuery_chaincode_and_view_payloads_only(t *testing.T) { 172 | header("Query chaincode and view payloads only") 173 | 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") 174 | } 175 | 176 | //// ********** Invoke Chaincode ************ //// 177 | 178 | func TestInvoke_chaincode(t *testing.T) { 179 | header("Invoke chaincode") 180 | run("fabric-cli.go chaincode invoke --ccid=ExampleCC --args {\"Func\":\"move\",\"Args\":[\"A\",\"B\",\"1\"]} --config ../fixtures/config/config_test_local.yaml") 181 | } 182 | 183 | func TestInvoke_chaincode_5_times(t *testing.T) { 184 | header("Invoke chaincode 5 times") 185 | run("fabric-cli.go chaincode invoke --ccid=ExampleCC --args {\"Func\":\"move\",\"Args\":[\"A\",\"B\",\"1\"]} --iterations 5 --config ../fixtures/config/config_test_local.yaml") 186 | } 187 | 188 | func TestInvoke_chaincode_100_times_in_8_Go_routines(t *testing.T) { 189 | header("Invoke chaincode 100 times in 8 Go routines with 3 attempts for each invocation (in case the invocation fails)") 190 | 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") 191 | } 192 | 193 | func TestInvoke_chaincode_with_two_sets_of_args(t *testing.T) { 194 | 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)") 195 | 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") 196 | } 197 | 198 | func TestInvoke_chaincode_using_dynamic_selection_provider(t *testing.T) { 199 | header("Invoke chaincode using a 'dynamic' selection provider that chooses a minimal set of peers required to satisfy the endorsement policy of the chaincode:") 200 | 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") 201 | } 202 | 203 | //// ********** Events ************ //// 204 | 205 | func TestListen_for_block_events(t *testing.T) { 206 | header("Listen for block events (output in JSON)") 207 | run("fabric-cli.go event listenblock --format json --config ../fixtures/config/config_test_local.yaml") 208 | } 209 | 210 | func TestListen_for_filtered_block_events(t *testing.T) { 211 | header("Listen for filtered block events (output in JSON)") 212 | run("fabric-cli.go event listenfilteredblock --format json --config ../fixtures/config/config_test_local.yaml") 213 | } 214 | 215 | func TestListen_for_chaincode_events(t *testing.T) { 216 | header("Listen for chaincode events") 217 | run("fabric-cli.go event listencc --ccid=ExampleCC --event=testEvent --config ../fixtures/config/config_test_local.yaml") 218 | } 219 | -------------------------------------------------------------------------------- /fabric-cli/test/integration/go.mod: -------------------------------------------------------------------------------- 1 | // Copyright SecureKey Technologies Inc. All Rights Reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | module github.com/securekey/fabric-examples/integration 6 | 7 | require github.com/securekey/fabric-examples/fabric-cli v0.0.0 8 | 9 | replace github.com/securekey/fabric-examples/fabric-cli v0.0.0 => ../../../fabric-cli/cmd/fabric-cli 10 | 11 | go 1.13 12 | -------------------------------------------------------------------------------- /fabric-cli/test/integration/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 3 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 4 | github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= 5 | github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= 6 | github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= 7 | github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= 8 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= 9 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 10 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 11 | github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= 12 | github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5 h1:PqZ3bA4yzwywivzk7PBQWngJp2/PAS0bWRZerKteicY= 13 | github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= 14 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 16 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 17 | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= 18 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 19 | github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= 20 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 21 | github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= 22 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 23 | github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= 24 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 25 | github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= 26 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 27 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 28 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 29 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 30 | github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= 31 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 32 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= 33 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 34 | github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= 35 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 36 | github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93 h1:qdfmdGwtm13OVx+AxguOWUTbgmXGn2TbdUHipo3chMg= 37 | github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= 38 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 39 | github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce h1:xdsDDbiBDQTKASoGEZ+pEmF1OnWuu8AQ9I8iNbHNeno= 40 | github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= 41 | github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= 42 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 43 | github.com/hyperledger/fabric-lib-go v1.0.0 h1:UL1w7c9LvHZUSkIvHTDGklxFv2kTeva1QI2emOVc324= 44 | github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= 45 | github.com/hyperledger/fabric-protos-go v0.0.0-20190821180310-6b6ac9042dfd h1:z0IbaMd4Ry2Cmmxujzy4UDgCUsT/0dOqqoGtOcvDw9Q= 46 | github.com/hyperledger/fabric-protos-go v0.0.0-20190821180310-6b6ac9042dfd/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= 47 | github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= 48 | github.com/hyperledger/fabric-protos-go v0.0.0-20191204195335-3ddf3f16d6cf/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= 49 | github.com/hyperledger/fabric-sdk-go v1.0.0-alpha5.0.20190827185549-6c3f788a32f8 h1:VUal7sIRsOAO8KBIcStUTEmda41y5eTbZhQfHRDq4Uk= 50 | github.com/hyperledger/fabric-sdk-go v1.0.0-alpha5.0.20190827185549-6c3f788a32f8/go.mod h1:H5Atl/PpXhEKYYShSLFElohDoB11o4/R0OwBxOs7hcM= 51 | github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20190930220855-cea2ffaf627c/go.mod h1:i8yJ9t8i1fGe7opUcq6uESxhruMJNXlc+Rx9ooBZsYg= 52 | github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20191219180315-e1055f391525/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE= 53 | github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200106161850-8f3d32c9d1a6/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE= 54 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 55 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 56 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= 57 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 58 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 59 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 60 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 61 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 62 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 63 | github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 64 | github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= 65 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 66 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 67 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 68 | github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27 h1:XA/VH+SzpYyukhgh7v2mTp8rZoKKITXR/x3FIizVEXs= 69 | github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27/go.mod h1:WCBAbTOdfhHhz7YXujeZMF7owC4tPb1naKFsgfUISjo= 70 | github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 71 | github.com/mitchellh/mapstructure v0.0.0-20180511142126-bb74f1db0675 h1:/rdJjIiKG5rRdwG5yxHmSE/7ZREjpyC0kL7GxGT/qJw= 72 | github.com/mitchellh/mapstructure v0.0.0-20180511142126-bb74f1db0675/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 73 | github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= 74 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 75 | github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I= 76 | github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 77 | github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 78 | github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= 79 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 80 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 81 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 82 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 83 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 84 | github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8= 85 | github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 86 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= 87 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 88 | github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 89 | github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54= 90 | github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 91 | github.com/prometheus/procfs v0.0.0-20180705121852-ae68e2d4c00f/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 92 | github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7 h1:NgR6WN8nQ4SmFC1sSUHY8SriLuWCZ6cCIQtH4vDZN3c= 93 | github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 94 | github.com/securekey/fabric-examples v0.0.0-20190226225026-644fda76ee3b h1:hUFS/EkSw2bclWJ5nNpYYijbQhZIOxqGb74AR3RkfF4= 95 | github.com/securekey/fabric-examples v0.0.0-20190226225026-644fda76ee3b/go.mod h1:TFB0Em4NQmx/PNpsdoJxqRwdS9j70aGbdTL/pqgc8DE= 96 | github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 97 | github.com/spf13/afero v1.1.1 h1:Lt3ihYMlE+lreX1GS4Qw4ZsNpYQLxIXKBTEOXm3nt6I= 98 | github.com/spf13/afero v1.1.1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 99 | github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg= 100 | github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= 101 | github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= 102 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 103 | github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec h1:2ZXvIUGghLpdTVHR1UfvfrzoVlZaE/yOWC5LueIHZig= 104 | github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 105 | github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= 106 | github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 107 | github.com/spf13/viper v1.0.2 h1:Ncr3ZIuJn322w2k1qmzXDnkLAdQMlJqBa9kfAH+irso= 108 | github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= 109 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 110 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= 111 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 112 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= 113 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 114 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 115 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 116 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 117 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 118 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 119 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 120 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 121 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= 122 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 123 | golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= 124 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 125 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 126 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 127 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 128 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 129 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 130 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 131 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= 132 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 133 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= 134 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 135 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 136 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 137 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 138 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 139 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 140 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 141 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 142 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 143 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 144 | google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d h1:XB2jc5XQ9uhizGTS2vWcN01bc4dI6z3C4KY5MQm8SS8= 145 | google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 146 | google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= 147 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 148 | google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= 149 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 150 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 151 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 152 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 153 | gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= 154 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 155 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 156 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 157 | gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= 158 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 159 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 160 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 161 | --------------------------------------------------------------------------------