github.com/yous1230/fabric@v2.0.0-beta.0.20191224111736-74345bee6ac2+incompatible/internal/peer/lifecycle/chaincode/querycommitted.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package chaincode 8 9 import ( 10 "context" 11 "fmt" 12 "io" 13 "os" 14 "sort" 15 "strings" 16 17 "github.com/golang/protobuf/proto" 18 cb "github.com/hyperledger/fabric-protos-go/common" 19 pb "github.com/hyperledger/fabric-protos-go/peer" 20 lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" 21 "github.com/hyperledger/fabric/bccsp" 22 "github.com/hyperledger/fabric/protoutil" 23 "github.com/pkg/errors" 24 "github.com/spf13/cobra" 25 "github.com/spf13/viper" 26 ) 27 28 // CommittedQuerier holds the dependencies needed to query 29 // the committed chaincode definitions 30 type CommittedQuerier struct { 31 Command *cobra.Command 32 Input *CommittedQueryInput 33 EndorserClient EndorserClient 34 Signer Signer 35 Writer io.Writer 36 } 37 38 type CommittedQueryInput struct { 39 ChannelID string 40 Name string 41 OutputFormat string 42 } 43 44 // QueryCommittedCmd returns the cobra command for 45 // querying a committed chaincode definition given 46 // the chaincode name 47 func QueryCommittedCmd(c *CommittedQuerier, cryptoProvider bccsp.BCCSP) *cobra.Command { 48 chaincodeQueryCommittedCmd := &cobra.Command{ 49 Use: "querycommitted", 50 Short: "Query the committed chaincode definitions by channel on a peer.", 51 Long: "Query the committed chaincode definitions by channel on a peer. Optional: provide a chaincode name to query a specific definition.", 52 RunE: func(cmd *cobra.Command, args []string) error { 53 if c == nil { 54 ccInput := &ClientConnectionsInput{ 55 CommandName: cmd.Name(), 56 EndorserRequired: true, 57 ChannelID: channelID, 58 PeerAddresses: peerAddresses, 59 TLSRootCertFiles: tlsRootCertFiles, 60 ConnectionProfilePath: connectionProfilePath, 61 TLSEnabled: viper.GetBool("peer.tls.enabled"), 62 } 63 64 cc, err := NewClientConnections(ccInput, cryptoProvider) 65 if err != nil { 66 return err 67 } 68 69 cqInput := &CommittedQueryInput{ 70 ChannelID: channelID, 71 Name: chaincodeName, 72 OutputFormat: output, 73 } 74 75 c = &CommittedQuerier{ 76 Command: cmd, 77 EndorserClient: cc.EndorserClients[0], 78 Input: cqInput, 79 Signer: cc.Signer, 80 Writer: os.Stdout, 81 } 82 } 83 return c.Query() 84 }, 85 } 86 87 flagList := []string{ 88 "channelID", 89 "name", 90 "peerAddresses", 91 "tlsRootCertFiles", 92 "connectionProfile", 93 "output", 94 } 95 attachFlags(chaincodeQueryCommittedCmd, flagList) 96 97 return chaincodeQueryCommittedCmd 98 } 99 100 // Query returns the committed chaincode definition 101 // for a given channel and chaincode name 102 func (c *CommittedQuerier) Query() error { 103 if c.Command != nil { 104 // Parsing of the command line is done so silence cmd usage 105 c.Command.SilenceUsage = true 106 } 107 108 err := c.validateInput() 109 if err != nil { 110 return err 111 } 112 113 proposal, err := c.createProposal() 114 if err != nil { 115 return errors.WithMessage(err, "failed to create proposal") 116 } 117 118 signedProposal, err := signProposal(proposal, c.Signer) 119 if err != nil { 120 return errors.WithMessage(err, "failed to create signed proposal") 121 } 122 123 proposalResponse, err := c.EndorserClient.ProcessProposal(context.Background(), signedProposal) 124 if err != nil { 125 return errors.WithMessage(err, "failed to endorse proposal") 126 } 127 128 if proposalResponse == nil { 129 return errors.New("received nil proposal response") 130 } 131 132 if proposalResponse.Response == nil { 133 return errors.New("received proposal response with nil response") 134 } 135 136 if proposalResponse.Response.Status != int32(cb.Status_SUCCESS) { 137 return errors.Errorf("query failed with status: %d - %s", proposalResponse.Response.Status, proposalResponse.Response.Message) 138 } 139 140 if strings.ToLower(c.Input.OutputFormat) == "json" { 141 return c.printResponseAsJSON(proposalResponse) 142 } 143 return c.printResponse(proposalResponse) 144 } 145 146 func (c *CommittedQuerier) printResponseAsJSON(proposalResponse *pb.ProposalResponse) error { 147 if c.Input.Name != "" { 148 return printResponseAsJSON(proposalResponse, &lb.QueryChaincodeDefinitionResult{}, c.Writer) 149 } 150 return printResponseAsJSON(proposalResponse, &lb.QueryChaincodeDefinitionsResult{}, c.Writer) 151 } 152 153 // printResponse prints the information included in the response 154 // from the server as human readable plain-text. 155 func (c *CommittedQuerier) printResponse(proposalResponse *pb.ProposalResponse) error { 156 if c.Input.Name != "" { 157 result := &lb.QueryChaincodeDefinitionResult{} 158 err := proto.Unmarshal(proposalResponse.Response.Payload, result) 159 if err != nil { 160 return errors.Wrap(err, "failed to unmarshal proposal response's response payload") 161 } 162 fmt.Fprintf(c.Writer, "Committed chaincode definition for chaincode '%s' on channel '%s':\n", c.Input.Name, c.Input.ChannelID) 163 c.printSingleChaincodeDefinition(result) 164 c.printApprovals(result) 165 166 return nil 167 } 168 169 result := &lb.QueryChaincodeDefinitionsResult{} 170 err := proto.Unmarshal(proposalResponse.Response.Payload, result) 171 if err != nil { 172 return errors.Wrap(err, "failed to unmarshal proposal response's response payload") 173 } 174 fmt.Fprintf(c.Writer, "Committed chaincode definitions on channel '%s':\n", c.Input.ChannelID) 175 for _, cd := range result.ChaincodeDefinitions { 176 fmt.Fprintf(c.Writer, "Name: %s, ", cd.Name) 177 c.printSingleChaincodeDefinition(cd) 178 } 179 return nil 180 } 181 182 type ChaincodeDefinition interface { 183 GetVersion() string 184 GetSequence() int64 185 GetEndorsementPlugin() string 186 GetValidationPlugin() string 187 } 188 189 func (c *CommittedQuerier) printSingleChaincodeDefinition(cd ChaincodeDefinition) { 190 fmt.Fprintf(c.Writer, "Version: %s, Sequence: %d, Endorsement Plugin: %s, Validation Plugin: %s", cd.GetVersion(), cd.GetSequence(), cd.GetEndorsementPlugin(), cd.GetValidationPlugin()) 191 } 192 193 func (c *CommittedQuerier) printApprovals(qcdr *lb.QueryChaincodeDefinitionResult) { 194 orgs := []string{} 195 approved := qcdr.GetApprovals() 196 for org := range approved { 197 orgs = append(orgs, org) 198 } 199 sort.Strings(orgs) 200 201 approvals := "" 202 for _, org := range orgs { 203 approvals += fmt.Sprintf("%s: %t, ", org, approved[org]) 204 } 205 approvals = strings.TrimSuffix(approvals, ", ") 206 207 fmt.Fprintf(c.Writer, ", Approvals: [%s]\n", approvals) 208 } 209 210 func (c *CommittedQuerier) validateInput() error { 211 if c.Input.ChannelID == "" { 212 return errors.New("channel name must be specified") 213 } 214 215 return nil 216 } 217 218 func (c *CommittedQuerier) createProposal() (*pb.Proposal, error) { 219 var function string 220 var args proto.Message 221 222 if c.Input.Name != "" { 223 function = "QueryChaincodeDefinition" 224 args = &lb.QueryChaincodeDefinitionArgs{ 225 Name: c.Input.Name, 226 } 227 } else { 228 function = "QueryChaincodeDefinitions" 229 args = &lb.QueryChaincodeDefinitionsArgs{} 230 } 231 232 argsBytes, err := proto.Marshal(args) 233 if err != nil { 234 return nil, errors.Wrap(err, "failed to marshal args") 235 } 236 ccInput := &pb.ChaincodeInput{Args: [][]byte{[]byte(function), argsBytes}} 237 238 cis := &pb.ChaincodeInvocationSpec{ 239 ChaincodeSpec: &pb.ChaincodeSpec{ 240 ChaincodeId: &pb.ChaincodeID{Name: lifecycleName}, 241 Input: ccInput, 242 }, 243 } 244 245 signerSerialized, err := c.Signer.Serialize() 246 if err != nil { 247 return nil, errors.WithMessage(err, "failed to serialize identity") 248 } 249 250 proposal, _, err := protoutil.CreateProposalFromCIS(cb.HeaderType_ENDORSER_TRANSACTION, c.Input.ChannelID, cis, signerSerialized) 251 if err != nil { 252 return nil, errors.WithMessage(err, "failed to create ChaincodeInvocationSpec proposal") 253 } 254 255 return proposal, nil 256 }